View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    * 
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   * 
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.jetspeed.statistics.impl;
19  
20  import java.security.Principal;
21  import java.sql.Connection;
22  import java.sql.PreparedStatement;
23  import java.sql.ResultSet;
24  import java.sql.SQLException;
25  import java.sql.Timestamp;
26  import java.text.MessageFormat;
27  import java.text.SimpleDateFormat;
28  import java.util.ArrayList;
29  import java.util.Calendar;
30  import java.util.Collections;
31  import java.util.Date;
32  import java.util.GregorianCalendar;
33  import java.util.HashMap;
34  import java.util.List;
35  import java.util.Map;
36  import java.util.TreeMap;
37  
38  import javax.naming.NamingException;
39  import javax.servlet.http.HttpServletRequest;
40  import javax.sql.DataSource;
41  
42  import org.apache.commons.logging.Log;
43  import org.apache.commons.logging.LogFactory;
44  import org.apache.jetspeed.om.page.ContentPage;
45  import org.apache.jetspeed.request.RequestContext;
46  import org.apache.jetspeed.statistics.AggregateStatistics;
47  import org.apache.jetspeed.statistics.InvalidCriteriaException;
48  import org.apache.jetspeed.statistics.PortalStatistics;
49  import org.apache.jetspeed.statistics.StatisticsQueryCriteria;
50  import org.apache.jetspeed.statistics.UserStats;
51  import org.springframework.orm.ojb.support.PersistenceBrokerDaoSupport;
52  
53  /***
54   * <p>
55   * PortalStatisticsImpl
56   * </p>
57   * 
58   * @author <a href="mailto:chris@bluesunrise.com">Chris Schaefer </a>
59   * @author <a href="mailto:taylor@apache.org">David Sean Taylor </a>
60   * @version $Id: TestPortletEntityDAO.java,v 1.3 2005/05/24 14:43:19 ate Exp $
61   */
62  public class PortalStatisticsImpl extends PersistenceBrokerDaoSupport implements
63          PortalStatistics
64  {
65      /* CLF logger */
66      protected final static Log logger = LogFactory
67              .getLog(PortalStatisticsImpl.class);
68  
69      /* batch of portlet statistics */
70      protected BatchedStatistics portletBatch;
71  
72      /* batch if page statistics */
73      protected BatchedStatistics pageBatch;
74  
75      /* batch of user statistics */
76      protected BatchedStatistics userBatch;
77  
78      /* format string for a portlet access log entry */
79      protected static final String portletLogFormat = "{0} {1} {2} [{3}] \"{4} {5} {6}\" {7} {8}";
80  
81      /* format string for a page access log entry */
82      protected static final String pageLogFormat = "{0} {1} {2} [{3}] \"{4} {5}\" {6} {7}";
83  
84      /* Format string for a User Logout log entry */
85      protected static final String logoutLogFormat = "{0} {1} {2} [{3}] \"{4}\" {5} {6}";
86  
87      protected static final int STATUS_LOGGED_IN = 1;
88  
89      protected static final int STATUS_LOGGED_OUT = 2;
90  
91      /* the following fields should be settable with Spring injection */
92      protected boolean logToCLF = true;
93  
94      protected boolean logToDatabase = true;
95  
96      protected int maxRecordToFlush_Portlet = 30;
97  
98      protected int maxRecordToFlush_User = 30;
99  
100     protected int maxRecordToFlush_Page = 30;
101 
102     protected long maxTimeMsToFlush_Portlet = 10 * 1000;
103 
104     protected long maxTimeMsToFlush_User = 10 * 1000;
105 
106     protected long maxTimeMsToFlush_Page = 10 * 1000;
107 
108     //protected ConnectionRepositoryEntry jetspeedDSEntry;
109     
110     /* after this is NOT for injection */
111 
112     protected DataSource ds;
113 
114     protected int currentUserCount = 0;
115 
116     protected Map currentUsers;
117 
118     /* date formatter */
119     protected SimpleDateFormat formatter = null;
120 
121     /***
122      * <p>
123      * Default constructor.
124      * </p>
125      */
126     
127     public PortalStatisticsImpl(boolean logToCLF, boolean logToDatabase,
128             int maxRecordToFlush_Portal, int maxRecordToFlush_User,
129             int maxRecordToFlush_Page, long maxTimeMsToFlush_Portal,
130             long maxTimeMsToFlush_User, long maxTimeMsToFlush_Page,
131             DataSource dataSource)
132             //ConnectionRepositoryEntry jetspeedDSEntry)
133     {
134 
135         this.logToCLF = logToCLF;
136         this.logToDatabase = logToDatabase;
137         this.maxRecordToFlush_Portlet = maxRecordToFlush_Portal;
138         this.maxRecordToFlush_User = maxRecordToFlush_User;
139         this.maxRecordToFlush_Page = maxRecordToFlush_Page;
140         this.maxTimeMsToFlush_Portlet = maxTimeMsToFlush_Portal;
141         this.maxTimeMsToFlush_User = maxTimeMsToFlush_User;
142         this.maxTimeMsToFlush_Page = maxTimeMsToFlush_Page;
143         //this.jetspeedDSEntry = jetspeedDSEntry;
144         this.ds = dataSource;        
145         currentUsers = Collections.synchronizedMap(new TreeMap());
146     }
147 
148     public void springInit() throws NamingException
149     {
150         formatter = new SimpleDateFormat("dd/MM/yyyy:hh:mm:ss z");
151         currentUserCount = 0;
152     }
153 
154     public DataSource getDataSource()
155     {
156         return ds;
157     }
158 
159     public void logPortletAccess(RequestContext request, String portletName,
160             String statusCode, long msElapsedTime)
161     {
162 
163         try
164         {
165             HttpServletRequest req = request.getRequest();
166             Principal principal = req.getUserPrincipal();
167             String userName = (principal != null) ? principal.getName()
168                     : "guest";
169             Timestamp timestamp = new Timestamp(System.currentTimeMillis());
170             PortletLogRecord record = new PortletLogRecord();
171 
172             record.setPortletName(portletName);
173             record.setUserName(userName);
174             if (req.getRemoteAddr() != null)
175             {
176                 record.setIpAddress(req.getRemoteAddr());
177             }
178             ContentPage cp = request.getPage();
179             if (cp != null)
180             {
181                 if (cp.getPath() != null)
182                 {
183                     record.setPagePath(cp.getPath());
184                 }
185             }
186             record.setStatus(Integer.parseInt(statusCode));
187             record.setTimeStamp(timestamp);
188             record.setMsElapsedTime(msElapsedTime);
189 
190             if (logToCLF)
191             {
192                 saveAccessToCLF(record);
193             }
194             if (logToDatabase)
195             {
196                 storeAccessToStats(record);
197             }
198         } catch (Exception e)
199         {
200             logger.error("Exception", e);
201         }
202     }
203 
204     protected void storeAccessToStats(LogRecord record)
205     {
206 
207         if (record instanceof PortletLogRecord)
208         {
209             if (portletBatch == null)
210             {
211                 portletBatch = new BatchedPortletStatistics(ds,
212                         this.maxRecordToFlush_Portlet,
213                         this.maxTimeMsToFlush_Portlet, "portletLogBatcher");
214                 portletBatch.startThread();
215             }
216             portletBatch.addStatistic(record);
217 
218         }
219         if (record instanceof PageLogRecord)
220         {
221             if (pageBatch == null)
222             {
223                 pageBatch = new BatchedPageStatistics(ds,
224                         this.maxRecordToFlush_Page, this.maxTimeMsToFlush_Page,
225                         "pageLogBatcher");
226                 pageBatch.startThread();
227             }
228             pageBatch.addStatistic(record);
229 
230         }
231         if (record instanceof UserLogRecord)
232         {
233             if (userBatch == null)
234             {
235                 userBatch = new BatchedUserStatistics(ds,
236                         this.maxRecordToFlush_User, this.maxTimeMsToFlush_User,
237                         "userLogBatcher");
238                 userBatch.startThread();
239             }
240             userBatch.addStatistic(record);
241 
242         }
243     }
244 
245     protected void saveAccessToCLF(LogRecord record)
246     {
247         Object[] args =  {""};
248         String logMessage = "";
249         if (record instanceof PortletLogRecord)
250         {
251             PortletLogRecord rec = (PortletLogRecord) record;
252             Object[] args1 =
253             { rec.getIpAddress(), "-", rec.getUserName(), rec.getTimeStamp(),
254                     rec.getLogType(), formatter.format(rec.getTimeStamp()),
255                     rec.getPortletName(),
256                     new Integer(rec.getStatus()).toString(),
257                     new Long(rec.getMsElapsedTime())};
258             args = args1;
259             logMessage = MessageFormat.format(portletLogFormat, args)
260                     .toString();
261         }
262         if (record instanceof PageLogRecord)
263         {
264             PageLogRecord rec = (PageLogRecord) record;
265             Object[] args1 =
266             { rec.getIpAddress(), "-", rec.getUserName(), rec.getTimeStamp(),
267                     rec.getLogType(), formatter.format(rec.getTimeStamp()),
268                     new Integer(rec.getStatus()).toString(),
269                     new Long(rec.getMsElapsedTime())};
270             args = args1;
271             logMessage = MessageFormat.format(pageLogFormat, args).toString();
272         }
273         if (record instanceof UserLogRecord)
274         {
275             UserLogRecord rec = (UserLogRecord) record;
276             Object[] args1 =
277             { rec.getIpAddress(), "-", rec.getUserName(), rec.getTimeStamp(),
278                     rec.getLogType(), formatter.format(rec.getTimeStamp()),
279                     new Integer(rec.getStatus()).toString(),
280                     new Long(rec.getMsElapsedTime())};
281             args = args1;
282             logMessage = MessageFormat.format(logoutLogFormat, args).toString();
283         }
284         logger.info(logMessage);
285     }
286 
287     public void logPageAccess(RequestContext request, String statusCode,
288             long msElapsedTime)
289     {
290         try
291         {
292             HttpServletRequest req = request.getRequest();
293             Principal principal = req.getUserPrincipal();
294             String userName = (principal != null) ? principal.getName()
295                     : "guest";
296             Timestamp timestamp = new Timestamp(System.currentTimeMillis());
297             PageLogRecord record = new PageLogRecord();
298 
299             record.setUserName(userName);
300             record.setIpAddress(req.getRemoteAddr());
301             ContentPage cp = request.getPage();
302             if (cp != null)
303             {
304                 if (cp.getPath() != null)
305                 {
306                     record.setPagePath(cp.getPath());
307                 }
308             }
309             record.setStatus(Integer.parseInt(statusCode));
310             record.setTimeStamp(timestamp);
311             record.setMsElapsedTime(msElapsedTime);
312 
313             if (logToCLF)
314             {
315                 saveAccessToCLF(record);
316             }
317             if (logToDatabase)
318             {
319                 storeAccessToStats(record);
320             }
321 
322         } catch (Exception e)
323         {
324             logger.error("Exception", e);
325         }
326     }
327 
328     public void logUserLogout(String ipAddress, String userName,
329             long msSessionLength)
330     {
331         try
332         {
333 
334             if (userName == null)
335             {
336                 userName = "guest";
337             }
338 
339             if (!"guest".equals(userName))
340             {
341                 synchronized (currentUsers)
342                 {
343                 	UserStats userStats = null;
344                 	
345                 	Map users = (Map)currentUsers.get(userName);                	
346                 	if(users != null && users.size() > 0)
347                 	{
348                 		userStats = (UserStats) users.get(ipAddress);                		
349                 	}                	
350             	
351                 	if(userStats != null)
352                     {
353                     	// only decrement if user has been logged in
354                     	currentUserCount = currentUserCount - 1;
355                         
356                     	userStats.setNumberOfSession(userStats
357                                 .getNumberOfSessions() - 1);                    
358                         if (userStats.getNumberOfSessions() <= 0)
359                         {
360                         	users.remove(ipAddress);
361                             currentUsers.put(userName, users);
362                         }
363                     }
364                 }
365             }
366 
367             Timestamp timestamp = new Timestamp(System.currentTimeMillis());
368             UserLogRecord record = new UserLogRecord();
369 
370             record.setUserName(userName);
371             record.setIpAddress(ipAddress);
372             record.setStatus(STATUS_LOGGED_OUT);
373             record.setTimeStamp(timestamp);
374             record.setMsElapsedTime(msSessionLength);
375 
376             if (logToCLF)
377             {
378                 saveAccessToCLF(record);
379             }
380             if (logToDatabase)
381             {
382                 storeAccessToStats(record);
383             }
384 
385         } catch (Exception e)
386         {
387             logger.error("Exception", e);
388         }
389     }
390 
391     /*
392      * (non-Javadoc)
393      * 
394      * @see org.apache.jetspeed.statistics.PortalStatistics#logUserLogin(org.apache.jetspeed.request.RequestContext,
395      *      long)
396      */
397     public void logUserLogin(RequestContext request, long msElapsedLoginTime)
398     {
399         try
400         {
401             HttpServletRequest req = request.getRequest();
402             Principal principal = req.getUserPrincipal();
403             String userName = (principal != null) ? principal.getName()
404                     : "guest";
405             String ipAddress = req.getRemoteAddr();
406             Timestamp timestamp = new Timestamp(System.currentTimeMillis());
407             UserLogRecord record = new UserLogRecord();
408 
409             if (!"guest".equals(userName))
410             {
411                 currentUserCount = currentUserCount + 1;
412 
413                 synchronized (currentUsers)
414                 {
415                 	
416                 	UserStats userStats = null;
417                 	
418                 	Map users = (Map)currentUsers.get(userName);                	
419                 	if(users != null && users.size() > 0)
420                 	{
421                 		userStats = (UserStats) users.get(ipAddress);                		
422                 	}
423                 	else
424                 	{
425                 		users = new TreeMap();
426                 	}
427                 	
428                 	if(userStats == null)
429                     {
430                         userStats = new UserStatsImpl();
431                         userStats.setNumberOfSession(0);
432                         userStats.setUsername(userName);
433                         userStats.setInetAddressFromIp(ipAddress);                        
434                     }
435                     
436                     userStats.setNumberOfSession(userStats
437                             .getNumberOfSessions() + 1);
438                     users.put(ipAddress, userStats);
439             		currentUsers.put(userName, users);
440                 }
441             }
442 
443             record.setUserName(userName);
444             record.setIpAddress(ipAddress);
445             record.setStatus(STATUS_LOGGED_IN);
446             record.setTimeStamp(timestamp);
447             record.setMsElapsedTime(msElapsedLoginTime);
448 
449             if (logToCLF)
450             {
451                 saveAccessToCLF(record);
452             }
453             if (logToDatabase)
454             {
455                 storeAccessToStats(record);
456             }
457 
458         } catch (Exception e)
459         {
460             logger.error("Exception", e);
461         }
462 
463     }
464 
465     /***
466      * @see org.springframework.beans.factory.DisposableBean#destroy()
467      */
468     public void springDestroy()
469     {
470         if (portletBatch != null)
471         {
472             portletBatch.tellThreadToStop();
473             synchronized (portletBatch.thread)
474             {
475                 portletBatch.thread.notify();
476             }
477 
478         }
479         if (userBatch != null)
480         {
481             userBatch.tellThreadToStop();
482             synchronized (userBatch.thread)
483             {
484                 userBatch.thread.notify();
485             }
486         }
487         if (pageBatch != null)
488         {
489             pageBatch.tellThreadToStop();
490             synchronized (pageBatch.thread)
491             {
492                 pageBatch.thread.notify();
493             }
494         }
495 
496         if ((this.currentUserCount != 0) && logger.isDebugEnabled())
497         {
498             logger.debug("destroying while users are logged in");
499         }
500         boolean done = false;
501         while (!done)
502         {
503             done = true;
504             if (portletBatch != null)
505             {
506                 if (!portletBatch.isDone())
507                 {
508                     done = false;
509                 }
510             }
511             if (userBatch != null)
512             {
513                 if (!userBatch.isDone())
514                 {
515                     done = false;
516                 }
517             }
518             if (pageBatch != null)
519             {
520                 if (!pageBatch.isDone())
521                 {
522                     done = false;
523                 }
524             }
525 
526             try
527             {
528                 Thread.sleep(2);
529             } catch (InterruptedException ie)
530             {
531             }
532         }
533 
534     }
535 
536     /***
537      * @see org.apache.jetspeed.statistics.PortalStatistics#getNumberOfCurrentUsers()
538      */
539     public int getNumberOfCurrentUsers()
540     {
541         return currentUserCount;
542     }
543 
544     protected Date getStartDateFromPeriod(String period, Date end)
545     {
546         GregorianCalendar gcEnd = new GregorianCalendar();
547         gcEnd.setTime(end);
548         if (period != null)
549         {
550             if (period.endsWith("m"))
551             {
552                 // months
553                 String p = period.substring(0, period.length() - 1);
554                 int ret = Integer.parseInt(p);
555                 gcEnd.add(Calendar.MONTH, (ret * -1));
556             } else if (period.endsWith("d"))
557             {
558                 // days
559                 String p = period.substring(0, period.length() - 1);
560                 int ret = Integer.parseInt(p);
561                 gcEnd.add(Calendar.HOUR, (ret * 24 * -1));
562             } else if (period.endsWith("h"))
563             {
564                 // hours
565                 String p = period.substring(0, period.length() - 1);
566                 int ret = Integer.parseInt(p);
567                 gcEnd.add(Calendar.HOUR, (ret * -1));
568             } else if (period.equals("all"))
569             {
570                 gcEnd = new GregorianCalendar();
571                 gcEnd.set(1968, 07, 15);
572             } else
573             {
574                 // minutes
575                 int ret = Integer.parseInt(period);
576                 gcEnd.add(Calendar.MINUTE, (ret * -1));
577             }
578         } else
579         {
580             gcEnd = new GregorianCalendar();
581             gcEnd.set(1968, 07, 15);
582 
583         }
584         return gcEnd.getTime();
585     }
586 
587     
588     /* (non-Javadoc)
589      * @see org.apache.jetspeed.statistics.PortalStatistics#getDefaultEmptyStatisticsQueryCriteria()
590      */
591     public StatisticsQueryCriteria createStatisticsQueryCriteria()
592     {
593         return new StatisticsQueryCriteriaImpl();
594     }
595 
596     /* (non-Javadoc)
597      * @see org.apache.jetspeed.statistics.PortalStatistics#getDefaultEmptyAggregateStatistics()
598      */
599     public AggregateStatistics getDefaultEmptyAggregateStatistics()
600     {
601         return new AggregateStatisticsImpl();
602     }
603 
604     /***
605      * @see org.apache.jetspeed.statistics.PortalStatistics#queryStatistics(org.apache.jetspeed.statistics.StatisticsQueryCriteria)
606      */
607     public AggregateStatistics queryStatistics(StatisticsQueryCriteria criteria)
608             throws InvalidCriteriaException
609     {
610         AggregateStatistics as = new AggregateStatisticsImpl();
611         String query;
612         String query2;
613 
614         String tableName;
615         String groupColumn;
616 
617         Date end = new Date();
618         Date start = getStartDateFromPeriod(criteria.getTimePeriod(), end);
619 
620         String queryType = criteria.getQueryType();
621         
622 
623         if (PortalStatistics.QUERY_TYPE_USER.equals(queryType))
624         {
625             tableName = "USER_STATISTICS";
626             groupColumn = "USER_NAME";
627         } else if (PortalStatistics.QUERY_TYPE_PORTLET.equals(queryType))
628         {
629             tableName = "PORTLET_STATISTICS";
630             groupColumn = "PORTLET";
631         } else if (PortalStatistics.QUERY_TYPE_PAGE.equals(queryType))
632         {
633             tableName = "PAGE_STATISTICS";
634             groupColumn = "PAGE";
635         } else
636         {
637             throw new InvalidCriteriaException(
638                     " invalid queryType passed to queryStatistics");
639         }
640         String orderColumn = "itemcount";
641 
642         String ascDesc = "DESC";
643 
644         if (!PortalStatistics.QUERY_TYPE_USER.equals(queryType))
645         {
646             query = "select count(*) as itemcount , MIN(ELAPSED_TIME) as amin ,AVG(ELAPSED_TIME) as aavg ,MAX(ELAPSED_TIME) as amax from "
647                     + tableName + " where time_stamp > ? and time_stamp < ?";
648             query2 = "select count(*) as itemcount ,"
649                     + groupColumn
650                     + ", MIN(ELAPSED_TIME) as amin ,AVG(ELAPSED_TIME) as aavg ,MAX(ELAPSED_TIME) as amax "
651                     + "from " + tableName
652                     + " where time_stamp > ? and time_stamp < ? group by "
653                     + groupColumn + "  order by " + orderColumn + " " + ascDesc;
654         } else
655         {
656             query = "select count(*) as itemcount , MIN(ELAPSED_TIME) as amin,AVG(ELAPSED_TIME) as aavg ,MAX(ELAPSED_TIME) as amax from "
657                     + tableName
658                     + " where time_stamp > ? and time_stamp < ? and status = 2";
659             query2 = "select count(*) as itemcount ,"
660                     + groupColumn
661                     + ", MIN(ELAPSED_TIME) as amin ,AVG(ELAPSED_TIME) as aavg ,MAX(ELAPSED_TIME) as amax "
662                     + "from "
663                     + tableName
664                     + " where time_stamp > ? and time_stamp < ? and status = 2 group by "
665                     + groupColumn + "  order by " + orderColumn + " " + ascDesc;
666         }
667         Connection con = null;
668         try
669         {
670             con = ds.getConnection();
671             PreparedStatement pstmt = con.prepareStatement(query);
672             pstmt.setTimestamp(1, new Timestamp(start.getTime()));
673             pstmt.setTimestamp(2, new Timestamp(end.getTime()));
674             ResultSet rs = pstmt.executeQuery();
675             float denominator = 1.0f;
676             if (PortalStatistics.QUERY_TYPE_USER.equals(queryType))
677             {
678                 denominator = 1000f * 60f; // this should convert from mS to
679                                            // minutes
680             }
681             if (rs.next())
682             {
683                 as.setHitCount(rs.getInt("itemcount"));
684 
685                 as.setMinProcessingTime(rs.getFloat("amin") / denominator);
686                 as.setAvgProcessingTime(rs.getFloat("aavg") / denominator);
687                 as.setMaxProcessingTime(rs.getFloat("amax") / denominator);
688 
689             }
690             PreparedStatement pstmt2 = con.prepareStatement(query2);
691             pstmt2.setTimestamp(1, new Timestamp(start.getTime()));
692             pstmt2.setTimestamp(2, new Timestamp(end.getTime()));
693             ResultSet rs2 = pstmt2.executeQuery();
694 
695             int rowCount = 0;
696             int totalRows = 5;
697             String listsizeStr = criteria.getListsize();
698             int temp = -1;
699             try 
700             {
701                 temp = Integer.parseInt(listsizeStr);
702             } 
703             catch (NumberFormatException e) 
704             {
705             }
706             if(temp != -1) {
707                 totalRows = temp;
708             }
709             
710             while ((rs2.next()) && (rowCount < totalRows))
711             {
712                 Map row = new HashMap();
713                 row.put("count", "" + rs2.getInt("itemcount"));
714                 String col = rs2.getString(groupColumn);
715                 int maxColLen = 35;
716                 if (col != null)
717                 {
718 
719                     if (col.length() > maxColLen)
720                     {
721                         col = col.substring(0, maxColLen);
722                     }
723                 }
724 
725                 row.put("groupColumn", col);
726                 row.put("min", ""
727                         + floatFormatter(rs2.getFloat("amin") / denominator));
728                 row.put("avg", ""
729                         + floatFormatter(rs2.getFloat("aavg") / denominator));
730                 row.put("max", ""
731                         + floatFormatter(rs2.getFloat("amax") / denominator));
732                 as.addRow(row);
733                 rowCount++;
734             }
735 
736         } 
737         catch (SQLException e)
738         {
739             throw new InvalidCriteriaException(e.toString());
740         }
741         finally 
742         {
743             try 
744             {
745                 if(con != null) 
746                 {
747                     con.close();
748                 }
749             } 
750             catch (SQLException e) 
751             {
752                 logger.error("error releasing the connection",e);
753             }
754         }
755 
756         return as;
757     }
758 
759     protected String floatFormatter(float f)
760     {
761         // for now we'll just truncate as int
762         int f2 = new Float(f).intValue();
763         return Integer.toString(f2);
764     }
765 
766     /*
767      * (non-Javadoc)
768      * 
769      * @see org.apache.jetspeed.statistics.PortalStatistics#getListOfLoggedInUsers()
770      */
771     public List getListOfLoggedInUsers()
772     {
773         List list = new ArrayList();
774 
775         synchronized (currentUsers)
776         {
777             list.addAll(currentUsers.values());
778         }
779         return list;
780     }
781 
782     /*
783      * (non-Javadoc)
784      * 
785      * @see org.apache.jetspeed.statistics.PortalStatistics#getNumberOfLoggedInUsers()
786      */
787     public int getNumberOfLoggedInUsers()
788     {
789         return this.currentUserCount;
790     }
791     
792 
793     /***
794      * @see org.apache.jetspeed.statistics.PortalStatistics#forceFlush()
795      */
796     public void forceFlush()
797     {
798         if (pageBatch != null)
799         {
800             this.pageBatch.flush();
801         }
802         if (portletBatch != null)
803         {
804             this.portletBatch.flush();
805         }
806         if (userBatch != null)
807         {
808             this.userBatch.flush();
809         }
810     }
811     
812 }