简体   繁体   中英

Implementing Grizzly Websockets with Glassfish 3.1.2 and Spring

I'm trying to add web-socket notifications to an old application running on Glassfish 3.1.2 and Spring 4.1.5-RELEASE. Implementing Spring's websockets is not working because it needs GlassFish 4.1+ and we cannot upgrade the application server. I'm using Grizzly web-sockets 1.9.x and I created a very basic @Component extending the WebSocketApplication class and implementing bean-events-related interfaces. Here is the object

@Component
public class CCMarshaller extends WebSocketApplication implements InitializingBean, DisposableBean   {

    private static final String TOPIC = "/realtime-channel";

    @Override
    public WebSocket createWebSocket(ProtocolHandler protocolHandler, WebSocketListener... listeners) {
        return new DefaultWebSocket(protocolHandler, listeners);
    }

    @Override
    public boolean isApplicationRequest(Request request) {
        final String uri = request.requestURI().toString();
        return uri.endsWith(TOPIC);
    }

    /* Test */
    @Override
    public void onMessage(WebSocket socket, String text) {
        EventDto e = new EventDto();
        e.setId(45);
        broadcast(e);
    }

    private void broadcast(EventDto evt) {
        for (WebSocket webSocket : getWebSockets()) {
            if (!webSocket.isConnected()) {
               continue;
            }
            try {
                ObjectMapper mapper = new ObjectMapper();
                webSocket.send(mapper.writeValueAsString(evt));
            } catch (WebSocketException e) {
                e.printStackTrace();
                webSocket.close();
            } catch (JsonProcessingException e) {
                e.printStackTrace();
                webSocket.close();
            }
        }
    }


    @Override
    public void afterPropertiesSet() throws Exception {
        WebSocketEngine.getEngine().register(this);
    }


    @Override
    public void destroy() throws Exception {
        WebSocketEngine.getEngine().unregister(this);
    }

}

I'm pretty new to Spring world, but my understanding of lifecycle of this bean is (approx): (1) singleton creation at startup, (2) then the framework calls afterPropertiesSet, (3) which registers the WebSocketApplication object (this) and (4) every request to /realtime-channel will be handled by WebSocketApplication calling the OnMessage callback. The broadcast function is an helper for broadcasting an object to all connected sockets (object is converted to json).

It works... for a while :)

When the application starts I can login and navigate the first page where the javascript connection is done with few lines of code:

var WSManager = {
        url: 'ws://' + window.location.host + '/realtime-channel',
        init: function() {
            websocket = new WebSocket(WSManager.url);
            websocket.onmessage = function (evt) {
                // process message with jquery
            };
        }
    };
WSManager.init();

after the client is connected via websocket, the application can send messages and receives (in broadcast) object, so it's working good. Even if i connect with other websocket test tools ot's working good. The problem arises when I try to navigate to other pages (pure Spring navigation). The application hangs and server.log shows the following messages:

[#|2017-11-24T13:36:32.350+0100|WARNING|glassfish3.1.2|javax.enterprise.system.container.web.com.sun.enterprise.web|_ThreadID=139;_ThreadName=Thread-2;|StandardWrapperValve[mvc-dispatcher]: PWC1406: Servlet.service() for servlet mvc-dispatcher threw exception
java.lang.NullPointerException
    at org.apache.catalina.connector.Request.setAttribute(Request.java:1688)
    at org.apache.catalina.connector.RequestFacade.setAttribute(RequestFacade.java:570)
    at org.springframework.web.context.request.async.WebAsyncUtils.getAsyncManager(WebAsyncUtils.java:49)
    at org.springframework.web.servlet.DispatcherServlet.processDispatchResult(DispatcherServlet.java:1023)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:955)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:877)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:966)
    at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:857)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:668)
    at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:842)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:770)
    at org.apache.catalina.core.StandardWrapper.service(StandardWrapper.java:1542)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:281)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
    at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:655)
    at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:595)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:161)
    at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:331)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:231)
    at com.sun.enterprise.v3.services.impl.ContainerMapper$AdapterCallable.call(ContainerMapper.java:317)
    at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:195)
    at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:849)
    at com.sun.grizzly.arp.DefaultAsyncExecutor.execute(DefaultAsyncExecutor.java:159)
    at com.sun.grizzly.arp.DefaultAsyncExecutor.interrupt(DefaultAsyncExecutor.java:145)
    at com.sun.grizzly.arp.AsyncProcessorTask.doTask(AsyncProcessorTask.java:102)
    at com.sun.grizzly.http.TaskBase.run(TaskBase.java:193)
    at com.sun.grizzly.http.TaskBase.execute(TaskBase.java:175)
    at com.sun.grizzly.arp.DefaultAsyncHandler.handle(DefaultAsyncHandler.java:145)
    at com.sun.grizzly.arp.AsyncProtocolFilter.execute(AsyncProtocolFilter.java:210)
    at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:137)
    at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:104)
    at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:90)
    at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:79)
    at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:54)
    at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:59)
    at com.sun.grizzly.ContextTask.run(ContextTask.java:71)
    at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:532)
    at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:513)
    at java.lang.Thread.run(Thread.java:745)
|#]

[#|2017-11-24T13:36:32.351+0100|SEVERE|glassfish3.1.2|org.apache.catalina.connector.CoyoteAdapter|_ThreadID=139;_ThreadName=Thread-2;|PWC3989: An exception or error occurred in the container during the request processing
java.lang.NullPointerException
    at org.apache.catalina.connector.Request.setAttribute(Request.java:1688)
    at org.apache.catalina.connector.RequestFacade.setAttribute(RequestFacade.java:570)
    at org.apache.catalina.core.StandardWrapperValve.exception(StandardWrapperValve.java:465)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:335)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:175)
    at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:655)
    at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:595)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:161)
    at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:331)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:231)
    at com.sun.enterprise.v3.services.impl.ContainerMapper$AdapterCallable.call(ContainerMapper.java:317)
    at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:195)
    at com.sun.grizzly.http.ProcessorTask.invokeAdapter(ProcessorTask.java:849)
    at com.sun.grizzly.arp.DefaultAsyncExecutor.execute(DefaultAsyncExecutor.java:159)
    at com.sun.grizzly.arp.DefaultAsyncExecutor.interrupt(DefaultAsyncExecutor.java:145)
    at com.sun.grizzly.arp.AsyncProcessorTask.doTask(AsyncProcessorTask.java:102)
    at com.sun.grizzly.http.TaskBase.run(TaskBase.java:193)
    at com.sun.grizzly.http.TaskBase.execute(TaskBase.java:175)
    at com.sun.grizzly.arp.DefaultAsyncHandler.handle(DefaultAsyncHandler.java:145)
    at com.sun.grizzly.arp.AsyncProtocolFilter.execute(AsyncProtocolFilter.java:210)
    at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:137)
    at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:104)
    at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:90)
    at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:79)
    at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:54)
    at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:59)
    at com.sun.grizzly.ContextTask.run(ContextTask.java:71)
    at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:532)
    at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:513)
    at java.lang.Thread.run(Thread.java:745)
|#]

[#|2017-11-24T13:36:32.354+0100|SEVERE|glassfish3.1.2|com.sun.grizzly.config.GrizzlyServiceListener|_ThreadID=139;_ThreadName=Thread-2;|java.lang.NullPointerException
    at com.sun.grizzly.arp.AsyncProcessorTask.obtainAndSetThreadAttachment(AsyncProcessorTask.java:230)
    at com.sun.grizzly.arp.AsyncProcessorTask.enableTimeout(AsyncProcessorTask.java:223)
    at com.sun.grizzly.arp.AsyncProcessorTask.doTask(AsyncProcessorTask.java:127)
    at com.sun.grizzly.http.TaskBase.run(TaskBase.java:193)
    at com.sun.grizzly.http.TaskBase.execute(TaskBase.java:175)
    at com.sun.grizzly.arp.DefaultAsyncHandler.handle(DefaultAsyncHandler.java:145)
    at com.sun.grizzly.arp.AsyncProtocolFilter.execute(AsyncProtocolFilter.java:210)
    at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:137)
    at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:104)
    at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:90)
    at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:79)
    at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:54)
    at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:59)
    at com.sun.grizzly.ContextTask.run(ContextTask.java:71)
    at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:532)
    at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:513)
    at java.lang.Thread.run(Thread.java:745)
|#]

[#|2017-11-24T13:36:32.354+0100|INFO|glassfish3.1.2|com.sun.grizzly.config.GrizzlyServiceListener|_ThreadID=139;_ThreadName=Thread-2;|Processor exception
java.lang.RuntimeException: java.lang.NullPointerException
    at com.sun.grizzly.arp.AsyncProcessorTask.doTask(AsyncProcessorTask.java:140)
    at com.sun.grizzly.http.TaskBase.run(TaskBase.java:193)
    at com.sun.grizzly.http.TaskBase.execute(TaskBase.java:175)
    at com.sun.grizzly.arp.DefaultAsyncHandler.handle(DefaultAsyncHandler.java:145)
    at com.sun.grizzly.arp.AsyncProtocolFilter.execute(AsyncProtocolFilter.java:210)
    at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:137)
    at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:104)
    at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:90)
    at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:79)
    at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:54)
    at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:59)
    at com.sun.grizzly.ContextTask.run(ContextTask.java:71)
    at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:532)
    at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:513)
    at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.NullPointerException
    at com.sun.grizzly.arp.AsyncProcessorTask.obtainAndSetThreadAttachment(AsyncProcessorTask.java:230)
    at com.sun.grizzly.arp.AsyncProcessorTask.enableTimeout(AsyncProcessorTask.java:223)
    at com.sun.grizzly.arp.AsyncProcessorTask.doTask(AsyncProcessorTask.java:127)
    ... 14 more
|#]

I already launched this command on glassfish:

asadmin set configs.config.server-config.network-config.protocols.protocol.http-listener-1.http.websockets-support-enabled=true

It seems that somewhere Spring is loosing the REQUEST object, that seems to be null. Maybe there is some sort of configuration I have to do in web.xml file related to the URL /realtime-channel?

If I remove the websocket registration WebSocketEngine.getEngine().register(this); everything works fine, but the websocket, of course, does not work anymore.

OTHER EXCEPTIONS

Sometimes the application throws other exceptions as well:

[#|2017-11-24T14:47:11.655+0100|SEVERE|glassfish3.1.2|com.sun.grizzly.config.GrizzlyServiceListener|_ThreadID=123;_ThreadName=Thread-2;|java.lang.NullPointerException
    at com.sun.grizzly.arp.AsyncProcessorTask.obtainAndSetThreadAttachment(AsyncProcessorTask.java:230)
    at com.sun.grizzly.arp.AsyncProcessorTask.enableTimeout(AsyncProcessorTask.java:223)
    at com.sun.grizzly.arp.AsyncProcessorTask.doTask(AsyncProcessorTask.java:127)
    at com.sun.grizzly.http.TaskBase.run(TaskBase.java:193)
    at com.sun.grizzly.http.TaskBase.execute(TaskBase.java:175)
    at com.sun.grizzly.arp.DefaultAsyncHandler.handle(DefaultAsyncHandler.java:145)
    at com.sun.grizzly.arp.AsyncProtocolFilter.execute(AsyncProtocolFilter.java:210)
    at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:137)
    at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:104)
    at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:90)
    at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:79)
    at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:54)
    at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:59)
    at com.sun.grizzly.ContextTask.run(ContextTask.java:71)
    at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:532)
    at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:513)
    at java.lang.Thread.run(Thread.java:745)
|#]

[#|2017-11-24T14:47:11.657+0100|INFO|glassfish3.1.2|com.sun.grizzly.config.GrizzlyServiceListener|_ThreadID=123;_ThreadName=Thread-2;|Processor exception
java.lang.RuntimeException: java.lang.NullPointerException
    at com.sun.grizzly.arp.AsyncProcessorTask.doTask(AsyncProcessorTask.java:140)
    at com.sun.grizzly.http.TaskBase.run(TaskBase.java:193)
    at com.sun.grizzly.http.TaskBase.execute(TaskBase.java:175)
    at com.sun.grizzly.arp.DefaultAsyncHandler.handle(DefaultAsyncHandler.java:145)
    at com.sun.grizzly.arp.AsyncProtocolFilter.execute(AsyncProtocolFilter.java:210)
    at com.sun.grizzly.DefaultProtocolChain.executeProtocolFilter(DefaultProtocolChain.java:137)
    at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:104)
    at com.sun.grizzly.DefaultProtocolChain.execute(DefaultProtocolChain.java:90)
    at com.sun.grizzly.http.HttpProtocolChain.execute(HttpProtocolChain.java:79)
    at com.sun.grizzly.ProtocolChainContextTask.doCall(ProtocolChainContextTask.java:54)
    at com.sun.grizzly.SelectionKeyContextTask.call(SelectionKeyContextTask.java:59)
    at com.sun.grizzly.ContextTask.run(ContextTask.java:71)
    at com.sun.grizzly.util.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:532)
    at com.sun.grizzly.util.AbstractThreadPool$Worker.run(AbstractThreadPool.java:513)
    at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.NullPointerException
    at com.sun.grizzly.arp.AsyncProcessorTask.obtainAndSetThreadAttachment(AsyncProcessorTask.java:230)
    at com.sun.grizzly.arp.AsyncProcessorTask.enableTimeout(AsyncProcessorTask.java:223)
    at com.sun.grizzly.arp.AsyncProcessorTask.doTask(AsyncProcessorTask.java:127)
    ... 14 more
|#]

UPDATE

If I define a HandlerInterceptor for all the URLs and add breakpoints I can see that the exceptions are raising after the execution of preHandle hook and after the execution of postHandle hook (in both functions the HttpServletRequest object is valid).

几天后,我设法解决了使用Grizzly Framework 1.9.50升级到Glassfish Server 3.1.2.2的问题,因为Grizzly Framework 1.9.46似乎不适用于Web套接字。

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM