2016-09-11 3 views
1

Ich schreibe einen Container-agnostic Websocket-Server. Meine Entwicklungsumgebung verwendet IntelliJ IDEA mit einer eingebetteten Jetty-Version 9.3.11.v20160721 (Code unten einbetten).Container-Agnostic Websocket wirft NPE mit Embedded Jetty

Mein Code verwendet jedoch die Tomcat Websocket-Bibliotheken tomcat-websocket-api und tomcat-websocket, Version 8.5.4.

Ich möchte den Websocket EndPoint mit einem ServletContextListener registrieren. Nach einigen Beispielen aus der Tyrus project, sowie einigen Antworten auf SO und in der Jetty-Mailing-Liste von Joakim Erdfelt (@ joakim-erdfelt), schrieb ich die folgende Implementierung und fügte sie über eine listener in web.xml hinzu.

Der Code tritt in die contextInitialized()-Methode ein, so dass Teil scheint ordnungsgemäß zu funktionieren, aber der ServletContext enthält leider nicht das Attribut javax.websocket.server.ServerContainer und daher gibt es null zurück.

@Override 
public void contextInitialized(ServletContextEvent servletContextEvent) { 

    final ServerContainer serverContainer = (ServerContainer) servletContextEvent 
      .getServletContext() 
      .getAttribute("javax.websocket.server.ServerContainer"); 

    // *** serverContainer is null *** 

    try { 
     serverContainer.addEndpoint(ChatAnnotation.class); 
    } 
    catch (DeploymentException e) { e.printStackTrace(); } 
} 

Die einzigen verfügbaren Attribute sind javax.servlet.context.tempdir, org.eclipse.jetty.util.DecoratedObjectFactory, org.eclipse.jetty.tlds, org.eclipse.jetty.resources, org.eclipse.jetty.server.Executor, org.eclipse.jetty.webFragments

Was mache ich falsch? Ist das nur ein Einbettungsproblem? Wird es ordnungsgemäß in Standard Jetty (d. H. Nicht eingebettet) laufen?

Der Code einbetten unter:

WebAppContext webapp = new WebAppContext(); 
webapp.setContextPath("/"); 
webapp.setResourceBase(webroot); 
webapp.setDescriptor(webroot + "/WEB-INF/web.xml"); 

Server server = new Server(); 

ServerConnector connector = new ServerConnector(server); 
connector.setPort(8080);    

server.setConnectors(new ServerConnector[] { connector }); 
server.setHandler(webapp);  
server.start(); 
server.join(); 

Antwort

2

JSR ServerContainer nicht automatisch in Embedded-Anlegestelle initialisiert wird.

Verwenden Sie die WebSocketServerContainerInitializer ...

WebAppContext webapp = new WebAppContext(); 
webapp.setContextPath("/"); 
webapp.setResourceBase(webroot); 
webapp.setDescriptor(webroot + "/WEB-INF/web.xml"); 

Server server = new Server(); 

ServerConnector connector = new ServerConnector(server); 
connector.setPort(8080);    

server.setConnectors(new ServerConnector[] { connector }); 
server.setHandler(webapp); 

// Add this line 
WebSocketServerContainerInitializer.configureContext(webapp); 

server.start(); 
server.join(); 

Hinweis: Die WebSocketServerContainerInitializer ist ein javax.servlet.ServerContainerInitializer und Sie könnten Ihre embedded-jetty automatisch, dass ServerContainerInitializer auszuführen einzurichten.

Wenn Sie sich stark auf Bytecode-Scannen von Annotationen verlassen oder eine javax.websocket.server.ServerApplicationConfig Implementierung haben, dann sollten Sie die ServerContainerInitializer automatisch ausführen lassen.

Hinweis: Die javax.servlet.ServerContainerInitializer gilt nur für eine org.eclipse.jetty.webapp.WebAppContext.

Wenn Sie das org.eclipse.jetty.servlet.ServletContextHandler (das häufigere Formular in Embedded-Jetty) verwenden, können Sie kein javax.servlet.ServerContainerInitializer verwenden.

einzustellen, dass auf, dies zu tun:

private void enableAnnotationScanning(Server server) 
{ 
    Configuration.ClassList classlist = Configuration.ClassList.setServerDefault(server); 
    classlist.addAfter("org.eclipse.jetty.webapp.FragmentConfiguration", 
      "org.eclipse.jetty.plus.webapp.EnvConfiguration", 
      "org.eclipse.jetty.plus.webapp.PlusConfiguration"); 
    classlist.addBefore("org.eclipse.jetty.webapp.JettyWebXmlConfiguration", 
      "org.eclipse.jetty.annotations.AnnotationConfiguration"); 
} 

// ... later on ... 

Server server = new Server(); 
enableAnnotationScanning(server); 
+0

Dank für die prompte Antwort danken. Um dies klarzustellen, ist dies streng genommen ein Embed-Problem und sollte nicht auftreten, wenn es in Standard-Servlet-Containern implementiert wird, ist das korrekt? – isapir

+0

Das Hinzufügen dieser Zeile führt zu einem anderen NPE: 'Ausnahme im Thread" main "java.lang.NullPointerException Verbindung zur Ziel-VM getrennt, Adresse: '127.0.0.1:50113', Transport: 'Socket' \t bei org.eclipse .jetty.websocket.jsr356.server.deploy.WebSocketServerContainerInitializer.configureContext (WebSocketServerContainerInitializer.java: 100) ' – isapir

+0

Ich habe deine Antwort aktualisiert. Ich musste die Zeile nach 'server.setHandler (webapp)' runterziehen und das beide NPEs behoben haben. Vielen Dank! – isapir