Skip to content

Latest commit

 

History

History
177 lines (128 loc) · 11.4 KB

File metadata and controls

177 lines (128 loc) · 11.4 KB

Jetty APIs Implementation

When you write a WebSocket application using the Jetty WebSocket APIs, your code typically need to depend on just the Jetty WebSocket APIs to compile your application. However, at runtime you need to have the implementation of the Jetty WebSocket APIs in your class-path (or module-path).

Jetty’s WebSocket APIs are provided by the following Maven artifact:

<dependency>
  <groupId>org.eclipse.jetty.websocket</groupId>
  <artifactId>websocket-jetty-api</artifactId>
  <version>{version}</version>
</dependency>

Jetty’s implementation of the Jetty WebSocket APIs is provided by the following Maven artifact (and its transitive dependencies):

<dependency>
  <groupId>org.eclipse.jetty.websocket</groupId>
  <artifactId>websocket-jetty-server</artifactId>
  <version>{version}</version>
</dependency>
Note

The websocket-jetty-api artifact and the websocket-jetty-server artifact (and its transitive dependencies) should be present in the server class-path (or module-path), and never in the web application’s /WEB-INF/lib directory.

To configure correctly your WebSocket application based on the Jetty WebSocket APIs, you need two steps:

  1. Make sure that Jetty sets up an instance of JettyWebSocketServerContainer.

  2. Use the JettyWebSocketServerContainer APIs in your applications to register your WebSocket endpoints that implement your application logic.

Setting up JettyWebSocketServerContainer

Jetty sets up a JettyWebSocketServerContainer instance using JettyWebSocketServletContainerInitializer.

When you deploy web applications using WebAppContext, then JettyWebSocketServletContainerInitializer is automatically discovered and initialized by Jetty when the web application starts, so that it sets up the JettyWebSocketServerContainer. In this way, you do not need to write any additional code:

link:../../{doc_code}/org/eclipse/jetty/docs/programming/server/websocket/WebSocketServerDocs.java[role=include]

On the other hand, when you deploy web applications using ServletContextHandler, you have to write the code to ensure that the JettyWebSocketServletContainerInitializer is initialized, so that it sets up the JettyWebSocketServerContainer:

link:../../{doc_code}/org/eclipse/jetty/docs/programming/server/websocket/WebSocketServerDocs.java[role=include]

Calling JettyWebSocketServletContainerInitializer.configure(...) must be done before the ServletContextHandler is started, and configures the Jetty WebSocket implementation for that web application context.

Configuring Endpoints

Once you have setup the JettyWebSocketServerContainer, you can configure your WebSocket endpoints.

Differently from the configuration of standard WebSocket endpoints, WebSocket endpoint classes may be annotated with Jetty WebSocket API annotations, or extend the org.eclipse.jetty.websocket.api.WebSocketListener interface, but they are not automatically discovered, not even when deploying web applications using WebAppContext.

Important

When using the Jetty WebSocket APIs, WebSocket endpoints must always be explicitly configured.

There are two ways of configuring WebSocket endpoints when using the Jetty WebSocket APIs:

Using JettyWebSocketServerContainer

To register WebSocket endpoints using the Jetty WebSocket APIs you need to access the JettyWebSocketServerContainer APIs.

The JettyWebSocketServerContainer instance is stored in the ServletContext, so it can be retrieved when the ServletContext is initialized, either from a ServletContextListener or from a HttpServlet:

link:../../{doc_code}/org/eclipse/jetty/docs/programming/server/websocket/WebSocketServerDocs.java[role=include]
link:../../{doc_code}/org/eclipse/jetty/docs/programming/server/websocket/WebSocketServerDocs.java[role=include]

You can also use this variant to set up the JettyWebSocketServerContainer and configure the WebSocket endpoints in one step:

link:../../{doc_code}/org/eclipse/jetty/docs/programming/server/websocket/WebSocketServerDocs.java[role=include]

When the ServletContextHandler is started, the Configurator lambda (the second parameter passed to JettyWebSocketServletContainerInitializer.configure(...)) is invoked and allows you to explicitly configure the WebSocket endpoints using the Jetty WebSocket APIs provided by JettyWebSocketServerContainer.

Under the hood, the call to JettyWebSocketServerContainer.addMapping(...) installs the org.eclipse.jetty.websocket.servlet.WebSocketUpgradeFilter, which is the component that intercepts HTTP requests to upgrade to WebSocket, described in this section. For more information about the WebSocketUpgradeFilter see also this section.

One last alternative to register your WebSocket endpoints is to use a programmatic WebSocket upgrade via JettyWebSocketServerContainer.upgrade(...), which allows you to use a standard HttpServlet subclass (rather than a JettyWebSocketServlet as explained in this section) to perform a direct WebSocket upgrade when your application logic demands so:

link:../../{doc_code}/org/eclipse/jetty/docs/programming/server/websocket/WebSocketServerDocs.java[role=include]
link:../../{doc_code}/org/eclipse/jetty/docs/programming/server/websocket/WebSocketServerDocs.java[role=include]

When using JettyWebSocketServerContainer.upgrade(...), the WebSocketUpgradeFilter is not installed, since the WebSocket upgrade is performed programmatically.

Using JettyWebSocketServlet

An alternative way to register WebSocket endpoints using the Jetty WebSocket APIs is to use a JettyWebSocketServlet subclass (or even many different JettyWebSocketServlet subclasses).

This method has the advantage that it does not install the WebSocketUpgradeFilter under the hood, because the WebSocket upgrade is handled directly by your JettyWebSocketServlet subclass. This may also have a performance benefit for non-WebSocket HTTP requests (as they will not pass through the WebSocketUpgradeFilter).

Your JettyWebSocketServlet subclass may be declared and configured either in code or in web.xml. Declaring your JettyWebSocketServlet subclass explicitly in code or in web.xml also simplifies the declaration and configuration of other web components such as other Servlets and/or Filters (for example, it is easier to configure the CrossOriginFilter, see also this section for more information).

For example, your JettyWebSocketServlet subclass may be declared in code in this way:

link:../../{doc_code}/org/eclipse/jetty/docs/programming/server/websocket/WebSocketServerDocs.java[role=include]
link:../../{doc_code}/org/eclipse/jetty/docs/programming/server/websocket/WebSocketServerDocs.java[role=include]

Note how in the call to JettyWebSocketServletContainerInitializer.configure(...) the second parameter is null, because WebSocket endpoints are not created here, but instead by one (or more) JettyWebSocketServlet subclasses. Yet the call is necessary to create other WebSocket implementation components that are necessary also when using JettyWebSocketServlet subclasses.

An HTTP upgrade request to WebSocket that matches your JettyWebSocketServlet subclass path mapping (specified above via ServletContextHandler.addServlet(...)) arrives at the Servlet and is inspected to verify whether it is a valid upgrade to WebSocket.

If the HTTP request is a valid upgrade to WebSocket, JettyWebSocketServlet calls configure(JettyWebSocketServletFactory factory) that you have overridden in your subclass, so that your application can instantiate and return the WebSocket endpoint. After having obtained the WebSocket endpoint, JettyWebSocketServlet performs the WebSocket upgrade. From this point on, the communication happens with the WebSocket protocol, and HTTP components such as Filters and Servlets are not relevant anymore.

If the HTTP request is not an upgrade to WebSocket, JettyWebSocketServlet delegates the processing to the superclass, javax.servlet.HttpServlet, which in turn invokes methods such as doGet(...) or doPost(...) depending on the HTTP method. If your JettyWebSocketServlet subclass did not override the doXYZ(...) method corresponding to the HTTP request, a 405 Method Not Allowed response is returned to the client, as per the standard HttpServlet class implementation.

Note

It is possible to use both JettyWebSocketServerContainer and JettyWebSocketServlet.

However, it is typically best to avoid mixing the use of JettyWebSocketServerContainer with the use of JettyWebSocketServlet, so that all your WebSocket endpoints are initialized by the same code in one place only.

Using JettyWebSocketServerContainer.addMapping(...) will install the WebSocketUpgradeFilter under the hood, which by default will intercepts all HTTP requests to upgrade to WebSocket. However, as explained in this section, if WebSocketUpgradeFilter does not find a matching WebSocket endpoint for the request URI path, then the HTTP request is passed to the Filter chain of your web application and may arrive to your JettyWebSocketServlet subclass, where it would be processed and possibly result in a WebSocket upgrade.