Making a Java EE 7 WebSocket ServerEndpoint class discoverable

The problem

Is your @ServerEndpoint annotated class not discoverable? Does the server log not contain any erroneous entries for you to examine? Your ClientEndpoint trying to connect to the server has most likely thrown a javax.websocket.DeploymentException in your face with a wrapped cause: org.glassfish.tyrus.websockets.HandshakeException. This last exception has a message for you:

Response code was not 101: 404

The message isn’t that cryptic, really. HTTP 1.1 status code 101 is something the WebSocket client rightfully expect. The server has to send that status code if he, during the handskake process, is willing to upgrade the currently used application protocol (HTTP!) into a WebSocket. But as the exception message reveals, the server sent a 404 code instead, saying that the resource our client was looking for couldn’t be found.

The solution

If you’re dead sure that your POJO is annoted with a @ServerEndpoint annotation, and that the required value element has been provided, then I think you have a packaging problem. Not that uncommon in the world of Java!

Let’s have a look at what the Java API for WebSocket specification (JSR-356) says, on page 25:

The class files for the endpoints and any resources they need such as text or image files are packaged into the Java EE-defined WAR file, either directly under WEB-INF/classes or packaged as a JAR file and located under WEB-INF/lib.

Java EE containers are not required to support deployment of websocket endpoints if they are not packaged in a WAR file as described above.

For my part, I had my WebSocket endpoint class packaged in a regular JAR file alongside other Enterprise JavaBeans, that was finally put in an EAR package. I figured that was a splendid design, but also one that made my endpoint totally undiscoverable. My EAR package already hosted a WAR module. So moving the endpoint into the WAR solved my problem.

Same page in the specification gives a hint why this must be:

The Java WebSocket implementation must use the web container scanning mechanism defined in [Servlet 3.0] to find annotated and programmatic endpoints contained within the WAR file at deployment time.

Further reading

The Java EE 7 Tutorial says:

When you deploy your application, the endpoint is available at ws://<host>:<port>/<application>/echo; for example, ws://localhost:8080/echoapp/echo.

Thus the tutorial does not touch the topic on packaging at all. Another Oracle article says:

In GlassFish, if your application is deployed with the contextroot mycontextroot in a Web container listening at port 8080 of localhost, the WebSocket will be accessible using ws://localhost:8080/mycontextroot/hello.

The word “if” in this quote might actually be interpreted as there is a free choice where we put our endpoint. At least that was what I read in when scanning through. I should emphasize that the Oracle article never said a word about any other container than a Web container (!). The JavaDoc of ServerContainer also, implicitly, state what we now know:

[blablabla..] during the deployment of the WAR file containing the endpoint.

Leave a Reply

Your email address will not be published. Required fields are marked *