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