use of org.atmosphere.cache.BroadcastMessage in project atmosphere by Atmosphere.
the class DefaultBroadcaster method deliverPush.
protected void deliverPush(Deliver deliver, boolean rec) {
recentActivity.set(true);
String prevMessage = deliver.message.toString();
if (rec && !delayedBroadcast.isEmpty()) {
Iterator<Deliver> i = delayedBroadcast.iterator();
StringBuilder b = new StringBuilder();
while (i.hasNext()) {
Deliver e = i.next();
e.future.cancel(true);
try {
// Append so we do a single flush
if (e.message instanceof String && deliver.message instanceof String) {
b.append(e.message);
} else {
deliverPush(e, false);
}
} finally {
i.remove();
}
}
if (b.length() > 0) {
deliver.message = b.append(deliver.message).toString();
}
}
Object finalMsg = callable(deliver.message);
if (finalMsg == null) {
logger.error("Callable exception. Please catch all exceptions from your callable. Message {} will be lost and all AtmosphereResource " + "associated with this Broadcaster resumed.", deliver.message);
entryDone(deliver.future);
switch(deliver.type) {
case ALL:
synchronized (resources) {
for (AtmosphereResource r : resources) {
if (Utils.resumableTransport(r.transport()))
try {
r.resume();
} catch (Throwable t) {
logger.trace("resumeAll", t);
}
}
}
break;
case RESOURCE:
deliver.resource.resume();
break;
case SET:
for (AtmosphereResource r : deliver.resources) {
r.resume();
}
break;
}
return;
}
notifyOnMessage(deliver);
Object prevM = deliver.originalMessage;
deliver.originalMessage = (deliver.originalMessage != deliver.message ? callable(deliver.originalMessage) : finalMsg);
if (deliver.originalMessage == null) {
logger.trace("Broadcasted message was null {}", prevM);
entryDone(deliver.future);
return;
}
deliver.message = finalMsg;
Map<String, CacheMessage> cacheForSet = deliver.type == Deliver.TYPE.SET ? new HashMap<String, CacheMessage>() : null;
// We cache first, and if the broadcast succeed, we will remove it.
switch(deliver.type) {
case ALL:
deliver.cache = bc.getBroadcasterCache().addToCache(getID(), BroadcasterCache.NULL, new BroadcastMessage(deliver.originalMessage));
break;
case RESOURCE:
deliver.cache = bc.getBroadcasterCache().addToCache(getID(), deliver.resource.uuid(), new BroadcastMessage(deliver.originalMessage));
break;
case SET:
for (AtmosphereResource r : deliver.resources) {
cacheForSet.put(r.uuid(), bc.getBroadcasterCache().addToCache(getID(), r.uuid(), new BroadcastMessage(deliver.originalMessage)));
}
break;
}
if (resources.isEmpty()) {
logger.trace("No resource available for {} and message {}", getID(), finalMsg);
entryDone(deliver.future);
if (cacheForSet != null) {
cacheForSet.clear();
}
return;
}
try {
if (logger.isTraceEnabled()) {
for (AtmosphereResource r : resources) {
logger.trace("AtmosphereResource {} available for {}", r.uuid(), deliver.message);
}
}
boolean hasFilters = bc.hasPerRequestFilters();
Object beforeProcessingMessage = deliver.message;
switch(deliver.type) {
case ALL:
AtomicInteger count = new AtomicInteger(resources.size());
for (AtmosphereResource r : resources) {
deliver.message = beforeProcessingMessage;
boolean deliverMessage = perRequestFilter(r, deliver);
if (endBroadcast(deliver, r, deliver.cache, deliverMessage))
continue;
if (deliver.writeLocally) {
queueWriteIO(r, hasFilters ? new Deliver(r, deliver) : deliver, count);
}
}
break;
case RESOURCE:
boolean deliverMessage = perRequestFilter(deliver.resource, deliver);
if (endBroadcast(deliver, deliver.resource, deliver.cache, deliverMessage))
return;
if (deliver.writeLocally) {
queueWriteIO(deliver.resource, deliver, new AtomicInteger(1));
}
break;
case SET:
count = new AtomicInteger(deliver.resources.size());
for (AtmosphereResource r : deliver.resources) {
deliver.message = beforeProcessingMessage;
deliverMessage = perRequestFilter(r, deliver);
CacheMessage cacheMsg = cacheForSet.remove(r.uuid());
if (endBroadcast(deliver, r, cacheMsg, deliverMessage))
continue;
if (deliver.writeLocally) {
queueWriteIO(r, new Deliver(r, deliver, cacheMsg), count);
}
}
break;
}
deliver.message = prevMessage;
} catch (InterruptedException ex) {
logger.debug(ex.getMessage(), ex);
if (cacheForSet != null) {
cacheForSet.clear();
}
}
}
use of org.atmosphere.cache.BroadcastMessage in project atmosphere by Atmosphere.
the class BroadcasterCacheTest method testCache.
@Test
public void testCache() throws ExecutionException, InterruptedException, ServletException {
broadcaster.getBroadcasterConfig().setBroadcasterCache(new AbstractBroadcasterCache() {
@Override
public CacheMessage addToCache(String id, String uuid, BroadcastMessage e) {
CacheMessage c = put(e, System.nanoTime(), uuid, broadcaster.getID());
cachedMessage.set(messages);
return c;
}
@Override
public List<Object> retrieveFromCache(String id, String uuid) {
return Collections.<Object>emptyList();
}
}).getBroadcasterCache().inspector(new BroadcasterCacheInspector() {
@Override
public boolean inspect(BroadcastMessage message) {
return true;
}
});
broadcaster.broadcast("foo", ar).get();
assertEquals(cachedMessage.get().size(), 0);
}
use of org.atmosphere.cache.BroadcastMessage in project atmosphere by Atmosphere.
the class BroadcasterCacheTest method testEmptyCache.
@Test
public void testEmptyCache() throws ExecutionException, InterruptedException, ServletException {
final CountDownLatch latch = new CountDownLatch(1);
broadcaster.getBroadcasterConfig().setBroadcasterCache(new AbstractBroadcasterCache() {
@Override
public CacheMessage addToCache(String id, String uuid, BroadcastMessage e) {
CacheMessage c = put(e, System.nanoTime(), uuid, broadcaster.getID());
cachedMessage.set(messages);
latch.countDown();
return c;
}
@Override
public List<Object> retrieveFromCache(String id, String uuid) {
return Collections.<Object>emptyList();
}
}).getBroadcasterCache().inspector(new BroadcasterCacheInspector() {
@Override
public boolean inspect(BroadcastMessage message) {
return true;
}
});
broadcaster.broadcast("foo", ar);
latch.await(10, TimeUnit.SECONDS);
assertEquals(cachedMessage.get().size(), 1);
}
use of org.atmosphere.cache.BroadcastMessage in project atmosphere by Atmosphere.
the class DefaultBroadcaster method checkCachedAndPush.
protected boolean checkCachedAndPush(final AtmosphereResource r, final AtmosphereResourceEvent e) {
boolean cache = retrieveTrackedBroadcast(r, e);
if (!cache)
return false;
if (!((List) e.getMessage()).isEmpty()) {
logger.debug("Sending cached message {} to {}", e.getMessage(), r.uuid());
List<Object> cacheMessages = (List) e.getMessage();
BroadcasterFuture<Object> f = new BroadcasterFuture<Object>(e.getMessage(), 1);
LinkedList<Object> filteredMessage = new LinkedList<Object>();
LinkedList<Object> filteredMessageClone = null;
Deliver deliver;
Object newMessage;
for (Object o : cacheMessages) {
newMessage = filter(o);
if (newMessage == null) {
continue;
}
deliver = new Deliver(newMessage, r, f, o);
// Can be aborted by a Filter
if (!perRequestFilter(r, deliver)) {
continue;
}
if (deliver.message != null) {
filteredMessage.addLast(deliver.message);
}
}
if (filteredMessage.isEmpty()) {
return false;
}
e.setMessage(filteredMessage);
final boolean willBeResumed = Utils.resumableTransport(r.transport());
if (willBeResumed) {
filteredMessageClone = (LinkedList<Object>) filteredMessage.clone();
}
List<AtmosphereResourceEventListener> listeners = willBeResumed ? new ArrayList() : EMPTY_LISTENERS;
AtmosphereResourceImpl rImpl = AtmosphereResourceImpl.class.cast(r);
if (willBeResumed && !rImpl.atmosphereResourceEventListener().isEmpty()) {
listeners.addAll(rImpl.atmosphereResourceEventListener());
}
// Must make sure execute only one thread
synchronized (rImpl) {
try {
rImpl.getRequest().setAttribute(CACHED, "true");
prepareInvokeOnStateChange(r, e);
} catch (Throwable t) {
// An exception occurred
logger.error("Unable to write cached message {} for {}", e.getMessage(), r.uuid());
logger.error("", t);
for (Object o : cacheMessages) {
bc.getBroadcasterCache().addToCache(getID(), r != null ? r.uuid() : BroadcasterCache.NULL, new BroadcastMessage(o));
}
return true;
}
// If long-polling or JSONP is used we need to set the messages for the event again, because onResume() have cleared them
if (willBeResumed) {
e.setMessage(filteredMessageClone);
}
for (AtmosphereResourceEventListener l : willBeResumed ? listeners : rImpl.atmosphereResourceEventListener()) {
l.onBroadcast(e);
}
switch(r.transport()) {
case UNDEFINED:
case JSONP:
case AJAX:
case LONG_POLLING:
return true;
case SSE:
break;
default:
try {
r.getResponse().flushBuffer();
} catch (IOException ioe) {
logger.trace("", ioe);
AtmosphereResourceImpl.class.cast(r)._destroy();
}
break;
}
}
}
return false;
}
use of org.atmosphere.cache.BroadcastMessage in project atmosphere by Atmosphere.
the class DefaultBroadcaster method cacheLostMessage.
/**
* Cache the message because an unexpected exception occurred.
*
* @param r {@link AtmosphereResource}
*/
public void cacheLostMessage(AtmosphereResource r, AsyncWriteToken token, boolean force) {
if (!force) {
return;
}
try {
if (token != null && token.originalMessage != null) {
bc.getBroadcasterCache().addToCache(getID(), r != null ? r.uuid() : BroadcasterCache.NULL, new BroadcastMessage(String.valueOf(token.future.hashCode()), token.originalMessage));
logger.trace("Lost message cached {}", token.originalMessage);
}
} catch (Throwable t2) {
logger.error("Unable to cache message {} for AtmosphereResource {}", token.originalMessage, r != null ? r.uuid() : "");
logger.error("Unable to cache message", t2);
}
}
Aggregations