Using STOMP protocol - Atmosphere/atmosphere Wiki

Background

This document shows how you can write your application with Atmosphere and its support for STOMP protocol. With this support, Atmosphere exposes an API that helps developers to implement their features efficiently with minimal line of codes.

This tutorial focuses on how we can create virtual handlers mapped to different destinations over a single connection which is indeed mapped to only one real destination. By managing virtual destinations, Atmosphere's STOMP support provides the ability to map any method you want to expose as a service. Only thing you have to do is declare the mapping with a simple method annotation exactly like you do with JAX-RS.

Prerequities

To follow this tutorial, you have to be confortable with Atmosphere concepts. If this is not case, you may follow the getting started guide. You should also know what is STOMP and the javascript client library we recommend in this tutorial: stomp.js.

Installation

Inside your pom.xml, you can add the dependency for STOMP support by Atmosphere. You can get the latest version available on maven central.

<dependency>
    <groupId>org.atmosphere</groupId>
    <artifactId>atmosphere-stomp</artifactId>
    <version>${atmosphere-stomp.version}</version>
</dependency>

That's it! The Atmosphere Framework will enable automatically STOMP support by installing appropriate interceptors, filters and handler.

Writing your service

First your service class must be annotated with @StompEndpoint:

@StompEndpoint
public class StompBusinessService {

}

Then you can write your service in several ways regarding what you want to consume and what you want to broadcast. However, any method exposed by STOMP support must be annotated with @StompService. The annotation contains the "destination" atribute that indicates the mapped virtual path:

@StompService(destination = "/foo")
public void foo() {

}

Service that returns a string broadcasted to all destination's subscribers

In this sample, we additionally specify the AtmosphereResource that sends the message to "/broadcast-retval". The method returns the resource's UUID. Any returned value will be broadcasted to all connections which subsribed to "/broadcast-retval".

@StompService(destination = "/broadcast-retval")
public String bar(final AtmosphereResource r) {
    return r.uuid();
}

void method that broadcast nothing by default

In this sample, we use a void method because we don't want to broadcast anything by default. However, we ask for the broacaster identified by the mapped destination to take control over the broadcast strategy.

@StompService(destination = "/do-not-broadcast-by-default")
public void baz(final AtmosphereResource r, final Broadcaster broadcaster) {
    broadcaster.broadcast(r.uuid() + " from " + DESTINATION_HELLO_WORLD);
}

Dealing with DTO

Most of the time, you want to send complex objects to your services. This example takes advantage from the encoders and decoders provided by atmosphere:

@StompService(destination = "/using-dto")
@Message(encoders = { BusinessDtoEncoder.class }, decoders = {BusinessDtoDecoder.class })
public BusinessDto dto(final BusinessDto dto) {
    return dto;
}

If you're not confortable with encoders and decoders, see this tutorial.

Writing your client code

Be sure you have included the atmosphere-javascript library first.

In this sample, we used stomp.js as client library that builds instance over an atmosphere subscription.

// Build atmosphere request object as usual
var request = { {
    url: document.location.protocol + "//" + document.location.host + '/stomp',
    ...
};

// We use Stomp.js here
var client = Stomp.over(new $.atmosphere.WebsocketApiAdapter(request));

// Bind a callback to a subscription
client.subscribe("/using-dto", function(e) {
    ...
});

// Send data to the destination
var myDto = { ... };
client.send("/using-dto", {}, myDto);

This code:

Conclusion

You finally get how you can take advantage from STOMP support by Atmosphere to create very easily your services. You can now write your services over a single websocket connection with fallback transport at a higher level like JAX-RS offers!