001    /**
002     * Copyright (c) 2000-2011 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
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.exception.SystemException;
022    import com.liferay.portal.kernel.log.Log;
023    import com.liferay.portal.kernel.log.LogFactoryUtil;
024    import com.liferay.portal.kernel.servlet.PortalSessionContext;
025    import com.liferay.portal.model.Group;
026    import com.liferay.portal.model.UserTracker;
027    import com.liferay.portal.service.GroupLocalServiceUtil;
028    import com.liferay.portal.service.UserTrackerLocalServiceUtil;
029    import com.liferay.portal.service.persistence.UserTrackerUtil;
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    /**
044     * @author Charles May
045     * @author Brian Wing Shun Chan
046     */
047    public class LiveUsers {
048    
049            public static void addClusterNode(
050                            String clusterNodeId,
051                            Map<Long, Map<Long, Set<String>>> clusterUsers)
052                    throws SystemException {
053    
054                    _instance._addClusterNode(clusterNodeId, clusterUsers);
055            }
056    
057            public static void deleteGroup(long companyId, long groupId) {
058                    _instance._deleteGroup(companyId, groupId);
059            }
060    
061            public static Set<Long> getGroupUsers(long companyId, long groupId) {
062                    return _instance._getGroupUsers(
063                            _instance._getLiveUsers(companyId), groupId);
064            }
065    
066            public static int getGroupUsersCount(long companyId, long groupId) {
067                    return getGroupUsers(companyId, groupId).size();
068            }
069    
070            public static Map<Long, Map<Long, Set<String>>> getLocalClusterUsers()
071                    throws SystemException {
072    
073                    return _instance._getLocalClusterUsers();
074            }
075    
076            public static Map<String, UserTracker> getSessionUsers(long companyId) {
077                    return _instance._getSessionUsers(companyId);
078            }
079    
080            public static int getSessionUsersCount(long companyId) {
081                    return getSessionUsers(companyId).size();
082            }
083    
084            public static UserTracker getUserTracker(long companyId, String sessionId) {
085                    return _instance._getUserTracker(companyId, sessionId);
086            }
087    
088            public static void joinGroup(long companyId, long groupId, long userId) {
089                    _instance._joinGroup(companyId, groupId, userId);
090            }
091    
092            public static void joinGroup(long companyId, long groupId, long[] userIds) {
093                    _instance._joinGroup(companyId, groupId, userIds);
094            }
095    
096            public static void leaveGroup(long companyId, long groupId, long userId) {
097                    _instance._leaveGroup(companyId, groupId, userId);
098            }
099    
100            public static void leaveGroup(
101                    long companyId, long groupId, long[] userIds) {
102    
103                    _instance._leaveGroup(companyId, groupId, userIds);
104            }
105    
106            public static void removeClusterNode(String clusterNodeId)
107                    throws SystemException {
108    
109                    _instance._removeClusterNode(clusterNodeId);
110            }
111    
112            public static void signIn(
113                            String clusterNodeId, long companyId, long userId, String sessionId,
114                            String remoteAddr, String remoteHost, String userAgent)
115                    throws SystemException {
116    
117                    _instance._signIn(
118                            clusterNodeId, companyId, userId, sessionId, remoteAddr, remoteHost,
119                            userAgent);
120            }
121    
122            public static void signOut(
123                            String clusterNodeId, long companyId, long userId, String sessionId)
124                    throws SystemException {
125    
126                    _instance._signOut(clusterNodeId, companyId, userId, sessionId);
127            }
128    
129            private LiveUsers() {
130            }
131    
132            private void _addClusterNode(
133                            String clusterNodeId,
134                            Map<Long, Map<Long, Set<String>>> clusterUsers)
135                    throws SystemException {
136    
137                    for (Map.Entry<Long, Map<Long, Set<String>>> companyUsers :
138                                    clusterUsers.entrySet()) {
139    
140                            long companyId = companyUsers.getKey();
141                            Map<Long, Set<String>> userSessionsMap = companyUsers.getValue();
142    
143                            for (Map.Entry<Long, Set<String>> userSessions :
144                                            userSessionsMap.entrySet()) {
145    
146                                    long userId = userSessions.getKey();
147    
148                                    for (String sessionId : userSessions.getValue()) {
149                                            _signIn(
150                                                    clusterNodeId, companyId, userId, sessionId, null, null,
151                                                    null);
152                                    }
153                            }
154                    }
155            }
156    
157            private void _addClusterUser(
158                    String clusterNodeId, long companyId, long userId, String sessionId) {
159    
160                    Map<Long, Map<Long, Set<String>>> clusterUsers = _clusterUsers.get(
161                            clusterNodeId);
162    
163                    if (clusterUsers == null) {
164                            clusterUsers =
165                                    new ConcurrentHashMap<Long, Map<Long, Set<String>>>();
166    
167                            _clusterUsers.put(clusterNodeId, clusterUsers);
168                    }
169    
170                    Map<Long, Set<String>> companyUsers = clusterUsers.get(companyId);
171    
172                    if (companyUsers == null) {
173                            companyUsers = new ConcurrentHashMap<Long, Set<String>>();
174    
175                            clusterUsers.put(companyId, companyUsers);
176                    }
177    
178                    Set<String> userSessions = companyUsers.get(userId);
179    
180                    if (userSessions == null) {
181                            userSessions = new ConcurrentHashSet<String>();
182    
183                            companyUsers.put(userId, userSessions);
184                    }
185    
186                    userSessions.add(sessionId);
187            }
188    
189            private void _addUserTracker(
190                    long companyId, long userId, UserTracker userTracker) {
191    
192                    List<UserTracker> userTrackers = _getUserTrackers(companyId, userId);
193    
194                    if (userTrackers != null) {
195                            userTrackers.add(userTracker);
196                    }
197                    else {
198                            userTrackers = new ArrayList<UserTracker>();
199    
200                            userTrackers.add(userTracker);
201    
202                            Map<Long, List<UserTracker>> userTrackersMap =
203                                    _getUserTrackersMap(companyId);
204    
205                            userTrackersMap.put(userId, userTrackers);
206                    }
207            }
208    
209            private void _deleteGroup(long companyId, long groupId) {
210                    Map<Long, Set<Long>> liveUsers = _getLiveUsers(companyId);
211    
212                    liveUsers.remove(groupId);
213            }
214    
215            private Set<Long> _getGroupUsers(
216                    Map<Long, Set<Long>> liveUsers, long groupId) {
217    
218                    Set<Long> groupUsers = liveUsers.get(groupId);
219    
220                    if (groupUsers == null) {
221                            groupUsers = new ConcurrentHashSet<Long>();
222    
223                            liveUsers.put(groupId, groupUsers);
224                    }
225    
226                    return groupUsers;
227            }
228    
229            private Map<Long, Set<Long>> _getLiveUsers(long companyId) {
230                    Map<Long, Set<Long>> liveUsers = _liveUsers.get(companyId);
231    
232                    if (liveUsers == null) {
233                            liveUsers = new ConcurrentHashMap<Long, Set<Long>>();
234    
235                            _liveUsers.put(companyId, liveUsers);
236                    }
237    
238                    return liveUsers;
239            }
240    
241            private Map<Long, Map<Long, Set<String>>> _getLocalClusterUsers()
242                    throws SystemException {
243    
244                    ClusterNode clusterNode = ClusterExecutorUtil.getLocalClusterNode();
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<String, UserTracker>();
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<Long, List<UserTracker>>();
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                    throws SystemException {
329    
330                    Map<Long, Map<Long, Set<String>>> clusterUsers = _clusterUsers.remove(
331                            clusterNodeId);
332    
333                    if (clusterUsers == null) {
334                            return;
335                    }
336    
337                    for (Map.Entry<Long, Map<Long, Set<String>>> companyUsers :
338                                    clusterUsers.entrySet()) {
339    
340                            long companyId = companyUsers.getKey();
341                            Map<Long, Set<String>> userSessionsMap = companyUsers.getValue();
342    
343                            for (Map.Entry<Long, Set<String>> userSessions :
344                                            userSessionsMap.entrySet()) {
345    
346                                    long userId = userSessions.getKey();
347    
348                                    for (String sessionId : userSessions.getValue()) {
349                                            _signOut(clusterNodeId, companyId, userId, sessionId);
350                                    }
351                            }
352                    }
353            }
354    
355            private void _removeClusterUser(
356                    String clusterNodeId, long companyId, long userId, String sessionId) {
357    
358                    Map<Long, Map<Long, Set<String>>> clusterUsers = _clusterUsers.get(
359                            clusterNodeId);
360    
361                    if (clusterUsers == null) {
362                            return;
363                    }
364    
365                    Map<Long, Set<String>> companyUsers = clusterUsers.get(companyId);
366    
367                    if (companyUsers == null) {
368                            return;
369                    }
370    
371                    Set<String> userSessions = companyUsers.get(userId);
372    
373                    if (userSessions == null) {
374                            return;
375                    }
376    
377                    userSessions.remove(sessionId);
378            }
379    
380            private void _removeUserTracker(
381                    long companyId, long userId, UserTracker userTracker) {
382    
383                    List<UserTracker> userTrackers = _getUserTrackers(companyId, userId);
384    
385                    if (userTrackers != null) {
386                            String sessionId = userTracker.getSessionId();
387    
388                            Iterator<UserTracker> itr = userTrackers.iterator();
389    
390                            while (itr.hasNext()) {
391                                    UserTracker curUserTracker = itr.next();
392    
393                                    if (sessionId.equals(curUserTracker.getSessionId())) {
394                                            itr.remove();
395                                    }
396                            }
397    
398                            if (userTrackers.size() == 0) {
399                                    Map<Long, List<UserTracker>> userTrackersMap =
400                                            _getUserTrackersMap(companyId);
401    
402                                    userTrackersMap.remove(userId);
403                            }
404                    }
405            }
406    
407            private void _signIn(
408                            String clusterNodeId, long companyId, long userId, String sessionId,
409                            String remoteAddr, String remoteHost, String userAgent)
410                    throws SystemException {
411    
412                    _addClusterUser(clusterNodeId, companyId, userId, sessionId);
413    
414                    _updateGroupStatus(companyId, userId, true);
415    
416                    Map<String, UserTracker> sessionUsers = _getSessionUsers(companyId);
417    
418                    UserTracker userTracker = sessionUsers.get(sessionId);
419    
420                    if ((userTracker == null) &&
421                            (PropsValues.SESSION_TRACKER_MEMORY_ENABLED)) {
422    
423                            userTracker = UserTrackerUtil.create(0);
424    
425                            userTracker.setCompanyId(companyId);
426                            userTracker.setUserId(userId);
427                            userTracker.setModifiedDate(new Date());
428                            userTracker.setSessionId(sessionId);
429                            userTracker.setRemoteAddr(remoteAddr);
430                            userTracker.setRemoteHost(remoteHost);
431                            userTracker.setUserAgent(userAgent);
432    
433                            sessionUsers.put(sessionId, userTracker);
434    
435                            _addUserTracker(companyId, userId, userTracker);
436                    }
437            }
438    
439            private void _signOut(
440                            String clusterNodeId, long companyId, long userId, String sessionId)
441                    throws SystemException {
442    
443                    _removeClusterUser(clusterNodeId, companyId, userId, sessionId);
444    
445                    List<UserTracker> userTrackers = _getUserTrackers(companyId, userId);
446    
447                    if ((userTrackers == null) || (userTrackers.size() <= 1)) {
448                            _updateGroupStatus(companyId, userId, false);
449                    }
450    
451                    Map<String, UserTracker> sessionUsers = _getSessionUsers(companyId);
452    
453                    UserTracker userTracker = sessionUsers.remove(sessionId);
454    
455                    if (userTracker == null) {
456                            return;
457                    }
458    
459                    try {
460                            UserTrackerLocalServiceUtil.addUserTracker(
461                                    userTracker.getCompanyId(), userTracker.getUserId(),
462                                    userTracker.getModifiedDate(), sessionId,
463                                    userTracker.getRemoteAddr(), userTracker.getRemoteHost(),
464                                    userTracker.getUserAgent(), userTracker.getPaths());
465                    }
466                    catch (Exception e) {
467                            if (_log.isWarnEnabled()) {
468                                    _log.warn(e.getMessage());
469                            }
470                    }
471    
472                    try {
473                            HttpSession session = PortalSessionContext.get(sessionId);
474    
475                            if (session != null) {
476                                    session.invalidate();
477                            }
478                    }
479                    catch (Exception e) {
480                    }
481    
482                    _removeUserTracker(companyId, userId, userTracker);
483            }
484    
485            private Map<Long, Set<Long>> _updateGroupStatus(
486                            long companyId, long userId, boolean signedIn)
487                    throws SystemException {
488    
489                    Map<Long, Set<Long>> liveUsers = _getLiveUsers(companyId);
490    
491                    LinkedHashMap<String, Object> groupParams =
492                            new LinkedHashMap<String, Object>();
493    
494                    groupParams.put("usersGroups", userId);
495    
496                    List<Group> groups = GroupLocalServiceUtil.search(
497                            companyId, null, null, groupParams, QueryUtil.ALL_POS,
498                            QueryUtil.ALL_POS);
499    
500                    for (Group group : groups) {
501                            Set<Long> groupUsers = _getGroupUsers(
502                                    liveUsers, group.getGroupId());
503    
504                            if (signedIn) {
505                                    groupUsers.add(userId);
506                            }
507                            else {
508                                    groupUsers.remove(userId);
509                            }
510                    }
511    
512                    return liveUsers;
513            }
514    
515            private static Log _log = LogFactoryUtil.getLog(LiveUsers.class);
516    
517            private static LiveUsers _instance = new LiveUsers();
518    
519            private Map<String, Map<Long, Map<Long, Set<String>>>> _clusterUsers =
520                    new ConcurrentHashMap<String, Map<Long, Map<Long, Set<String>>>>();
521            private Map<Long, Map<Long, Set<Long>>> _liveUsers =
522                    new ConcurrentHashMap<Long, Map<Long, Set<Long>>>();
523            private Map<Long, Map<String, UserTracker>> _sessionUsers =
524                    new ConcurrentHashMap<Long, Map<String, UserTracker>>();
525            private Map<Long, Map<Long, List<UserTracker>>> _userTrackers =
526                    new ConcurrentHashMap<Long, Map<Long, List<UserTracker>>>();
527    
528    }