svk
svk

Reputation: 83

Jetty websocket class loading issue

I have implemented a basic websocket server in Jetty(Standalone mode).

MyWebSocketServlet.java

public class MyWebSocketServlet extends WebSocketServlet {

     @Override
     public void configure(WebSocketServletFactory webSocketServletFactory){

         webSocketServletFactory.getPolicy().setIdleTimeout(1000 * 10 * 60);
         webSocketServletFactory.setCreator(new MyWebSocketFactory());
     }
}

MyWebSocketFactory.java

public class MyWebSocketFactory implements WebSocketCreator {

    public Object createWebSocket(
        ServletUpgradeRequest servletUpgradeRequest
        , ServletUpgradeResponse servletUpgradeResponse) {

        return  new MyWebSocketListener();
    }
}

MyWebSocketListener.java

public class MyWebSocketListener implements WebSocketListener {
    private Session sessionInstance;

    public void onWebSocketBinary(byte[] bytes, int i, int i1) {
        ByteBuffer data = ByteBuffer.wrap(bytes, i, i1);
        try {
            sessionInstance.getRemote().sendBytes(data);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void onWebSocketClose(int i, String s) {
    }

    public void onWebSocketConnect(Session session) {
        sessionInstance = session;
    }

    public void onWebSocketError(Throwable throwable) {
        throwable.printStackTrace(System.err);
    }

    public void onWebSocketText(String s) {
        try {
            sessionInstance.getRemote().sendString(s);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app
   xmlns="http://xmlns.jcp.org/xml/ns/javaee"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
   metadata-complete="false"
   version="3.1">

    <servlet>
        <servlet-name>WsEcho</servlet-name>
        <servlet-class>org.test.sanket.MyWebSocketServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>WsEcho</servlet-name>
        <url-pattern>/echo/*</url-pattern>
    </servlet-mapping>
    <servlet>
        <servlet-name>HttpEcho</servlet-name>
        <servlet-class>org.test.sanket.MyHttpServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>HttpEcho</servlet-name>
        <url-pattern>/httpecho/*</url-pattern>
    </servlet-mapping>
</web-app>

Instead of using a Standalone Jetty if I use embedded jetty and programatically configure the server and add the Servlets then this sample runs fine.

But if I am packaging the same as a war, and then deploying the same in a standalone jetty instance I am having the following observation:

  1. I am able to hit the HttpServlet , i.e. MyHttpServlet and receive a response
  2. But when I try to hit the websocket servlet, i.e. MyWebSocketServlet, I am seeing the following error:

exception

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)

I did come across the following link: Jetty - stand alone WebSocket server

From the above link it seems to be a class loading issue, because jetty websocket package is treated as system class package and shouldn't be loaded by the WebApp if already loaded by the system.

So as referenced in the above link, I looked into the details suggested at: http://www.eclipse.org/jetty/documentation/9.2.10.v20150310/jetty-classloading.html

From this link, one of the ways to get around this issue is to call the org.eclipse.jetty.webapp.WebAppContext.setSystemClasses(String Array) or org.eclipse.jetty.webapp.WebAppContext.addSystemClass(String) to allow fine control over which classes are considered System classes.

So for being able to do that, I should be able to get an Instance of WebAppContext, when Jetty is initializing and add the WebSocket classes as system classes.

I tried searching for how one would be able to achieve the same but no luck so far ? Can anybody kindly point me to a reference implementation as to how this can be achieved ?


Java Version: OpenJDK 7(latest)

Jetty: 9.2.10.v20150310

Operating System: Ubuntu 14.04

Thanks in advance!

Upvotes: 1

Views: 574

Answers (2)

Sanket Naik
Sanket Naik

Reputation: 215

If you have followed this link to setup the Jetty Standalone Instance, then you might have run the following command:

[/opt/web/mybase]# java -jar /opt/jetty/jetty-distribution-9.2.10.v20150310/start.jar --add-to-start=deploy,http,logging

If so, then when you try to hit the websocket servlet you will see the exception that you are noticing.

All you need to do is, instead of that command, you as well need to initialize the websocket module as shown below:

[/opt/web/mybase]# java -jar /opt/jetty/jetty-distribution-9.2.10.v20150310/start.jar --add-to-start=deploy,http,logging,websocket

Hope this helps!

Upvotes: 0

Joakim Erdfelt
Joakim Erdfelt

Reputation: 49525

Don't include the org.eclipse.jetty.* classes in your war's WEB-INF/lib or WEB-INF/classes directories.

Upvotes: 0

Related Questions