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