Skip to content

Instantly share code, notes, and snippets.

@stephen-maina
Created April 12, 2015 13:53
Show Gist options
  • Save stephen-maina/56898ffaf116bab64d86 to your computer and use it in GitHub Desktop.
Save stephen-maina/56898ffaf116bab64d86 to your computer and use it in GitHub Desktop.
Using AtmosphereFramework with JerseyFramework for asynchronous communicationn with one URL, using stackoverflow as inspiration for posts
package com.api.services.websockets;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Future;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import org.atmosphere.config.service.AtmosphereService;
import org.atmosphere.cpr.ApplicationConfig;
import org.atmosphere.cpr.AtmosphereResource;
import org.atmosphere.cpr.AtmosphereResourceEvent;
import org.atmosphere.cpr.AtmosphereResourceEventListenerAdapter;
import org.atmosphere.cpr.BroadcasterFactory;
import org.atmosphere.cpr.DefaultBroadcaster;
import org.atmosphere.interceptor.AtmosphereResourceLifecycleInterceptor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.gson.Gson;
import com.rabbitmq.client.AMQP.BasicProperties;
import com.api.Account;
import com.api.json.JSONArray;
import com.api.json.JSONObject;
import com.api.services.chat.ChatActivity;
import com.api.utils.Utils;
@Path("async/ws")
@Consumes({ MediaType.APPLICATION_FORM_URLENCODED, MediaType.APPLICATION_JSON })
@Produces(MediaType.APPLICATION_JSON)
@AtmosphereService(path = "/shulemart/async/ws/", listeners = { com.api.services.websockets.WS.OnDisconnect.class }, dispatch = false, interceptors = { AtmosphereResourceLifecycleInterceptor.class }, servlet = "org.glassfish.jersey.servlet.ServletContainer")
public class WS {
public final static String HEARTBEAT_FUTURE = "heartbeat.future";
private static Account acc = null;
private static ConcurrentHashMap<String, Object> users = null;
private static Utils utils = new Utils();
private List<String> groupMemberList = null;
private final static ConcurrentHashMap<String, List<String>> group = new ConcurrentHashMap<String, List<String>>();
private final static ConcurrentHashMap<String, List<ConcurrentHashMap<String, Object>>> schoolUsers = new ConcurrentHashMap<String, List<ConcurrentHashMap<String, Object>>>();
private final static List<ConcurrentHashMap<String, Object>> user = Collections
.synchronizedList(new LinkedList<>());
static ConcurrentHashMap<String, Object> uuid = new ConcurrentHashMap<String, Object>();
private final static ConcurrentHashMap<String, ConcurrentHashMap<String, Object>> userUuid = new ConcurrentHashMap<String, ConcurrentHashMap<String, Object>>();
private AtmosphereResource userResource = null;
private BroadcasterFactory bf = null;
private HashMap<String, Object> auth = null;
@POST
public Response send(String json,
@QueryParam("AUTHORIZATION") String authorization,
@QueryParam("USER_SCHOOL") String school,
@Context HttpServletRequest req) {
userResource = (AtmosphereResource) req
.getAttribute(ApplicationConfig.ATMOSPHERE_RESOURCE);
bf = userResource.getAtmosphereConfig().getBroadcasterFactory();
String type = null;
String message = null;
String action = null;
String email = null;
String folderName = null;
String value = null;
Integer postType = null;
String parentId = null;
String body = null;
String creator = null;
String title = null;
String communityOwnedDate = null;
JSONArray tag = null;
boolean draft = false;
String postId = null;
try {
JSONObject object = new JSONObject(json);
value = object.getString("value");
type = object.getString("type");
action = object.getString("action");
if (object.keySet().contains("message")) {
message = object.getString("message");
}
if (object.keySet().contains("email")) {
email = object.getString("email");
}
if (object.keySet().contains("folder_name")) {
folderName = object.getString("folder_name");
}
if (object.keySet().contains("post_type")) {
postType = object.getInt("post_type");
}
if (object.keySet().contains("parent_id")) {
parentId = object.getString("parent_id");
}
if (object.keySet().contains("post_body")) {
body = object.getString("post_body");
}
if (object.keySet().contains("post_creator")) {
creator = object.getString("post_creator");
}
if (object.keySet().contains("post_title")) {
title = object.getString("post_title");
}
if (object.keySet().contains("post_community_date")) {
}
if (object.keySet().contains("post_tag")) {
tag = object.getJSONArray("post_tag");
}
if (object.keySet().contains("post_draft")) {
draft = object.getBoolean("post_draft");
}
if (object.keySet().contains("post_id")) {
postId = object.getString("post_id");
}
} catch (Exception e) {
e.printStackTrace();
Response res = Response
.status(Status.BAD_REQUEST)
.entity("{"
+ utils.createErrorResponse(Status.BAD_REQUEST,
"Invalid JSON string. " + e.getMessage())
+ "}").cacheControl(utils.cacheControl()).build();
return res;
}
auth = utils.suspendedAuthentication(authorization, school);
if (auth.containsKey("false")) {
return Response.status(Status.FORBIDDEN).entity(auth.get("false"))
.build();
}
acc = (Account) auth.get("true");
if (type.contains("chat")) {
if (!utils.getChatMembers(value, acc.getSchoolId()).contains(
acc.getAccountId())) {
throw new WebApplicationException(
Response.status(Status.FORBIDDEN)
.entity("{"
+ utils.createErrorResponse(
Status.FORBIDDEN,
"You do not have permission to access this ")
+ "}").build());
}
if (action.equalsIgnoreCase("GET")) {
DefaultBroadcaster jerseyCast = bf.lookup(
DefaultBroadcaster.class, "chat/" + value, true);
if (jerseyCast == null) {
jerseyCast = bf.get(DefaultBroadcaster.class, "chat/"
+ value);
}
jerseyCast.addAtmosphereResource(userResource);
if (group.containsKey(value)) {
synchronized (group.get(value)) {
if (!group.get(value).contains(acc.getAccountId())) {
group.get(value).add(acc.getAccountId());
}
}
} else {
groupMemberList = Collections
.synchronizedList(new LinkedList<>());
synchronized (groupMemberList) {
groupMemberList.add(acc.getAccountId());
group.putIfAbsent(value, groupMemberList);
}
}
System.out.println("jc: " + jerseyCast);
return Response
.ok("{\"type\":\"ack\",\"value\":\"chat\",\"action\":\"add\"}")
.build();
} else if (action.equalsIgnoreCase("POST")) {
if (message == null) {
return Response
.status(Status.EXPECTATION_FAILED)
.entity(utils.createErrorResponse(
Status.EXPECTATION_FAILED,
"you cannot have an empty message"))
.build();
}
if (utils.saveChatToDb(value, acc.getSchoolId(),
acc.getAccountId(), acc.getName(), message,
bf.lookup("chat/" + value),
bf.lookup("notification/" + acc.getAccountId()))) {
return Response
.ok("{\"type\":\"ack\",\"value\":\"chat\",\"action\":\"post\"}")
.build();
} else {
return Response
.status(Status.INTERNAL_SERVER_ERROR)
.entity("{\"type\":\"disack\",\"value\":\"chat\",\"action\":\"post\"}")
.build();
}
} else if (action.equalsIgnoreCase("DELETE")) {
if (value.equalsIgnoreCase("RESOURCE")) {
DefaultBroadcaster jerseyCast = bf.lookup("chat/" + value);
jerseyCast.removeAtmosphereResource(userResource);
synchronized (group.get(value)) {
group.get(value).remove(acc.getAccountId());
}
return Response
.ok("{\"type\":\"ack\",\"value\":\"chat\",\"action\":\"remove\"}")
.build();
} else {
DefaultBroadcaster jerseyCast = bf.lookup("chat/" + value);
Response res = utils.deleteChat(value, acc.getSchoolId(),
acc.getSchoolId());
if (res.getStatus() == 200) {
jerseyCast.broadcast(res.getEntity());
}
return res;
}
} else if (action.equalsIgnoreCase("PUT")) {
// TODO implement
return Response
.status(Status.FORBIDDEN)
.entity("{"
+ utils.createErrorResponse(Status.FORBIDDEN,
"You do not have permission to access this ")
+ "}").build();
} else {
// invalid input
return Response
.status(Status.FORBIDDEN)
.entity(utils.createErrorResponse(Status.FORBIDDEN,
"invalid choice")).build();
}
} else if (type.contains("post")) {
if (action.equalsIgnoreCase("GET")) {
DefaultBroadcaster jerseyCast = bf.lookup(
DefaultBroadcaster.class, "post/" + value, true);
if (jerseyCast == null) {
jerseyCast = bf.get(DefaultBroadcaster.class, "post/"
+ value);
}
jerseyCast.addAtmosphereResource(userResource);
return Response
.ok("{\"type\":\"ack\",\"value\":\"post\",\"action\":\"add\"}")
.build();
} else if (action.equalsIgnoreCase("DELETE")) {
if (value.equalsIgnoreCase("RESOURCE")) {
DefaultBroadcaster jerseyCast = bf.lookup("post/" + value);
jerseyCast.removeAtmosphereResource(userResource);
return Response
.ok("{\"type\":\"ack\",\"value\":\"post\",\"action\":\"remove\"}")
.build();
} else {
// TODO implement
return Response
.status(Status.FORBIDDEN)
.entity(utils.createErrorResponse(Status.FORBIDDEN,
"invalid choice")).build();
}
} else {
// invalid input
return Response
.status(Status.FORBIDDEN)
.entity(utils.createErrorResponse(Status.FORBIDDEN,
"invalid choice")).build();
}
} else if (type.contains("group")) {
//check if member of group and a member or admin
if(!utils.getGroupMembers(acc.getSchoolId(), value).contains(acc.getSchoolId())){
return Response
.status(Status.FORBIDDEN)
.entity(utils.createErrorResponse(Status.FORBIDDEN,
"You do not have permission to access this group ")).build();
}
if (action.equalsIgnoreCase("GET")) {
DefaultBroadcaster jerseyCast = bf.lookup(
DefaultBroadcaster.class, "group/" + value, true);
if (jerseyCast == null) {
jerseyCast = bf.get(DefaultBroadcaster.class, "group/"
+ value);
}
jerseyCast.addAtmosphereResource(userResource);
return Response
.ok("{\"type\":\"ack\",\"value\":\"group\",\"action\":\"add\"}")
.build();
} else if (action.equalsIgnoreCase("POST")) {
DefaultBroadcaster jerseyCast = bf.lookup("group/" + value);
HashMap<String, String> response = utils.addPost(
String.valueOf(System.currentTimeMillis()), postType,
parentId, body, creator, title, communityOwnedDate,
tag, acc.getSchoolId(), draft, null);
if (!response.get("status").contains("500")) {
if (utils.setGroupPost(value, postId, acc.getSchoolId())) {
userResource.setBroadcaster(jerseyCast);
jerseyCast.broadcast(response.get("response"));
}
} else {
jerseyCast.broadcast(response.get("response"));
}
return Response
.ok("{\"type\":\"ack\",\"value\":\"group\",\"action\":\"post\"}")
.build();
} else if (action.equalsIgnoreCase("DELETE")) {
if (value.equalsIgnoreCase("RESOURCE")) {
DefaultBroadcaster jerseyCast = bf.lookup("group/" + value);
jerseyCast.removeAtmosphereResource(userResource);
return Response
.ok("{\"type\":\"ack\",\"value\":\"group\",\"action\":\"remove\"}")
.build();
} else {
Response res = null;
DefaultBroadcaster jerseyCast = bf.lookup("group/" + value);
if (utils.deleteGroupPost(value, postId, acc.getSchoolId())) {
res = Response
.status(Status.OK)
.entity("{\"post id\" : \"" + postId
+ "\",\"deleted\" :\"true\"}")
.cacheControl(utils.cacheControl()).build();
jerseyCast.broadcast("{\"post id\" : \"" + postId
+ "\",\"deleted\" :\"true\"}");
} else {
res = Response
.status(Status.INTERNAL_SERVER_ERROR)
.entity("{\"post id\" : \""
+ postId
+ "\","
+ "\"deleted\" :\"false\","
+ "\"error\" : "
+ "{"
+ utils.createErrorResponse(
Status.INTERNAL_SERVER_ERROR,
"Oops it seems something went wrong while trying to delete post")
+ "}}")
.cacheControl(utils.cacheControl()).build();
}
return res;
}
} else if (action.equalsIgnoreCase("PUT")) {
// TODO implement
return Response
.status(Status.FORBIDDEN)
.entity(utils.createErrorResponse(Status.FORBIDDEN,
"invalid choice")).build();
} else {
// invalid input
return Response
.status(Status.FORBIDDEN)
.entity(utils.createErrorResponse(Status.FORBIDDEN,
"invalid choice")).build();
}
} else if (type.contains("email")) {
if (action.equalsIgnoreCase("PUT")) {
return Response
.status(Status.FORBIDDEN)
.entity(utils.createErrorResponse(Status.FORBIDDEN,
"invalid choice")).build();
} else if (action.equalsIgnoreCase("GET")) {
if (email == null || folderName == null) {
return Response
.status(Status.BAD_REQUEST)
.entity("{\"error\":{"
+ utils.createErrorResponse(
Status.BAD_REQUEST,
"ur request has null/empty values")
+ "}}").build();
}
DefaultBroadcaster jerseyCast = bf.lookup(
DefaultBroadcaster.class,
"email/" + acc.getAccountId(), true);
if (jerseyCast == null) {
jerseyCast = bf.get(DefaultBroadcaster.class, "email/"
+ acc.getAccountId());
}
jerseyCast.addAtmosphereResource(userResource);
// produce and consume
BasicProperties.Builder props = new BasicProperties.Builder();
props.contentType("Text/Plain").priority(0).appId("shule-mart")
.deliveryMode(2)
.messageId(String.valueOf(System.currentTimeMillis()))
.type("custom");
HashMap<String, Object> emailInfo = new HashMap<String, Object>();
emailInfo.put(
"host",
utils.getEmailHost(acc.getAccountId(),
acc.getSchoolId(), email));
emailInfo.put(
"password",
utils.getEmailAccountsPassword(acc.getAccountId(),
acc.getSchoolId(), email));
emailInfo.put("folder_name", folderName);
emailInfo.put("broadcaster", jerseyCast);
emailInfo.put("user_id", acc.getAccountId());
emailInfo.put("school_id", acc.getSchoolId());
utils.consumeMessage("EMAIL", "direct", "email", props.build(),
true);
utils.queueMessage("EMAIL", "direct", "email", props.build(),
emailInfo);
return Response
.ok("{\"type\":\"ack\",\"value\":\"email\",\"action\":\"add\"}")
.build();
} else if (action.equalsIgnoreCase("POST")) {
return Response
.status(Status.FORBIDDEN)
.entity(utils.createErrorResponse(Status.FORBIDDEN,
"invalid choice")).build();
}
if (action.equalsIgnoreCase("DELETE")) {
DefaultBroadcaster jerseyCast = bf.lookup("email/" + value);
jerseyCast.removeAtmosphereResource(userResource);
return Response
.ok("{\"type\":\"ack\",\"value\":\"email\",\"action\":\"remove\"}")
.build();
}
} else if (type.contains("notification")) {
if (action.equalsIgnoreCase("PUT")) {
return Response
.status(Status.FORBIDDEN)
.entity(utils.createErrorResponse(Status.FORBIDDEN,
"invalid choice")).build();
} else if (action.equalsIgnoreCase("DELETE")) {
// register notification
DefaultBroadcaster jerseyCast = bf.lookup("notification/"
+ acc.getAccountId());
jerseyCast.removeAtmosphereResource(userResource);
return Response
.ok("{\"type\":\"ack\",\"value\":\"notification\",\"action\":\"remove\"}")
.build();
} else if (action.equalsIgnoreCase("POST")) {
return Response
.status(Status.FORBIDDEN)
.entity(utils.createErrorResponse(Status.FORBIDDEN,
"invalid choice")).build();
} else if (action.equalsIgnoreCase("GET")) {
// register notification
DefaultBroadcaster jerseyCast = bf.lookup(
DefaultBroadcaster.class,
"notification/" + acc.getAccountId(), true);
if (jerseyCast == null) {
jerseyCast = bf.get(DefaultBroadcaster.class,
"notification/" + acc.getAccountId());
}
jerseyCast.addAtmosphereResource(userResource);
return Response
.ok("{\"type\":\"ack\",\"value\":\"notification\",\"action\":\"add\"}")
.build();
} else {
return Response
.status(Status.FORBIDDEN)
.entity(utils.createErrorResponse(Status.FORBIDDEN,
"invalid choice")).build();
}
}
return Response
.status(Status.FORBIDDEN)
.entity(utils.createErrorResponse(Status.FORBIDDEN,
"invalid choice")).build();
}
public static final class OnDisconnect extends
AtmosphereResourceEventListenerAdapter {
private final Logger logger = LoggerFactory
.getLogger(ChatActivity.class);
/**
* have a get method to create the broadcasters ad link them to related
* resources a POST method to post messages it gets type from message
* and deals with them chat if user not online sed notifiction
*/
/**
* {@inheritDoc}
*/
@Override
public void onDisconnect(AtmosphereResourceEvent event) {
System.out.println("on disconnect");
try {
// AtmosphereResource userResource = (AtmosphereResource) event
// .getResource().getRequest()
// .getAttribute(ApplicationConfig.ATMOSPHERE_RESOURCE);
AtmosphereResource userResource = event.getResource();
BroadcasterFactory bf = event.getResource()
.getAtmosphereConfig().getBroadcasterFactory();
System.out.println("bf: " + bf);
System.out.println("bc: " + event.broadcaster());
DefaultBroadcaster jerseyCast = bf.lookup(
"/shulemart/async/ws/", false);
System.out.println("jc " + jerseyCast);
String userSchool = (String) userUuid.get(
event.getResource().uuid()).get("school");
String accountId = (String) userUuid.get(
event.getResource().uuid()).get("id");
if (event.isCancelled()) {
logger.info(
"Browser {} unexpectedly disconnected (cancelled)",
event.getResource().uuid());
synchronized (schoolUsers.get(userSchool)) {
schoolUsers.get(userSchool).remove(
userUuid.get(event.getResource().uuid()));
userUuid.remove(Utils.userAcc.get(accountId));
Utils.userAcc.remove(accountId);
}
Gson gson = new Gson();
System.out.println("jcb0 " + jerseyCast);
Future<?> f = (Future<?>) event.getResource().getRequest()
.getAttribute(HEARTBEAT_FUTURE);
if (f != null)
f.cancel(false);
event.getResource().getRequest()
.removeAttribute(HEARTBEAT_FUTURE);
userResource.close();
System.out.println("ur " + userResource);
System.out.println("jcb " + jerseyCast);
jerseyCast.broadcast(gson.toJson(user));
} else if (event.isClosedByClient()) {
System.out.println("dfg 2");
logger.info("Browser {} closed the connection", event
.getResource().uuid());
synchronized (user) {
user.remove(userUuid.get(event.getResource().uuid()));
userUuid.remove(Utils.userAcc.get(accountId));
Utils.userAcc.remove(accountId);
}
Gson gson = new Gson();
Future<?> f = (Future<?>) event.getResource().getRequest()
.getAttribute(HEARTBEAT_FUTURE);
if (f != null)
f.cancel(false);
event.getResource().getRequest()
.removeAttribute(HEARTBEAT_FUTURE);
userResource.close();
System.out.println("ur " + userResource);
System.out.println("jcb " + jerseyCast);
jerseyCast.broadcast(gson.toJson(user));
} else if (event.isClosedByApplication()) {
System.out.println("dfg 3");
logger.info("Browser {} closed the connection", event
.getResource().uuid());
synchronized (schoolUsers.get(userSchool)) {
schoolUsers.get(userSchool).remove(
userUuid.get(event.getResource().uuid()));
userUuid.remove(Utils.userAcc.get(accountId));
Utils.userAcc.remove(accountId);
}
Gson gson = new Gson();
Future<?> f = (Future<?>) event.getResource().getRequest()
.getAttribute(HEARTBEAT_FUTURE);
if (f != null)
f.cancel(false);
event.getResource().getRequest()
.removeAttribute(HEARTBEAT_FUTURE);
userResource.close();
System.out.println("ur " + userResource);
System.out.println("jcb " + jerseyCast);
jerseyCast.broadcast(gson.toJson(user));
} else {
System.out.println("dfg 3");
logger.info("Browser {} closed the connection", event
.getResource().uuid());
synchronized (schoolUsers.get(userSchool)) {
schoolUsers.get(userSchool).remove(
userUuid.get(event.getResource().uuid()));
userUuid.remove(Utils.userAcc.get(accountId));
Utils.userAcc.remove(accountId);
}
Gson gson = new Gson();
Future<?> f = (Future<?>) event.getResource().getRequest()
.getAttribute(HEARTBEAT_FUTURE);
if (f != null)
f.cancel(false);
event.getResource().getRequest()
.removeAttribute(HEARTBEAT_FUTURE);
jerseyCast.removeAtmosphereResource(userResource);
userResource.close();
System.out.println("ur " + userResource);
System.out.println("jcb " + jerseyCast);
jerseyCast
.broadcast(gson.toJson(schoolUsers.get(accountId)));
}
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void onSuspend(AtmosphereResourceEvent event) {
// TODO Auto-generated method stub
System.out.println("suspend: ");
// TODO check validity of use of UserState
HashMap<String, Object> auth = null;
AtmosphereResource userResource = (AtmosphereResource) event
.getResource().getRequest()
.getAttribute(ApplicationConfig.ATMOSPHERE_RESOURCE);
BroadcasterFactory bf = userResource.getAtmosphereConfig()
.getBroadcasterFactory();
DefaultBroadcaster jerseyCast = bf.lookup(DefaultBroadcaster.class,
"/shulemart/async/ws/", true);
if (jerseyCast == null) {
jerseyCast = bf.get(DefaultBroadcaster.class,
"/shulemart/async/ws/");
}
try {
auth = utils.suspendedAuthentication(
event.getResource().getRequest().queryStringsMap()
.get("AUTHORIZATION")[0],
event.getResource().getRequest().queryStringsMap()
.get("USER_SCHOOL")[0]);
Gson gson = new Gson();
if (auth.containsKey("true")) {
System.out.println("is true");
acc = (Account) auth.get("true");
String rolesOutput = "";
HashMap<String, String> badges = utils.getUsersBadges(
acc.getAccountId(), acc.getSchoolId());
for (String key : badges.keySet()) {
rolesOutput += "{\"id\":\"" + key + "\",\"name\" : \""
+ badges.get(key) + "\"},";
}
int last = rolesOutput.lastIndexOf(",");
users = new ConcurrentHashMap<String, Object>();
users.put("id", acc.getAccountId());
users.put("school", acc.getSchoolId());
users.put("name", acc.getName());
users.put(
"badge",
"["
+ new StringBuilder(rolesOutput).replace(
last, last + 1, "").toString()
+ "]");
schoolUsers.putIfAbsent(acc.getSchoolId(), user);
synchronized (schoolUsers.get(acc.getSchoolId())) {
// if
// (!schoolUsers.get(acc.getSchoolId()).contains(users))
// {
schoolUsers.get(acc.getSchoolId()).add(users);
// }
if (Utils.userAcc.contains(acc.getAccountId())) {
AtmosphereResource res = (AtmosphereResource) uuid
.get(Utils.userAcc.get(acc.getAccountId()));
res.getBroadcaster().broadcast(
"{\"type\":\"unsubscribe\"}");
Future<?> f = (Future<?>) res.getRequest()
.getAttribute(HEARTBEAT_FUTURE);
if (f != null)
f.cancel(false);
res.getRequest().removeAttribute(HEARTBEAT_FUTURE);
userUuid.remove(Utils.userAcc.get(acc
.getAccountId()));
uuid.remove(Utils.userAcc.get(acc.getAccountId()));
Utils.userAcc.remove(acc.getAccountId());
}
Utils.userAcc.put(acc.getAccountId(), event
.getResource().uuid());
userUuid.putIfAbsent(event.getResource().uuid(), users);
uuid.put(event.getResource().uuid(), userResource);
}
} else {
userResource.getBroadcaster().broadcast(auth.get("false"));
jerseyCast.removeAtmosphereResource(userResource);
}
jerseyCast.broadcast(gson.toJson(schoolUsers.get(acc
.getSchoolId())));
} catch (Exception e) {
e.printStackTrace();
} finally {
acc = null;
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment