WebSocket Communication

Back

Loading concept...

๐Ÿš€ WebSocket Communication in Jakarta EE

The Story of the Magic Walkie-Talkie

Imagine you and your best friend have special walkie-talkies. Unlike regular phones where you call, talk, and hang up, these magical walkie-talkies stay connected ALL the time! You can talk whenever you want, and your friend hears you instantly. No need to dial again and again.

Thatโ€™s exactly what WebSocket is! A connection that stays open between your app and a server, so messages flow back and forth like a real conversation.


๐ŸŽฏ What Weโ€™ll Learn

Concept What It Does
Message Handlers Catch and respond to messages
Encoders Turn objects into text/bytes
Decoders Turn text/bytes back into objects
Path Parameters Add IDs in the URL
WebSocket Configurator Custom setup before connecting
WebSocket Client API Connect TO a server (not just receive)

๐Ÿ“ฌ Message Handlers

What Are They?

Think of message handlers like a mailbox with a smart helper inside. When a letter arrives, the helper reads it and knows exactly what to do!

In WebSocket, when someone sends you a message, a Message Handler catches it and runs your code.

The Three Types of Handlers

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

    // 1. Text messages (like letters)
    @OnMessage
    public void onTextMessage(
        String message,
        Session session) {
        System.out.println("Got: " + message);
    }

    // 2. Binary messages (like packages)
    @OnMessage
    public void onBinaryMessage(
        ByteBuffer data,
        Session session) {
        System.out.println("Got bytes!");
    }

    // 3. Pong messages (heartbeat reply)
    @OnMessage
    public void onPongMessage(
        PongMessage pong,
        Session session) {
        System.out.println("Still alive!");
    }
}

Simple Example: Echo Server

@ServerEndpoint("/echo")
public class EchoEndpoint {

    @OnMessage
    public String echo(String msg) {
        // Whatever you send, I send back!
        return "You said: " + msg;
    }
}

Real Life: This is like shouting in a canyon and hearing your voice come back!


๐ŸŽ Encoders

What Are They?

Imagine you want to send a toy car through the mail. You canโ€™t just throw it in the mailbox! You need to pack it in a box first.

Encoders pack your Java objects into text (JSON) or bytes so they can travel through WebSocket.

Text Encoder Example

public class MessageEncoder
    implements Encoder.Text<ChatMessage> {

    @Override
    public String encode(ChatMessage msg) {
        // Pack the object into JSON text
        return "{\"user\":\"" + msg.getUser()
             + "\",\"text\":\"" + msg.getText()
             + "\"}";
    }

    @Override
    public void init(EndpointConfig config) {}

    @Override
    public void destroy() {}
}

Using the Encoder

@ServerEndpoint(
    value = "/chat",
    encoders = { MessageEncoder.class }
)
public class ChatEndpoint {

    @OnMessage
    public ChatMessage respond(String input) {
        // Return an object - encoder packs it!
        return new ChatMessage("Bot", "Hi there!");
    }
}

Think of it like: Your encoder is a gift-wrapper that makes objects ready to travel!


๐Ÿ“ฆ Decoders

What Are They?

Now the opposite! When a package arrives, you need to unpack it to see the toy inside.

Decoders unpack incoming text or bytes back into Java objects you can use.

Text Decoder Example

public class MessageDecoder
    implements Decoder.Text<ChatMessage> {

    @Override
    public ChatMessage decode(String json) {
        // Unpack JSON into an object
        // (simplified parsing)
        String user = extractUser(json);
        String text = extractText(json);
        return new ChatMessage(user, text);
    }

    @Override
    public boolean willDecode(String json) {
        // Can we decode this message?
        return json.contains("user")
            && json.contains("text");
    }

    @Override
    public void init(EndpointConfig config) {}

    @Override
    public void destroy() {}
}

Using the Decoder

@ServerEndpoint(
    value = "/chat",
    decoders = { MessageDecoder.class }
)
public class ChatEndpoint {

    @OnMessage
    public void handleMessage(ChatMessage msg) {
        // Decoder already unpacked it!
        System.out.println(msg.getUser()
            + " says: " + msg.getText());
    }
}
graph TD A["Client sends JSON text"] --> B["Decoder unpacks it"] B --> C["Your code gets ChatMessage object"] C --> D["You create response object"] D --> E["Encoder packs it"] E --> F["Client receives JSON text"]

๐Ÿ›ค๏ธ WebSocket Path Parameters

What Are They?

Think about houses on a street. Each house has a number. When the pizza delivery person looks for โ€œ123 Main Street,โ€ they use the number to find YOUR house.

Path Parameters are like house numbers in your WebSocket URL!

Example: Chat Rooms

@ServerEndpoint("/chat/{roomId}")
public class RoomEndpoint {

    @OnOpen
    public void onOpen(
        Session session,
        @PathParam("roomId") String roomId) {

        System.out.println(
            "Joined room: " + roomId);
    }

    @OnMessage
    public void onMessage(
        String message,
        @PathParam("roomId") String roomId) {

        System.out.println(
            "Message in " + roomId
            + ": " + message);
    }
}

How Clients Connect

URL Room ID
ws://server/chat/games games
ws://server/chat/music music
ws://server/chat/123 123

Multiple Parameters

@ServerEndpoint("/game/{gameId}/player/{playerId}")
public class GameEndpoint {

    @OnOpen
    public void join(
        @PathParam("gameId") String gameId,
        @PathParam("playerId") String playerId) {

        System.out.println(playerId
            + " joined game " + gameId);
    }
}

URL: ws://server/game/chess/player/alice Result: Alice joins the chess game!


โš™๏ธ WebSocket Configurator

What Is It?

Before guests enter a party, sometimes you check their invitation at the door. You might also give them a name tag!

Configurator lets you do special setup BEFORE the WebSocket connection opens.

Common Uses

  1. Check cookies or tokens (authentication)
  2. Read HTTP headers
  3. Pass custom data to the endpoint

Example: Authentication Check

public class AuthConfigurator
    extends ServerEndpointConfig.Configurator {

    @Override
    public void modifyHandshake(
        ServerEndpointConfig config,
        HandshakeRequest request,
        HandshakeResponse response) {

        // Get cookies from the request
        Map<String, List<String>> headers =
            request.getHeaders();

        // Store user info for later
        String token = extractToken(headers);
        config.getUserProperties()
            .put("authToken", token);
    }
}

Using the Configurator

@ServerEndpoint(
    value = "/secure",
    configurator = AuthConfigurator.class
)
public class SecureEndpoint {

    @OnOpen
    public void onOpen(
        Session session,
        EndpointConfig config) {

        // Get the token we saved earlier
        String token = (String) config
            .getUserProperties()
            .get("authToken");

        if (!isValid(token)) {
            session.close();
        }
    }
}
graph TD A["Client connects"] --> B["Configurator runs first"] B --> C{Check token} C -->|Valid| D["Allow connection"] C -->|Invalid| E["Reject connection"] D --> F["OnOpen runs"]

๐Ÿ“ก WebSocket Client API

What Is It?

So far, weโ€™ve been the server waiting for connections. But what if YOUR code needs to connect TO another server?

The Client API lets your Java code be the one making the call!

Simple Client Example

@ClientEndpoint
public class MyClient {

    private Session session;

    @OnOpen
    public void onOpen(Session session) {
        this.session = session;
        System.out.println("Connected!");
    }

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

    public void sendMessage(String msg)
        throws IOException {
        session.getBasicRemote()
            .sendText(msg);
    }
}

Connecting to a Server

public class ClientApp {

    public static void main(String[] args)
        throws Exception {

        WebSocketContainer container =
            ContainerProvider
                .getWebSocketContainer();

        URI uri = new URI(
            "ws://example.com/chat");

        MyClient client = new MyClient();

        // Make the connection!
        Session session = container
            .connectToServer(client, uri);

        // Send a message
        client.sendMessage("Hello server!");
    }
}

Client with Encoders/Decoders

@ClientEndpoint(
    encoders = { MessageEncoder.class },
    decoders = { MessageDecoder.class }
)
public class SmartClient {

    @OnMessage
    public void onMessage(ChatMessage msg) {
        // Decoder already unpacked it!
        System.out.println(
            msg.getUser() + ": " + msg.getText());
    }
}

๐ŸŽจ Putting It All Together

Hereโ€™s a complete chat room example using EVERYTHING:

// The message object
public class ChatMessage {
    private String user;
    private String text;
    private String room;
    // getters and setters...
}

// Encoder
public class ChatEncoder
    implements Encoder.Text<ChatMessage> {
    @Override
    public String encode(ChatMessage m) {
        return String.format(
            "{\"user\":\"%s\",\"text\":\"%s\"}",
            m.getUser(), m.getText());
    }
    // init and destroy...
}

// Decoder
public class ChatDecoder
    implements Decoder.Text<ChatMessage> {
    @Override
    public ChatMessage decode(String s) {
        // Parse JSON and return object
        return parseJson(s);
    }
    @Override
    public boolean willDecode(String s) {
        return s.contains("user");
    }
    // init and destroy...
}

// Configurator
public class ChatConfig
    extends ServerEndpointConfig.Configurator {
    @Override
    public void modifyHandshake(
        ServerEndpointConfig sec,
        HandshakeRequest req,
        HandshakeResponse res) {
        sec.getUserProperties()
            .put("ip", getClientIP(req));
    }
}

// The endpoint (server)
@ServerEndpoint(
    value = "/chat/{room}",
    encoders = { ChatEncoder.class },
    decoders = { ChatDecoder.class },
    configurator = ChatConfig.class
)
public class ChatServer {

    @OnOpen
    public void onOpen(
        Session session,
        @PathParam("room") String room) {
        System.out.println(
            "Someone joined " + room);
    }

    @OnMessage
    public ChatMessage onMessage(
        ChatMessage msg,
        @PathParam("room") String room) {
        msg.setRoom(room);
        return msg; // Echo to sender
    }
}

๐Ÿ† Quick Summary

Concept One-Liner
Message Handlers Catch messages with @OnMessage
Encoders Pack objects โ†’ text/bytes
Decoders Unpack text/bytes โ†’ objects
Path Parameters IDs in the URL like /chat/{roomId}
Configurator Setup before connection opens
Client API YOUR code connects to a server

๐Ÿ’ก Remember This!

WebSocket = Always-open walkie-talkie

  • Handlers answer the call
  • Encoders pack your gifts
  • Decoders unwrap incoming gifts
  • Path Params are room numbers
  • Configurator checks invitations
  • Client API lets YOU call someone

Youโ€™re now ready to build real-time apps that talk back and forth instantly! ๐ŸŽ‰

Loading story...

Story - Premium Content

Please sign in to view this story and start learning.

Upgrade to Premium to unlock full access to all stories.

Stay Tuned!

Story is coming soon.

Story Preview

Story - Premium Content

Please sign in to view this concept and start learning.

Upgrade to Premium to unlock full access to all content.