001
014
015 package com.liferay.portal.liveusers;
016
017 import com.liferay.portal.kernel.cluster.ClusterExecutorUtil;
018 import com.liferay.portal.kernel.cluster.ClusterNode;
019 import com.liferay.portal.kernel.concurrent.ConcurrentHashSet;
020 import com.liferay.portal.kernel.dao.orm.QueryUtil;
021 import com.liferay.portal.kernel.log.Log;
022 import com.liferay.portal.kernel.log.LogFactoryUtil;
023 import com.liferay.portal.kernel.model.Group;
024 import com.liferay.portal.kernel.model.UserTracker;
025 import com.liferay.portal.kernel.service.GroupLocalServiceUtil;
026 import com.liferay.portal.kernel.service.UserTrackerLocalServiceUtil;
027 import com.liferay.portal.kernel.service.persistence.UserTrackerUtil;
028 import com.liferay.portal.kernel.servlet.PortalSessionContext;
029 import com.liferay.portal.kernel.util.Validator;
030 import com.liferay.portal.util.PropsValues;
031
032 import java.util.ArrayList;
033 import java.util.Date;
034 import java.util.Iterator;
035 import java.util.LinkedHashMap;
036 import java.util.List;
037 import java.util.Map;
038 import java.util.Set;
039 import java.util.concurrent.ConcurrentHashMap;
040
041 import javax.servlet.http.HttpSession;
042
043
047 public class LiveUsers {
048
049 public static void addClusterNode(
050 String clusterNodeId, Map<Long, Map<Long, Set<String>>> clusterUsers) {
051
052 _instance._addClusterNode(clusterNodeId, clusterUsers);
053 }
054
055 public static void deleteGroup(long companyId, long groupId) {
056 _instance._deleteGroup(companyId, groupId);
057 }
058
059 public static Set<Long> getGroupUsers(long companyId, long groupId) {
060 return _instance._getGroupUsers(
061 _instance._getLiveUsers(companyId), groupId);
062 }
063
064 public static int getGroupUsersCount(long companyId, long groupId) {
065 return getGroupUsers(companyId, groupId).size();
066 }
067
068 public static Map<Long, Map<Long, Set<String>>> getLocalClusterUsers() {
069 return _instance._getLocalClusterUsers();
070 }
071
072 public static Map<String, UserTracker> getSessionUsers(long companyId) {
073 return _instance._getSessionUsers(companyId);
074 }
075
076 public static int getSessionUsersCount(long companyId) {
077 return getSessionUsers(companyId).size();
078 }
079
080 public static UserTracker getUserTracker(long companyId, String sessionId) {
081 return _instance._getUserTracker(companyId, sessionId);
082 }
083
084 public static void joinGroup(long companyId, long groupId, long userId) {
085 _instance._joinGroup(companyId, groupId, userId);
086 }
087
088 public static void joinGroup(long companyId, long groupId, long[] userIds) {
089 _instance._joinGroup(companyId, groupId, userIds);
090 }
091
092 public static void leaveGroup(long companyId, long groupId, long userId) {
093 _instance._leaveGroup(companyId, groupId, userId);
094 }
095
096 public static void leaveGroup(
097 long companyId, long groupId, long[] userIds) {
098
099 _instance._leaveGroup(companyId, groupId, userIds);
100 }
101
102 public static void removeClusterNode(String clusterNodeId) {
103 _instance._removeClusterNode(clusterNodeId);
104 }
105
106 public static void signIn(
107 String clusterNodeId, long companyId, long userId, String sessionId,
108 String remoteAddr, String remoteHost, String userAgent) {
109
110 _instance._signIn(
111 clusterNodeId, companyId, userId, sessionId, remoteAddr, remoteHost,
112 userAgent);
113 }
114
115 public static void signOut(
116 String clusterNodeId, long companyId, long userId, String sessionId) {
117
118 _instance._signOut(clusterNodeId, companyId, userId, sessionId);
119 }
120
121 private LiveUsers() {
122 }
123
124 private void _addClusterNode(
125 String clusterNodeId,
126 Map<Long, Map<Long, Set<String>>> clusterUsers) {
127
128 if (Validator.isNull(clusterNodeId)) {
129 return;
130 }
131
132 for (Map.Entry<Long, Map<Long, Set<String>>> companyUsers :
133 clusterUsers.entrySet()) {
134
135 long companyId = companyUsers.getKey();
136 Map<Long, Set<String>> userSessionsMap = companyUsers.getValue();
137
138 for (Map.Entry<Long, Set<String>> userSessions :
139 userSessionsMap.entrySet()) {
140
141 long userId = userSessions.getKey();
142
143 for (String sessionId : userSessions.getValue()) {
144 _signIn(
145 clusterNodeId, companyId, userId, sessionId, null, null,
146 null);
147 }
148 }
149 }
150 }
151
152 private void _addClusterUser(
153 String clusterNodeId, long companyId, long userId, String sessionId) {
154
155 if (Validator.isNull(clusterNodeId)) {
156 return;
157 }
158
159 Map<Long, Map<Long, Set<String>>> clusterUsers = _clusterUsers.get(
160 clusterNodeId);
161
162 if (clusterUsers == null) {
163 clusterUsers = new ConcurrentHashMap<>();
164
165 _clusterUsers.put(clusterNodeId, clusterUsers);
166 }
167
168 Map<Long, Set<String>> companyUsers = clusterUsers.get(companyId);
169
170 if (companyUsers == null) {
171 companyUsers = new ConcurrentHashMap<>();
172
173 clusterUsers.put(companyId, companyUsers);
174 }
175
176 Set<String> userSessions = companyUsers.get(userId);
177
178 if (userSessions == null) {
179 userSessions = new ConcurrentHashSet<>();
180
181 companyUsers.put(userId, userSessions);
182 }
183
184 userSessions.add(sessionId);
185 }
186
187 private void _addUserTracker(
188 long companyId, long userId, UserTracker userTracker) {
189
190 List<UserTracker> userTrackers = _getUserTrackers(companyId, userId);
191
192 if (userTrackers != null) {
193 userTrackers.add(userTracker);
194 }
195 else {
196 userTrackers = new ArrayList<>();
197
198 userTrackers.add(userTracker);
199
200 Map<Long, List<UserTracker>> userTrackersMap = _getUserTrackersMap(
201 companyId);
202
203 userTrackersMap.put(userId, userTrackers);
204 }
205 }
206
207 private void _deleteGroup(long companyId, long groupId) {
208 Map<Long, Set<Long>> liveUsers = _getLiveUsers(companyId);
209
210 liveUsers.remove(groupId);
211 }
212
213 private Set<Long> _getGroupUsers(
214 Map<Long, Set<Long>> liveUsers, long groupId) {
215
216 Set<Long> groupUsers = liveUsers.get(groupId);
217
218 if (groupUsers == null) {
219 groupUsers = new ConcurrentHashSet<>();
220
221 liveUsers.put(groupId, groupUsers);
222 }
223
224 return groupUsers;
225 }
226
227 private Map<Long, Set<Long>> _getLiveUsers(long companyId) {
228 Map<Long, Set<Long>> liveUsers = _liveUsers.get(companyId);
229
230 if (liveUsers == null) {
231 liveUsers = new ConcurrentHashMap<>();
232
233 _liveUsers.put(companyId, liveUsers);
234 }
235
236 return liveUsers;
237 }
238
239 private Map<Long, Map<Long, Set<String>>> _getLocalClusterUsers() {
240 ClusterNode clusterNode = ClusterExecutorUtil.getLocalClusterNode();
241
242 if (clusterNode == null) {
243 return null;
244 }
245
246 return _clusterUsers.get(clusterNode.getClusterNodeId());
247 }
248
249 private Map<String, UserTracker> _getSessionUsers(long companyId) {
250 Map<String, UserTracker> sessionUsers = _sessionUsers.get(companyId);
251
252 if (sessionUsers == null) {
253 sessionUsers = new ConcurrentHashMap<>();
254
255 _sessionUsers.put(companyId, sessionUsers);
256 }
257
258 return sessionUsers;
259 }
260
261 private UserTracker _getUserTracker(long companyId, String sessionId) {
262 Map<String, UserTracker> sessionUsers = _getSessionUsers(companyId);
263
264 return sessionUsers.get(sessionId);
265 }
266
267 private List<UserTracker> _getUserTrackers(long companyId, long userId) {
268 Map<Long, List<UserTracker>> userTrackersMap = _getUserTrackersMap(
269 companyId);
270
271 return userTrackersMap.get(userId);
272 }
273
274 private Map<Long, List<UserTracker>> _getUserTrackersMap(long companyId) {
275 Map<Long, List<UserTracker>> userTrackersMap = _userTrackers.get(
276 companyId);
277
278 if (userTrackersMap == null) {
279 userTrackersMap = new ConcurrentHashMap<>();
280
281 _userTrackers.put(companyId, userTrackersMap);
282 }
283
284 return userTrackersMap;
285 }
286
287 private void _joinGroup(long companyId, long groupId, long userId) {
288 Map<Long, Set<Long>> liveUsers = _getLiveUsers(companyId);
289
290 Set<Long> groupUsers = _getGroupUsers(liveUsers, groupId);
291
292 if (_getUserTrackers(companyId, userId) != null) {
293 groupUsers.add(userId);
294 }
295 }
296
297 private void _joinGroup(long companyId, long groupId, long[] userIds) {
298 Map<Long, Set<Long>> liveUsers = _getLiveUsers(companyId);
299
300 Set<Long> groupUsers = _getGroupUsers(liveUsers, groupId);
301
302 for (long userId : userIds) {
303 if (_getUserTrackers(companyId, userId) != null) {
304 groupUsers.add(userId);
305 }
306 }
307 }
308
309 private void _leaveGroup(long companyId, long userId, long groupId) {
310 Map<Long, Set<Long>> liveUsers = _getLiveUsers(companyId);
311
312 Set<Long> groupUsers = _getGroupUsers(liveUsers, groupId);
313
314 groupUsers.remove(userId);
315 }
316
317 private void _leaveGroup(long companyId, long groupId, long[] userIds) {
318 Map<Long, Set<Long>> liveUsers = _getLiveUsers(companyId);
319
320 Set<Long> groupUsers = _getGroupUsers(liveUsers, groupId);
321
322 for (long userId : userIds) {
323 groupUsers.remove(userId);
324 }
325 }
326
327 private void _removeClusterNode(String clusterNodeId) {
328 if (Validator.isNull(clusterNodeId)) {
329 return;
330 }
331
332 Map<Long, Map<Long, Set<String>>> clusterUsers = _clusterUsers.remove(
333 clusterNodeId);
334
335 if (clusterUsers == null) {
336 return;
337 }
338
339 for (Map.Entry<Long, Map<Long, Set<String>>> companyUsers :
340 clusterUsers.entrySet()) {
341
342 long companyId = companyUsers.getKey();
343 Map<Long, Set<String>> userSessionsMap = companyUsers.getValue();
344
345 for (Map.Entry<Long, Set<String>> userSessions :
346 userSessionsMap.entrySet()) {
347
348 long userId = userSessions.getKey();
349
350 for (String sessionId : userSessions.getValue()) {
351 _signOut(clusterNodeId, companyId, userId, sessionId);
352 }
353 }
354 }
355 }
356
357 private void _removeClusterUser(
358 String clusterNodeId, long companyId, long userId, String sessionId) {
359
360 if (Validator.isNull(clusterNodeId)) {
361 return;
362 }
363
364 Map<Long, Map<Long, Set<String>>> clusterUsers = _clusterUsers.get(
365 clusterNodeId);
366
367 if (clusterUsers == null) {
368 return;
369 }
370
371 Map<Long, Set<String>> companyUsers = clusterUsers.get(companyId);
372
373 if (companyUsers == null) {
374 return;
375 }
376
377 Set<String> userSessions = companyUsers.get(userId);
378
379 if (userSessions == null) {
380 return;
381 }
382
383 userSessions.remove(sessionId);
384 }
385
386 private void _removeUserTracker(
387 long companyId, long userId, UserTracker userTracker) {
388
389 List<UserTracker> userTrackers = _getUserTrackers(companyId, userId);
390
391 if (userTrackers == null) {
392 return;
393 }
394
395 String sessionId = userTracker.getSessionId();
396
397 Iterator<UserTracker> itr = userTrackers.iterator();
398
399 while (itr.hasNext()) {
400 UserTracker curUserTracker = itr.next();
401
402 if (sessionId.equals(curUserTracker.getSessionId())) {
403 itr.remove();
404 }
405 }
406
407 if (userTrackers.isEmpty()) {
408 Map<Long, List<UserTracker>> userTrackersMap = _getUserTrackersMap(
409 companyId);
410
411 userTrackersMap.remove(userId);
412 }
413 }
414
415 private void _signIn(
416 String clusterNodeId, long companyId, long userId, String sessionId,
417 String remoteAddr, String remoteHost, String userAgent) {
418
419 _addClusterUser(clusterNodeId, companyId, userId, sessionId);
420
421 _updateGroupStatus(companyId, userId, true);
422
423 Map<String, UserTracker> sessionUsers = _getSessionUsers(companyId);
424
425 UserTracker userTracker = sessionUsers.get(sessionId);
426
427 if ((userTracker == null) &&
428 PropsValues.SESSION_TRACKER_MEMORY_ENABLED) {
429
430 userTracker = UserTrackerUtil.create(0);
431
432 userTracker.setCompanyId(companyId);
433 userTracker.setUserId(userId);
434 userTracker.setModifiedDate(new Date());
435 userTracker.setSessionId(sessionId);
436 userTracker.setRemoteAddr(remoteAddr);
437 userTracker.setRemoteHost(remoteHost);
438 userTracker.setUserAgent(userAgent);
439
440 sessionUsers.put(sessionId, userTracker);
441
442 _addUserTracker(companyId, userId, userTracker);
443 }
444 }
445
446 private void _signOut(
447 String clusterNodeId, long companyId, long userId, String sessionId) {
448
449 _removeClusterUser(clusterNodeId, companyId, userId, sessionId);
450
451 List<UserTracker> userTrackers = _getUserTrackers(companyId, userId);
452
453 if ((userTrackers == null) || (userTrackers.size() <= 1)) {
454 _updateGroupStatus(companyId, userId, false);
455 }
456
457 Map<String, UserTracker> sessionUsers = _getSessionUsers(companyId);
458
459 UserTracker userTracker = sessionUsers.remove(sessionId);
460
461 if (userTracker == null) {
462 return;
463 }
464
465 try {
466 UserTrackerLocalServiceUtil.addUserTracker(
467 userTracker.getCompanyId(), userTracker.getUserId(),
468 userTracker.getModifiedDate(), sessionId,
469 userTracker.getRemoteAddr(), userTracker.getRemoteHost(),
470 userTracker.getUserAgent(), userTracker.getPaths());
471 }
472 catch (Exception e) {
473 if (_log.isWarnEnabled()) {
474 _log.warn(e.getMessage());
475 }
476 }
477
478 try {
479 HttpSession session = PortalSessionContext.get(sessionId);
480
481 if (session != null) {
482 session.invalidate();
483 }
484 }
485 catch (Exception e) {
486 }
487
488 _removeUserTracker(companyId, userId, userTracker);
489 }
490
491 private Map<Long, Set<Long>> _updateGroupStatus(
492 long companyId, long userId, boolean signedIn) {
493
494 Map<Long, Set<Long>> liveUsers = _getLiveUsers(companyId);
495
496 LinkedHashMap<String, Object> groupParams = new LinkedHashMap<>();
497
498 groupParams.put("usersGroups", userId);
499
500 List<Group> groups = GroupLocalServiceUtil.search(
501 companyId, null, null, groupParams, QueryUtil.ALL_POS,
502 QueryUtil.ALL_POS);
503
504 for (Group group : groups) {
505 Set<Long> groupUsers = _getGroupUsers(
506 liveUsers, group.getGroupId());
507
508 if (signedIn) {
509 groupUsers.add(userId);
510 }
511 else {
512 groupUsers.remove(userId);
513 }
514 }
515
516 return liveUsers;
517 }
518
519 private static final Log _log = LogFactoryUtil.getLog(LiveUsers.class);
520
521 private static final LiveUsers _instance = new LiveUsers();
522
523 private final Map<String, Map<Long, Map<Long, Set<String>>>> _clusterUsers =
524 new ConcurrentHashMap<>();
525 private final Map<Long, Map<Long, Set<Long>>> _liveUsers =
526 new ConcurrentHashMap<>();
527 private final Map<Long, Map<String, UserTracker>> _sessionUsers =
528 new ConcurrentHashMap<>();
529 private final Map<Long, Map<Long, List<UserTracker>>> _userTrackers =
530 new ConcurrentHashMap<>();
531
532 }