Search code examples
javawebsocketjettyembedded-jettyatmosphere

Running a Websocket connexion with an embedded atmosphere and jersey servlet


I am trying to get an instance of Atmosphere to run as a servlet without using a Web.xml and using the WebSocket functionnality.

It seems that the mapping is not working, because I am able to connect to the server (localhost:8080) and the JavaScript tells me that the WS connection is working, but the handler is not being recognized (methods are never called). The WebSocketHandlerAdapter seems to be never used by AtmosphereServlet.

All the examples I found were using a Web.xml to setup the servlets, but I need to be able to instantiate my servlets (Atmosphere and Jersey in a Jetty container) programmatically.

I have been using this example Atmosphere Websocket Chat for the WebSocketHandlerAdapter setup and Jersey Atmosphere Servlet to instantiate my servlets in Jetty.

Here is my code to instantiate my server / servlets :

public Server create() throws Exception {
    logger.info("creating http server");
    Server server = new Server();
    server.setStopAtShutdown(true);

    // configure http
    SelectChannelConnector httpConnector = new SelectChannelConnector();
    httpConnector.setPort(config.getHttpPort());
    server.setConnectors(new Connector[] { httpConnector });

    handlers = new HandlerCollection();
    handlers.setServer(server);
    handlers.addHandler(createLoggingHandler());
    handlers.addHandler(createFileHandler());
    handlers.addHandler(createJerseyRestServletHandler());
    server.setHandler(handlers);
    return server;
}

private ServletContextHandler createJerseyRestServletHandler() {
    ServletHolder atmosphereHolder = initAtmosphereServletHolder();
    ServletHolder jerseyHolder = initJerseyServletHolder();

    // atmosphere
    atmosphereHolder.setInitParameter("org.atmosphere.useWebSocket", "true");
    atmosphereHolder.setInitParameter("WebSocketProtocol", "ChatAtmosphereHandler");
    atmosphereHolder.setAsyncSupported(true);

    FilterHolder filterHolder = new FilterHolder(CrossOriginFilter.class);
    filterHolder.setInitParameter("allowedOrigins", "*");
    filterHolder.setInitParameter("allowedMethods", "GET, POST");

    ServletContextHandler servletHandler = new ServletContextHandler(handlers, "/");
    servletHandler.addServlet(atmosphereHolder, "/websocket/*");
    servletHandler.addServlet(jerseyHolder, "/jersey/*");
    servletHandler.addFilter(filterHolder, "/*", null);

    return servletHandler;
}

private ServletHolder initJerseyServletHolder() {
        ...
}

private ServletHolder initAtmosphereServletHolder() {
    AtmosphereServlet atmosServlet = new AtmosphereServlet();
    ServletHolder atmosphere = new ServletHolder(atmosServlet);

    return atmosphere;
}

handler websocket :

@WebSocketHandlerService(path = "/websocket", broadcaster = SimpleBroadcaster.class)
public class ChatAtmosphereHandler extends WebSocketHandlerAdapter {

private final ObjectMapper mapper = new ObjectMapper();

@Override
public void onOpen(WebSocket webSocket) throws IOException {
    System.out.println("on Open");
    webSocket.resource().setBroadcaster(BroadcasterFactory.getDefault().lookup("/websocket", true));
}

public void onTextMessage(WebSocket webSocket, String message) throws IOException {
    System.out.println("on Message");
    AtmosphereResource r = webSocket.resource();
    Broadcaster b = r.getBroadcaster();
    b.broadcast(mapper.writeValueAsString(mapper.readValue(message, Data.class)));
}

public final static class Data {

    private String message;
    private String author;
    private long time;

    public Data() {
        this("", "");
    }

    public Data(String author, String message) {
        this.author = author;
        this.message = message;
        this.time = new Date().getTime();
    }

    public String getMessage() {
        return message;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

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

    public long getTime() {
        return time;
    }

    public void setTime(long time) {
        this.time = time;
    }
}
}

And finally the pom.xml

        <dependency>
        <groupId>org.eclipse.jetty</groupId>
        <artifactId>jetty-servlets</artifactId>
        <version>7.6.4.v20120524</version>
    </dependency>
    <dependency>
        <groupId>org.eclipse.jetty</groupId>
        <artifactId>jetty-websocket</artifactId>
        <version>7.6.4.v20120524</version>
    </dependency>
    <dependency>
        <groupId>eu.infomas</groupId>
        <artifactId>annotation-detector</artifactId>
        <version>3.0.0</version>
    </dependency>
    <dependency>
        <groupId>org.codehaus.jackson</groupId>
        <artifactId>jackson-mapper-asl</artifactId>
        <version>1.9.3</version>
    </dependency>
    <dependency>
        <groupId>org.atmosphere</groupId>
        <artifactId>atmosphere-annotations</artifactId>
        <version>1.1.0.beta3</version>
    </dependency>
    <dependency>
        <groupId>org.atmosphere</groupId>
        <artifactId>atmosphere-jersey</artifactId>
        <version>1.1.0.beta3</version>
    </dependency>
    <dependency>
        <groupId>org.atmosphere</groupId>
        <artifactId>atmosphere-commons</artifactId>
        <version>0.6.5</version>
    </dependency>

Solution

  • I'm the Atmosphere lead.

    Can you paste your server's log? Also, the URL should be localhost:8080/websocket/<something> for connecting.

    Second, why are you defining Jersey Servlet? You don't need that with Atmosphere, so just define AtmosphereServlet.

    If you can, jump on the mailing list for more information.