}
if (action == Action.NONE) return response;
// Check first if something was defined in web.xml
AtmosphereConfig config = (AtmosphereConfig) servletReq.getAttribute(ATMOSPHERE_CONFIG);
if (config == null) {
logger.error(INSTALLATION_ERROR);
throw new WebApplicationException(new IllegalStateException(INSTALLATION_ERROR));
}
AtmosphereFramework atmosphereFramework = config.framework();
String p = config.getInitParameter(JERSEY_CONTAINER_RESPONSE_WRITER_CLASS);
ContainerResponseWriter w;
if (p != null) {
try {
w = (ContainerResponseWriter) Thread.currentThread().getContextClassLoader().loadClass(p).newInstance();
logger.trace("Installing ContainerResponseWriter {}", p);
} catch (Throwable e) {
logger.error("Error loading ContainerResponseWriter {}", p, e);
}
}
// Now check if it was defined as an attribute
w = (ContainerResponseWriter) servletReq.getAttribute(FrameworkConfig.JERSEY_CONTAINER_RESPONSE_WRITER_INSTANCE);
if (w != null) {
response.setContainerResponseWriter(w);
}
AtmosphereResource r =
(AtmosphereResource) servletReq
.getAttribute(FrameworkConfig.ATMOSPHERE_RESOURCE);
if (Boolean.parseBoolean(config.getInitParameter(SUPPORT_LOCATION_HEADER))) {
useResumeAnnotation = true;
}
// Force the status code to 200 events independently of the value of the entity (null or not)
if (response.getStatus() == 204) {
response.setStatus(200);
}
switch (action) {
case ASYNCHRONOUS:
String transport = getHeaderOrQueryValue(X_ATMOSPHERE_TRANSPORT);
String broadcasterName = uuid(r);
if (!topic.equalsIgnoreCase(HeaderConfig.X_ATMOSPHERE_TRACKING_ID)) {
broadcasterName = getHeaderOrQueryValue(topic);
}
if (transport == null) {
transport = HeaderConfig.LONG_POLLING_TRANSPORT;
}
if (broadcasterName == null) {
StringBuilder s = new StringBuilder();
Enumeration<String> e = servletReq.getHeaderNames();
String t;
while (e.hasMoreElements()) {
t = e.nextElement();
s.append(t).append("=").append(servletReq.getHeader(t)).append("\n");
}
logger.error("\nQueryString:\n{}\n\nHeaders:\n{}", servletReq.getQueryString(), s.toString());
throw new WebApplicationException(new IllegalStateException("Must specify transport using header value "
+ transport
+ " and uuid " + broadcasterName));
}
String subProtocol = (String) servletReq.getAttribute(FrameworkConfig.WEBSOCKET_SUBPROTOCOL);
final boolean waitForResource = waitFor == -1 ? true : false;
Broadcaster newBroadcaster;
// See issue https://github.com/Atmosphere/atmosphere/issues/676
synchronized (broadcasterName.intern()) {
newBroadcaster = config.getBroadcasterFactory().lookup(broadcasterName, true);
newBroadcaster.setBroadcasterLifeCyclePolicy(BroadcasterLifeCyclePolicy.EMPTY_DESTROY);
}
final Broadcaster bcaster = newBroadcaster;
if (!waitForResource || (!transport.startsWith(POLLING_TRANSPORT) && subProtocol == null)) {
final boolean resumeOnBroadcast = transport.equals(JSONP_TRANSPORT) || transport.equals(LONG_POLLING_TRANSPORT);
if (listeners != null) {
for (Class<? extends AtmosphereResourceEventListener> listener : listeners) {
try {
AtmosphereResourceEventListener el = atmosphereFramework.newClassInstance(AtmosphereResourceEventListener.class, listener);
r.addEventListener(el);
} catch (Throwable t) {
throw new WebApplicationException(
new IllegalStateException("Invalid AtmosphereResourceEventListener " + listener));
}
}
}
final Object entity = response.getEntity();
r.addEventListener(new OnSuspend() {
@Override
public void onSuspend(AtmosphereResourceEvent event) {
try {
if (entity != null) {
if (waitForResource) {
bcaster.awaitAndBroadcast(entity, 30, TimeUnit.SECONDS);
} else {
bcaster.broadcastOnResume(entity);
event.getResource().resume();
}
}
} finally {
event.getResource().removeEventListener(this);
}
}
});
if (resumeOnBroadcast) {
servletReq.setAttribute(RESUME_ON_BROADCAST, new Boolean(true));
}
r.setBroadcaster(bcaster);
executeSuspend(r, timeout, resumeOnBroadcast, null, request, response, writeEntity);
} else {
Object entity = response.getEntity();
if (waitForResource) {
bcaster.awaitAndBroadcast(entity, 30, TimeUnit.SECONDS);
} else {
bcaster.broadcast(entity);
}
if (subProtocol == null && writeEntity) {
try {
if (Callable.class.isAssignableFrom(entity.getClass())) {
entity = Callable.class.cast(entity).call();
}
synchronized (response) {
response.setEntity(entity);
response.write();
}
} catch (Throwable t) {
logger.debug("Error running Callable", t);
response.setEntity(null);
}
} else {
response.setEntity(null);
}
}
break;
case SUSPEND_RESPONSE:
SuspendResponse<?> s = SuspendResponse.class.cast(JResponseAsResponse.class.cast(response.getResponse()).getJResponse());
boolean resumeOnBroadcast = resumeOnBroadcast(s.resumeOnBroadcast());
for (AtmosphereResourceEventListener el : s.listeners()) {
r.addEventListener(el);
}
if (s.getEntity() == null) {
//https://github.com/Atmosphere/atmosphere/issues/423
response.setEntity("");
}
Broadcaster bc = s.broadcaster();
if (bc == null && s.scope() != Suspend.SCOPE.REQUEST) {
bc = (Broadcaster) servletReq.getAttribute(INJECTED_BROADCASTER);
}
suspend(resumeOnBroadcast,
translateTimeUnit(s.period().value(), s.period().timeUnit()), request, response, bc, r, s.scope(), s.writeEntity());
break;
case SUBSCRIBE:
case SUSPEND:
case SUSPEND_RESUME:
resumeOnBroadcast = resumeOnBroadcast((action == Action.SUSPEND_RESUME));
if (listeners != null) {
for (Class<? extends AtmosphereResourceEventListener> listener : listeners) {
try {
AtmosphereResourceEventListener el = atmosphereFramework.newClassInstance(AtmosphereResourceEventListener.class, listener);
r.addEventListener(el);
} catch (Throwable t) {
throw new WebApplicationException(
new IllegalStateException("Invalid AtmosphereResourceEventListener " + listener, t));
}
}
}
Broadcaster broadcaster = (Broadcaster) servletReq.getAttribute(INJECTED_BROADCASTER);
// @Subscribe
// TODO: Optimize me
if (action == Action.SUBSCRIBE) {
Class<Broadcaster> c = null;
try {
c = (Class<Broadcaster>) Class.forName((String) servletReq.getAttribute(BROADCASTER_CLASS));
} catch (Throwable e) {
throw new IllegalStateException(e.getMessage());
}
broadcaster = config.getBroadcasterFactory().lookup(c, topic, true);
}
suspend(resumeOnBroadcast, timeout, request, response,
broadcaster, r, scope, writeEntity);
break;
case RESUME:
if (response.getEntity() != null) {
try {
synchronized (response) {
response.write();
}
} catch (IOException ex) {
throw new WebApplicationException(ex);
}
}
String path = response.getContainerRequest().getPath();
r = resumeCandidates.remove(path.substring(path.lastIndexOf("/") + 1));
if (r != null) {
resume(r);
} else {
throw new WebApplicationException(
new IllegalStateException("Unable to retrieve suspended Response. " +
"Either session-support is not enabled in atmosphere.xml or the" +
"path used to resume is invalid."));
}
break;
case BROADCAST:
case PUBLISH:
case RESUME_ON_BROADCAST:
AtmosphereResource ar = (AtmosphereResource) servletReq.getAttribute(SUSPENDED_RESOURCE);
if (ar != null) {
r = ar;
}
if (action == Action.PUBLISH) {
Class<Broadcaster> c = null;
try {
c = (Class<Broadcaster>) Class.forName((String) servletReq.getAttribute(BROADCASTER_CLASS));
} catch (Throwable e) {
throw new IllegalStateException(e.getMessage());
}
r.setBroadcaster(config.getBroadcasterFactory().lookup(c, topic, true));
}
broadcast(response, r, timeout);
if (!writeEntity) {
synchronized (response) {