use of org.atmosphere.runtime.AtmosphereResourceEvent in project atmosphere by Atmosphere.
the class BlockingIOCometSupport method suspend.
/**
* Suspend the connection by blocking the current {@link Thread}
*
* @param action The {@link Action}
* @param req the {@link AtmosphereRequest}
* @param res the {@link AtmosphereResponse}
* @throws java.io.IOException
* @throws javax.servlet.ServletException
*/
protected void suspend(Action action, AtmosphereRequest req, AtmosphereResponse res) throws IOException, ServletException {
final CountDownLatch latch = new CountDownLatch(1);
req.setAttribute(LATCH, latch);
boolean ok = true;
AtmosphereResource resource = req.resource();
if (resource != null) {
try {
resource.addEventListener(new AtmosphereResourceEventListenerAdapter.OnResume() {
@Override
public void onResume(AtmosphereResourceEvent event) {
latch.countDown();
}
});
if (action.timeout() != -1) {
ok = latch.await(action.timeout(), TimeUnit.MILLISECONDS);
} else {
latch.await();
}
} catch (InterruptedException ex) {
logger.trace("", ex);
} finally {
if (!ok) {
timedout(req, res);
} else {
AtmosphereResourceImpl.class.cast(resource).cancel();
}
}
}
}
use of org.atmosphere.runtime.AtmosphereResourceEvent in project atmosphere by Atmosphere.
the class AtmosphereServiceProcessor method handle.
@Override
public void handle(AtmosphereFramework framework, Class<Object> annotatedClass) {
try {
Class<?> aClass = annotatedClass;
AtmosphereService a = aClass.getAnnotation(AtmosphereService.class);
framework.setBroadcasterCacheClassName(a.broadcasterCache().getName());
atmosphereConfig(a.atmosphereConfig(), framework);
framework.setDefaultBroadcasterClassName(a.broadcaster().getName());
filters(a.broadcastFilters(), framework);
LinkedList<AtmosphereInterceptor> l = new LinkedList<AtmosphereInterceptor>();
AtmosphereInterceptor aa = listeners(a.listeners(), framework);
if (aa != null) {
l.add(aa);
}
if (!a.servlet().isEmpty()) {
final ReflectorServletProcessor r = framework.newClassInstance(ReflectorServletProcessor.class, ReflectorServletProcessor.class);
r.setServletClassName(a.servlet());
String mapping = a.path();
AnnotationUtil.interceptorsForHandler(framework, Arrays.asList(a.interceptors()), l);
if (!a.dispatch()) {
AtmosphereHandler proxy = new AtmosphereServletProcessor() {
private String method = "GET";
@Override
public void onRequest(AtmosphereResource resource) throws IOException {
if (!resource.getRequest().getMethod().equalsIgnoreCase(method)) {
r.onRequest(resource);
}
}
@Override
public void onStateChange(AtmosphereResourceEvent event) throws IOException {
r.onStateChange(event);
}
@Override
public void destroy() {
r.destroy();
}
@Override
public void init(AtmosphereConfig config) throws ServletException {
String s = config.getInitParameter(ATMOSPHERERESOURCE_INTERCEPTOR_METHOD);
if (s != null) {
method = s;
}
r.init(config);
}
};
framework.addAtmosphereHandler(mapping, proxy, l);
} else {
framework.addAtmosphereHandler(mapping, r, l);
}
} else {
interceptors(a.interceptors(), framework);
}
} catch (Throwable e) {
logger.warn("", e);
}
}
use of org.atmosphere.runtime.AtmosphereResourceEvent in project atmosphere by Atmosphere.
the class HeartbeatInterceptor method inspect.
@Override
public Action inspect(final AtmosphereResource r) {
final AtmosphereResourceImpl impl = AtmosphereResourceImpl.class.cast(r);
final AtmosphereRequest request = impl.getRequest(false);
final AtmosphereResponse response = impl.getResponse(false);
// Check heartbeat
if (clientHeartbeatFrequencyInSeconds > 0) {
byte[] body = new byte[0];
try {
if (!request.getMethod().equalsIgnoreCase("GET")) {
body = IOUtils.readEntirelyAsByte(r);
}
} catch (IOException e) {
logger.warn("", e);
cancelF(request);
return Action.CONTINUE;
}
if (Arrays.equals(paddingBytes, body)) {
// Dispatch an event to notify that a heartbeat has been intercepted
// TODO: see https://github.com/Atmosphere/atmosphere/issues/1561
final AtmosphereResourceEvent event = new HeartbeatAtmosphereResourceEvent(AtmosphereResourceImpl.class.cast(r));
if (AtmosphereResourceHeartbeatEventListener.class.isAssignableFrom(r.getAtmosphereHandler().getClass())) {
r.addEventListener(new AtmosphereResourceEventListenerAdapter.OnHeartbeat() {
@Override
public void onHeartbeat(AtmosphereResourceEvent event) {
AtmosphereResourceHeartbeatEventListener.class.cast(r.getAtmosphereHandler()).onHeartbeat(event);
}
});
}
// Fire event
r.notifyListeners(event);
return Action.CANCELLED;
}
request.body(body);
}
if (Utils.webSocketMessage(r))
return Action.CONTINUE;
final int interval = extractHeartbeatInterval(impl);
if (interval != 0) {
if (!(Utils.pollableTransport(r.transport()) || r.transport() == AtmosphereResource.TRANSPORT.UNDEFINED)) {
super.inspect(r);
final boolean wasSuspended = r.isSuspended();
// Otherwise, the listener will do the job
if (wasSuspended) {
clock(interval, r, request, response);
}
r.addEventListener(new Clock() {
@Override
public void onSuspend(AtmosphereResourceEvent event) {
// We did not clocked when this listener was added because connection was not already suspended
if (!wasSuspended) {
clock(interval, r, request, response);
}
}
@Override
public void onResume(AtmosphereResourceEvent event) {
cancelF(request);
}
@Override
public void onDisconnect(AtmosphereResourceEvent event) {
cancelF(request);
}
@Override
public void onClose(AtmosphereResourceEvent event) {
cancelF(request);
}
});
} else {
return Action.CONTINUE;
}
final AsyncIOWriter writer = response.getAsyncIOWriter();
if (!Utils.resumableTransport(r.transport()) && AtmosphereInterceptorWriter.class.isAssignableFrom(writer.getClass()) && request.getAttribute(INTERCEPTOR_ADDED) == null) {
AtmosphereInterceptorWriter.class.cast(writer).interceptor(new AsyncIOInterceptorAdapter() {
@Override
public byte[] transformPayload(AtmosphereResponse response, byte[] responseDraft, byte[] data) throws IOException {
cancelF(request);
return responseDraft;
}
@Override
public void postPayload(final AtmosphereResponse response, byte[] data, int offset, int length) {
logger.trace("Scheduling heartbeat for {}", r.uuid());
clock(interval, r, request, response);
}
});
request.setAttribute(INTERCEPTOR_ADDED, Boolean.TRUE);
}
}
return Action.CONTINUE;
}
use of org.atmosphere.runtime.AtmosphereResourceEvent in project atmosphere by Atmosphere.
the class AtmosphereResourceStateRecovery method inspect.
@Override
public Action inspect(final AtmosphereResource r) {
if (!Utils.pollableTransport(r.transport()) && !Utils.webSocketMessage(r)) {
final BroadcasterTracker tracker = track(r).tick();
List<Object> cachedMessages = retrieveCache(r, tracker, false);
if (!cachedMessages.isEmpty()) {
logger.trace("cached messages");
writeCache(r, cachedMessages);
return Action.CANCELLED;
} else {
r.addEventListener(new OnAlwaysSuspend() {
public void onSuspend(AtmosphereResourceEvent event) {
r.removeEventListener(this);
logger.trace("onSuspend first");
final AtomicBoolean doNotSuspend = new AtomicBoolean(false);
/**
* If a message gets broadcasted during the execution of the code below, we don't need to
* suspend the connection. This code is needed to prevent the connection being suspended
* with messages already written.
*/
r.addEventListener(new OnBroadcast() {
@Override
public void onBroadcast(AtmosphereResourceEvent event) {
r.removeEventListener(this);
doNotSuspend.set(true);
logger.trace("onBroadcast");
}
});
for (String broadcasterID : tracker.ids()) {
Broadcaster b = factory.lookup(broadcasterID, false);
logger.trace("About to associate resource {} with Broadcaster {}", r.uuid(), broadcasterID);
if (b != null && !b.getID().equalsIgnoreCase(r.getBroadcaster().getID())) {
logger.trace("Associate AtmosphereResource {} with Broadcaster {}", r.uuid(), broadcasterID);
b.addAtmosphereResource(r);
} else if (b == null) {
logger.trace("Broadcaster {} is no longer available for {}", broadcasterID, r);
} else {
logger.trace("AtmosphereResource {} already associated with {}", r.uuid(), broadcasterID);
}
}
/**
* Check the cache to see if messages has been added directly by using
* {@link BroadcasterCache#addToCache(String, org.atmosphere.runtime.AtmosphereResource, org.atmosphere.cache.BroadcastMessage)}
* after {@link Broadcaster#addAtmosphereResource(org.atmosphere.runtime.AtmosphereResource)} has been
* invoked.
*/
final List<Object> cachedMessages = retrieveCache(r, tracker, true);
if (logger.isTraceEnabled()) {
logger.trace("message size {}", cachedMessages.size());
}
if (!cachedMessages.isEmpty()) {
logger.trace("About to write to the cache {}", r.uuid());
writeCache(r, cachedMessages);
doNotSuspend.set(true);
}
// Force doNotSuspend.
if (doNotSuspend.get()) {
AtmosphereResourceImpl.class.cast(r).action().type(Action.TYPE.CONTINUE);
}
if (logger.isTraceEnabled()) {
logger.trace("doNotSuspend {}", doNotSuspend.get());
}
}
});
}
}
return Action.CONTINUE;
}
use of org.atmosphere.runtime.AtmosphereResourceEvent in project atmosphere by Atmosphere.
the class JavaScriptProtocol method inspect.
@Override
public Action inspect(final AtmosphereResource ar) {
if (Utils.webSocketMessage(ar))
return Action.CONTINUE;
final AtmosphereResourceImpl r = AtmosphereResourceImpl.class.cast(ar);
final AtmosphereRequest request = r.getRequest(false);
final AtmosphereResponse response = r.getResponse(false);
String uuid = request.getHeader(HeaderConfig.X_ATMOSPHERE_TRACKING_ID);
String handshakeUUID = request.getHeader(HeaderConfig.X_ATMO_PROTOCOL);
if (uuid != null && uuid.equals("0") && handshakeUUID != null) {
if (enforceAtmosphereVersion) {
String javascriptVersion = request.getHeader(HeaderConfig.X_ATMOSPHERE_FRAMEWORK);
int version = 0;
if (javascriptVersion != null) {
version = parseVersion(javascriptVersion.split("-")[0]);
}
if (version < 221) {
logger.error("Invalid Atmosphere Version {}", javascriptVersion);
response.setStatus(501);
response.addHeader(X_ATMOSPHERE_ERROR, "Atmosphere Protocol version not supported.");
try {
response.flushBuffer();
} catch (IOException e) {
}
return Action.CANCELLED;
}
}
request.header(HeaderConfig.X_ATMO_PROTOCOL, null);
// Extract heartbeat data
int heartbeatInterval = 0;
String heartbeatData = "";
for (final AtmosphereInterceptor interceptor : framework.interceptors()) {
if (HeartbeatInterceptor.class.isAssignableFrom(interceptor.getClass())) {
final HeartbeatInterceptor heartbeatInterceptor = HeartbeatInterceptor.class.cast(interceptor);
heartbeatInterval = heartbeatInterceptor.clientHeartbeatFrequencyInSeconds() * 1000;
heartbeatData = new String(heartbeatInterceptor.getPaddingBytes());
break;
}
}
String message;
if (enforceAtmosphereVersion) {
// UUID since 1.0.10
message = new StringBuilder(r.uuid()).append(wsDelimiter).append(heartbeatInterval).append(wsDelimiter).append(heartbeatData).append(wsDelimiter).toString();
} else {
// UUID since 1.0.10
message = r.uuid();
}
// https://github.com/Atmosphere/atmosphere/issues/993
final AtomicReference<String> protocolMessage = new AtomicReference<String>(message);
if (r.getBroadcaster().getBroadcasterConfig().hasFilters()) {
for (BroadcastFilter bf : r.getBroadcaster().getBroadcasterConfig().filters()) {
if (TrackMessageSizeFilter.class.isAssignableFrom(bf.getClass())) {
protocolMessage.set((String) f.filter(r.getBroadcaster().getID(), r, protocolMessage.get(), protocolMessage.get()).message());
break;
}
}
}
if (!Utils.resumableTransport(r.transport())) {
OnSuspend a = new OnSuspend() {
@Override
public void onSuspend(AtmosphereResourceEvent event) {
response.write(protocolMessage.get());
try {
response.flushBuffer();
} catch (IOException e) {
logger.trace("", e);
}
r.removeEventListener(this);
}
};
// Pass the information to Servlet Based Framework
request.setAttribute(CALLBACK_JAVASCRIPT_PROTOCOL, a);
r.addEventListener(a);
} else {
response.write(protocolMessage.get());
}
// We don't need to reconnect here
if (r.transport() == AtmosphereResource.TRANSPORT.WEBSOCKET || r.transport() == AtmosphereResource.TRANSPORT.STREAMING || r.transport() == AtmosphereResource.TRANSPORT.SSE) {
return Action.CONTINUE;
} else {
return Action.CANCELLED;
}
}
return Action.CONTINUE;
}
Aggregations