How can I access a HttpSession object inside an annotated @WebSocket class in Jetty 9?
I found how to do it using @ServerEndpoint annotation, like here: HttpSession from @ServerEndpoint
Using the @WebSocket annotation, like in the class bellow, how can I do it?
@WebSocket
public class AuctionWebSocket {
// NEED TO ACCESS HttpSession OBJECT INSIDE THESE METHODS:
@OnWebSocketConnect
public void onConnect(Session session) {
System.out.println("onConnect...");
}
@OnWebSocketMessage
public void onMessage(String message) {
System.out.println("Message: " + message);
}
@OnWebSocketClose
public void onClose(int statusCode, String reason) {
System.out.println("onClose...");
}
@OnWebSocketError
public void onError(Throwable t) {
System.out.println("onError...");
}
}
Inside the method onConnect(Session session)
, I tried to call session.getUpgradeRequest().getSession()
which always returns null
.
For sake of information, here is how I start embedded Jetty 9:
public class Main {
public static void main(String[] args) throws Exception {
String webPort = System.getenv("PORT");
if (webPort == null || webPort.isEmpty()) {
webPort = "8080";
}
Server server = new Server(Integer.parseInt(webPort));
ClassList classlist = org.eclipse.jetty.webapp.Configuration.ClassList.setServerDefault(server);
classlist.addBefore("org.eclipse.jetty.webapp.JettyWebXmlConfiguration",
"org.eclipse.jetty.annotations.AnnotationConfiguration");
WebAppContext wac = new WebAppContext();
String webappDirLocation = "./src/main/webapp/";
wac.setAttribute("org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern", ".*/classes/.*");
wac.setDescriptor(webappDirLocation + "/WEB-INF/web.xml");
wac.setBaseResource(new ResourceCollection(new String[]{webappDirLocation, "./target"}));
wac.setResourceAlias("/WEB-INF/classes/", "/classes/");
wac.setContextPath("/");
wac.setParentLoaderPriority(true);
/*
* WebSocket handler.
*/
WebSocketHandler wsh = new WebSocketHandler() {
@Override
public void configure(WebSocketServletFactory wssf) {
wssf.register(AuctionWebSocket.class);
}
};
ContextHandler wsc = new ContextHandler();
wsc.setContextPath("/auction-notifications");
wsc.setHandler(wsh);
ContextHandlerCollection chc = new ContextHandlerCollection();
chc.setHandlers(new Handler[]{wac, wsc});
server.setHandler(chc);
server.start();
server.join();
}
}
Let me know if you need more information.
Any help will be appreciated.
Thanks in advance.
You'll want to use the WebSocketCreator concepts.
First you set the WebSocketCreator
of your choice in the WebSocketServletFactory
that you configure in your WebSocketServlet
public class MySessionSocketServlet extends WebSocketServlet
{
@Override
public void configure(WebSocketServletFactory factory)
{
factory.getPolicy().setIdleTimeout(30000);
factory.setCreator(new MySessionSocketCreator());
}
}
Next, you'll want to grab the HttpSession
during the upgrade and pass it into the WebSocket object that you are creating.
public class MySessionSocketCreator implements WebSocketCreator
{
@Override
public Object createWebSocket(ServletUpgradeRequest req, ServletUpgradeResponse resp)
{
HttpSession httpSession = req.getSession();
return new MySessionSocket(httpSession);
}
}
Finally, just keep track of that HttpSession
in your own WebSocket
.
@WebSocket
public class MySessionSocket
{
private HttpSession httpSession;
private Session wsSession;
public MySessionSocket(HttpSession httpSession)
{
this.httpSession = httpSession;
}
@OnWebSocketConnect
public void onOpen(Session wsSession)
{
this.wsSession = wsSession;
}
}
Of note: the HttpSession
can expire and be scavenged and cleaned up while a WebSocket is active. Also, the HttpSession
contents at this point are not guaranteed to be kept in sync with changes from other web actions (this mostly depends on what Session storage / caching technology you use on the server side)
And one more note: resist the urge to store / track the ServletUpgradeRequest
object in your Socket instance, as this object is recycled and cleaned up aggressively by Jetty proper.