Enterprise Java

Web socket Java client for Stomp-Spring server side

Problem :

As an analysis for an issue I had to write a simple java web socket client site code connecting to a Spring based application on the server side with a stomp based web socket broker .

Solution :

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.rnd</groupId>
    <artifactId>SockWebsocketClient</artifactId>
    <version>1.0-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.0.3.RELEASE</version>
    </parent>
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-messaging</artifactId>
            <version>5.0.7.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.9.5</version>
        </dependency>
        <dependency>
            <groupId>org.apache.tomcat.embed</groupId>
            <artifactId>tomcat-embed-websocket</artifactId>
            <version>9.0.8</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-dependencies</artifactId>
            <version>2.0.2.RELEASE</version>
            <type>pom</type>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.0.7.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-websocket</artifactId>
            <version>5.0.7.RELEASE</version>
        </dependency>
    </dependencies>
</project>

Sock JS Client

Its the main class , a simple one doing the basic job . As most of the web sockets these days are meant to use SSL , so tried to by pass the trust manager issue by creating a dummy TrustManager .

The input to this code is the topic string you want to subscribe to .

Also dont miss to change the <URL> string in the code before you run , pointing to your web socket url.

package com.client;

import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHeaders;
import org.springframework.messaging.converter.MessageConverter;
import org.springframework.messaging.converter.SimpleMessageConverter;
import org.springframework.messaging.converter.StringMessageConverter;
import org.springframework.messaging.simp.stomp.StompHeaders;
import org.springframework.web.socket.WebSocketHttpHeaders;
import org.springframework.web.socket.client.standard.StandardWebSocketClient;
import org.springframework.web.socket.messaging.WebSocketStompClient;
import org.springframework.web.socket.sockjs.client.Transport;
import org.springframework.web.socket.sockjs.client.WebSocketTransport;
import org.springframework.web.socket.sockjs.frame.Jackson2SockJsMessageCodec;

import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.net.URI;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class SockJsClient {


    public static void main(String[] args) {

        try {
            StandardWebSocketClient simpleWebSocketClient = new StandardWebSocketClient();


            TrustManager[] trustAllCerts = new TrustManager[] {new X509TrustManager() {
                public X509Certificate[] getAcceptedIssuers() {
                    return null;
                }
                public void checkClientTrusted(X509Certificate[] certs, String authType) {
                }
                public void checkServerTrusted(X509Certificate[] certs, String authType) {
                }
            }
            };


            SSLContext sc = SSLContext.getInstance("SSL");
            sc.init(null, trustAllCerts, new java.security.SecureRandom());
            HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());

            Map<String, Object> properties = new HashMap<>();
            properties.put("org.apache.tomcat.websocket.SSL_CONTEXT", sc);
            simpleWebSocketClient.setUserProperties(properties);

            List<Transport> transports = new ArrayList();
            transports.add(new WebSocketTransport(simpleWebSocketClient));

            org.springframework.web.socket.sockjs.client.SockJsClient sockJsClient = new org.springframework.web.socket.sockjs.client.SockJsClient(transports);
            sockJsClient.setMessageCodec(new Jackson2SockJsMessageCodec());
            WebSocketStompClient stompClient = new WebSocketStompClient(sockJsClient);
            stompClient.setMessageConverter(new MessageConverter() {
                @Override
                public Object fromMessage(Message<?> message, Class<?> aClass) {
                    return new String((byte[])message.getPayload());
                }

                @Override
                public Message<?> toMessage(Object o, MessageHeaders messageHeaders) {
                    return null;
                }
            });

            // url : pointing to websocket as sockJs first tries to get info by sending a HTTP request
            // and then sends an upgrade request to ws or wss. So your url should be some thing like htttp://

            URI stompUrlEndpoint = new URI("<url>");

            WebSocketHttpHeaders handshakeHeaders = new WebSocketHttpHeaders();
            StompHeaders connectHeaders = new StompHeaders();

            /*Can set connection header like login , passcode in connectHeaders  */

            stompClient.connect(stompUrlEndpoint.toString(), handshakeHeaders, connectHeaders, new SessionHandler(args[0]), new Object[0]);

            Thread.sleep(30000);
            stompClient.stop();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Session Handler

Every socket connection need a session handler and here is one which takes care of connection setup and in-coming messages.

package com.client;

import org.springframework.messaging.simp.stomp.StompCommand;
import org.springframework.messaging.simp.stomp.StompFrameHandler;
import org.springframework.messaging.simp.stomp.StompHeaders;
import org.springframework.messaging.simp.stomp.StompSession;
import org.springframework.messaging.simp.stomp.StompSessionHandlerAdapter;

import java.lang.reflect.Type;

public class SessionHandler extends StompSessionHandlerAdapter {

    private final String topicName ;

    public SessionHandler(String topicName) {
        this.topicName = topicName;
    }

    @Override
    public void afterConnected(StompSession session, StompHeaders connectedHeaders) {
        this.subscribeTo(session);
    }

    @Override
    public void handleException(StompSession session,StompCommand command,StompHeaders headers,byte[] payload,Throwable exception ) {
        exception.printStackTrace();
    }


    public void handleFrame(StompHeaders headers, Object payload) {
        System.out.println(payload.toString());
    }


    @Override
    public void handleTransportError(StompSession session, Throwable exception) {
        exception.printStackTrace();
    }

    private void subscribeTo(StompSession session) {
        StompHeaders headers = new StompHeaders();
        headers.add("id","websocket-session-standalone-0");
        headers.add("destination",topicName);

        session.subscribe(headers, new StompFrameHandler() {
            @Override
            public Type getPayloadType(StompHeaders stompHeaders) {
                return String.class;
            }

            @Override
            public void handleFrame(StompHeaders stompHeaders, Object o) {
                System.out.println( " Message is " +
                        o.toString()
                );
            }
        });
    }
}
Published on Java Code Geeks with permission by Abhijeet Iyengar, partner at our JCG program. See the original article here: Web socket java client for Stomp-Spring server side.

 

Opinions expressed by Java Code Geeks contributors are their own.

Want to know how to develop your skillset to become a Java Rockstar?

Join our newsletter to start rocking!

To get you started we give you our best selling eBooks for FREE!

 

1. JPA Mini Book

2. JVM Troubleshooting Guide

3. JUnit Tutorial for Unit Testing

4. Java Annotations Tutorial

5. Java Interview Questions

6. Spring Interview Questions

7. Android UI Design

 

and many more ....

 

Receive Java & Developer job alerts in your Area

I have read and agree to the terms & conditions

 

Abhijeet Iyengar

Abhijeet is a Software Engineer working with financial client . He has been involved in building UI and service based applications.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Back to top button