-
-
Notifications
You must be signed in to change notification settings - Fork 761
Understanding Broadcaster
The Broadcaster is Atmosphere's pub/sub message bus. It delivers messages to all suspended AtmosphereResource connections that have been added to it.
For most applications, you won't interact with Broadcaster directly —
@ManagedServicehandles it automatically. This page is useful when you need to customize message delivery or build advanced patterns.
Client A ──┐
├── Broadcaster ──┬── Client A (receives)
Client B ──┤ "/chat" ├── Client B (receives)
│ └── Client C (receives)
Client C ──┘
- Each
@ManagedService(path = "/chat")creates a Broadcaster with ID/chat - When a client connects, its
AtmosphereResourceis added to the Broadcaster - When
@Messagereturns a value, it's broadcast to all resources on that Broadcaster - Messages pass through BroadcastFilters before delivery
- Undelivered messages are stored in the BroadcasterCache for reconnecting clients
@ManagedService(path = "/chat") public class Chat { @Inject @Named("/chat") private Broadcaster broadcaster; @Inject private BroadcasterFactory factory; @Ready public void onReady() { // Broadcast to everyone on this path broadcaster.broadcast("A new user joined!"); // Look up any broadcaster by ID Broadcaster other = factory.lookup("/notifications", true); other.broadcast("New user in chat"); } }
// Broadcasting broadcaster.broadcast(message); // To all members broadcaster.broadcast(message, resource); // Exclude one resource broadcaster.broadcast(message, Set.of(r1, r2)); // To specific resources only // Delayed / scheduled broadcaster.delayBroadcast(message, 5, TimeUnit.SECONDS); broadcaster.scheduleFixedBroadcast(message, 10, TimeUnit.SECONDS); // Resource management broadcaster.addAtmosphereResource(resource); broadcaster.removeAtmosphereResource(resource); broadcaster.getAtmosphereResources(); // All connected resources
The cache stores messages that were broadcast while a client was disconnected (e.g., during a long-polling reconnect cycle). When the client reconnects, cached messages are delivered automatically.
@ManagedService uses UUIDBroadcasterCache by default — no configuration needed.
@ManagedService(path = "/chat", broadcasterCache = MyCache.class) public class Chat { /* ... */ }
Implement the BroadcasterCache interface:
public interface BroadcasterCache { void start(); void stop(); void cleanup(); // Store a message during broadcast CacheMessage addToCache(String broadcasterId, String uuid, BroadcastMessage message); // Retrieve cached messages for a reconnecting client List<Object> retrieveFromCache(String broadcasterId, String uuid); }
Filters transform or reject messages before they reach clients. Use them for content transformation, sanitization, or selective delivery.
public class ProfanityFilter implements BroadcastFilter { @Override public BroadcastAction filter(String broadcasterId, Object originalMessage, Object message) { String text = message.toString(); if (containsProfanity(text)) { return new BroadcastAction(ACTION.ABORT); // Drop the message } String cleaned = sanitize(text); return new BroadcastAction(ACTION.CONTINUE, cleaned); // Transform } }
| Action | Effect |
|---|---|
CONTINUE |
Pass message to next filter (optionally transformed) |
ABORT |
Drop the message entirely |
SKIP |
Skip remaining filters, deliver as-is |
// Via annotation @ManagedService(path = "/chat", broadcastFilters = {ProfanityFilter.class}) public class Chat { /* ... */ } // Or via annotation on the filter class itself @BroadcasterFilterService public class ProfanityFilter implements BroadcastFilter { /* ... */ }
For filters that need access to the target resource (e.g., to filter differently per user), implement PerRequestBroadcastFilter:
public class RoleFilter implements PerRequestBroadcastFilter { @Override public BroadcastAction filter(String broadcasterId, AtmosphereResource r, Object originalMessage, Object message) { // Access r.getRequest() for session/auth info if (isAdmin(r)) { return new BroadcastAction(ACTION.CONTINUE, message); } return new BroadcastAction(ACTION.CONTINUE, redact(message)); } @Override public BroadcastAction filter(String broadcasterId, Object originalMessage, Object message) { return new BroadcastAction(ACTION.CONTINUE, message); } }
Listen to Broadcaster lifecycle events:
@BroadcasterListenerService public class MyListener implements BroadcasterListener { public void onPostCreate(Broadcaster b) { /* new broadcaster */ } public void onComplete(Broadcaster b) { /* broadcast delivered */ } public void onPreDestroy(Broadcaster b) { /* broadcaster shutting down */ } public void onAddAtmosphereResource(Broadcaster b, AtmosphereResource r) { /* client joined */ } public void onRemoveAtmosphereResource(Broadcaster b, AtmosphereResource r) { /* client left */ } public void onMessage(Broadcaster b, Deliver deliver) { /* message queued */ } }
| Feature | Broadcaster | Room |
|---|---|---|
| Level | Low-level | High-level |
| Identity | Path-based ID | Named group |
| Presence | Manual tracking | Built-in events |
| Direct messaging | Manual UUID lookup | room.sendTo(memberId, msg) |
| Message history | Via BroadcasterCache | room.enableHistory(n) |
| Client protocol | Manual | Built into atmosphere.js |
For most chat/collaboration apps, prefer Rooms. Use Broadcaster directly when you need fine-grained control over message delivery.