Multi tenancy pattern using JGroups - Atmosphere/atmosphere Wiki

Each tenant requires a separate JGroups cluster to receive messages. This can cause issues with too many sockets opened and port conflict issues if using TCP.

The JGroupsBroadcaster can act as a hub for many local broadcasters on each node. Each instance of a local broadcaster represents a tenant on that node. Only a single JGroups cluster is created and shared. Messages are relayed from the JGroupBroadcaster to the local ones.

The tenant name needs to get passed around in order to match the local broadcaster held in a map

Client connection: ` public void doGet(AtmosphereResource ar) {

	String tenantName = ar.getRequest().getParameter("tenant");
	String broadcasterName = "LocalBroadcaster-" + tenantName;

	BroadcasterFactory factory = ar.getAtmosphereConfig().getBroadcasterFactory();
	Broadcaster globalBroadcaster = factory.lookup(JGroupsBroadcasterTCP.class, "GlobalBroadcaster", true);
	
	// Create local broadcaster
	Broadcaster localBroadcaster = factory.lookup(DefaultBroadcaster.class, broadcasterName, true);
	
	// Add local broadcaster to registry
	localBroadcasterRegistry.putIfAbsent(tenantName, broadcasterName);
	
	// Attach broadcaster to the client connection
	ar.setBroadcaster(localBroadcaster);
	
	// Create listener and add to global broadcaster
	BroadcasterListener globalBcListener = new BroadcasterListener() {

		@Override
		public void onRemoveAtmosphereResource(Broadcaster b, AtmosphereResource r) {
		}

		@Override
		public void onPreDestroy(Broadcaster b) {
		}

		@Override
		public void onPostCreate(Broadcaster b) {
		}

		@Override
		public void onMessage(Broadcaster b, Deliver deliver) {
			
			String key = ((MyPayload) deliver.getMessage()).getTenantName();
			String localBcName = localBroadcasterRegistry.get(key);
			
			Broadcaster localBc = factory.lookup(DefaultBroadcaster.class, localBcName, true);
			localBc.broadcast(deliver.getMessage());
		}

		@Override
		public void onComplete(Broadcaster b) {
		}

		@Override
		public void onAddAtmosphereResource(Broadcaster b, AtmosphereResource r) {
		}
	};
	
	globalBroadcaster.addBroadcasterListener(globalBcListener);

	ar.suspend();
}

`

Send events:

`Broadcaster br = broadcasterFactory.lookup(JGroupsBroadcasterTCP.class, "GlobalBroadcaster", true);

br.broadcast(context);`