Java WebSocket - 1.0


Compatibility: v2 v3 Express
What's new? Release Notes
ID: com.castsoftware.java.websocket

Description

This extension should be installed when analyzing projects containing WebSocket applications, and you want to view a transaction consisting of Client and Server objects for WebSocket communication with their corresponding links.

In what situation should you install this extension?

If your Java application uses Websocket communication APIs.

Technology support

Library name Package/namespace Supported Version supported
Java EE WebSocket javax.websocket Up to 8.0
Jakarta WebSocket jakarta.websocket Up to 2.3.0
Spring WebSocket org.springframework.web.socket Up to 7.0.x
Spring WebFlux WebSocket org.springframework.web.reactive Up to 5.0.0
Jetty WebSocket Server org.eclipse.jetty.websocket.server Up to 12.1.10
Jetty WebSocket Client org.eclipse.jetty.websocket.client Up to 12.1.10
Netty io.netty.handler.codec.http.websocketx Up to 4.2.15
Vert.x io.vertx Up to 5.1.2
Undertow io.undertow Up to 2.3
Tyrus Server org.glassfish.tyrus.server Up to 2.3.0
Tyrus Client org.glassfish.tyrus.client Up to 2.3.0

Supported Annotations

Name Description Comment
@ServerEndpoint jakarta.websocket.server.ServerEndpoint
javax.websocket.server.ServerEndpoint
build WebSocket Server objects
@ClientEndpoint jakarta.websocket.ClientEndpoint
javax.websocket.ClientEndpoint
build WebSocket Client objects
@WebSocket org.eclipse.jetty.websocket.api.annotations.WebSocket indicates a Jetty WebSocket class
@OnOpen jakarta.websocket.OnOpen
javax.websocket.OnOpen
decorate a Java method to indicate a new web socket session is open
@OnMessage jakarta.websocket.OnMessage
javax.websocket.OnMessage
makes a Java method receive incoming web socket messages
@OnError jakarta.websocket.OnError
javax.websocket.OnError
decorate a Java method to indicate it handle errors
@OnClose jakarta.websocket.OnClose
javax.websocket.OnClose
decorate a Java method to indicate when a web socket session is closing
@OnWebSocketOpen org.eclipse.jetty.websocket.api.annotations.OnWebSocketOpen decorate a Java method to indicate a new web socket session is open in Jetty framework
@OnWebSocketMessage org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage makes a Java method receive incoming web socket messages in Jetty framework
@OnWebSocketError org.eclipse.jetty.websocket.api.annotations.OnWebSocketError decorate a Java method to indicate it handle errors in Jetty framework
@OnWebSocketClose org.eclipse.jetty.websocket.api.annotations.OnWebSocketClose decorate a Java method to indicate when a web socket session is closing in Jetty framework

Transactions

Transaction support is derived from metamodel concepts used to build CAST Imaging Blueprint and structural transaction flows. Entry Points start transactions; Exit Points include both output/boundary concepts and Data Entities manipulated by transactions.

Role Support Breakdown
Entry Point N/A No data available
Exit Point N/A No data available

ISO 5055 Structural Rules

Quality support is based on ISO 5055 structural rules available for the selected extension version.

Reliability Maintainability Security Performance Efficiency
N/A N/A N/A N/A

Dependencies

Some CAST extensions require the presence of other CAST extensions in order to function correctly. The Java Websocket extension requires the following CAST extensions to be installed:

Download and installation instructions

For Java applications using websocket libraries, the extension will be automatically installed by CAST Console. For upgrade, if the Extension Strategy is not set to Auto update, you can manually install the extension using the Application - Extensions interface.

What results can you expect?

Once the analysis/snapshot generation has completed, you can view the below objects and links created.

Objects

Icon Description Comment
Java Server WebSocket An object to represent server WebSocket
Java Client WebSocket An object to represent client WebSocket
Java Unknown WebSocket Socket An object to represent server WebSocket when URI is not resolved
Java Unknown Client WebSocket An object to represent client WebSocket when URI is not resolved
Link Type Source and Destination Link Supported Methods
callLink From Java Server WebSocket / Java Unknown Server WebSocket to Caller Java method
JEE WebSocketjakarta.websocket.server.ServerEndpoint
javax.websocket.server.ServerEndpoint
jakarta.websocket.server.ServerContainer.addEndpoint
javax.websocket.server.ServerContainer.addEndpoint
Spring Raw WebSocketorg.springframework.web.socket.config.annotation.WebSocketHandlerRegistry.addHandler
Spring Reactive WebSocketorg.springframework.web.reactive.function.server.RequestPredicates.path
Jetty WebSocketorg.eclipse.jetty.websocket.server.ServerWebSocketContainer.addMapping
Netty WebSocketio.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler.WebSocketServerProtocolHandler
io.netty.bootstrap.AbstractBootstrap.bind
io.netty.handler.codec.http.websocketx.WebSocketServerProtocolConfig.newBuilder
io.netty.handler.codec.http.websocketx.WebSocketServerProtocolConfig.Builder.websocketPath
Vertx WebSocketio.vertx.ext.web.Router.route
Undertow WebSocketio.undertow.server.handlers.PathHandler.addPrefixPath
callLink From Caller Java method to Java Client WebSocket / Java Unknown Client WebSocket
JEE WebSocketjavax.websocket.WebSocketContainer.connectToServer
jakarta.websocket.WebSocketContainer.connectToServer
Spring Raw WebSocketorg.springframework.web.socket.client.standard.StandardWebSocketClient.execute
org.springframework.web.socket.client.AbstractWebSocketClient.execute
Spring Reactive WebSocketorg.springframework.web.reactive.socket.client.WebSocketClient.execute
Jetty WebSocketorg.eclipse.jetty.websocket.client.WebSocketClient.connect
Netty WebSocketio.netty.handler.codec.http.websocketx.WebSocketClientHandshakerFactory.newHandshaker
Vertx WebSocketio.vertx.core.http.WebSocketConnectOptions.setURI
io.vertx.core.http.WebSocketConnectOptions.setHost
io.vertx.core.http.WebSocketConnectOptions.setPort
Undertow WebSocketio.undertow.websockets.client.WebSocketClient.connectionBuilder
callLink From Java Server WebSocket to Annotated methods
JEE WebSocketjakarta.websocket.OnOpen
jakarta.websocket.OnMessage
jakarta.websocket.OnError
jakarta.websocket.OnClose
Jetty WebSocketorg.eclipse.jetty.websocket.api.annotations.OnWebSocketOpen
jorg.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage
org.eclipse.jetty.websocket.api.annotations.OnWebSocketError
org.eclipse.jetty.websocket.api.annotations.OnWebSocketClose
callLink From Java Client WebSocket to Annotated methods
JEE WebSocketjakarta.websocket.OnOpen
jakarta.websocket.OnMessage
jakarta.websocket.OnError
jakarta.websocket.OnClose
Jetty WebSocketorg.eclipse.jetty.websocket.api.annotations.OnWebSocketOpen
jorg.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage
org.eclipse.jetty.websocket.api.annotations.OnWebSocketError
org.eclipse.jetty.websocket.api.annotations.OnWebSocketClose
callLink From Java Client WebSocket to Java Server WebSocket Linking is handled by Universal Linker

Code Examples

JEE WebSocket with Tyrus Server
ChatServerEndpoint.java
package com.example;

import jakarta.websocket.*;
import jakarta.websocket.server.ServerEndpoint;

@ServerEndpoint("/chat")
public class ChatServerEndpoint {

    @OnOpen
    public void onOpen(Session session) {
        System.out.println("[SERVER] OPEN: " + session.getId());
    }

    @OnMessage
    public void onMessage(String message, Session session) {
        System.out.println("[SERVER] RECV from " + session.getId() + ": " + message);
        try {
            // Echo the message back to the client
            session.getBasicRemote().sendText("echo: " + message);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @OnClose
    public void onClose(Session session, CloseReason reason) {
        System.out.println("[SERVER] CLOSE: " + session.getId() + " (" + reason + ")");
    }

    @OnError
    public void onError(Session session, Throwable t) {
        System.out.println("[SERVER] ERROR on " + session.getId());
        t.printStackTrace();
    }
}
JavaWsClient.java ``` java import jakarta.websocket.*; import java.net.URI;

@ClientEndpoint public class JavaWsClient {

@OnOpen
public void onOpen(Session session) throws Exception {
    System.out.println("connected");
    session.getBasicRemote().sendText("hello server");
}

@OnMessage
public void onMessage(String message) {
    System.out.println("received: " + message);
}

public static void main(String[] args) throws Exception {
    // This is the client-side container:
    WebSocketContainer container = ContainerProvider.getWebSocketContainer();

    container.connectToServer(
        JavaWsClient.class,
        URI.create("ws://localhost:8080/app/chat")
    );

    Thread.sleep(5000); // keep the JVM alive to receive messages
}

}

</details>
<details><summary>ServerMain.java</summary>
``` java
package com.example;

import org.glassfish.tyrus.server.Server;

import java.util.Collections;

public class ServerMain {

    public static final String HOST = "localhost";
    public static final int    PORT = 8080;
    public static final String CONTEXT_PATH = "/app";   

    public static void main(String[] args) throws Exception {
        Server server = new Server(HOST, PORT, CONTEXT_PATH,
                Collections.emptyMap(),
                ChatServerEndpoint.class);

        try {
            server.start();
            System.out.println("[SERVER] Started at ws://" + HOST + ":" + PORT
                    + CONTEXT_PATH + "/chat");
            System.out.println("[SERVER] Press ENTER to stop...");
            System.in.read();   
        } finally {
            server.stop();
            System.out.println("[SERVER] Stopped.");
        }
    }
}

Jetty WebSocket
ChatServerEndpoint.java
package com.example;

import org.eclipse.jetty.websocket.api.Callback;
import org.eclipse.jetty.websocket.api.Session;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketClose;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketError;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketOpen;
import org.eclipse.jetty.websocket.api.annotations.WebSocket;

@WebSocket  // autoDemand = true by default
public class ChatServerEndpoint {

    @OnWebSocketOpen
    public void onOpen(Session session) {
        System.out.println("[SERVER] OPEN: " + session.getRemoteSocketAddress());
    }

    @OnWebSocketMessage
    public void onMessage(Session session, String message) {
        System.out.println("[SERVER] RECV: " + message);
        // Echo it back. The async send takes a Callback (use NOOP to ignore completion).
        session.sendText("echo: " + message, Callback.NOOP);
    }

    @OnWebSocketClose
    public void onClose(int statusCode, String reason) {
        System.out.println("[SERVER] CLOSE: " + statusCode + " " + reason);
    }

    @OnWebSocketError
    public void onError(Throwable cause) {
        cause.printStackTrace();
    }
}
JettyWsClient.java
package com.example;

import java.net.URI;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;

import org.eclipse.jetty.websocket.api.Session;
import org.eclipse.jetty.websocket.client.WebSocketClient;

public class JettyWsClient {

    public static void main(String[] args) throws Exception {
        WebSocketClient client = new WebSocketClient();
        Object endpoint = new JettyWsClientEndpoint();
        URI serverUri = URI.create("ws://localhost:8080/chat");

        try {
            client.start();
            System.out.println("[CLIENT] connecting to " + serverUri);

            CompletableFuture<Session> sessionPromise = client.connect(endpoint, serverUri);
            sessionPromise.get(5, TimeUnit.SECONDS);

            endpoint.awaitClose(5);
        } finally {
            client.stop();
        }
        System.out.println("[CLIENT] done.");
    }
}
JettyWsClientEndpoint.java
package com.example;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

import org.eclipse.jetty.websocket.api.Callback;
import org.eclipse.jetty.websocket.api.Session;
import org.eclipse.jetty.websocket.api.StatusCode;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketClose;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketError;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketMessage;
import org.eclipse.jetty.websocket.api.annotations.OnWebSocketOpen;
import org.eclipse.jetty.websocket.api.annotations.WebSocket;

@WebSocket
public class JettyWsClientEndpoint {

    private final CountDownLatch closeLatch = new CountDownLatch(1);

    @OnWebSocketOpen
    public void onOpen(Session session) {
        System.out.println("[CLIENT] connected");
        session.sendText("hello server", Callback.NOOP);   // � outgoing message
    }

    @OnWebSocketMessage
    public void onMessage(Session session, String message) {
        System.out.println("[CLIENT] received: " + message);
        session.close(StatusCode.NORMAL, "done", Callback.NOOP);
    }

    @OnWebSocketClose
    public void onClose(int statusCode, String reason) {
        System.out.println("[CLIENT] closed: " + statusCode + " " + reason);
        closeLatch.countDown();
    }

    @OnWebSocketError
    public void onError(Throwable cause) {
        cause.printStackTrace();
    }

    public boolean awaitClose(int seconds) throws InterruptedException {
        return closeLatch.await(seconds, TimeUnit.SECONDS);
    }
}
ServerMain.java
package com.example;

import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.websocket.server.WebSocketUpgradeHandler;

public class ServerMain {

    public static void main(String[] args) throws Exception {
        
        Server server = new Server(8080);

        WebSocketUpgradeHandler wsHandler = WebSocketUpgradeHandler.from(server);
        server.setHandler(wsHandler);

        wsHandler.getServerWebSocketContainer()
                 .addMapping("/chat",
                         (upgradeRequest, upgradeResponse, callback) -> new ChatServerEndpoint());

        server.start();
        System.out.println("[SERVER] Started at ws://localhost:8080/chat");
        server.join();   
    }
}

Netty WebSocket
NettyWsClient.java
import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.http.DefaultHttpHeaders;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketClientHandshaker;
import io.netty.handler.codec.http.websocketx.WebSocketClientHandshakerFactory;
import io.netty.handler.codec.http.websocketx.WebSocketVersion;

import java.net.URI;

public class NettyWsClient {

    private final URI serverUri;

    public NettyWsClient(URI serverUri) {
        this.serverUri = serverUri;
    }

    public void start() throws InterruptedException {
        EventLoopGroup group = new NioEventLoopGroup();

        try {
            WebSocketClientHandshaker handshaker = WebSocketClientHandshakerFactory.newHandshaker(
                    serverUri, WebSocketVersion.V13, null, true, new DefaultHttpHeaders());

            NettyWsClientHandler handler = new NettyWsClientHandler(handshaker);

            Bootstrap bootstrap = new Bootstrap();
            bootstrap.group(group)
                     .channel(NioSocketChannel.class)
                     .handler(new NettyWsClientInitializer(handler));

            Channel channel = bootstrap.connect(serverUri.getHost(), serverUri.getPort()).sync().channel();
            handler.handshakeFuture().sync();

            channel.writeAndFlush(new TextWebSocketFrame("Hello from config-builder client"));

            Thread.sleep(1000);
            channel.close().sync();
        } finally {
            group.shutdownGracefully();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        URI uri = URI.create("ws://localhost:8080/ws/chat");
        new NettyWsClient(uri).start();
    }
}
NettyWsServerInitializer.java
import io.netty.channel.ChannelInitializer;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolConfig;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;

public class NettyWsServerInitializer extends ChannelInitializer<SocketChannel> {

    @Override
    protected void initChannel(SocketChannel ch) {
        WebSocketServerProtocolConfig config = WebSocketServerProtocolConfig.newBuilder()
                .websocketPath("/ws/chat")
                .checkStartsWith(true)
                .build();

        ch.pipeline()
          .addLast(new HttpServerCodec())
          .addLast(new HttpObjectAggregator(65536))
          .addLast(new WebSocketServerProtocolHandler(config))
          .addLast(new NettyWsFrameHandler());
    }
}