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