Understanding Broadcaster - Atmosphere/atmosphere GitHub Wiki
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 resourcesThe 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.