vdenotaris
vdenotaris

Reputation: 13637

Configure a WebSocket Server in Spring 4

I'm developing a realtime notification system through WebSockets by using Spring 4.

The source code is as follows:

WebSocketConfig:

@Configuration
@EnableScheduling
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/lrt").withSockJS();
    }

    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
        registry.enableSimpleBroker("/queue/", "/topic/");
        registry.setApplicationDestinationPrefixes("/app");
    }

}

LRTStatusListener:

@Service
public class LRTStatusListener implements ApplicationListener<BrokerAvailabilityEvent>{

    private static final Logger LOG = LoggerFactory.getLogger(LRTStatusListener.class);
    private final static long LRT_ID = 1234567890;
    private final static String LRT_OWNER = "Walter White";
    private final LRTStatusGenerator lrtStatusGenerator = new LRTStatusGenerator(LRT_ID, LRT_OWNER);
    private final MessageSendingOperations<String> messagingTemplate;
    private AtomicBoolean brokerAvailable = new AtomicBoolean();

    @Autowired
    public LRTStatusListener(MessageSendingOperations<String> messagingTemplate) {
        this.messagingTemplate = messagingTemplate;
    }

    @Override
    public void onApplicationEvent(BrokerAvailabilityEvent event) {
        this.brokerAvailable.set(event.isBrokerAvailable());
    }

    @Scheduled(fixedDelay=2000)
    public void sendLRTStatus() {
        LRTStatus lrtStatus = this.lrtStatusGenerator.generateLRTStatus();
        if (LOG.isTraceEnabled())
            LOG.trace("Sending LRT status");
        if (this.brokerAvailable.get())
            this.messagingTemplate
                .convertAndSend("/topic/status" + lrtStatus.getLRTId(), lrtStatus);
    }

    // Random status generator
    private static class LRTStatusGenerator {

        private LRTStatus lrtStatus;

        public LRTStatusGenerator(long lrtId, String owner) {
            lrtStatus = new LRTStatus(lrtId, owner, getCurrentTimestamp(), generateLRTStatusMessage());
        }

        public LRTStatus generateLRTStatus() {
            lrtStatus.setMessage(generateLRTStatusMessage());
            return lrtStatus;
        }

        private String getCurrentTimestamp() {
            Date date = new Date();
            Timestamp timestamp = new Timestamp(date.getTime());
            return timestamp.toString();
        }

        private String generateLRTStatusMessage() {
            String statusMessage;
            switch ((int) Math.random() * 2) {
            case 1:
                statusMessage =
                        "HANK: What? You want me to beg? You're the smartest guy I ever met. " +
                        "And you're too stupid to see... he made up his mind ten minutes ago.";
                break;
            case 2:
                statusMessage =
                        "WALTER: That's right. Now say my name. " +
                        "- DECLAN: ...You're Heisenberg. - WALTER: You're goddamn right.";
                break;
            default:
                statusMessage =
                        "WALTER: I am not in danger, Skyler. I am the danger! " +
                        "A guy opens his door and gets shot and you think that of me? " +
                        "No. I am the one who knocks!";
                break;
            }
            return statusMessage;
        }

    }

}

CheckLRTStatusController

@Controller
public class CheckLRTStatusController {

    @MessageExceptionHandler
    @SendToUser("/topic/errors")
    public String handleException(Throwable exception) {
        return exception.getMessage();
    }

}

The application simulates the status of a long running transaction (LRT), by changing its info every 2000ms.

Now, I'm testing the WebSocket by defining a client via SockJS:

<script src="http://cdn.sockjs.org/sockjs-0.3.min.js"></script>
<script>
    var sock = new SockJS('/lrt');
    sock.onopen = function() {
        console.log('open');
    };
    sock.onmessage = function(e) {
        console.log('message', e.data);
    };
    sock.onclose = function() {
        console.log('close');
    };
</script>

The connection works fine, but I'm unable to see the data stream.

How can I properly configure my application in order to produce and then route on my client's console the messages sent by the WebSocket Server?

Note that I'm also using a build-in Message Broker with the aim to manage the message queue.

Upvotes: 4

Views: 807

Answers (1)

Bogdan
Bogdan

Reputation: 24590

Is this the only JavaScript code you currently have?:

<script src="http://cdn.sockjs.org/sockjs-0.3.min.js"></script>
<script>
    var sock = new SockJS('/lrt');
    sock.onopen = function() {
        console.log('open');
    };
    sock.onmessage = function(e) {
        console.log('message', e.data);
    };
    sock.onclose = function() {
        console.log('close');
    };
</script>

That only sets up the connection with fallback on SockJS but you are not subscribing to the message broker. You need to do that too.

In your current setup you have:

registry.enableSimpleBroker("/queue/", "/topic/");

You need to create a JavaScript STOMP client (over SockJS) that subscribes for those, something like:

stompClient.subscribe("/topic/status*", function(message) {
    ...
});

stompClient.subscribe("/queue/whatever", function(message) {
    ...
});

Have a look at the spring-websocket-portfolio application for a complete working example.

Upvotes: 4

Related Questions