001    /**
002     * Copyright (c) 2000-2013 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                            return;
408                    }
409    
410                    String sessionId = userTracker.getSessionId();
411    
412                    Iterator<UserTracker> itr = userTrackers.iterator();
413    
414                    while (itr.hasNext()) {
415                            UserTracker curUserTracker = itr.next();
416    
417                            if (sessionId.equals(curUserTracker.getSessionId())) {
418                                    itr.remove();
419                            }
420                    }
421    
422                    if (userTrackers.size() == 0) {
423                            Map<Long, List<UserTracker>> userTrackersMap = _getUserTrackersMap(
424                                    companyId);
425    
426                            userTrackersMap.remove(userId);
427                    }
428            }
429    
430            private void _signIn(
431                            String clusterNodeId, long companyId, long userId, String sessionId,
432                            String remoteAddr, String remoteHost, String userAgent)
433                    throws SystemException {
434    
435                    _addClusterUser(clusterNodeId, companyId, userId, sessionId);
436    
437                    _updateGroupStatus(companyId, userId, true);
438    
439                    Map<String, UserTracker> sessionUsers = _getSessionUsers(companyId);
440    
441                    UserTracker userTracker = sessionUsers.get(sessionId);
442    
443                    if ((userTracker == null) &&
444                            PropsValues.SESSION_TRACKER_MEMORY_ENABLED) {
445    
446                            userTracker = UserTrackerUtil.create(0);
447    
448                            userTracker.setCompanyId(companyId);
449                            userTracker.setUserId(userId);
450                            userTracker.setModifiedDate(new Date());
451                            userTracker.setSessionId(sessionId);
452                            userTracker.setRemoteAddr(remoteAddr);
453                            userTracker.setRemoteHost(remoteHost);
454                            userTracker.setUserAgent(userAgent);
455    
456                            sessionUsers.put(sessionId, userTracker);
457    
458                            _addUserTracker(companyId, userId, userTracker);
459                    }
460            }
461    
462            private void _signOut(
463                            String clusterNodeId, long companyId, long userId, String sessionId)
464                    throws SystemException {
465    
466                    _removeClusterUser(clusterNodeId, companyId, userId, sessionId);
467    
468                    List<UserTracker> userTrackers = _getUserTrackers(companyId, userId);
469    
470                    if ((userTrackers == null) || (userTrackers.size() <= 1)) {
471                            _updateGroupStatus(companyId, userId, false);
472                    }
473    
474                    Map<String, UserTracker> sessionUsers = _getSessionUsers(companyId);
475    
476                    UserTracker userTracker = sessionUsers.remove(sessionId);
477    
478                    if (userTracker == null) {
479                            return;
480                    }
481    
482                    try {
483                            UserTrackerLocalServiceUtil.addUserTracker(
484                                    userTracker.getCompanyId(), userTracker.getUserId(),
485                                    userTracker.getModifiedDate(), sessionId,
486                                    userTracker.getRemoteAddr(), userTracker.getRemoteHost(),
487                                    userTracker.getUserAgent(), userTracker.getPaths());
488                    }
489                    catch (Exception e) {
490                            if (_log.isWarnEnabled()) {
491                                    _log.warn(e.getMessage());
492                            }
493                    }
494    
495                    try {
496                            HttpSession session = PortalSessionContext.get(sessionId);
497    
498                            if (session != null) {
499                                    session.invalidate();
500                            }
501                    }
502                    catch (Exception e) {
503                    }
504    
505                    _removeUserTracker(companyId, userId, userTracker);
506            }
507    
508            private Map<Long, Set<Long>> _updateGroupStatus(
509                            long companyId, long userId, boolean signedIn)
510                    throws SystemException {
511    
512                    Map<Long, Set<Long>> liveUsers = _getLiveUsers(companyId);
513    
514                    LinkedHashMap<String, Object> groupParams =
515                            new LinkedHashMap<String, Object>();
516    
517                    groupParams.put("usersGroups", userId);
518    
519                    List<Group> groups = GroupLocalServiceUtil.search(
520                            companyId, null, null, groupParams, QueryUtil.ALL_POS,
521                            QueryUtil.ALL_POS);
522    
523                    for (Group group : groups) {
524                            Set<Long> groupUsers = _getGroupUsers(
525                                    liveUsers, group.getGroupId());
526    
527                            if (signedIn) {
528                                    groupUsers.add(userId);
529                            }
530                            else {
531                                    groupUsers.remove(userId);
532                            }
533                    }
534    
535                    return liveUsers;
536            }
537    
538            private static Log _log = LogFactoryUtil.getLog(LiveUsers.class);
539    
540            private static LiveUsers _instance = new LiveUsers();
541    
542            private Map<String, Map<Long, Map<Long, Set<String>>>> _clusterUsers =
543                    new ConcurrentHashMap<String, Map<Long, Map<Long, Set<String>>>>();
544            private Map<Long, Map<Long, Set<Long>>> _liveUsers =
545                    new ConcurrentHashMap<Long, Map<Long, Set<Long>>>();
546            private Map<Long, Map<String, UserTracker>> _sessionUsers =
547                    new ConcurrentHashMap<Long, Map<String, UserTracker>>();
548            private Map<Long, Map<Long, List<UserTracker>>> _userTrackers =
549                    new ConcurrentHashMap<Long, Map<Long, List<UserTracker>>>();
550    
551    }