Search code examples
websocketjetty-9

Jetty - stand alone WebSocket server


in these days I try to implement a WebSocket server by using Jetty.

I've created a Jetty project called "WebSocketServer" as demo-base in the distribution of Jetty 9.2.0.v20140526.

After that, I write some codes to implement the WebSocket mechanism and export all codes to a war file to push it to the webapps folder of "WebSocketServer". When I java -jar ..<jetty.home>/start.jar, it is all workable. But, after I create a new connection to this WebSocket project, there are some error codes happened.

java.lang.ClassCastException: org.eclipse.jetty.server.HttpConnection cannot be cast to org.eclipse.jetty.server.HttpConnection
at org.eclipse.jetty.websocket.server.WebSocketServerFactory.acceptWebSocket(WebSocketServerFactory.java:175)
at org.eclipse.jetty.websocket.server.WebSocketServerFactory.acceptWebSocket(WebSocketServerFactory.java:148)
at org.eclipse.jetty.websocket.servlet.WebSocketServlet.service(WebSocketServlet.java:151)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:751)
at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:566)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:143)
at org.eclipse.jetty.security.SecurityHandler.handle(SecurityHandler.java:578)
at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:221)
at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1111)
at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:498)
at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:183)
at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1045)
at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
at org.eclipse.jetty.server.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:199)
at org.eclipse.jetty.server.handler.HandlerCollection.handle(HandlerCollection.java:109)
at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:98)
at org.eclipse.jetty.server.Server.handle(Server.java:461)
at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:284)
at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:244)
at org.eclipse.jetty.io.AbstractConnection$2.run(AbstractConnection.java:534)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:607)
at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:536)
at java.lang.Thread.run(Thread.java:744)

I have no idea what's going on? The following codes are what I write to build a simple WebSocket server.

Servlet:

@SuppressWarnings("serial")
public class XYZWebSocketServlet extends WebSocketServlet{
    @Override
    public void configure(WebSocketServletFactory factory) {
        factory.getPolicy().setIdleTimeout(600000);
        factory.register(XYZWebSocketEvent.class);
    }
}

Event:

@WebSocket
public class XYZWebSocketEvent {
    private Session session;

    @OnWebSocketConnect
    public void onConnect(Session sess) {
        session = sess;

        // Get parameters while client connect to server
        Map<String,List<String>> parameters = session.getUpgradeRequest().getParameterMap();
        String encyptedID = parameters.get("ID").get(0);

        System.out.println("Connect: " + session.getRemoteAddress().getPort());
        try {
            session.setIdleTimeout(600000);
            session.getRemote().sendString("Hello!");
        } catch (IOException ioe) {
            ioe.printStackTrace();
        }
    }

    @OnWebSocketMessage
    public void onMessage(String message) {
            try {   
                session.getRemote().sendString("Message: " + message);
            }
            catch (Exception ex) {
            }
    }

    @OnWebSocketClose
    public void onClose(int statusCode, String reason) {
            try {
                session.getRemote().sendString("Close: statusCode=" + statusCode + ", reason=" +reason);
        }
            catch (Exception ex) {
            }
    }

    @OnWebSocketError
    public void onError(Throwable t) {
        System.out.println("Error: " + t.getMessage());
    }

    public Session getSession() {
        return this.session;
    }
}

web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app>
    <display-name>WebSocket application</display-name>
    <servlet>
        <servlet-name>XYZWebSocketServlet</servlet-name>
        <servlet-class>com.newKinpo.servlet.XYZWebSocketServlet</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>XYZWebSocketServlet</servlet-name>
        <url-pattern>/events/*</url-pattern>
    </servlet-mapping>
</web-app>

Is there something wrong? Thanks for your attention.


Solution

  • I had similiar problem and I have found the cause and the solution. Embeded jetty server is loaded by SUN class loader (will call it system class loader later) after webapp directory is scanned my app is loaded by WebApp class loader and when it comes to WebSocketServerFactory it is loaded by WebApp. However org.eclipse.jetty.server.HttpConnection object obtained from the request is loaded by the system class loader.

    According to https://wiki.eclipse.org/Jetty/Reference/Jetty_Classloading jetty websocket package is treated as system class package and shouldn't be loaded by the WebApp if already loaded by the system.

    The solution is to force loading of the package org.eclipse.jetty.websocket at the time jetty server is initialized.

    I just create dummy instance of WebSocketHandler for example. There are many options to force package loading but they are irrelevant to this question.