How to deploy Tyrus (JSR 356 implementation) to a web container?
Categories:
Deploying Tyrus (JSR 356) to Web Containers: A Comprehensive Guide

Learn how to successfully deploy Tyrus, the reference implementation for JSR 356 (Java API for WebSocket), to popular web containers like Apache Tomcat.
Tyrus is the reference implementation of the Java API for WebSocket (JSR 356), providing a robust and flexible framework for building WebSocket applications in Java. While Tyrus can be used in standalone applications, deploying it within a web container like Apache Tomcat is a common scenario for enterprise applications. This guide will walk you through the necessary steps and configurations to ensure a smooth deployment of your Tyrus-based WebSocket applications.
Understanding Tyrus Deployment in Web Containers
When deploying a JSR 356 (Tyrus) application to a web container, it's crucial to understand how the container discovers and initializes WebSocket endpoints. JSR 356 leverages the Servlet 3.0+ API's pluggability features, allowing containers to scan for WebSocket annotations (@ServerEndpoint
) or programmatic configurations. Tyrus provides its own TyrusServerContainer
which integrates with the container's ServletContext
to manage WebSocket lifecycle events.
flowchart TD A[Web Container Startup] --> B{Scan for JSR 356 Endpoints} B --> C{Discover @ServerEndpoint Annotations} C --> D[Initialize TyrusServerContainer] D --> E[Register WebSocket Endpoints] E --> F[WebSocket Application Ready]
Tyrus WebSocket Endpoint Discovery Flow
Prerequisites and Dependencies
Before deploying your Tyrus application, ensure your project includes the necessary dependencies and that your web container meets the minimum requirements. For Tyrus, you'll typically need the tyrus-container-servlet
dependency, which bridges Tyrus with the Servlet API. Your web container must support at least Servlet 3.0 and WebSocket 1.0 (JSR 356). Apache Tomcat 7.0.27+ or Jetty 9+ are common choices.
<dependency>
<groupId>org.glassfish.tyrus.containers</groupId>
<artifactId>tyrus-container-servlet</artifactId>
<version>2.1.5</version> <!-- Use the latest stable version -->
</dependency>
<dependency>
<groupId>org.glassfish.tyrus</groupId>
<artifactId>tyrus-server</artifactId>
<version>2.1.5</version>
</dependency>
<dependency>
<groupId>org.glassfish.tyrus</groupId>
<artifactId>tyrus-client</artifactId>
<version>2.1.5</version>
</dependency>
Maven dependencies for Tyrus WebSocket application
Configuring Your Web Application for Tyrus
To enable Tyrus within your web application, you typically don't need extensive web.xml
configuration if you're using @ServerEndpoint
annotations. The tyrus-container-servlet
module includes a ServletContainerInitializer
that automatically registers the Tyrus WebSocket runtime. However, for programmatic endpoint registration or specific configurations, you might need to interact with the ServerContainer
directly.
package com.example.websocket;
import jakarta.websocket.OnClose;
import jakarta.websocket.OnError;
import jakarta.websocket.OnMessage;
import jakarta.websocket.OnOpen;
import jakarta.websocket.Session;
import jakarta.websocket.server.ServerEndpoint;
@ServerEndpoint("/websocket/echo")
public class EchoWebSocketEndpoint {
@OnOpen
public void onOpen(Session session) {
System.out.println("WebSocket opened: " + session.getId());
}
@OnMessage
public String onMessage(String message, Session session) {
System.out.println("Message from " + session.getId() + ": " + message);
return "Echo: " + message;
}
@OnClose
public void onClose(Session session) {
System.out.println("WebSocket closed: " + session.getId());
}
@OnError
public void onError(Session session, Throwable throwable) {
System.err.println("WebSocket error on " + session.getId() + ": " + throwable.getMessage());
}
}
Example of a simple Tyrus @ServerEndpoint
For programmatic registration, you would typically implement jakarta.servlet.ServletContextListener
and register endpoints within the contextInitialized
method. This approach is useful when endpoints are dynamically created or require complex configuration not easily expressed via annotations.
package com.example.websocket;
import jakarta.servlet.ServletContextEvent;
import jakarta.servlet.ServletContextListener;
import jakarta.servlet.annotation.WebListener;
import jakarta.websocket.DeploymentException;
import jakarta.websocket.server.ServerContainer;
import jakarta.websocket.server.ServerEndpointConfig;
@WebListener
public class WebSocketConfigurator implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
ServerContainer sc = (ServerContainer) sce.getServletContext().getAttribute("jakarta.websocket.server.ServerContainer");
if (sc != null) {
try {
// Programmatic registration of an endpoint
sc.addEndpoint(ServerEndpointConfig.Builder.create(
ProgrammaticEchoEndpoint.class, "/websocket/programmatic-echo").build()
);
System.out.println("Programmatic WebSocket endpoint registered.");
} catch (DeploymentException e) {
System.err.println("Error deploying programmatic WebSocket endpoint: " + e.getMessage());
}
} else {
System.err.println("ServerContainer not found. WebSocket support might be missing.");
}
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
// Clean up resources if necessary
}
}
Programmatic WebSocket endpoint registration using ServletContextListener
web.xml
(if present) does not disable annotation scanning (e.g., metadata-complete="true"
on <web-app>
) if you rely on @ServerEndpoint
annotations. For programmatic registration, the ServerContainer
attribute might be named differently depending on your container's Jakarta EE version (e.g., javax.websocket.server.ServerContainer
for older versions).Deployment Steps for Apache Tomcat
Deploying your Tyrus application to Apache Tomcat involves packaging your application as a WAR file and placing it in Tomcat's webapps
directory. Tomcat, being a Servlet 3.0+ compliant container, will automatically detect and initialize your WebSocket endpoints.
1. Package Your Application
Build your Java project into a Web Application Archive (WAR) file. If you're using Maven, the maven-war-plugin
typically handles this. Ensure all Tyrus dependencies are correctly packaged within the WAR (usually in WEB-INF/lib
).
2. Deploy to Tomcat
Copy the generated .war
file into the webapps
directory of your Tomcat installation. Tomcat will automatically unpack and deploy the application. For example, if your WAR is named mywebsocketapp.war
, it will be deployed to http://localhost:8080/mywebsocketapp
.
3. Verify Deployment
Check Tomcat's logs (catalina.out
or localhost.<date>.log
) for messages indicating successful deployment and WebSocket endpoint registration. You should see messages from Tyrus confirming the endpoints are active. Then, try connecting to your WebSocket endpoint using a client (e.g., a simple HTML page with JavaScript or a WebSocket testing tool).
<!DOCTYPE html>
<html>
<head>
<title>WebSocket Test</title>
</head>
<body>
<h1>Tyrus WebSocket Echo Test</h1>
<input type="text" id="messageInput" placeholder="Type a message">
<button onclick="sendMessage()">Send</button>
<div id="output"></div>
<script>
const output = document.getElementById('output');
const messageInput = document.getElementById('messageInput');
const ws = new WebSocket('ws://localhost:8080/mywebsocketapp/websocket/echo'); // Adjust URL as needed
ws.onopen = function() {
output.innerHTML += '<p>Connected to WebSocket!</p>';
};
ws.onmessage = function(event) {
output.innerHTML += '<p>Received: ' + event.data + '</p>';
};
ws.onclose = function() {
output.innerHTML += '<p>Disconnected from WebSocket.</p>';
};
ws.onerror = function(error) {
output.innerHTML += '<p style="color:red;">Error: ' + error.message + '</p>';
};
function sendMessage() {
const message = messageInput.value;
if (message) {
ws.send(message);
output.innerHTML += '<p>Sent: ' + message + '</p>';
messageInput.value = '';
}
}
</script>
</body>
</html>
Simple HTML/JavaScript client to test the Echo WebSocket endpoint