View Javadoc
1   /*
2    * Copyright 2005 the original author or authors.
3    * 
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * 
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    * 
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package net.sf.sensor.timer;
18  
19  
20  /***
21   * Short-lived, non thread-safe input frontend class for working with timers.
22   * <p>
23   * This class is not thread-safe and for good reasons. The TimerData instance that
24   * is nested inside each Timer instance <b>is</b> thread-safe and is shared between
25   * many seperate instances of Timer. When the {@link #stop()} method is called, a
26   * synchronized call to TimerData.updateStatistics(long)} will be made to
27   * update the "real" timer. After that call, the instance of Timer can be safely
28   * reused or garbage collected.
29   * 
30   * @author Age Mooy
31   */
32  public final class Timer {
33  
34    // ==========================================================================
35    // Fields
36    // ==========================================================================
37    
38    /*** The TimerData that will be fed with data from the new Timer instance. */
39    private TimerData timerData = null;
40    
41    /*** The exact time (in milliseconds since 01-01-1970 00:00) the start method was last called. */
42    private long startTime = 0L;
43    
44    /*** Is this instance currently between calls to {@link #start()} and {@link #stop()}. */
45    private boolean isRunning = false;
46    
47    
48    // ==========================================================================
49    // Constructors
50    // ==========================================================================
51    
52    /***
53     * Constructs a new Timer instance for the specified TimerData.
54     * Package private since only TimerData instances are allowed to create Timers.
55     * 
56     * @param timerData the TimerData that will be fed with data from the
57     *                  new Timer instance.
58     */
59    Timer(TimerData timerData) {
60      this.timerData = timerData;
61    }
62    
63    
64    // ==========================================================================
65    // Simple properties
66    // ==========================================================================
67    
68    /***
69     * Adds the specified label to the set of labels associated with this instance.
70     * @param label
71     */
72    public void addLabel(String label) {
73      timerData.addLabel(label);
74    }
75    
76    /***
77     * Returns the id straight from the nested TimerData.
78     * Unsynchronized since the label is immutable.
79     * @return Returns the label.
80     */
81    public String getId() {
82      return timerData.getId();
83    }
84    
85    
86    // ==========================================================================
87    // Timing API
88    // ==========================================================================
89    
90    /***
91     * Starts the timer. Will not do anything if the timer has already been started
92     * (meaning the {@link #start()} method has been called but the {@link #stop()}
93     * method has not yet been called. For convernience, this method returns the 'this'
94     * reference.
95     * 
96     * @return the current instance (the 'this' reference).
97     * 
98     * @todo implement runtime detection of java 5 VMs so we can use nanoseconds instead of milliseconds
99     *       without becoming java 5 specific or using a multi-target build system
100    */
101   public Timer start() {
102     if (!isRunning) {
103       startTime = System.currentTimeMillis();
104       isRunning = true;
105     }
106     
107     return this;
108   }
109   
110   /***
111    * Is this Timer instance currently running (ie {@link #start()} was called but
112    * {@link #stop()} was not called yet.
113    * @return true if this Timer instance is in a runing state, false otherwise.
114    */
115   public boolean isRunning() {
116     return isRunning;
117   }
118   
119   /***
120    * Stops the timer and reports the time that passed since the first call to 
121    * {@link #start()} to the nested TimerData instance.
122    */
123   public void stop() {
124     if (isRunning) {
125       // update the real data store
126       timerData.updateFromTimer(System.currentTimeMillis() - startTime);
127       
128       // stop running
129       isRunning = false;
130     }
131   }
132   
133 }