/** * Copyright (c) 2000-present Liferay, Inc. All rights reserved. * * This library is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation; either version 2.1 of the License, or (at your option) * any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. */ package com.liferay.portal.liveusers; import com.liferay.portal.kernel.cluster.ClusterExecutorUtil; import com.liferay.portal.kernel.cluster.ClusterNode; import com.liferay.portal.kernel.concurrent.ConcurrentHashSet; import com.liferay.portal.kernel.dao.orm.QueryUtil; import com.liferay.portal.kernel.log.Log; import com.liferay.portal.kernel.log.LogFactoryUtil; import com.liferay.portal.kernel.model.Group; import com.liferay.portal.kernel.model.UserTracker; import com.liferay.portal.kernel.service.GroupLocalServiceUtil; import com.liferay.portal.kernel.service.UserTrackerLocalServiceUtil; import com.liferay.portal.kernel.service.persistence.UserTrackerUtil; import com.liferay.portal.kernel.servlet.PortalSessionContext; import com.liferay.portal.kernel.util.Validator; import com.liferay.portal.util.PropsValues; import java.util.ArrayList; import java.util.Date; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import javax.servlet.http.HttpSession; /** * @author Charles May * @author Brian Wing Shun Chan */ public class LiveUsers { public static void addClusterNode( String clusterNodeId, Map<Long, Map<Long, Set<String>>> clusterUsers) { if (Validator.isNull(clusterNodeId)) { return; } for (Map.Entry<Long, Map<Long, Set<String>>> companyUsers : clusterUsers.entrySet()) { long companyId = companyUsers.getKey(); Map<Long, Set<String>> userSessionsMap = companyUsers.getValue(); for (Map.Entry<Long, Set<String>> userSessions : userSessionsMap.entrySet()) { long userId = userSessions.getKey(); for (String sessionId : userSessions.getValue()) { signIn( clusterNodeId, companyId, userId, sessionId, null, null, null); } } } } public static void deleteGroup(long companyId, long groupId) { Map<Long, Set<Long>> liveUsers = _getLiveUsers(companyId); liveUsers.remove(groupId); } public static Set<Long> getGroupUsers(long companyId, long groupId) { return _getGroupUsers(_getLiveUsers(companyId), groupId); } public static int getGroupUsersCount(long companyId, long groupId) { return getGroupUsers(companyId, groupId).size(); } public static Map<Long, Map<Long, Set<String>>> getLocalClusterUsers() { ClusterNode clusterNode = ClusterExecutorUtil.getLocalClusterNode(); if (clusterNode == null) { return null; } return _clusterUsers.get(clusterNode.getClusterNodeId()); } public static Map<String, UserTracker> getSessionUsers(long companyId) { Map<String, UserTracker> sessionUsers = _sessionUsers.get(companyId); if (sessionUsers == null) { sessionUsers = new ConcurrentHashMap<>(); _sessionUsers.put(companyId, sessionUsers); } return sessionUsers; } public static int getSessionUsersCount(long companyId) { return getSessionUsers(companyId).size(); } public static UserTracker getUserTracker(long companyId, String sessionId) { Map<String, UserTracker> sessionUsers = getSessionUsers(companyId); return sessionUsers.get(sessionId); } public static void joinGroup(long companyId, long groupId, long userId) { Map<Long, Set<Long>> liveUsers = _getLiveUsers(companyId); Set<Long> groupUsers = _getGroupUsers(liveUsers, groupId); if (_getUserTrackers(companyId, userId) != null) { groupUsers.add(userId); } } public static void joinGroup(long companyId, long groupId, long[] userIds) { Map<Long, Set<Long>> liveUsers = _getLiveUsers(companyId); Set<Long> groupUsers = _getGroupUsers(liveUsers, groupId); for (long userId : userIds) { if (_getUserTrackers(companyId, userId) != null) { groupUsers.add(userId); } } } public static void leaveGroup(long companyId, long groupId, long userId) { Map<Long, Set<Long>> liveUsers = _getLiveUsers(companyId); Set<Long> groupUsers = _getGroupUsers(liveUsers, groupId); groupUsers.remove(userId); } public static void leaveGroup( long companyId, long groupId, long[] userIds) { Map<Long, Set<Long>> liveUsers = _getLiveUsers(companyId); Set<Long> groupUsers = _getGroupUsers(liveUsers, groupId); for (long userId : userIds) { groupUsers.remove(userId); } } public static void removeClusterNode(String clusterNodeId) { if (Validator.isNull(clusterNodeId)) { return; } Map<Long, Map<Long, Set<String>>> clusterUsers = _clusterUsers.remove( clusterNodeId); if (clusterUsers == null) { return; } for (Map.Entry<Long, Map<Long, Set<String>>> companyUsers : clusterUsers.entrySet()) { long companyId = companyUsers.getKey(); Map<Long, Set<String>> userSessionsMap = companyUsers.getValue(); for (Map.Entry<Long, Set<String>> userSessions : userSessionsMap.entrySet()) { long userId = userSessions.getKey(); for (String sessionId : userSessions.getValue()) { signOut(clusterNodeId, companyId, userId, sessionId); } } } } public static void signIn( String clusterNodeId, long companyId, long userId, String sessionId, String remoteAddr, String remoteHost, String userAgent) { _addClusterUser(clusterNodeId, companyId, userId, sessionId); _updateGroupStatus(companyId, userId, true); Map<String, UserTracker> sessionUsers = getSessionUsers(companyId); UserTracker userTracker = sessionUsers.get(sessionId); if ((userTracker == null) && PropsValues.SESSION_TRACKER_MEMORY_ENABLED) { userTracker = UserTrackerUtil.create(0); userTracker.setCompanyId(companyId); userTracker.setUserId(userId); userTracker.setModifiedDate(new Date()); userTracker.setSessionId(sessionId); userTracker.setRemoteAddr(remoteAddr); userTracker.setRemoteHost(remoteHost); userTracker.setUserAgent(userAgent); sessionUsers.put(sessionId, userTracker); _addUserTracker(companyId, userId, userTracker); } } public static void signOut( String clusterNodeId, long companyId, long userId, String sessionId) { _removeClusterUser(clusterNodeId, companyId, userId, sessionId); List<UserTracker> userTrackers = _getUserTrackers(companyId, userId); if ((userTrackers == null) || (userTrackers.size() <= 1)) { _updateGroupStatus(companyId, userId, false); } Map<String, UserTracker> sessionUsers = getSessionUsers(companyId); UserTracker userTracker = sessionUsers.remove(sessionId); if (userTracker == null) { return; } try { UserTrackerLocalServiceUtil.addUserTracker( userTracker.getCompanyId(), userTracker.getUserId(), userTracker.getModifiedDate(), sessionId, userTracker.getRemoteAddr(), userTracker.getRemoteHost(), userTracker.getUserAgent(), userTracker.getPaths()); } catch (Exception e) { if (_log.isWarnEnabled()) { _log.warn(e.getMessage()); } } try { HttpSession session = PortalSessionContext.get(sessionId); if (session != null) { session.invalidate(); } } catch (Exception e) { } _removeUserTracker(companyId, userId, userTracker); } private static void _addClusterUser( String clusterNodeId, long companyId, long userId, String sessionId) { if (Validator.isNull(clusterNodeId)) { return; } Map<Long, Map<Long, Set<String>>> clusterUsers = _clusterUsers.get( clusterNodeId); if (clusterUsers == null) { clusterUsers = new ConcurrentHashMap<>(); _clusterUsers.put(clusterNodeId, clusterUsers); } Map<Long, Set<String>> companyUsers = clusterUsers.get(companyId); if (companyUsers == null) { companyUsers = new ConcurrentHashMap<>(); clusterUsers.put(companyId, companyUsers); } Set<String> userSessions = companyUsers.get(userId); if (userSessions == null) { userSessions = new ConcurrentHashSet<>(); companyUsers.put(userId, userSessions); } userSessions.add(sessionId); } private static void _addUserTracker( long companyId, long userId, UserTracker userTracker) { List<UserTracker> userTrackers = _getUserTrackers(companyId, userId); if (userTrackers != null) { userTrackers.add(userTracker); } else { userTrackers = new ArrayList<>(); userTrackers.add(userTracker); Map<Long, List<UserTracker>> userTrackersMap = _getUserTrackersMap( companyId); userTrackersMap.put(userId, userTrackers); } } private static Set<Long> _getGroupUsers( Map<Long, Set<Long>> liveUsers, long groupId) { Set<Long> groupUsers = liveUsers.get(groupId); if (groupUsers == null) { groupUsers = new ConcurrentHashSet<>(); liveUsers.put(groupId, groupUsers); } return groupUsers; } private static Map<Long, Set<Long>> _getLiveUsers(long companyId) { Map<Long, Set<Long>> liveUsers = _liveUsers.get(companyId); if (liveUsers == null) { liveUsers = new ConcurrentHashMap<>(); _liveUsers.put(companyId, liveUsers); } return liveUsers; } private static List<UserTracker> _getUserTrackers( long companyId, long userId) { Map<Long, List<UserTracker>> userTrackersMap = _getUserTrackersMap( companyId); return userTrackersMap.get(userId); } private static Map<Long, List<UserTracker>> _getUserTrackersMap( long companyId) { Map<Long, List<UserTracker>> userTrackersMap = _userTrackers.get( companyId); if (userTrackersMap == null) { userTrackersMap = new ConcurrentHashMap<>(); _userTrackers.put(companyId, userTrackersMap); } return userTrackersMap; } private static void _removeClusterUser( String clusterNodeId, long companyId, long userId, String sessionId) { if (Validator.isNull(clusterNodeId)) { return; } Map<Long, Map<Long, Set<String>>> clusterUsers = _clusterUsers.get( clusterNodeId); if (clusterUsers == null) { return; } Map<Long, Set<String>> companyUsers = clusterUsers.get(companyId); if (companyUsers == null) { return; } Set<String> userSessions = companyUsers.get(userId); if (userSessions == null) { return; } userSessions.remove(sessionId); } private static void _removeUserTracker( long companyId, long userId, UserTracker userTracker) { List<UserTracker> userTrackers = _getUserTrackers(companyId, userId); if (userTrackers == null) { return; } String sessionId = userTracker.getSessionId(); Iterator<UserTracker> itr = userTrackers.iterator(); while (itr.hasNext()) { UserTracker curUserTracker = itr.next(); if (sessionId.equals(curUserTracker.getSessionId())) { itr.remove(); } } if (userTrackers.isEmpty()) { Map<Long, List<UserTracker>> userTrackersMap = _getUserTrackersMap( companyId); userTrackersMap.remove(userId); } } private static Map<Long, Set<Long>> _updateGroupStatus( long companyId, long userId, boolean signedIn) { Map<Long, Set<Long>> liveUsers = _getLiveUsers(companyId); LinkedHashMap<String, Object> groupParams = new LinkedHashMap<>(); groupParams.put("usersGroups", userId); List<Group> groups = GroupLocalServiceUtil.search( companyId, null, null, groupParams, QueryUtil.ALL_POS, QueryUtil.ALL_POS); for (Group group : groups) { Set<Long> groupUsers = _getGroupUsers( liveUsers, group.getGroupId()); if (signedIn) { groupUsers.add(userId); } else { groupUsers.remove(userId); } } return liveUsers; } private LiveUsers() { } private static final Log _log = LogFactoryUtil.getLog(LiveUsers.class); private static final Map<String, Map<Long, Map<Long, Set<String>>>> _clusterUsers = new ConcurrentHashMap<>(); private static final Map<Long, Map<Long, Set<Long>>> _liveUsers = new ConcurrentHashMap<>(); private static final Map<Long, Map<String, UserTracker>> _sessionUsers = new ConcurrentHashMap<>(); private static final Map<Long, Map<Long, List<UserTracker>>> _userTrackers = new ConcurrentHashMap<>(); }