0

I have a @ServerEndpoint that adds web socket sessions and I want it to @Observes an event that will be fired by a servlet and then broadcast a message to all the web sockets.

I get a NullPointerException in my servlet when I try to use the event that was defined with @Inject. What am i doing wrong?

WebSocket Handler:

    import javax.ejb.Asynchronous;
    import javax.enterprise.event.Observes;
    import javax.enterprise.inject.Any;
    import javax.websocket.*;
    import javax.websocket.server.ServerEndpoint;
    import java.util.Collections;
    import java.util.HashSet;
    import java.util.Set;

    @ServerEndpoint("/events")
    public class WebSocketHandler
    {
        //This holds our sessions for async retrieval
        private static final Set<Session> sessions = Collections.synchronizedSet( new HashSet<Session>() );

        @OnOpen
        public void open(Session session)
        {
            //Add to our collection
            sessions.add( session );
        }

        @OnClose
        public void close(Session session, CloseReason closeReason)
        {
            //Just remove it
            sessions.remove( session );
        }

        ...elided...

        @Asynchronous
        public void notify(@Observes @Any TestEvent event)
        {
            synchronized( sessions )
            {
                //Loop through and send to all listeners
                for ( Session session : sessions )
                {
                    //Make sure it's still open
                    if ( session.isOpen() )
                    {
                        try
                        {
                            session.getBasicRemote().sendText( event.getMessage() );
                        }
                        catch (Exception e)
                        {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    }

Event type:

    import java.io.Serializable;

    public class TestEvent implements Serializable
    {
        private String message;

        public TestEvent()
        {
        }

        public TestEvent(String message)
        {
            this.message = message;
        }

        public void setMessage(String message)
        {
            this.message = message;
        }

        public String getMessage()
        {
            return message;
        }

        @Override
        public String toString()
        {
            return "TestEvent: " + message;
        }
    }

Servlet:

    import javax.ejb.Asynchronous;
    import javax.enterprise.event.Event;
    import javax.inject.Inject;
    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;

    @WebServlet("/broadcast")
    public class SendMessageServlet extends HttpServlet
    {
        @Inject
        Event<TestEvent> testEvent;

        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
        {
            //Fire the event (THIS "testEvent" IS NULL)
            testEvent.fire( new TestEvent( "{\"message\":\"An event occurred at " + System.currentTimeMillis() + "\",\"status\":200}" ) );
        }
    }

beans.xml:

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://java.sun.com/xml/ns/javaee"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="
        http://java.sun.com/xml/ns/javaee
        http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
    </beans>

pom.xml:

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>

        <groupId>groupId</groupId>
        <artifactId>TestWebSocket</artifactId>
        <version>1.0</version>

        <packaging>war</packaging>

        <!-- Tell Maven what language version to use -->
        <properties>
            <maven.compiler.source>1.8</maven.compiler.source>
            <maven.compiler.target>1.8</maven.compiler.target>
        </properties>

        <dependencies>

            <!-- Enables the annotations, etc needed -->
            <dependency>
                <groupId>javax</groupId>
                <artifactId>javaee-api</artifactId>
                <version>7.0</version>
            </dependency>

        </dependencies>

    </project>
Don Rhummy
  • 20,170
  • 31
  • 134
  • 252
  • What container are you deploying to? – John Ament May 29 '17 at 02:21
  • @JohnAment I realized I was not deploying to any CDI container. I was using Tomcat. I'm now using Weld and it works. Is there no reference CDI for JavaEE7? – Don Rhummy May 29 '17 at 04:57
  • Tomcat does not support CDI. You need to use a full Java EE server or you can install CDI/Weld in Tomcat. You can have a look at this thread : https://stackoverflow.com/questions/18995951/how-to-install-and-use-cdi-on-tomcat – Rouliboy May 29 '17 at 09:01
  • Or just take a peek at the original source of information - [Weld Docs about servlet intergration](http://docs.jboss.org/weld/reference/latest/en-US/html_single/#weld-servlet). Injection should work for you pretty well, however note that servlets/filters are non-contextual components - you can (amongst other things) inject into them, but you cannot place an observer there.On naother note - you are using `@Asynchronous` on a synchronous CDI observer. I kind of doubt this will work, you would be better on double checking on that (think I bumped into this already). – Siliarus May 29 '17 at 12:37
  • @Siliarus Is there a way to enable asynchronous CDI observing? – Don Rhummy May 29 '17 at 15:53
  • @Siliarus Would marking the ServerEndpoint as a Singleton make it asynchronous? – Don Rhummy May 29 '17 at 16:18
  • @Don Rhummy Well, if you are up to new stuff, CDI 2.0 has just been released and there you can `fireAsync()` and `@ObservesAsync`. In 1.2 I am afraid the answer is no. Did you try `@Asynchronous` in your app? It *might do something* but basically it is undefined so hard to tell. – Siliarus May 29 '17 at 16:25
  • @Siliarus Thank you. Do you know the Maven for CDI 2.0? – Don Rhummy May 29 '17 at 17:46
  • @Siliarus I tried using the maven dependencies for `weld-servlet-core` and `weld-core-impl` 3.0.0.Final and `cdi-api` 2.0 but still there's no fireAsync method available on `Event`. What maven dependencies do I need? – Don Rhummy May 29 '17 at 18:07
  • CDI API 2.0 for sure, the method is there, just [look at the src](https://github.com/cdi-spec/cdi/blob/2.0/api/src/main/java/javax/enterprise/event/Event.java#L124). As for Weld artifacts, use the same one you did before but in 3.0.0.Final version. – Siliarus May 30 '17 at 06:48

0 Answers0