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.commons.monitoring.impl.stopwatches;
19  
20  import org.apache.commons.monitoring.Monitor;
21  import org.apache.commons.monitoring.StopWatch;
22  import org.apache.commons.monitoring.Unit;
23  
24  /**
25   * Estimates the time required for process execution (monitored method, service
26   * invocation, database request...).
27   *
28   * @author <a href="mailto:nicolas@apache.org">Nicolas De Loof</a>
29   */
30  public class DefaultStopWatch
31      implements StopWatch
32  {
33      /** Time the probe was started */
34      private final long startedAt;
35  
36      /** Time the probe was stopped */
37      private long stopedAt;
38  
39      /** Time the probe was paused */
40      private long pauseDelay;
41  
42      /** flag for stopped probe */
43      private boolean stoped;
44  
45      /** flag for paused probe */
46      private boolean paused;
47  
48      /** Monitor that is notified of process execution state */
49      private final Monitor monitor;
50  
51      /**
52       * Constructor.
53       * <p>
54       * The monitor can be set to null to use the StopWatch without the
55       * monitoring infrastructure.
56       *
57       * @param monitor the monitor associated with the process to be monitored
58       */
59      public DefaultStopWatch( Monitor monitor )
60      {
61          super();
62          this.monitor = monitor;
63          startedAt = nanotime();
64          if ( monitor != null )
65          {
66              monitor.getGauge( Monitor.CONCURRENCY ).increment( Unit.UNARY );
67          }
68      }
69  
70      /**
71       * {@inheritDoc}
72       *
73       * @see org.apache.commons.monitoring.StopWatch#getElapsedTime()
74       */
75      public long getElapsedTime()
76      {
77          if ( stoped || paused )
78          {
79              return stopedAt - startedAt - pauseDelay;
80          }
81          else
82          {
83              // Still running !
84              return nanotime() - startedAt - pauseDelay;
85          }
86      }
87  
88      /**
89       * {@inheritDoc}
90       *
91       * @see org.apache.commons.monitoring.StopWatch#pause()
92       */
93      public void pause()
94      {
95          if ( !paused && !stoped )
96          {
97              stopedAt = nanotime();
98              paused = true;
99          }
100     }
101 
102     /**
103      * {@inheritDoc}
104      *
105      * @see org.apache.commons.monitoring.StopWatch#resume()
106      */
107     public void resume()
108     {
109         if ( paused && !stoped )
110         {
111             pauseDelay = nanotime() - stopedAt;
112             paused = false;
113             stopedAt = 0;
114         }
115     }
116 
117     /**
118      * {@inheritDoc}
119      *
120      * @see org.apache.commons.monitoring.StopWatch#stop()
121      */
122     public void stop()
123     {
124         if ( !stoped )
125         {
126             long t = nanotime();
127             if ( paused )
128             {
129                 pauseDelay = t - stopedAt;
130             }
131             stopedAt = t;
132             stoped = true;
133             if ( monitor != null )
134             {
135                 monitor.getGauge( Monitor.CONCURRENCY ).decrement( Unit.UNARY );
136                 monitor.getCounter( Monitor.PERFORMANCES ).add( getElapsedTime(), Unit.NANOS );
137             }
138         }
139     }
140 
141     /**
142      * {@inheritDoc}
143      *
144      * @see org.apache.commons.monitoring.StopWatch#stop(boolean)
145      */
146     public void stop( boolean canceled )
147     {
148         if ( canceled )
149         {
150             cancel();
151         }
152         else
153         {
154             stop();
155         }
156     }
157 
158     /**
159      * {@inheritDoc}
160      *
161      * @see org.apache.commons.monitoring.StopWatch#cancel()
162      */
163     public void cancel()
164     {
165         if ( !stoped )
166         {
167             stoped = true;
168             if ( monitor != null )
169             {
170                 monitor.getGauge( Monitor.CONCURRENCY ).decrement( Unit.UNARY );
171             }
172         }
173     }
174 
175     /**
176      * {@inheritDoc}
177      * <p>
178      * Monitored application should use a <code>try/finally</code> block to
179      * ensure on of {@link #stop()} or {@link #cancel()} method is invoked, even
180      * when an exception occurs. To avoid StopWatches to keep running if the
181      * application didn't follow this recommendation, the finalizer is used to
182      * cancel the StopWatch and will log a educational warning.
183      *
184      * @see java.lang.Object#finalize()
185      */
186     protected void finalize()
187     {
188         // This probe is reclaimed by garbage-collector and still running,
189         // the monitored code "forgot" to stop/cancel it properly.
190         if ( !stoped && ( monitor != null ) )
191         {
192             System.err.println( "WARNING : Execution for " + monitor.getKey().toString() + " was not stoped properly. "
193                 + "This can result in wrong concurrency monitoring. " + "Use try/finally blocks to avoid this warning" );
194         }
195     }
196 
197     /**
198      * Returns the current value of the most precise available system timer, in
199      * nanoseconds. The real precision depends on the JVM and the underlying
200      * system. On JRE before java5, <tt>backport-util-concurrent</tt> provides
201      * some limited support for equivalent timer.
202      *
203      * @see System#nanoTime()
204      * @return time in nanosecond
205      */
206     protected long nanotime()
207     {
208         return System.nanoTime();
209     }
210 
211     /**
212      * {@inheritDoc}
213      *
214      * @see org.apache.commons.monitoring.StopWatch#isStoped()
215      */
216     public boolean isStoped()
217     {
218         return stoped;
219     }
220 
221     /**
222      * {@inheritDoc}
223      *
224      * @see org.apache.commons.monitoring.StopWatch#isPaused()
225      */
226     public boolean isPaused()
227     {
228         return paused;
229     }
230 
231     @Override
232     public String toString()
233     {
234         StringBuffer stb = new StringBuffer();
235         if ( monitor != null )
236         {
237             stb.append( "Execution for " ).append( monitor.getKey().toString() ).append( " " );
238         }
239         if ( paused )
240         {
241             stb.append( "paused after " ).append( getElapsedTime() ).append( "ns" );
242         }
243         else if ( stoped )
244         {
245             stb.append( "stoped after " ).append( getElapsedTime() ).append( "ns" );
246         }
247         else
248         {
249             stb.append( "running for " ).append( getElapsedTime() ).append( "ns" );
250         }
251         return stb.toString();
252 
253     }
254 
255     /**
256      * {@inheritDoc}
257      *
258      * @see org.apache.commons.monitoring.StopWatch#getMonitor()
259      */
260     public Monitor getMonitor()
261     {
262         return monitor;
263     }
264 }