Index: lams_tool_chat/src/java/org/lamsfoundation/lams/tool/chat/web/actions/LearningWebsocketServer.java =================================================================== diff -u -r5e319c889c9776238ecaf338e3b2d330b2186914 -r187836d78d83ba86212116f1bf465f567b47f133 --- lams_tool_chat/src/java/org/lamsfoundation/lams/tool/chat/web/actions/LearningWebsocketServer.java (.../LearningWebsocketServer.java) (revision 5e319c889c9776238ecaf338e3b2d330b2186914) +++ lams_tool_chat/src/java/org/lamsfoundation/lams/tool/chat/web/actions/LearningWebsocketServer.java (.../LearningWebsocketServer.java) (revision 187836d78d83ba86212116f1bf465f567b47f133) @@ -1,7 +1,6 @@ package org.lamsfoundation.lams.tool.chat.web.actions; import java.io.IOException; -import java.util.Collections; import java.util.Date; import java.util.HashSet; import java.util.Iterator; @@ -11,6 +10,7 @@ import java.util.Set; import java.util.TreeMap; import java.util.TreeSet; +import java.util.concurrent.ConcurrentHashMap; import javax.websocket.CloseReason; import javax.websocket.CloseReason.CloseCodes; @@ -78,27 +78,24 @@ try { // websocket communication bypasses standard HTTP filters, so Hibernate session needs to be initialised manually HibernateSessionManager.openSession(); - // synchronize websockets as a new Learner entering Chat could modify this collection - synchronized (LearningWebsocketServer.websockets) { - Iterator>> entryIterator = LearningWebsocketServer.websockets - .entrySet().iterator(); - // go throus Tool Session and update registered users with messages and roster - while (entryIterator.hasNext()) { - Entry> entry = entryIterator.next(); - Long toolSessionId = entry.getKey(); - Long lastSendTime = lastSendTimes.get(toolSessionId); - if ((lastSendTime == null) - || ((System.currentTimeMillis() - lastSendTime) >= SendWorker.CHECK_INTERVAL)) { - send(toolSessionId); - } - // if all users left the chat, remove the obsolete mapping - Set sessionWebsockets = entry.getValue(); - if (sessionWebsockets.isEmpty()) { - entryIterator.remove(); - LearningWebsocketServer.rosters.remove(toolSessionId); - lastSendTimes.remove(toolSessionId); - } + Iterator>> entryIterator = LearningWebsocketServer.websockets.entrySet() + .iterator(); + // go throus Tool Session and update registered users with messages and roster + while (entryIterator.hasNext()) { + Entry> entry = entryIterator.next(); + Long toolSessionId = entry.getKey(); + Long lastSendTime = lastSendTimes.get(toolSessionId); + if ((lastSendTime == null) + || ((System.currentTimeMillis() - lastSendTime) >= SendWorker.CHECK_INTERVAL)) { + send(toolSessionId); } + // if all users left the chat, remove the obsolete mapping + Set sessionWebsockets = entry.getValue(); + if (sessionWebsockets.isEmpty()) { + entryIterator.remove(); + LearningWebsocketServer.rosters.remove(toolSessionId); + lastSendTimes.remove(toolSessionId); + } } } catch (Exception e) { // error caught, but carry on @@ -125,9 +122,8 @@ ChatSession chatSession = LearningWebsocketServer.getChatService().getSessionBySessionId(toolSessionId); List messages = LearningWebsocketServer.getChatService().getLastestMessages(chatSession, null, true); - // make a copy of the websocket collection so it does not get blocked while sending messages - Set sessionWebsockets = new HashSet( - LearningWebsocketServer.websockets.get(toolSessionId)); + + Set sessionWebsockets = LearningWebsocketServer.websockets.get(toolSessionId); Roster roster = null; JSONArray rosterJSON = null; String rosterString = null; @@ -227,9 +223,8 @@ private static IChatService chatService; private static final SendWorker sendWorker = new SendWorker(); - private static final Map rosters = Collections.synchronizedMap(new TreeMap()); - private static final Map> websockets = Collections - .synchronizedMap(new TreeMap>()); + private static final Map rosters = new ConcurrentHashMap(); + private static final Map> websockets = new ConcurrentHashMap>(); static { // run the singleton thread @@ -245,7 +240,7 @@ .valueOf(session.getRequestParameterMap().get(AttributeNames.PARAM_TOOL_SESSION_ID).get(0)); Set sessionWebsockets = LearningWebsocketServer.websockets.get(toolSessionId); if (sessionWebsockets == null) { - sessionWebsockets = Collections.synchronizedSet(new HashSet()); + sessionWebsockets = ConcurrentHashMap.newKeySet(); LearningWebsocketServer.websockets.put(toolSessionId, sessionWebsockets); } final Set finalSessionWebsockets = sessionWebsockets; @@ -281,14 +276,12 @@ Long toolSessionId = Long .valueOf(session.getRequestParameterMap().get(AttributeNames.PARAM_TOOL_SESSION_ID).get(0)); Set sessionWebsockets = LearningWebsocketServer.websockets.get(toolSessionId); - synchronized (sessionWebsockets) { - Iterator websocketIterator = sessionWebsockets.iterator(); - while (websocketIterator.hasNext()) { - Websocket websocket = websocketIterator.next(); - if (websocket.session.equals(session)) { - websocketIterator.remove(); - break; - } + Iterator websocketIterator = sessionWebsockets.iterator(); + while (websocketIterator.hasNext()) { + Websocket websocket = websocketIterator.next(); + if (websocket.session.equals(session)) { + websocketIterator.remove(); + break; } } Index: lams_tool_leader/src/java/org/lamsfoundation/lams/tool/leaderselection/web/actions/LearningWebsocketServer.java =================================================================== diff -u -rac8b64b03ce6d8c718e55823f23fd995159b7ca0 -r187836d78d83ba86212116f1bf465f567b47f133 --- lams_tool_leader/src/java/org/lamsfoundation/lams/tool/leaderselection/web/actions/LearningWebsocketServer.java (.../LearningWebsocketServer.java) (revision ac8b64b03ce6d8c718e55823f23fd995159b7ca0) +++ lams_tool_leader/src/java/org/lamsfoundation/lams/tool/leaderselection/web/actions/LearningWebsocketServer.java (.../LearningWebsocketServer.java) (revision 187836d78d83ba86212116f1bf465f567b47f133) @@ -1,11 +1,9 @@ package org.lamsfoundation.lams.tool.leaderselection.web.actions; import java.io.IOException; -import java.util.Collections; -import java.util.HashSet; import java.util.Map; import java.util.Set; -import java.util.TreeMap; +import java.util.concurrent.ConcurrentHashMap; import javax.websocket.CloseReason; import javax.websocket.CloseReason.CloseCodes; @@ -30,19 +28,18 @@ private static Logger log = Logger.getLogger(LearningWebsocketServer.class); - private static final Map> websockets = Collections - .synchronizedMap(new TreeMap>()); + private static final Map> websockets = new ConcurrentHashMap>(); /** - * Registeres the Learner for processing by SendWorker. + * Registeres the Learner for processing. */ @OnOpen public void registerUser(Session websocket) throws JSONException, IOException { Long toolSessionId = Long .valueOf(websocket.getRequestParameterMap().get(AttributeNames.PARAM_TOOL_SESSION_ID).get(0)); Set sessionWebsockets = websockets.get(toolSessionId); if (sessionWebsockets == null) { - sessionWebsockets = Collections.synchronizedSet(new HashSet()); + sessionWebsockets = ConcurrentHashMap.newKeySet(); websockets.put(toolSessionId, sessionWebsockets); } sessionWebsockets.add(websocket); @@ -83,8 +80,6 @@ if (sessionWebsockets == null) { return; } - // make a copy of the websocket collection so it does not get blocked while sending messages - sessionWebsockets = new HashSet(sessionWebsockets); JSONObject responseJSON = new JSONObject(); responseJSON.put("pageRefresh", true); @@ -96,5 +91,4 @@ } } } - } \ No newline at end of file Index: lams_tool_scratchie/src/java/org/lamsfoundation/lams/tool/scratchie/web/action/LearningWebsocketServer.java =================================================================== diff -u -r5e319c889c9776238ecaf338e3b2d330b2186914 -r187836d78d83ba86212116f1bf465f567b47f133 --- lams_tool_scratchie/src/java/org/lamsfoundation/lams/tool/scratchie/web/action/LearningWebsocketServer.java (.../LearningWebsocketServer.java) (revision 5e319c889c9776238ecaf338e3b2d330b2186914) +++ lams_tool_scratchie/src/java/org/lamsfoundation/lams/tool/scratchie/web/action/LearningWebsocketServer.java (.../LearningWebsocketServer.java) (revision 187836d78d83ba86212116f1bf465f567b47f133) @@ -2,13 +2,12 @@ import java.io.IOException; import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.TreeMap; +import java.util.concurrent.ConcurrentHashMap; import javax.websocket.CloseReason; import javax.websocket.CloseReason.CloseCodes; @@ -51,26 +50,23 @@ try { // websocket communication bypasses standard HTTP filters, so Hibernate session needs to be initialised manually HibernateSessionManager.openSession(); - // synchronize websockets as a new Learner entering the activity could modify this collection - synchronized (LearningWebsocketServer.websockets) { - Iterator>> entryIterator = LearningWebsocketServer.websockets - .entrySet().iterator(); - // go through activities and update registered learners with reports and vote count - while (entryIterator.hasNext()) { - Entry> entry = entryIterator.next(); - Long toolSessionId = entry.getKey(); - try { - send(toolSessionId); - } catch (JSONException e) { - LearningWebsocketServer.log.error("Error while building Scratchie answer JSON", e); - } - // if all learners left the activity, remove the obsolete mapping - Set sessionWebsockets = entry.getValue(); - if (sessionWebsockets.isEmpty()) { - entryIterator.remove(); - LearningWebsocketServer.cache.remove(toolSessionId); - } + Iterator>> entryIterator = LearningWebsocketServer.websockets.entrySet() + .iterator(); + // go through activities and update registered learners with reports and vote count + while (entryIterator.hasNext()) { + Entry> entry = entryIterator.next(); + Long toolSessionId = entry.getKey(); + try { + send(toolSessionId); + } catch (JSONException e) { + LearningWebsocketServer.log.error("Error while building Scratchie answer JSON", e); } + // if all learners left the activity, remove the obsolete mapping + Set sessionWebsockets = entry.getValue(); + if (sessionWebsockets.isEmpty()) { + entryIterator.remove(); + LearningWebsocketServer.cache.remove(toolSessionId); + } } } catch (Exception e) { // error caught, but carry on @@ -146,9 +142,7 @@ } String response = responseJSON.toString(); - // make a copy of the websocket collection so it does not get blocked while sending messages - Set sessionWebsockets = new HashSet( - LearningWebsocketServer.websockets.get(toolSessionId)); + Set sessionWebsockets = LearningWebsocketServer.websockets.get(toolSessionId); for (Session websocket : sessionWebsockets) { websocket.getBasicRemote().sendText(response); } @@ -161,10 +155,8 @@ private static final SendWorker sendWorker = new SendWorker(); // maps toolSessionId -> itemUid -> answerUid -> isCorrect - private static final Map>> cache = Collections - .synchronizedMap(new TreeMap>>()); - private static final Map> websockets = Collections - .synchronizedMap(new TreeMap>()); + private static final Map>> cache = new ConcurrentHashMap>>(); + private static final Map> websockets = new ConcurrentHashMap>(); static { // run the singleton thread @@ -180,7 +172,7 @@ .valueOf(websocket.getRequestParameterMap().get(AttributeNames.PARAM_TOOL_SESSION_ID).get(0)); Set sessionWebsockets = LearningWebsocketServer.websockets.get(toolSessionId); if (sessionWebsockets == null) { - sessionWebsockets = Collections.synchronizedSet(new HashSet()); + sessionWebsockets = ConcurrentHashMap.newKeySet(); LearningWebsocketServer.websockets.put(toolSessionId, sessionWebsockets); } sessionWebsockets.add(websocket); @@ -221,8 +213,6 @@ if (sessionWebsockets == null) { return; } - // make a copy of the websocket collection so it does not get blocked while sending messages - sessionWebsockets = new HashSet(sessionWebsockets); JSONObject responseJSON = new JSONObject(); responseJSON.put("close", true); @@ -244,8 +234,6 @@ if (sessionWebsockets == null) { return; } - // make a copy of the websocket collection so it does not get blocked while sending messages - sessionWebsockets = new HashSet(sessionWebsockets); JSONObject responseJSON = new JSONObject(); responseJSON.put("pageRefresh", true); Index: lams_tool_scribe/src/java/org/lamsfoundation/lams/tool/scribe/web/actions/LearningWebsocketServer.java =================================================================== diff -u -r5e319c889c9776238ecaf338e3b2d330b2186914 -r187836d78d83ba86212116f1bf465f567b47f133 --- lams_tool_scribe/src/java/org/lamsfoundation/lams/tool/scribe/web/actions/LearningWebsocketServer.java (.../LearningWebsocketServer.java) (revision 5e319c889c9776238ecaf338e3b2d330b2186914) +++ lams_tool_scribe/src/java/org/lamsfoundation/lams/tool/scribe/web/actions/LearningWebsocketServer.java (.../LearningWebsocketServer.java) (revision 187836d78d83ba86212116f1bf465f567b47f133) @@ -1,14 +1,13 @@ package org.lamsfoundation.lams.tool.scribe.web.actions; import java.io.IOException; -import java.util.Collections; -import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import java.util.TreeMap; import java.util.TreeSet; +import java.util.concurrent.ConcurrentHashMap; import javax.websocket.CloseReason; import javax.websocket.CloseReason.CloseCodes; @@ -62,26 +61,23 @@ try { // websocket communication bypasses standard HTTP filters, so Hibernate session needs to be initialised manually HibernateSessionManager.openSession(); - // synchronize websockets as a new Learner entering the activity could modify this collection - synchronized (LearningWebsocketServer.websockets) { - Iterator>> entryIterator = LearningWebsocketServer.websockets - .entrySet().iterator(); - // go through activities and update registered learners with reports and vote count - while (entryIterator.hasNext()) { - Entry> entry = entryIterator.next(); - Long toolSessionId = entry.getKey(); - try { - send(toolSessionId, null); - } catch (JSONException e) { - LearningWebsocketServer.log.error("Error while building Scribe report JSON", e); - } - // if all learners left the activity, remove the obsolete mapping - Set sessionWebsockets = entry.getValue(); - if (sessionWebsockets.isEmpty()) { - entryIterator.remove(); - LearningWebsocketServer.cache.remove(toolSessionId); - } + Iterator>> entryIterator = LearningWebsocketServer.websockets.entrySet() + .iterator(); + // go through activities and update registered learners with reports and vote count + while (entryIterator.hasNext()) { + Entry> entry = entryIterator.next(); + Long toolSessionId = entry.getKey(); + try { + send(toolSessionId, null); + } catch (JSONException e) { + LearningWebsocketServer.log.error("Error while building Scribe report JSON", e); } + // if all learners left the activity, remove the obsolete mapping + Set sessionWebsockets = entry.getValue(); + if (sessionWebsockets.isEmpty()) { + entryIterator.remove(); + LearningWebsocketServer.cache.remove(toolSessionId); + } } } catch (Exception e) { // error caught, but carry on @@ -171,10 +167,7 @@ // either send only to the new user or to everyone if (newWebsocket == null) { - // make a copy of the websocket collection so it does not get blocked while sending messages - Set sessionWebsockets = new HashSet( - LearningWebsocketServer.websockets.get(toolSessionId)); - // synchronize websockets as a new Learner entering Scribe could modify this collection + Set sessionWebsockets = LearningWebsocketServer.websockets.get(toolSessionId); for (Session websocket : sessionWebsockets) { String userName = websocket.getUserPrincipal().getName(); responseJSON.put("approved", learnersApproved.contains(userName)); @@ -194,10 +187,8 @@ private static final SendWorker sendWorker = new SendWorker(); // maps toolSessionId -> cached session data - private static final Map cache = Collections - .synchronizedMap(new TreeMap()); - private static final Map> websockets = Collections - .synchronizedMap(new TreeMap>()); + private static final Map cache = new ConcurrentHashMap(); + private static final Map> websockets = new ConcurrentHashMap>(); static { // run the singleton thread @@ -213,7 +204,7 @@ .valueOf(websocket.getRequestParameterMap().get(AttributeNames.PARAM_TOOL_SESSION_ID).get(0)); Set sessionWebsockets = LearningWebsocketServer.websockets.get(toolSessionId); if (sessionWebsockets == null) { - sessionWebsockets = Collections.synchronizedSet(new HashSet()); + sessionWebsockets = ConcurrentHashMap.newKeySet(); LearningWebsocketServer.websockets.put(toolSessionId, sessionWebsockets); } sessionWebsockets.add(websocket); @@ -308,8 +299,6 @@ if (sessionWebsockets == null) { return; } - // make a copy of the websocket collection so it does not get blocked while sending messages - sessionWebsockets = new HashSet(sessionWebsockets); JSONObject responseJSON = new JSONObject(); responseJSON.put("close", true);