0

Given that:

I'd like to deploy webapp, packaged as WAR having web.xml in it, to Jetty server.

Within that app, I'd like to be able to have a JSR-356 specified javax websocket endpoints configured. I prefer, that those endpoints to be provided via ServerEndpointConfig, not an annotation scan.

There are many resources exemplifying that with an embedded Jetty, utilizing already famous WebSocketServerContainerInitializer.configureContext(context); API. I can't do that, obviously.

There are others, jumping directly to ServletContextListener and obtaining the ServerContainer via famous context.getAttribute("javax.websocket.server.ServerContainer"). So far I'm getting pretty much NULL via this API, so obviously container is not added.

Question:

What is that bit of configuration that is missing? Can it be done, preferably, via web.xml? If it is about config files like jetty.xml or jetty.ini - example would be nice, again, preferably for xml syntax.

Update:

As per answer below (the accepted one) and as I've actually tried to describe here - the known way of configuration is absolutely working just fine. Saying known I mean either by adding --module=websocket to some *.ini file for a non-embedded Jetty, or by calling WebSocketServerContainerInitializer.configureContext for an embedded one.

So rephrasing the question: is there any experience/knowledge from someone to enable websocket module by purely XML based configuration?

GullerYA
  • 1,320
  • 14
  • 27

1 Answers1

1

If using the ${jetty.base} and ${jetty.home} recommended installation process for Standalone Jetty, you should go to your ${jetty.base} instance directory and enable the websocket module.

$ cd /path/to/mybase
$ java -jar /opt/jetty/jetty-home-9.4.14.v20181114/start.jar --add-to-start=websocket
$ grep "websocket" start.ini
--module=websocket

Now you have websocket enabled for that ${jetty.base} instance.

If you want Jetty to discover your Server WebSocket endpoints via bytecode scanning your deployed webapps for annotations, then you'll also want the annotations module.

$ cd /path/to/mybase
$ java -jar /opt/jetty/jetty-home-9.4.14.v20181114/start.jar --add-to-start=annotations
$ grep "annotations" start.ini
--module=annotations

Once that's complete, you can do one (or more) of the following to have the websocket server endpoints deployed with your webapp.

Why does this work in standalone Jetty? What is standalone Jetty doing to make this possible?

The following happens:

  • The websocket module adds the lib/websocket/*.jar to the server classpath
  • The websocket module depends on both client and annotations modules
  • The client module adds lib/jetty-client-<jetty.version>.jar to the server classpath
  • The annotations module adds lib/jetty-annotations-<jetty.version>.jar and lib/annotations/*.jar to the server classpath
  • The annotations module depends on the plus module
  • The annotations module selects etc/jetty-annotations.xml for execution on startup
  • The annotations module adds JPMS modules by name org.objectweb.asm
  • The plus module adds lib/jetty-plus-<jetty.version>.jar to the server classpath
  • The plus module selects etc/jetty-plus.xml for execution on startup
  • The plus module depends on the server, security, jndi, webapp, and transactions modules

(I'll skip the rest of the modules that are selected this way)

In short, with just adding websocket module you gain the following server classpath entries

lib/websocket/*.jar
lib/jetty-client-<jetty.version>.jar
lib/jetty-annotations-<jetty.version>.jar
lib/annotations/*.jar
lib/jetty-plus-<jetty.version>.jar

And the following XML files

lib/jetty-annotations.xml
lib/jetty-plus.xml

Both of these XML files simply modify the default Configuration list on the server side, making the Configuration behavior they introduce available to all deployed WebApps.

You can alternatively set the Configuration on the WebAppContext (before it's started) for webapp specific behaviors.

Example:

WebAppContext context = new WebAppContext();
context.setContextPath("/");
context.setBaseResource(Resource.newResource(rootResourceUrl));

context.setConfigurations(new Configuration[] {
            new AnnotationConfiguration(),
            new WebXmlConfiguration(),
            new WebInfConfiguration(),
            new PlusConfiguration(), 
            new MetaInfConfiguration(),
            new FragmentConfiguration(), 
            new EnvConfiguration()});    

handlerList.addHandler(context);

Note: for javax.websocket you must use a WebAppContext, as the behaviors defined for its initialization require a full Web App to function. While you can use a ServletContextHandler with javax.websocket endpoints, this style is 100% manually defined, intialized, and declared, with no automatic bytecode / annotation scanning features that JSR-356 relies on.

You can see all of this from the command line too.

Show the active ${jetty.base} configuration, what the XML property values are, what the server classpath is, and what XML is going to be executed (and in what order!!)

$ cd /path/to/mybase
$ java -jar /opt/jetty/jetty-home-9.4.14.v20181114/start.jar --list-config

Show the list of modules and how they relate (along with which ones are selected in your ${jetty.base} configuration)

$ cd /path/to/mybase
$ java -jar /opt/jetty/jetty-home-9.4.14.v20181114/start.jar --list-modules
Joakim Erdfelt
  • 46,896
  • 7
  • 86
  • 136
  • As it is stated in my question, the path you outline here is known **and working** to me (both, `--module=websocket` and some flavor of `WebSocketServerContainerInitializer.configureContext(context)`. Too bad my case is more difficult: it is somewhat historically given to me deployment where **embedded** Jetty is configured from Java to read **XML** files and be configured by them. Any suggestion for that? – GullerYA Nov 29 '18 at 08:42
  • 1
    "Modules" are a purely standalone Jetty concept in Jetty 9.x. "Modules" for embedded-jetty are being introduced in Jetty 10.x, but as formal JPMS Modules. – Joakim Erdfelt Nov 29 '18 at 13:14
  • Thanks for this approval of what seemingly was not possible (Jetty 9.4..). Well, looks like I'm going to give up on JAVAX way and do the WebSockets 'Jetty' way (servlet etc). – GullerYA Nov 30 '18 at 12:56
  • 1
    You can still do the [inferior javax way](https://stackoverflow.com/questions/25770789/jetty-websocket-api-vs-the-standard-jsr-356-api) if you want, you just have to declare the Server `Configuration` before you start the `WebAppContext` for your JSR-356 (`javax.websocket`) behaviors. Note: you must use a `WebAppContext`, not a `ServletContextHandler`. – Joakim Erdfelt Nov 30 '18 at 14:11