0

There is a good example for sharing HttpSession between Websocket and Rest service. (Spring DispatchServlet cannot find resource within Jetty) But it doesn't work for me. I'm not sure is there any thing I'm missing?

I'm using Jetty as websocket server and also I created a WebApp as well which injected by SpringConfig.

private void init() throws Exception
{
    Server server = new Server();

    // Create SSL Connector
    ServerConnector serverConnector = getSSLConnector(server);

    // Bundle to server
    server.setConnectors(new Connector[] { serverConnector });

    // Create request handler collection
    HandlerCollection handlers = new HandlerCollection();


    // Add WebSocket handler
    final ServletContextHandler servletContextHandler = getWebSocketContextHandler();
    handlers.addHandler(servletContextHandler);

    // Add Servlet handler
    handlers.addHandler(getWebAppServletContextHandler());


    server.setHandler(handlers);
    // Initial WebSocket
    WebSocketServerContainerInitializer.configureContext(servletContextHandler);

    // Start Jetty
    server.start();
    server.join();
}

Both WebSocket and Rest are working under same port perfectly, of course, with different context paths.

Now, I created a Rest service:

@RequestMapping(value = "/login", method = RequestMethod.POST)
@Consumes({ MediaType.APPLICATION_JSON_VALUE })
@Produces({ MediaType.APPLICATION_JSON_VALUE })
public @ResponseBody Message login(@RequestBody Credential credential, @Context HttpServletRequest servlerRequest) 
{
    ...
    HttpSession session = servlerRequest.getSession(true);
    session.setAttribute("userName", credential.getUserName());
    ...
    Message message = new Message();
    ...
    return message;
}

In this service I created a HttpSession and stored something in. As I said, it works, and so does the session.

Rest client:

public void login() throws KeyManagementException, NoSuchAlgorithmException
{
    final String loginServiceUri = HTTP_SERVICE_BASE_URI + "/login";

    ClientConfig clientConfig = new DefaultClientConfig();
    ...

    Client client = Client.create(clientConfig);
    WebResource webResource = client.resource(loginServiceUri);
    ClientResponse response = webResource
            .type("application/json")
            .post(ClientResponse.class, new Credential("user","pass"));

    if (response.getStatus() != 200) {
        throw new RuntimeException("Failed : HTTP error code : " + response.getStatus());
    }

    List<NewCookie>cookies = response.getCookies();
    ClientEndpointConfigurator.setCookies(cookies);     <== Store cookies as well as session to ClientEndpointConfigrator class

    Message message = response.getEntity(Message.class);
    ...
}

ClientEndpointConfigrator class has a static list for all cookies which like this:

public class ClientEndpointConfigurator extends ClientEndpointConfig.Configurator {
    private static List<NewCookie> cookies = null;
    public static void setCookies(List<NewCookie> cookies) {
        ClientEndpointConfigurator.cookies = cookies;
    }
    ...
    @Override
    public void beforeRequest(Map<String, List<String>> headers) {
        ...
        if(null != cookies)
        {
            List<String> cookieList = new ArrayList<String>();
            for(NewCookie cookie: cookies)
            {
                cookieList.add(cookie.toString());
            }
            headers.put("Cookie", cookieList);
        }
        ...
    }
}

beforeRequest() method will put all cookies to request header. If you inspect the cookieList, you will see:

[JSESSIONID=tvum36z6j2bc1p9uf2gumxguh;Version=1;Path=/rs;Secure]

Things looks prefect.

Finally, create a server end ServerEndpointConfigurator class, and override the modifyHandshake() method to retrieve the session and cookies

public class SpringServerEndpointConfigurator extends ServerEndpointConfig.Configurator {
    @Override
    public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) {
        super.modifyHandshake(sec, request, response);
        httpSession = (HttpSession)request.getHttpSession();    <== **It returns null here!**
        ...

        }
    }
}

I can't get my HttpSession back! and if you print headers out, you will see the cookie has been changed:

Cookie: JSESSIONID="tvum36z6j2bc1p9uf2gumxguh";$Path="/rs"

Any one knows what's the reason?

Community
  • 1
  • 1
user3593261
  • 560
  • 4
  • 17

1 Answers1

1

All right, I figured it out, it's because I put WebSocket and Rest to different context handler. Jetty keeps handlers isolate to each other. To share session information, you have to put them together.

But if someone does want to separate them, it is still possible done by sharing SessionManager or SessionHandler. There are many ways to achieve this, you can inject SessionHandler to each ServletContext or just define it as a static variable and put it on somewhere every one can reach, each way works.

user3593261
  • 560
  • 4
  • 17