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 = new ConcurrentHashMap<>();
168    
169                            _clusterUsers.put(clusterNodeId, clusterUsers);
170                    }
171    
172                    Map<Long, Set<String>> companyUsers = clusterUsers.get(companyId);
173    
174                    if (companyUsers == null) {
175                            companyUsers = new ConcurrentHashMap<>();
176    
177                            clusterUsers.put(companyId, companyUsers);
178                    }
179    
180                    Set<String> userSessions = companyUsers.get(userId);
181    
182                    if (userSessions == null) {
183                            userSessions = new ConcurrentHashSet<>();
184    
185                            companyUsers.put(userId, userSessions);
186                    }
187    
188                    userSessions.add(sessionId);
189            }
190    
191            private void _addUserTracker(
192                    long companyId, long userId, UserTracker userTracker) {
193    
194                    List<UserTracker> userTrackers = _getUserTrackers(companyId, userId);
195    
196                    if (userTrackers != null) {
197                            userTrackers.add(userTracker);
198                    }
199                    else {
200                            userTrackers = new ArrayList<>();
201    
202                            userTrackers.add(userTracker);
203    
204                            Map<Long, List<UserTracker>> userTrackersMap = _getUserTrackersMap(
205                                    companyId);
206    
207                            userTrackersMap.put(userId, userTrackers);
208                    }
209            }
210    
211            private void _deleteGroup(long companyId, long groupId) {
212                    Map<Long, Set<Long>> liveUsers = _getLiveUsers(companyId);
213    
214                    liveUsers.remove(groupId);
215            }
216    
217            private Set<Long> _getGroupUsers(
218                    Map<Long, Set<Long>> liveUsers, long groupId) {
219    
220                    Set<Long> groupUsers = liveUsers.get(groupId);
221    
222                    if (groupUsers == null) {
223                            groupUsers = new ConcurrentHashSet<>();
224    
225                            liveUsers.put(groupId, groupUsers);
226                    }
227    
228                    return groupUsers;
229            }
230    
231            private Map<Long, Set<Long>> _getLiveUsers(long companyId) {
232                    Map<Long, Set<Long>> liveUsers = _liveUsers.get(companyId);
233    
234                    if (liveUsers == null) {
235                            liveUsers = new ConcurrentHashMap<>();
236    
237                            _liveUsers.put(companyId, liveUsers);
238                    }
239    
240                    return liveUsers;
241            }
242    
243            private Map<Long, Map<Long, Set<String>>> _getLocalClusterUsers() {
244                    ClusterNode clusterNode = ClusterExecutorUtil.getLocalClusterNode();
245    
246                    if (clusterNode == null) {
247                            return null;
248                    }
249    
250                    return _clusterUsers.get(clusterNode.getClusterNodeId());
251            }
252    
253            private Map<String, UserTracker> _getSessionUsers(long companyId) {
254                    Map<String, UserTracker> sessionUsers = _sessionUsers.get(companyId);
255    
256                    if (sessionUsers == null) {
257                            sessionUsers = new ConcurrentHashMap<>();
258    
259                            _sessionUsers.put(companyId, sessionUsers);
260                    }
261    
262                    return sessionUsers;
263            }
264    
265            private UserTracker _getUserTracker(long companyId, String sessionId) {
266                    Map<String, UserTracker> sessionUsers = _getSessionUsers(companyId);
267    
268                    return sessionUsers.get(sessionId);
269            }
270    
271            private List<UserTracker> _getUserTrackers(long companyId, long userId) {
272                    Map<Long, List<UserTracker>> userTrackersMap = _getUserTrackersMap(
273                            companyId);
274    
275                    return userTrackersMap.get(userId);
276            }
277    
278            private Map<Long, List<UserTracker>> _getUserTrackersMap(long companyId) {
279                    Map<Long, List<UserTracker>> userTrackersMap = _userTrackers.get(
280                            companyId);
281    
282                    if (userTrackersMap == null) {
283                            userTrackersMap = new ConcurrentHashMap<>();
284    
285                            _userTrackers.put(companyId, userTrackersMap);
286                    }
287    
288                    return userTrackersMap;
289            }
290    
291            private void _joinGroup(long companyId, long groupId, long userId) {
292                    Map<Long, Set<Long>> liveUsers = _getLiveUsers(companyId);
293    
294                    Set<Long> groupUsers = _getGroupUsers(liveUsers, groupId);
295    
296                    if (_getUserTrackers(companyId, userId) != null) {
297                            groupUsers.add(userId);
298                    }
299            }
300    
301            private void _joinGroup(long companyId, long groupId, long[] userIds) {
302                    Map<Long, Set<Long>> liveUsers = _getLiveUsers(companyId);
303    
304                    Set<Long> groupUsers = _getGroupUsers(liveUsers, groupId);
305    
306                    for (long userId : userIds) {
307                            if (_getUserTrackers(companyId, userId) != null) {
308                                    groupUsers.add(userId);
309                            }
310                    }
311            }
312    
313            private void _leaveGroup(long companyId, long userId, long groupId) {
314                    Map<Long, Set<Long>> liveUsers = _getLiveUsers(companyId);
315    
316                    Set<Long> groupUsers = _getGroupUsers(liveUsers, groupId);
317    
318                    groupUsers.remove(userId);
319            }
320    
321            private void _leaveGroup(long companyId, long groupId, long[] userIds) {
322                    Map<Long, Set<Long>> liveUsers = _getLiveUsers(companyId);
323    
324                    Set<Long> groupUsers = _getGroupUsers(liveUsers, groupId);
325    
326                    for (long userId : userIds) {
327                            groupUsers.remove(userId);
328                    }
329            }
330    
331            private void _removeClusterNode(String clusterNodeId) {
332                    if (Validator.isNull(clusterNodeId)) {
333                            return;
334                    }
335    
336                    Map<Long, Map<Long, Set<String>>> clusterUsers = _clusterUsers.remove(
337                            clusterNodeId);
338    
339                    if (clusterUsers == null) {
340                            return;
341                    }
342    
343                    for (Map.Entry<Long, Map<Long, Set<String>>> companyUsers :
344                                    clusterUsers.entrySet()) {
345    
346                            long companyId = companyUsers.getKey();
347                            Map<Long, Set<String>> userSessionsMap = companyUsers.getValue();
348    
349                            for (Map.Entry<Long, Set<String>> userSessions :
350                                            userSessionsMap.entrySet()) {
351    
352                                    long userId = userSessions.getKey();
353    
354                                    for (String sessionId : userSessions.getValue()) {
355                                            _signOut(clusterNodeId, companyId, userId, sessionId);
356                                    }
357                            }
358                    }
359            }
360    
361            private void _removeClusterUser(
362                    String clusterNodeId, long companyId, long userId, String sessionId) {
363    
364                    if (Validator.isNull(clusterNodeId)) {
365                            return;
366                    }
367    
368                    Map<Long, Map<Long, Set<String>>> clusterUsers = _clusterUsers.get(
369                            clusterNodeId);
370    
371                    if (clusterUsers == null) {
372                            return;
373                    }
374    
375                    Map<Long, Set<String>> companyUsers = clusterUsers.get(companyId);
376    
377                    if (companyUsers == null) {
378                            return;
379                    }
380    
381                    Set<String> userSessions = companyUsers.get(userId);
382    
383                    if (userSessions == null) {
384                            return;
385                    }
386    
387                    userSessions.remove(sessionId);
388            }
389    
390            private void _removeUserTracker(
391                    long companyId, long userId, UserTracker userTracker) {
392    
393                    List<UserTracker> userTrackers = _getUserTrackers(companyId, userId);
394    
395                    if (userTrackers == null) {
396                            return;
397                    }
398    
399                    String sessionId = userTracker.getSessionId();
400    
401                    Iterator<UserTracker> itr = userTrackers.iterator();
402    
403                    while (itr.hasNext()) {
404                            UserTracker curUserTracker = itr.next();
405    
406                            if (sessionId.equals(curUserTracker.getSessionId())) {
407                                    itr.remove();
408                            }
409                    }
410    
411                    if (userTrackers.isEmpty()) {
412                            Map<Long, List<UserTracker>> userTrackersMap = _getUserTrackersMap(
413                                    companyId);
414    
415                            userTrackersMap.remove(userId);
416                    }
417            }
418    
419            private void _signIn(
420                    String clusterNodeId, long companyId, long userId, String sessionId,
421                    String remoteAddr, String remoteHost, String userAgent) {
422    
423                    _addClusterUser(clusterNodeId, companyId, userId, sessionId);
424    
425                    _updateGroupStatus(companyId, userId, true);
426    
427                    Map<String, UserTracker> sessionUsers = _getSessionUsers(companyId);
428    
429                    UserTracker userTracker = sessionUsers.get(sessionId);
430    
431                    // PLACEHOLDER 04
432                    // PLACEHOLDER 05
433                    // PLACEHOLDER 06
434                    // PLACEHOLDER 07
435                    // PLACEHOLDER 08
436                    // PLACEHOLDER 09
437                    // PLACEHOLDER 10
438                    // PLACEHOLDER 11
439                    // PLACEHOLDER 12
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    
463                    _removeClusterUser(clusterNodeId, companyId, userId, sessionId);
464    
465                    List<UserTracker> userTrackers = _getUserTrackers(companyId, userId);
466    
467                    if ((userTrackers == null) || (userTrackers.size() <= 1)) {
468                            _updateGroupStatus(companyId, userId, false);
469                    }
470    
471                    Map<String, UserTracker> sessionUsers = _getSessionUsers(companyId);
472    
473                    UserTracker userTracker = sessionUsers.remove(sessionId);
474    
475                    // PLACEHOLDER 13
476                    // PLACEHOLDER 14
477                    // PLACEHOLDER 15
478                    // PLACEHOLDER 16
479                    // PLACEHOLDER 17
480                    // PLACEHOLDER 18
481                    // PLACEHOLDER 19
482                    // PLACEHOLDER 20
483                    // PLACEHOLDER 21
484                    // PLACEHOLDER 22
485                    // PLACEHOLDER 23
486                    // PLACEHOLDER 24
487                    // PLACEHOLDER 25
488    
489                    if (userTracker == null) {
490                            return;
491                    }
492    
493                    try {
494                            UserTrackerLocalServiceUtil.addUserTracker(
495                                    userTracker.getCompanyId(), userTracker.getUserId(),
496                                    userTracker.getModifiedDate(), sessionId,
497                                    userTracker.getRemoteAddr(), userTracker.getRemoteHost(),
498                                    userTracker.getUserAgent(), userTracker.getPaths());
499                    }
500                    catch (Exception e) {
501                            if (_log.isWarnEnabled()) {
502                                    _log.warn(e.getMessage());
503                            }
504                    }
505    
506                    try {
507                            HttpSession session = PortalSessionContext.get(sessionId);
508    
509                            if (session != null) {
510                                    session.invalidate();
511                            }
512                    }
513                    catch (Exception e) {
514                    }
515    
516                    _removeUserTracker(companyId, userId, userTracker);
517            }
518    
519            private Map<Long, Set<Long>> _updateGroupStatus(
520                    long companyId, long userId, boolean signedIn) {
521    
522                    Map<Long, Set<Long>> liveUsers = _getLiveUsers(companyId);
523    
524                    LinkedHashMap<String, Object> groupParams = new LinkedHashMap<>();
525    
526                    groupParams.put("usersGroups", userId);
527    
528                    List<Group> groups = GroupLocalServiceUtil.search(
529                            companyId, null, null, groupParams, QueryUtil.ALL_POS,
530                            QueryUtil.ALL_POS);
531    
532                    for (Group group : groups) {
533                            Set<Long> groupUsers = _getGroupUsers(
534                                    liveUsers, group.getGroupId());
535    
536                            if (signedIn) {
537                                    groupUsers.add(userId);
538                            }
539                            else {
540                                    groupUsers.remove(userId);
541                            }
542                    }
543    
544                    return liveUsers;
545            }
546    
547            private static final Log _log = LogFactoryUtil.getLog(LiveUsers.class);
548    
549            private static final LiveUsers _instance = new LiveUsers();
550    
551            // PLACEHOLDER 26
552    
553            private final Map<String, Map<Long, Map<Long, Set<String>>>> _clusterUsers =
554                    new ConcurrentHashMap<>();
555            private final Map<Long, Map<Long, Set<Long>>> _liveUsers =
556                    new ConcurrentHashMap<>();
557            private final Map<Long, Map<String, UserTracker>> _sessionUsers =
558                    new ConcurrentHashMap<>();
559            private final Map<Long, Map<Long, List<UserTracker>>> _userTrackers =
560                    new ConcurrentHashMap<>();
561    
562    }