Skip to content

Understanding ManagedService

jfarcand edited this page Feb 18, 2026 · 2 revisions

Understanding @ManagedService

@ManagedService is the recommended way to build Atmosphere applications. It provides an annotation-driven programming model with automatic lifecycle management, message encoding/decoding, and dependency injection.

Quick Example

@ManagedService(path = "/chat")
public class Chat {

    @Inject
    private BroadcasterFactory factory;

    @Inject
    private AtmosphereResource r;

    @Inject
    private AtmosphereResourceEvent event;

    @Ready
    public void onReady() {
        // Connection is suspended and ready to receive messages
    }

    @Disconnect
    public void onDisconnect() {
        if (event.isCancelled()) {
            // Unexpected disconnect
        } else if (event.isClosedByClient()) {
            // Client closed the connection
        }
    }

    @Message(encoders = {JacksonEncoder.class}, decoders = {JacksonDecoder.class})
    public Message onMessage(Message message) {
        // Return value is broadcast to all connected clients
        return message;
    }

    @Heartbeat
    public void onHeartbeat(AtmosphereResourceEvent event) {
        // Client heartbeat received
    }
}

What @ManagedService Configures Automatically

When you annotate a class with @ManagedService, Atmosphere automatically installs:

Component Purpose
UUIDBroadcasterCache Caches messages so reconnecting clients don't miss data
AtmosphereResourceLifecycleInterceptor Manages connection suspend/resume lifecycle
TrackMessageSizeInterceptor Guarantees complete message delivery
HeartbeatInterceptor Keeps connections alive across proxies
SuspendTrackerInterceptor Tracks suspended connections

Annotation Reference

@ManagedService (class-level)

Attribute Type Default Description
path String "/" URL mapping for this handler
broadcaster Class DefaultBroadcaster.class Broadcaster implementation
broadcasterCache Class UUIDBroadcasterCache.class Message cache implementation
interceptors Class[] {} Additional interceptors (appended to defaults)
broadcastFilters Class[] {} Message filters applied before broadcast
listeners Class[] {} Event listeners for connection tracking
atmosphereConfig String[] {} Key-value config (e.g. "org.atmosphere.cpr.maxInactiveActivity=120000")

Lifecycle Annotations (method-level)

Annotation When Invoked Typical Use
@Ready Connection suspended and ready Log connection, send welcome message
@Disconnect Client disconnects Clean up, notify others
@Message Message received from Broadcaster Process and optionally re-broadcast
@Heartbeat Client heartbeat received Logging, presence tracking

HTTP Method Annotations (method-level)

Annotation Description
@Get Handle HTTP GET (e.g. set response encoding)
@Post Handle HTTP POST
@Put Handle HTTP PUT
@Delete Handle HTTP DELETE

Utility Annotations

Annotation Target Description
@Singleton Class Single instance shared across all connections
@PathParam Field Bind URI template variable (e.g. /chat/{room})
@DeliverTo Method Control broadcast scope: RESOURCE, BROADCASTER, or ALL

Dependency Injection

@ManagedService classes support @Inject (Jakarta CDI) for:

@Inject private AtmosphereResource r;           // Current connection
@Inject private AtmosphereResourceEvent event;   // Current event
@Inject private BroadcasterFactory factory;      // Create/lookup broadcasters
@Inject @Named("/chat") private Broadcaster b;   // Named broadcaster

Encoders and Decoders

The @Message annotation supports automatic type conversion:

// Encoder: converts your object to a String for the wire
public class JacksonEncoder implements Encoder<Message, String> {
    @Inject private ObjectMapper mapper;

    @Override
    public String encode(Message m) {
        return mapper.writeValueAsString(m);
    }
}

// Decoder: converts incoming String to your object
public class JacksonDecoder implements Decoder<String, Message> {
    @Inject private ObjectMapper mapper;

    @Override
    public Message decode(String s) {
        return mapper.readValue(s, Message.class);
    }
}

// Usage
@Message(encoders = {JacksonEncoder.class}, decoders = {JacksonDecoder.class})
public Message onMessage(Message message) {
    return message; // Automatically decoded from JSON, re-encoded for broadcast
}

Path Templates

Use @PathParam to capture URI variables:

@ManagedService(path = "/chat/{room}")
public class Chat {

    @PathParam("room")
    private String roomName;

    @Ready
    public void onReady() {
        // roomName is populated from the URL
        // e.g. /chat/lobby → roomName = "lobby"
    }
}

Each unique path creates a separate Broadcaster, so /chat/lobby and /chat/general have independent message streams.

Delivery Scope

Control who receives the return value of a @Message method:

@Message
@DeliverTo(DeliverTo.DELIVER_TO.BROADCASTER)  // All connections on this path
public String onMessage(String message) {
    return "Echo: " + message;
}

@Message
@DeliverTo(DeliverTo.DELIVER_TO.RESOURCE)     // Only the sender
public String onPrivateMessage(String message) {
    return "Only you see this";
}

Configuration

Pass Atmosphere config via the atmosphereConfig attribute:

@ManagedService(
    path = "/chat",
    atmosphereConfig = {
        "org.atmosphere.cpr.maxInactiveActivity=120000",
        "org.atmosphere.websocket.maxTextMessageSize=65536"
    }
)

See Also

Clone this wiki locally