0
|
1 package nabble.view.web.user;
|
|
2
|
|
3 import fschmidt.util.servlet.ServletUtils;
|
|
4 import nabble.model.Executors;
|
|
5 import nabble.model.ModelHome;
|
|
6 import nabble.model.Person;
|
|
7 import nabble.model.Site;
|
|
8 import nabble.model.User;
|
|
9 import nabble.view.lib.Jtp;
|
|
10 import org.slf4j.Logger;
|
|
11 import org.slf4j.LoggerFactory;
|
|
12
|
|
13 import javax.servlet.http.HttpServletRequest;
|
|
14 import java.util.ArrayList;
|
|
15 import java.util.Collection;
|
|
16 import java.util.HashMap;
|
|
17 import java.util.Iterator;
|
|
18 import java.util.List;
|
|
19 import java.util.Map;
|
|
20 import java.util.Set;
|
|
21 import java.util.concurrent.TimeUnit;
|
|
22
|
|
23 public class OnlineStatus {
|
|
24
|
|
25 private static final Logger logger = LoggerFactory.getLogger(OnlineStatus.class);
|
|
26
|
|
27 private static final long TIMEOUT = 3 * 60 * 1000L; // 3 minutes
|
|
28 private static final String INVISIBLE = "invisible:";
|
|
29
|
|
30 /** Maps a site ID to a map (Person-Source-ID > last time) */
|
|
31 private static final Map<Long, Map<String, Long>> sitesMap = new HashMap<Long, Map<String, Long>>();
|
|
32
|
|
33 public static void setOnline(HttpServletRequest request, Person visitor, Site site) {
|
|
34 setOnline(request,visitor.getSearchId(),site);
|
|
35 }
|
|
36
|
|
37 private static void setOnline(HttpServletRequest request, String sourceId, Site site) {
|
|
38 synchronized(sitesMap) {
|
|
39 Map<String, Long> map = sitesMap.get(site.getId());
|
|
40 if (map == null) {
|
|
41 map = new HashMap<String, Long>();
|
|
42 sitesMap.put(site.getId(), map);
|
|
43 logger.debug("New map for site ID = " + site.getId());
|
|
44 }
|
|
45 boolean isVisible = ServletUtils.getCookieValue(request, "visible") == null || !Jtp.isInteger(sourceId);
|
|
46 map.put(isVisible? sourceId : INVISIBLE+sourceId, System.currentTimeMillis());
|
|
47 }
|
|
48 }
|
|
49
|
|
50 public static boolean isOnline(Person visitor, Site site) {
|
|
51 return isOnline(visitor.getSearchId(),site);
|
|
52 }
|
|
53
|
|
54 public static boolean isOnline(String sourceId, Site site) {
|
|
55 synchronized(sitesMap) {
|
|
56 Map<String, Long> map = sitesMap.get(site.getId());
|
|
57 return map != null && map.get(sourceId) != null;
|
|
58 }
|
|
59 }
|
|
60
|
|
61 private static void runGC() {
|
|
62 final long start = System.currentTimeMillis();
|
|
63 synchronized(sitesMap) {
|
|
64 for( Iterator<Map<String, Long>> iter = sitesMap.values().iterator(); iter.hasNext(); ) {
|
|
65 Map<String, Long> map = iter.next();
|
|
66 for( Iterator<Long> subIter = map.values().iterator(); subIter.hasNext(); ) {
|
|
67 long time = subIter.next();
|
|
68 if (start - time > TIMEOUT) {
|
|
69 subIter.remove();
|
|
70 logger.debug("Removed user");
|
|
71 }
|
|
72 }
|
|
73 if( map.isEmpty() ) {
|
|
74 iter.remove();
|
|
75 logger.debug("Removed map");
|
|
76 }
|
|
77 }
|
|
78 }
|
|
79 logger.info("OnlineStatus GC took " + (System.currentTimeMillis()-start) + " ms");
|
|
80 }
|
|
81
|
|
82 public static String getOnlineStats() {
|
|
83 int count = 0;
|
|
84 int sites;
|
|
85 float ratio = 0f;
|
|
86 synchronized(sitesMap) {
|
|
87 Collection<Map<String, Long>> entries = sitesMap.values();
|
|
88 for (Map<String, Long> entry : entries) {
|
|
89 count += entry.keySet().size();
|
|
90 }
|
|
91 sites = sitesMap.size();
|
|
92 if (sites > 0)
|
|
93 ratio = count / (float) sitesMap.size();
|
|
94 }
|
|
95 return "Users = " + count + " | Sites = " + sites + " | Ratio = " + String.format("%.2f", ratio);
|
|
96 }
|
|
97
|
|
98 public static Map<String, Integer> getOnlineSites() {
|
|
99 Map<String, Integer> sites = new HashMap<String, Integer>();
|
|
100
|
|
101 synchronized(sitesMap) {
|
|
102 for (Map.Entry<Long, Map<String, Long>> entry : sitesMap.entrySet()) {
|
|
103 String url = ModelHome.getSite(entry.getKey()).getBaseUrl();
|
|
104 sites.put(url, entry.getValue().size());
|
|
105 }
|
|
106 }
|
|
107 return sites;
|
|
108 }
|
|
109
|
|
110 public static List<User> getOnlineUsers(Site site, boolean includeInvisibleUsers) {
|
|
111 String[] visitorIDs = getVisitorIds(site);
|
|
112 List<User> users = new ArrayList<User>();
|
|
113 for (String id : visitorIDs) {
|
|
114 long userId = 0;
|
|
115 if (Jtp.isInteger(id)) {
|
|
116 userId = Long.valueOf(id);
|
|
117 } else if (includeInvisibleUsers && isInvisible(id)) {
|
|
118 userId = Long.valueOf(id.substring(INVISIBLE.length()));
|
|
119 }
|
|
120 if (userId > 0) {
|
|
121 User u = site.getUser(userId);
|
|
122 if (u != null)
|
|
123 users.add(u);
|
|
124 }
|
|
125 }
|
|
126 return users;
|
|
127 }
|
|
128
|
|
129 public static int getOnlineAnonymousUsersCount(Site site) {
|
|
130 String[] visitorIDs = getVisitorIds(site);
|
|
131 int c = 0;
|
|
132 for (String id : visitorIDs)
|
|
133 if (!Jtp.isInteger(id) && !isInvisible(id)) {
|
|
134 c++;
|
|
135 }
|
|
136 return c;
|
|
137 }
|
|
138
|
|
139 public static int getOnlineInvisibleUsersCount(Site site) {
|
|
140 String[] visitorIDs = getVisitorIds(site);
|
|
141 int c = 0;
|
|
142 for (String id : visitorIDs) {
|
|
143 if (isInvisible(id))
|
|
144 c++;
|
|
145 }
|
|
146 return c;
|
|
147 }
|
|
148
|
|
149 private static String[] getVisitorIds(Site site) {
|
|
150 synchronized(sitesMap) {
|
|
151 Map<String, Long> map = sitesMap.get(site.getId());
|
|
152 if (map == null)
|
|
153 return new String[0];
|
|
154 Set<String> set = map.keySet();
|
|
155 String[] visitorIds = new String[set.size()];
|
|
156 set.toArray(visitorIds);
|
|
157 return visitorIds;
|
|
158 }
|
|
159 }
|
|
160
|
|
161 private static boolean isInvisible(String id) {
|
|
162 return id.startsWith(INVISIBLE);
|
|
163 }
|
|
164
|
|
165 static {
|
|
166 Executors.scheduleWithFixedDelay(new Runnable(){
|
|
167 public void run(){
|
|
168 runGC();
|
|
169 }
|
|
170 }, 2*60, 2*60, TimeUnit.SECONDS); // Every 2 minutes
|
|
171 }
|
|
172
|
|
173 }
|