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 }