-
New Feature
-
Resolution: Done
-
Normal
-
10.0.0, 9.6.5
-
None
-
None
User Story
As an developer, I want to use the ZK websocket and WebsocketServerPush in a Quarkus application.
Acceptance Criteria
Adding the WebsocketWebappInit to enable similar WS support as other environments
Details
Multiple failure points currently:
Quarkus appear to not trigger the WebsocketFilter, even though it is registered in the WebappInit
Quarkus wraps websocket requests in its own io.undertow.websockets.vertx.VertxWebSocketHttpExchange which always returns null when prompted for session, which means that no session is ever retrieved from Quarkus
Additional config info
In Quarkus / undertow, zk.xml must be deployed under src/main/resources/metainfo/zk/zk.xml
Quarkus / undertow doesn't start WS unless a WS config exist in Java code (not created during WebAppInit), so need to create a Dummy class (attached EnableWebsocket class) to enable WS support
Quarkus require a specific extra library to support WS
enable with quarkus command or in pom directly with
<dependency> <groupId>io.quarkus</groupId> <artifactId>quarkus-websockets</artifactId> </dependency>
Reopened with test case
Running manual websockets cause Error:
See sample zk-quarkus-ws-2.zip
2024-11-07 15:15:49,334 ERROR [io.und.web.request] (vert.x-eventloop-thread-0) UT026013: Unhandled error in annotated endpoint org.zkoss.foo.EchoServer@318be2a1: java.lang.IllegalStateException: Cannot use the basic remote from an IO thread at io.undertow.websockets.UndertowSession.getBasicRemote(UndertowSession.java:336) at org.zkoss.foo.EchoServer.onMessage(EchoServer.java:41) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.base/java.lang.reflect.Method.invoke(Method.java:568) at io.undertow.websockets.annotated.BoundMethod.invoke(BoundMethod.java:87) at io.undertow.websockets.annotated.AnnotatedEndpoint$2.onMessage(AnnotatedEndpoint.java:140) at io.undertow.websockets.FrameHandler$5.run(FrameHandler.java:355) at io.undertow.websockets.ServerWebSocketContainer$1.call(ServerWebSocketContainer.java:143) at io.undertow.websockets.ServerWebSocketContainer$1.call(ServerWebSocketContainer.java:140) at io.quarkus.websockets.client.runtime.WebsocketCoreRecorder$4$1.call(WebsocketCoreRecorder.java:181) at io.undertow.websockets.ServerWebSocketContainer.invokeEndpointMethod(ServerWebSocketContainer.java:536) at io.undertow.websockets.ServerWebSocketContainer.invokeEndpointMethod(ServerWebSocketContainer.java:525) at io.undertow.websockets.FrameHandler.invokeTextHandler(FrameHandler.java:335) at io.undertow.websockets.FrameHandler.onText(FrameHandler.java:250) at io.undertow.websockets.FrameHandler.processFrame(FrameHandler.java:156) at io.undertow.websockets.FrameHandler.channelRead0(FrameHandler.java:131) at io.undertow.websockets.FrameHandler.channelRead0(FrameHandler.java:61) at io.netty.channel.SimpleChannelInboundHandler.channelRead(SimpleChannelInboundHandler.java:99) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:444) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420) at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412) at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:346) at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:318) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:444) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420) at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412) at io.netty.handler.timeout.IdleStateHandler.channelRead(IdleStateHandler.java:289) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:442) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420) at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412) at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1407) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:440) at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420) at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:918) at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:166) at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:788) at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:724) at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:650) at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:562) at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:994) at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74) at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30) at java.base/java.lang.Thread.run(Thread.java:840)