View Javadoc

1   /*
2    *  Licensed to the Apache Software Foundation (ASF) under one
3    *  or more contributor license agreements.  See the NOTICE file
4    *  distributed with this work for additional information
5    *  regarding copyright ownership.  The ASF licenses this file
6    *  to you under the Apache License, Version 2.0 (the
7    *  "License"); you may not use this file except in compliance
8    *  with the License.  You may obtain a copy of the License at
9    *
10   *    http://www.apache.org/licenses/LICENSE-2.0
11   *
12   *  Unless required by applicable law or agreed to in writing,
13   *  software distributed under the License is distributed on an
14   *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   *  KIND, either express or implied.  See the License for the
16   *  specific language governing permissions and limitations
17   *  under the License.
18   *
19   */
20  package org.apache.mina.filter.statistic;
21  
22  import java.util.HashSet;
23  import java.util.Set;
24  import java.util.concurrent.TimeUnit;
25  import java.util.concurrent.atomic.AtomicLong;
26  
27  import org.apache.mina.core.filterchain.IoFilterAdapter;
28  import org.apache.mina.core.session.IdleStatus;
29  import org.apache.mina.core.session.IoEventType;
30  import org.apache.mina.core.session.IoSession;
31  import org.apache.mina.core.write.WriteRequest;
32  
33  /**
34   * This class will measure the time it takes for a
35   * method in the {@link IoFilterAdapter} class to execute.  The basic
36   * premise of the logic in this class is to get the current time
37   * at the beginning of the method, call method on nextFilter, and
38   * then get the current time again.  An example of how to use
39   * the filter is:
40   *
41   * <pre>
42   * ProfilerTimerFilter profiler = new ProfilerTimerFilter(
43   *         TimeUnit.MILLISECOND, IoEventType.MESSAGE_RECEIVED);
44   * chain.addFirst("Profiler", profiler);
45   * </pre>
46   * 
47   * The profiled {@link IoEventType} are :
48   * <ul>
49   * <li>IoEventType.MESSAGE_RECEIVED</li>
50   * <li>IoEventType.MESSAGE_SENT</li>
51   * <li>IoEventType.SESSION_CREATED</li>
52   * <li>IoEventType.SESSION_OPENED</li>
53   * <li>IoEventType.SESSION_IDLE</li>
54   * <li>IoEventType.SESSION_CLOSED</li>
55   * </ul>
56   *
57   * @author The Apache MINA Project (dev@mina.apache.org)
58   * @version $Rev: 706057 $, $Date: 2008-10-19 21:40:20 +0200 (Sun, 19 Oct 2008) $
59   * @org.apache.xbean.XBean
60   */
61  public class ProfilerTimerFilter extends IoFilterAdapter {
62      /** TRhe selected time unit */
63      private volatile TimeUnit timeUnit;
64      
65      /** A TimerWorker for the MessageReceived events */
66      private TimerWorker messageReceivedTimerWorker;
67      
68      /** A flag to tell the filter that the MessageReceived must be profiled */
69      private boolean profileMessageReceived = false;
70  
71      /** A TimerWorker for the MessageSent events */
72      private TimerWorker messageSentTimerWorker;
73  
74      /** A flag to tell the filter that the MessageSent must be profiled */
75      private boolean profileMessageSent = false;
76  
77      /** A TimerWorker for the SessionCreated events */
78      private TimerWorker sessionCreatedTimerWorker;
79  
80      /** A flag to tell the filter that the SessionCreated must be profiled */
81      private boolean profileSessionCreated = false;
82  
83      /** A TimerWorker for the SessionOpened events */
84      private TimerWorker sessionOpenedTimerWorker;
85  
86      /** A flag to tell the filter that the SessionOpened must be profiled */
87      private boolean profileSessionOpened = false;
88  
89      /** A TimerWorker for the SessionIdle events */
90      private TimerWorker sessionIdleTimerWorker;
91  
92      /** A flag to tell the filter that the SessionIdle must be profiled */
93      private boolean profileSessionIdle = false;
94  
95      /** A TimerWorker for the SessionClosed events */
96      private TimerWorker sessionClosedTimerWorker;
97  
98      /** A flag to tell the filter that the SessionClosed must be profiled */
99      private boolean profileSessionClosed = false;
100 
101     /**
102      * Creates a new instance of ProfilerFilter.  This is the
103      * default constructor and will print out timings for
104      * messageReceived and messageSent and the time increment
105      * will be in milliseconds.
106      */
107     public ProfilerTimerFilter() {
108         this(
109                 TimeUnit.MILLISECONDS, 
110                 IoEventType.MESSAGE_RECEIVED, IoEventType.MESSAGE_SENT);
111     }
112     
113     /**
114      * Creates a new instance of ProfilerFilter.  This is the
115      * default constructor and will print out timings for
116      * messageReceived and messageSent.
117      * 
118      * @param timeUnit the time increment to set
119      */
120     public ProfilerTimerFilter(TimeUnit timeUnit) {
121         this(
122         		timeUnit, 
123                 IoEventType.MESSAGE_RECEIVED, IoEventType.MESSAGE_SENT);
124     }
125     
126     /**
127      * Creates a new instance of ProfilerFilter.  An example
128      * of this call would be:
129      *
130      * <pre>
131      * new ProfilerTimerFilter(
132      *         TimeUnit.MILLISECONDS,
133      *         IoEventType.MESSAGE_RECEIVED, IoEventType.MESSAGE_SENT);
134      * </pre>
135      * 
136      * Note : you can add as many {@link IoEventType} as you want. The method accepts
137      * a variable number of arguments.
138      * 
139      * @param timeUnit Used to determine the level of precision you need in your timing.
140      * @param eventTypes A list of {@link IoEventType} representation of the methods to profile
141      */
142     public ProfilerTimerFilter(TimeUnit timeUnit, IoEventType... eventTypes) {
143         this.timeUnit = timeUnit;
144 
145         setProfilers(eventTypes);
146     }
147     
148     /**
149      * Create the profilers for a list of {@link IoEventType}.
150      * 
151      * @param eventTypes the list of {@link IoEventType} to profile
152      */
153     private void setProfilers(IoEventType... eventTypes) {
154         for (IoEventType type : eventTypes) {
155         	switch (type) {
156 	        	case MESSAGE_RECEIVED :
157 	        		messageReceivedTimerWorker = new TimerWorker();
158 	        		profileMessageReceived = true;
159 	        		break;
160 
161 	        	case MESSAGE_SENT :
162 	        		messageSentTimerWorker = new TimerWorker();
163 	        		profileMessageSent = true;
164 	        		break;
165 
166 	        	case SESSION_CREATED :
167 	        		sessionCreatedTimerWorker = new TimerWorker();
168 	        		profileSessionCreated = true;
169 	        		break;
170 	        		
171 	        	case SESSION_OPENED :
172 	        		sessionOpenedTimerWorker = new TimerWorker();
173 	        		profileSessionOpened = true;
174 	        		break;
175 	        		
176 	        	case SESSION_IDLE :
177 	        		sessionIdleTimerWorker = new TimerWorker();
178 	        		profileSessionIdle = true;
179 	        		break;
180 	        		
181 	        	case SESSION_CLOSED :
182 	        		sessionClosedTimerWorker = new TimerWorker();
183 	        		profileSessionClosed = true;
184 	        		break;
185         	}
186         }
187     }
188 
189     /**
190      * Sets the {@link TimeUnit} being used.
191      *
192      * @param timeUnit the new {@link TimeUnit} to be used.
193      */
194     public void setTimeUnit(TimeUnit timeUnit) {
195     	this.timeUnit = timeUnit;
196     }
197 
198     /**
199      * Set the {@link IoEventType} to be profiled
200      *
201      * @param type The {@link IoEventType} to profile
202      */
203     public void profile(IoEventType type) {
204     	switch (type) {
205     		case MESSAGE_RECEIVED :
206 	    		profileMessageReceived = true;
207 	    		
208 	    		if (messageReceivedTimerWorker == null) {
209 	    			messageReceivedTimerWorker = new TimerWorker();
210 	    		}
211     	    	
212     	    	return;
213     			
214     		case MESSAGE_SENT :
215 	    		profileMessageSent = true;
216 	    		
217 	    		if (messageSentTimerWorker == null) {
218 	    			messageSentTimerWorker = new TimerWorker();
219 	    		}
220     	    	
221     	    	return;
222     	    	
223     		case SESSION_CREATED :
224 				profileSessionCreated = true;
225 	    		
226 	    		if (sessionCreatedTimerWorker == null) {
227 	    			sessionCreatedTimerWorker = new TimerWorker();
228 	    		}
229     	    	
230     		case SESSION_OPENED :
231 				profileSessionOpened = true;
232 	    		
233 	    		if (sessionOpenedTimerWorker == null) {
234 	    			sessionOpenedTimerWorker = new TimerWorker();
235 	    		}
236     	    	
237     		case SESSION_IDLE :
238 				profileSessionIdle = true;
239 	    		
240 	    		if (sessionIdleTimerWorker == null) {
241 	    			sessionIdleTimerWorker = new TimerWorker();
242 	    		}
243     	    	
244     		case SESSION_CLOSED :
245 				profileSessionClosed = true;
246 	    		
247 	    		if (sessionClosedTimerWorker == null) {
248 	    			sessionClosedTimerWorker = new TimerWorker();
249 	    		}
250     	}
251     }
252 
253     /**
254      * Stop profiling an {@link IoEventType}
255      *
256      * @param type The {@link IoEventType} to stop profiling
257      */
258     public void stopProfile(IoEventType type) {
259     	switch (type) {
260 			case MESSAGE_RECEIVED :
261 	    		profileMessageReceived = false;
262 		    	return;
263 				
264 			case MESSAGE_SENT :
265 				profileMessageSent = false;
266 		    	return;
267 		    	
268 			case SESSION_CREATED :
269 				profileSessionCreated = false;
270 				return;
271 
272 			case SESSION_OPENED :
273 				profileSessionOpened = false;
274 				return;
275 
276 			case SESSION_IDLE :
277 				profileSessionIdle = false;
278 				return;
279 
280 			case SESSION_CLOSED :
281 				profileSessionClosed = false;
282 				return;
283     	}
284     }
285 
286     /**
287      * Return the set of {@link IoEventType} which are profiled.
288      *
289      * @return a Set containing all the profiled {@link IoEventType} 
290      */
291     public Set<IoEventType> getEventsToProfile() {
292     	Set<IoEventType> set = new HashSet<IoEventType>();
293     	
294     	if ( profileMessageReceived ) {
295     		set.add(IoEventType.MESSAGE_RECEIVED);
296     	}
297     	
298     	if ( profileMessageSent) {
299     		set.add(IoEventType.MESSAGE_SENT);
300     	}
301     	
302     	if ( profileSessionCreated ) {
303     		set.add(IoEventType.SESSION_CREATED);
304     	}
305     	
306     	if ( profileSessionOpened ) {
307     		set.add(IoEventType.SESSION_OPENED);
308     	}
309     	
310     	if ( profileSessionIdle ) {
311     		set.add(IoEventType.SESSION_IDLE);
312     	}
313     	
314     	if ( profileSessionClosed ) {
315     		set.add(IoEventType.SESSION_CLOSED);
316     	}
317     	
318         return set;
319     }
320 
321     /**
322      * Set the profilers for a list of {@link IoEventType}
323      * 
324      * @param eventTypes the list of {@link IoEventType} to profile
325      */
326     public void setEventsToProfile(IoEventType... eventTypes) {
327         setProfilers(eventTypes);
328     }
329 
330     /**
331      * Profile a MessageReceived event. This method will gather the following
332      * informations :
333      * - the method duration
334      * - the shortest execution time
335      * - the slowest execution time
336      * - the average execution time
337      * - the global number of calls
338      * 
339      * @param nextFilter The filter to call next
340      * @param session The associated session
341      * @param message the received message
342      */
343     @Override
344     public void messageReceived(NextFilter nextFilter, IoSession session,
345             Object message) throws Exception {
346     	if (profileMessageReceived) {
347 	        long start = timeNow();
348 	        nextFilter.messageReceived(session, message);
349 	        long end = timeNow();
350 	        messageReceivedTimerWorker.addNewDuration(end - start);
351     	} else {
352 	        nextFilter.messageReceived(session, message);
353     	}
354     }
355 
356     /**
357      * Profile a MessageSent event. This method will gather the following
358      * informations :
359      * - the method duration
360      * - the shortest execution time
361      * - the slowest execution time
362      * - the average execution time
363      * - the global number of calls
364      * 
365      * @param nextFilter The filter to call next
366      * @param session The associated session
367      * @param writeRequest the sent message
368      */
369     @Override
370     public void messageSent(NextFilter nextFilter, IoSession session,
371             WriteRequest writeRequest) throws Exception {
372     	if (profileMessageSent) {
373 	        long start = timeNow();
374 	        nextFilter.messageSent(session, writeRequest);
375 	        long end = timeNow();
376 	        messageSentTimerWorker.addNewDuration(end - start);
377     	} else {
378 	        nextFilter.messageSent(session, writeRequest);
379     	}
380     }
381 
382     /**
383      * Profile a SessionCreated event. This method will gather the following
384      * informations :
385      * - the method duration
386      * - the shortest execution time
387      * - the slowest execution time
388      * - the average execution time
389      * - the global number of calls
390      * 
391      * @param nextFilter The filter to call next
392      * @param session The associated session
393      */
394     @Override
395     public void sessionCreated(NextFilter nextFilter, IoSession session)
396             throws Exception {
397     	if (profileSessionCreated) {
398 	        long start = timeNow();
399 	        nextFilter.sessionCreated(session);
400 	        long end = timeNow();
401 	        sessionCreatedTimerWorker.addNewDuration(end - start);
402     	} else {
403             nextFilter.sessionCreated(session);
404     	}
405     }
406 
407     /**
408      * Profile a SessionOpened event. This method will gather the following
409      * informations :
410      * - the method duration
411      * - the shortest execution time
412      * - the slowest execution time
413      * - the average execution time
414      * - the global number of calls
415      * 
416      * @param nextFilter The filter to call next
417      * @param session The associated session
418      */
419     @Override
420     public void sessionOpened(NextFilter nextFilter, IoSession session)
421             throws Exception {
422     	if (profileSessionOpened) {
423 	        long start = timeNow();
424 	        nextFilter.sessionOpened(session);
425 	        long end = timeNow();
426 	        sessionOpenedTimerWorker.addNewDuration(end - start);
427     	} else {
428             nextFilter.sessionOpened(session);
429     	}
430     }
431 
432     /**
433      * Profile a SessionIdle event. This method will gather the following
434      * informations :
435      * - the method duration
436      * - the shortest execution time
437      * - the slowest execution time
438      * - the average execution time
439      * - the global number of calls
440      * 
441      * @param nextFilter The filter to call next
442      * @param session The associated session
443      * @param status The session's status
444      */
445     @Override
446     public void sessionIdle(NextFilter nextFilter, IoSession session,
447             IdleStatus status) throws Exception {
448     	if (profileSessionIdle) {
449 	        long start = timeNow();
450 	        nextFilter.sessionIdle(session, status);
451 	        long end = timeNow();
452 	        sessionIdleTimerWorker.addNewDuration(end - start);
453     	} else {
454             nextFilter.sessionIdle(session, status);
455     	}
456     }
457 
458     /**
459      * Profile a SessionClosed event. This method will gather the following
460      * informations :
461      * - the method duration
462      * - the shortest execution time
463      * - the slowest execution time
464      * - the average execution time
465      * - the global number of calls
466      * 
467      * @param nextFilter The filter to call next
468      * @param session The associated session
469      */
470     @Override
471     public void sessionClosed(NextFilter nextFilter, IoSession session)
472             throws Exception {
473     	if (profileSessionClosed) {
474 	        long start = timeNow();
475 	        nextFilter.sessionClosed(session);
476 	        long end = timeNow();
477 	        sessionClosedTimerWorker.addNewDuration(end - start);
478     	} else {
479             nextFilter.sessionClosed(session);
480     	}
481     }
482 
483     /**
484      * Get the average time for the specified method represented by the {@link IoEventType}
485      *
486      * @param type
487      *  The {@link IoEventType} that the user wants to get the average method call time
488      * @return
489      *  The average time it took to execute the method represented by the {@link IoEventType}
490      */
491     public double getAverageTime(IoEventType type) {
492     	switch (type) {
493 	    	case MESSAGE_RECEIVED :
494 	    		if (profileMessageReceived) {
495 	    			return messageReceivedTimerWorker.getAverage();
496 	    		}
497 	    		
498 	    		break;
499 	    		
500 	    	case MESSAGE_SENT :
501 	    		if (profileMessageSent) {
502 	    			return messageSentTimerWorker.getAverage();
503 	    		}
504 	    		
505 	    		break;
506 	    		
507 	    	case SESSION_CREATED :
508 	    		if (profileSessionCreated) {
509 	    			return sessionCreatedTimerWorker.getAverage();
510 	    		}
511 	    		
512 	    		break;
513 	    		
514 	    	case SESSION_OPENED :
515 	    		if (profileSessionOpened) {
516 	    			return sessionOpenedTimerWorker.getAverage();
517 	    		}
518 	    		
519 	    		break;
520 	    		
521 	    	case SESSION_IDLE :
522 	    		if (profileSessionIdle) {
523 	    			return sessionIdleTimerWorker.getAverage();
524 	    		}
525 	    		
526 	    		break;
527 	    		
528 	    	case SESSION_CLOSED :
529 	    		if (profileSessionClosed) {
530 	    			return sessionClosedTimerWorker.getAverage();
531 	    		}
532 	    		
533 	    		break;
534     	}
535 
536     	throw new IllegalArgumentException(
537                 "You are not monitoring this event.  Please add this event first.");
538     }
539 
540     /**
541      * Gets the total number of times the method has been called that is represented by the
542      * {@link IoEventType}
543      *
544      * @param type
545      *  The {@link IoEventType} that the user wants to get the total number of method calls
546      * @return
547      *  The total number of method calls for the method represented by the {@link IoEventType}
548      */
549     public long getTotalCalls(IoEventType type) {
550     	switch (type) {
551 	    	case MESSAGE_RECEIVED :
552 	    		if (profileMessageReceived) {
553 	    			return messageReceivedTimerWorker.getCallsNumber();
554 	    		}
555 	    		
556 	    		break;
557 	    		
558 	    	case MESSAGE_SENT :
559 	    		if (profileMessageSent) {
560 	    			return messageSentTimerWorker.getCallsNumber();
561 	    		}
562 	    		
563 	    		break;
564 	    		
565 	    	case SESSION_CREATED :
566 	    		if (profileSessionCreated) {
567 	    			return sessionCreatedTimerWorker.getCallsNumber();
568 	    		}
569 	    		
570 	    		break;
571 	    		
572 	    	case SESSION_OPENED :
573 	    		if (profileSessionOpened) {
574 	    			return sessionOpenedTimerWorker.getCallsNumber();
575 	    		}
576 	    		
577 	    		break;
578 	    		
579 	    	case SESSION_IDLE :
580 	    		if (profileSessionIdle) {
581 	    			return sessionIdleTimerWorker.getCallsNumber();
582 	    		}
583 	    		
584 	    		break;
585 	    		
586 	    	case SESSION_CLOSED :
587 	    		if (profileSessionClosed) {
588 	    			return sessionClosedTimerWorker.getCallsNumber();
589 	    		}
590 	    		
591 	    		break;
592 		}
593 	
594 		throw new IllegalArgumentException(
595 	            "You are not monitoring this event.  Please add this event first.");
596     }
597 
598     /**
599      * The total time this method has been executing
600      *
601      * @param type
602      *  The {@link IoEventType} that the user wants to get the total time this method has
603      *  been executing
604      * @return
605      *  The total time for the method represented by the {@link IoEventType}
606      */
607     public long getTotalTime(IoEventType type) {
608     	switch (type) {
609 	    	case MESSAGE_RECEIVED :
610 	    		if (profileMessageReceived) {
611 	    			return messageReceivedTimerWorker.getTotal();
612 	    		}
613 	    		
614 	    		break;
615 	    		
616 	    	case MESSAGE_SENT :
617 	    		if (profileMessageSent) {
618 	    			return messageSentTimerWorker.getTotal();
619 	    		}
620 	    		
621 	    		break;
622 	    		
623 	    	case SESSION_CREATED :
624 	    		if (profileSessionCreated) {
625 	    			return sessionCreatedTimerWorker.getTotal();
626 	    		}
627 	    		
628 	    		break;
629 	    		
630 	    	case SESSION_OPENED :
631 	    		if (profileSessionOpened) {
632 	    			return sessionOpenedTimerWorker.getTotal();
633 	    		}
634 	    		
635 	    		break;
636 	    		
637 	    	case SESSION_IDLE :
638 	    		if (profileSessionIdle) {
639 	    			return sessionIdleTimerWorker.getTotal();
640 	    		}
641 	    		
642 	    		break;
643 	    		
644 	    	case SESSION_CLOSED :
645 	    		if (profileSessionClosed) {
646 	    			return sessionClosedTimerWorker.getTotal();
647 	    		}
648 	    		
649 	    		break;
650 		}
651 	
652 		throw new IllegalArgumentException(
653 	            "You are not monitoring this event.  Please add this event first.");
654     }
655 
656     /**
657      * The minimum time the method represented by {@link IoEventType} has executed
658      *
659      * @param type
660      *  The {@link IoEventType} that the user wants to get the minimum time this method has
661      *  executed
662      * @return
663      *  The minimum time this method has executed represented by the {@link IoEventType}
664      */
665     public long getMinimumTime(IoEventType type) {
666     	switch (type) {
667 	    	case MESSAGE_RECEIVED :
668 	    		if (profileMessageReceived) {
669 	    			return messageReceivedTimerWorker.getMinimum();
670 	    		}
671 	    		
672 	    		break;
673 	    		
674 	    	case MESSAGE_SENT :
675 	    		if (profileMessageSent) {
676 	    			return messageSentTimerWorker.getMinimum();
677 	    		}
678 	    		
679 	    		break;
680 	    		
681 	    	case SESSION_CREATED :
682 	    		if (profileSessionCreated) {
683 	    			return sessionCreatedTimerWorker.getMinimum();
684 	    		}
685 	    		
686 	    		break;
687 	    		
688 	    	case SESSION_OPENED :
689 	    		if (profileSessionOpened) {
690 	    			return sessionOpenedTimerWorker.getMinimum();
691 	    		}
692 	    		
693 	    		break;
694 	    		
695 	    	case SESSION_IDLE :
696 	    		if (profileSessionIdle) {
697 	    			return sessionIdleTimerWorker.getMinimum();
698 	    		}
699 	    		
700 	    		break;
701 	    		
702 	    	case SESSION_CLOSED :
703 	    		if (profileSessionClosed) {
704 	    			return sessionClosedTimerWorker.getMinimum();
705 	    		}
706 	    		
707 	    		break;
708 		}
709 	
710 		throw new IllegalArgumentException(
711 	            "You are not monitoring this event.  Please add this event first.");
712     }
713 
714     /**
715      * The maximum time the method represented by {@link IoEventType} has executed
716      *
717      * @param type
718      *  The {@link IoEventType} that the user wants to get the maximum time this method has
719      *  executed
720      * @return
721      *  The maximum time this method has executed represented by the {@link IoEventType}
722      */
723     public long getMaximumTime(IoEventType type) {
724     	switch (type) {
725 			case MESSAGE_RECEIVED :
726 				if (profileMessageReceived) {
727 					return messageReceivedTimerWorker.getMaximum();
728 				}
729 				
730 				break;
731 				
732 			case MESSAGE_SENT :
733 				if (profileMessageSent) {
734 					return messageSentTimerWorker.getMaximum();
735 				}
736 				
737 				break;
738 				
739 			case SESSION_CREATED :
740 				if (profileSessionCreated) {
741 					return sessionCreatedTimerWorker.getMaximum();
742 				}
743 				
744 				break;
745 				
746 			case SESSION_OPENED :
747 				if (profileSessionOpened) {
748 					return sessionOpenedTimerWorker.getMaximum();
749 				}
750 				
751 				break;
752 				
753 			case SESSION_IDLE :
754 				if (profileSessionIdle) {
755 					return sessionIdleTimerWorker.getMaximum();
756 				}
757 				
758 				break;
759 				
760 			case SESSION_CLOSED :
761 				if (profileSessionClosed) {
762 					return sessionClosedTimerWorker.getMaximum();
763 				}
764 				
765 				break;
766 		}
767 		
768 		throw new IllegalArgumentException(
769 		        "You are not monitoring this event.  Please add this event first.");
770     }
771 
772     /**
773      * Class that will track the time each method takes and be able to provide information
774      * for each method.
775      *
776      */
777     private class TimerWorker {
778     	/** The sum of all operation durations */
779         private final AtomicLong total;
780         
781         /** The number of calls */
782         private final AtomicLong callsNumber;
783         
784         /** The fastest operation */
785         private final AtomicLong minimum;
786         
787         /** The slowest operation */
788         private final AtomicLong maximum;
789         
790         /** A lock for synchinized blocks */
791         private final Object lock = new Object();
792 
793         /**
794          * Creates a new instance of TimerWorker.
795          *
796          */
797         public TimerWorker() {
798             total = new AtomicLong();
799             callsNumber = new AtomicLong();
800             minimum = new AtomicLong();
801             maximum = new AtomicLong();
802         }
803 
804         /**
805          * Add a new operation duration to this class.  Total is updated
806          * and calls is incremented
807          *
808          * @param duration
809          *  The new operation duration
810          */
811         public void addNewDuration(long duration) {
812         	callsNumber.incrementAndGet();
813             total.addAndGet(duration);
814 
815             synchronized (lock) {
816                 // this is not entirely thread-safe, must lock
817                 if (duration < minimum.longValue()) {
818                     minimum.set(duration);
819                 }
820 
821                 // this is not entirely thread-safe, must lock
822                 if (duration > maximum.longValue()) {
823                     maximum.set(duration);
824                 }
825             }
826         }
827 
828         /**
829          * Gets the average reading for this event
830          *
831          * @return the average reading for this event
832          */
833         public double getAverage() {
834         	synchronized (lock) {
835         		// There are two operations, we need to synchronize the block
836         		return total.longValue() / callsNumber.longValue();
837         	}
838         }
839 
840         /**
841          * Returns the total number of profiled operations
842          *
843          * @return The total number of profiled operation 
844          */
845         public long getCallsNumber() {
846             return callsNumber.longValue();
847         }
848 
849         /**
850          * Returns the total time
851          *
852          * @return the total time
853          */
854         public long getTotal() {
855             return total.longValue();
856         }
857 
858         /**
859          * Returns the lowest execution time 
860          *
861          * @return the lowest execution time
862          */
863         public long getMinimum() {
864             return minimum.longValue();
865         }
866 
867         /**
868          * Returns the longest execution time
869          *
870          * @return the longest execution time
871          */
872         public long getMaximum() {
873             return maximum.longValue();
874         }
875     }
876 
877     /**
878      * @return the current time, expressed using the fixed TimeUnit.
879      */
880     private long timeNow() {
881     	switch (timeUnit) {
882 	    	case SECONDS :
883 	    		return System.currentTimeMillis()/1000;
884 	    		
885 	    	case MICROSECONDS :
886 	    		return System.nanoTime()/1000;
887 	    		
888 	    	case NANOSECONDS :
889 	    		return System.nanoTime();
890 	    		
891 	    	default :
892 	    		return System.currentTimeMillis();
893     	}
894     }
895 }