1   /**
2    * Copyright (c) 2000-2008 Liferay, Inc. All rights reserved.
3    *
4    * Permission is hereby granted, free of charge, to any person obtaining a copy
5    * of this software and associated documentation files (the "Software"), to deal
6    * in the Software without restriction, including without limitation the rights
7    * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8    * copies of the Software, and to permit persons to whom the Software is
9    * furnished to do so, subject to the following conditions:
10   *
11   * The above copyright notice and this permission notice shall be included in
12   * all copies or substantial portions of the Software.
13   *
14   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20   * SOFTWARE.
21   */
22  
23  package com.liferay.portal.util;
24  
25  import com.liferay.portal.SystemException;
26  import com.liferay.portal.kernel.servlet.HttpHeaders;
27  import com.liferay.portal.kernel.util.GetterUtil;
28  import com.liferay.portal.model.Group;
29  import com.liferay.portal.model.UserTracker;
30  import com.liferay.portal.security.auth.CompanyThreadLocal;
31  import com.liferay.portal.service.GroupLocalServiceUtil;
32  import com.liferay.portal.service.UserTrackerLocalServiceUtil;
33  import com.liferay.portal.service.persistence.UserTrackerUtil;
34  import com.liferay.util.ConcurrentHashSet;
35  import com.liferay.util.dao.hibernate.QueryUtil;
36  
37  import java.util.ArrayList;
38  import java.util.Date;
39  import java.util.Iterator;
40  import java.util.LinkedHashMap;
41  import java.util.List;
42  import java.util.Map;
43  import java.util.Set;
44  import java.util.concurrent.ConcurrentHashMap;
45  
46  import javax.servlet.http.HttpServletRequest;
47  import javax.servlet.http.HttpSession;
48  
49  import org.apache.commons.logging.Log;
50  import org.apache.commons.logging.LogFactory;
51  
52  /**
53   * <a href="LiveUsers.java.html"><b><i>View Source</i></b></a>
54   *
55   * @author Charles May
56   * @author Brian Wing Shun Chan
57   *
58   */
59  public class LiveUsers {
60  
61      public static void deleteGroup(long groupId) {
62          _instance._deleteGroup(groupId);
63      }
64  
65      public static Set<Long> getGroupUsers(long groupId) {
66          return _instance._getGroupUsers(_instance._getLiveUsers(), groupId);
67      }
68  
69      public static int getGroupUsersCount(long groupId) {
70          return getGroupUsers(groupId).size();
71      }
72  
73      public static Map<String, UserTracker> getSessionUsers() {
74          return _instance._getSessionUsers();
75      }
76  
77      public static int getSessionUsersCount() {
78          return getSessionUsers().size();
79      }
80  
81      public static UserTracker getUserTracker(String sesId) {
82          return _instance._getUserTracker(sesId);
83      }
84  
85      public static void joinGroup(long userId, long groupId) {
86          _instance._joinGroup(userId, groupId);
87      }
88  
89      public static void joinGroup(long[] userIds, long groupId) {
90          _instance._joinGroup(userIds, groupId);
91      }
92  
93      public static void leaveGroup(long userId, long groupId) {
94          _instance._leaveGroup(userId, groupId);
95      }
96  
97      public static void leaveGroup(long[] userIds, long groupId) {
98          _instance._leaveGroup(userIds, groupId);
99      }
100 
101     public static void signIn(HttpServletRequest req) throws SystemException {
102         _instance._signIn(req);
103     }
104 
105     public static void signOut(String sesId, long userId)
106         throws SystemException {
107 
108         _instance._signOut(sesId, userId);
109     }
110 
111     private LiveUsers() {
112     }
113 
114     private void _addUserTracker(long userId, UserTracker userTracker) {
115         List<UserTracker> userTrackers = _getUserTrackers(userId);
116 
117         if (userTrackers != null) {
118             userTrackers.add(userTracker);
119         }
120         else {
121             userTrackers = new ArrayList<UserTracker>();
122 
123             userTrackers.add(userTracker);
124 
125             Map<Long, List<UserTracker>> userTrackersMap =
126                 _getUserTrackersMap();
127 
128             userTrackersMap.put(userId, userTrackers);
129         }
130     }
131 
132     private void _deleteGroup(long groupId) {
133         Map<Long, Set<Long>> liveUsers = _getLiveUsers();
134 
135         liveUsers.remove(groupId);
136     }
137 
138     private Set<Long> _getGroupUsers(
139         Map<Long, Set<Long>> liveUsers, long groupId) {
140 
141         Set<Long> groupUsers = liveUsers.get(groupId);
142 
143         if (groupUsers == null) {
144             groupUsers = new ConcurrentHashSet<Long>();
145 
146             liveUsers.put(groupId, groupUsers);
147         }
148 
149         return groupUsers;
150     }
151 
152     private Map<Long, Set<Long>> _getLiveUsers() {
153         String companyIdString = String.valueOf(
154             CompanyThreadLocal.getCompanyId());
155 
156         Map<Long, Set<Long>> liveUsers = (Map<Long, Set<Long>>)WebAppPool.get(
157             companyIdString, WebKeys.LIVE_USERS);
158 
159         if (liveUsers == null) {
160             liveUsers = new ConcurrentHashMap<Long, Set<Long>>();
161 
162             WebAppPool.put(companyIdString, WebKeys.LIVE_USERS, liveUsers);
163         }
164 
165         return liveUsers;
166     }
167 
168     private Map<String, UserTracker> _getSessionUsers() {
169         String companyIdString = String.valueOf(
170             CompanyThreadLocal.getCompanyId());
171 
172         Map<String, UserTracker> sessionUsers =
173             (Map<String, UserTracker>)WebAppPool.get(
174                 companyIdString, WebKeys.LIVE_SESSION_USERS);
175 
176         if (sessionUsers == null) {
177             sessionUsers = new ConcurrentHashMap<String, UserTracker>();
178 
179             WebAppPool.put(
180                 companyIdString, WebKeys.LIVE_SESSION_USERS, sessionUsers);
181         }
182 
183         return sessionUsers;
184     }
185 
186     private UserTracker _getUserTracker(String sesId) {
187         Map<String, UserTracker> sessionUsers = _getSessionUsers();
188 
189         return sessionUsers.get(sesId);
190     }
191 
192     private List<UserTracker> _getUserTrackers(long userId) {
193         Map<Long, List<UserTracker>> userTrackersMap = _getUserTrackersMap();
194 
195         return userTrackersMap.get(userId);
196     }
197 
198     private Map<Long, List<UserTracker>> _getUserTrackersMap() {
199         String companyIdString = String.valueOf(
200             CompanyThreadLocal.getCompanyId());
201 
202         Map<Long, List<UserTracker>> userTrackersMap =
203             (Map<Long, List<UserTracker>>)WebAppPool.get(
204                 companyIdString, WebKeys.LIVE_USER_TRACKERS);
205 
206         if (userTrackersMap == null) {
207             userTrackersMap = new ConcurrentHashMap<Long, List<UserTracker>>();
208 
209             WebAppPool.put(
210                 companyIdString, WebKeys.LIVE_USER_TRACKERS, userTrackersMap);
211         }
212 
213         return userTrackersMap;
214     }
215 
216     private void _joinGroup(long userId, long groupId) {
217         Map<Long, Set<Long>> liveUsers = _getLiveUsers();
218 
219         Set<Long> groupUsers = _getGroupUsers(liveUsers, groupId);
220 
221         if (_getUserTrackers(userId) != null) {
222             groupUsers.add(userId);
223         }
224     }
225 
226     private void _joinGroup(long[] userIds, long groupId) {
227         Map<Long, Set<Long>> liveUsers = _getLiveUsers();
228 
229         Set<Long> groupUsers = _getGroupUsers(liveUsers, groupId);
230 
231         for (long userId : userIds) {
232             if (_getUserTrackers(userId) != null) {
233                 groupUsers.add(userId);
234             }
235         }
236     }
237 
238     private void _leaveGroup(long userId, long groupId) {
239         Map<Long, Set<Long>> liveUsers = _getLiveUsers();
240 
241         Set<Long> groupUsers = _getGroupUsers(liveUsers, groupId);
242 
243         groupUsers.remove(userId);
244     }
245 
246     private void _leaveGroup(long[] userIds, long groupId) {
247         Map<Long, Set<Long>> liveUsers = _getLiveUsers();
248 
249         Set<Long> groupUsers = _getGroupUsers(liveUsers, groupId);
250 
251         for (long userId : userIds) {
252             groupUsers.remove(userId);
253         }
254     }
255 
256     private void _removeUserTracker(long userId, UserTracker userTracker) {
257         List<UserTracker> userTrackers = _getUserTrackers(userId);
258 
259         if (userTrackers != null) {
260             Iterator<UserTracker> itr = userTrackers.iterator();
261 
262             while (itr.hasNext()) {
263                 UserTracker curUserTracker = itr.next();
264 
265                 if (userTracker.equals(curUserTracker)) {
266                     itr.remove();
267                 }
268             }
269 
270             if (userTrackers.size() == 0) {
271                 Map<Long, List<UserTracker>> userTrackersMap =
272                     _getUserTrackersMap();
273 
274                 userTrackersMap.remove(userId);
275             }
276         }
277     }
278 
279     private void _signIn(HttpServletRequest req) throws SystemException {
280         HttpSession ses = req.getSession();
281 
282         long companyId = CompanyThreadLocal.getCompanyId();
283         long userId = GetterUtil.getLong(req.getRemoteUser());
284 
285         _updateGroupStatus(userId, true);
286 
287         Map<String, UserTracker> sessionUsers = _getSessionUsers();
288 
289         List<UserTracker> userTrackers = _getUserTrackers(userId);
290 
291         if (!PropsValues.AUTH_SIMULTANEOUS_LOGINS) {
292             if (userTrackers != null) {
293                 for (UserTracker userTracker : userTrackers) {
294 
295                     // Disable old login
296 
297                     userTracker.getHttpSession().setAttribute(
298                         WebKeys.STALE_SESSION, Boolean.TRUE);
299                 }
300             }
301         }
302 
303         UserTracker userTracker = sessionUsers.get(ses.getId());
304 
305         if ((userTracker == null) &&
306             (PropsValues.SESSION_TRACKER_MEMORY_ENABLED)) {
307 
308             userTracker = UserTrackerUtil.create(0);
309 
310             userTracker.setCompanyId(companyId);
311             userTracker.setUserId(userId);
312             userTracker.setModifiedDate(new Date());
313             userTracker.setHttpSession(ses);
314             userTracker.setRemoteAddr(req.getRemoteAddr());
315             userTracker.setRemoteHost(req.getRemoteHost());
316             userTracker.setUserAgent(req.getHeader(HttpHeaders.USER_AGENT));
317 
318             sessionUsers.put(ses.getId(), userTracker);
319 
320             _addUserTracker(userId, userTracker);
321         }
322     }
323 
324     private void _signOut(String sesId, long userId) throws SystemException {
325         List<UserTracker> userTrackers = _getUserTrackers(userId);
326 
327         if ((userTrackers == null) || (userTrackers.size() <= 1)) {
328             _updateGroupStatus(userId, false);
329         }
330 
331         Map<String, UserTracker> sessionUsers = _getSessionUsers();
332 
333         UserTracker userTracker = sessionUsers.remove(sesId);
334 
335         if (userTracker != null) {
336             try {
337                 UserTrackerLocalServiceUtil.addUserTracker(
338                     userTracker.getCompanyId(), userTracker.getUserId(),
339                     userTracker.getModifiedDate(), sesId,
340                     userTracker.getRemoteAddr(), userTracker.getRemoteHost(),
341                     userTracker.getUserAgent(), userTracker.getPaths());
342             }
343             catch (Exception e) {
344                 if (_log.isWarnEnabled()) {
345                     _log.warn(e.getMessage());
346                 }
347             }
348 
349             _removeUserTracker(userId, userTracker);
350         }
351     }
352 
353     private Map<Long, Set<Long>> _updateGroupStatus(
354             long userId, boolean signedIn)
355         throws SystemException {
356 
357         long companyId = CompanyThreadLocal.getCompanyId();
358 
359         Map<Long, Set<Long>> liveUsers = _getLiveUsers();
360 
361         LinkedHashMap<String, Object> groupParams =
362             new LinkedHashMap<String, Object>();
363 
364         groupParams.put("usersGroups", userId);
365 
366         List<Group> communities = GroupLocalServiceUtil.search(
367             companyId, null, null, groupParams, QueryUtil.ALL_POS,
368             QueryUtil.ALL_POS);
369 
370         for (Group community : communities) {
371             Set<Long> groupUsers = _getGroupUsers(
372                 liveUsers, community.getGroupId());
373 
374             if (signedIn) {
375                 groupUsers.add(userId);
376             }
377             else {
378                 groupUsers.remove(userId);
379             }
380         }
381 
382         return liveUsers;
383     }
384 
385     private static Log _log = LogFactory.getLog(LiveUsers.class);
386 
387     private static LiveUsers _instance = new LiveUsers();
388 
389 }