1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package com.commsen.stopwatch;
18
19 import java.io.File;
20 import java.io.FileInputStream;
21 import java.io.FileNotFoundException;
22 import java.io.IOException;
23 import java.io.InputStream;
24 import java.net.URI;
25 import java.net.URISyntaxException;
26 import java.util.Arrays;
27 import java.util.Properties;
28
29 import org.apache.log4j.Logger;
30
31 import com.commsen.stopwatch.engines.DefaultStopwatchEngine;
32 import com.commsen.stopwatch.jmx.StopwatchAgent;
33 import com.commsen.stopwatch.storages.DefaultHSQLInMemoryStorage;
34 import com.commsen.stopwatch.storages.StorageManager;
35 import com.commsen.stopwatch.util.ReportComparator;
36
37 /***
38 * Stopwatch allows you to measure performance of any given piece of code. It's basic usage is as
39 * follows:
40 *
41 * <code>
42 * <pre>
43 * .....
44 * long swId = Stopwatch.start("group", "label");
45 * // some code to be measured
46 * Stopwatch.stop(swId);
47 * ...
48 * </pre>
49 *</code>
50 *
51 * since version 0.4 there is also {@link Meter} object
52 *
53 * <code>
54 * <pre>
55 * .....
56 * Meter meter = Stopwatch.startMeter("group", "label");
57 * // some code to be measured
58 * meter.stop();
59 * ...
60 * </pre>
61 *</code>
62 *
63 * To skip already started mensuration (for example if an Exception is thrown) something similar to
64 * following code may be used:
65 *
66 * <code>
67 * <pre>
68 * .....
69 * long swId = Stopwatch.start("group", "label");
70 * try {
71 * // some code to be measured
72 * } catch (Exception) {
73 * Stopwatch.skip(swId);
74 * } finally {
75 * Stopwatch.stop(swId);
76 * }
77 * ...
78 * </pre>
79 *</code>
80 *
81 * or alternatively (since version 0.4) use {@link Meter} object
82 *
83 * <code>
84 * <pre>
85 * .....
86 * Meter meter = Stopwatch.startMeter("group", "label");
87 * try {
88 * // some code to be measured
89 * } catch (Exception) {
90 * meter.cancel();
91 * } finally {
92 * meter.stop();
93 * }
94 * ...
95 * </pre>
96 *</code>
97 *
98 * <p>
99 * <b>By default Stopwatch is not active!</b> It means all calls to {@link #start(String, String)},
100 * {@link #skip(long)} and {@link #stop(long)} methods are simply ignored. To activate Stopwatch do
101 * one of the following:
102 * <ul>
103 * <li>explicitly call Stopwatch.setActive(true)</li>
104 * <li>pass <code>-Dcom.commsen.stopwatch.activeOnStart=true</code> JVM parameter</li>
105 * <li>create "stopwatch.properties" file on classpath and set <code>activeOnStart=true</code></li>
106 * </ul>
107 * Stopwatch can also be activated/deactivated at runtime via JMX, RMI, etc.
108 * </p>
109 *
110 * @author Milen Dyankov
111 *
112 */
113 public class Stopwatch {
114
115 /***
116 * Logger for this class
117 */
118 private static final Logger log = Logger.getLogger(Stopwatch.class);
119
120 public static final String SYSTEM_PROPERTIES_PREFIX = "com.commsen.stopwatch.";
121 public static final String PROPERTY_ACTIVE = "activeOnStart";
122 public static final String PROPERTY_DEBUG = "debugEnabled";
123 public static final String PROPERTY_ENGINE = "engine";
124 public static final String PROPERTY_ENGINE_PROPERTIES = "engine.properties";
125 public static final String PROPERTY_STORAGE = "storage";
126 public static final String PROPERTY_STORAGE_PROPERTIES = "storage.properties";
127 public static final String PROPERTY_MODE = "persistenceMode";
128 public static final String PROPERTY_JMX_MANAGED = "jmxManaged";
129 public static final String PROPERTY_MBEAN_SERVER_NAME = "MBeanServer";
130
131 public static final String DEFAULT_ENGINE = DefaultStopwatchEngine.class.getName();
132 public static final String DEFAULT_ENGINE_PROPERTIES = "classpath:stopwatch-engine.properties";
133 public static final String DEFAULT_STORAGE = DefaultHSQLInMemoryStorage.class.getName();
134 public static final String DEFAULT_STORAGE_PROPERTIES = "classpath:stopwatch-storage.properties";
135 public static final int DEFAULT_MODE = StorageManager.DELAYED_MODE;
136
137 /***
138 * Indicates if stopwatch is active. When <code>false</code> all calls to
139 * {@link #start(String, String)} and {@link #stop(long)} are ignored.
140 */
141 private static boolean active;
142
143 /***
144 * Indicates if stopwatch was properly initialized. If <code>false</code> then Stopwatch can
145 * not be activated
146 */
147 private static boolean initialised;
148
149 /***
150 * Indicates if stopwatch should produce debug information
151 */
152 private static boolean debugEnabled;
153
154 /***
155 * Indicates if stopwatch should be managed via JMX
156 */
157 private static boolean jmxManaged;
158
159 /***
160 * The name of the MBean server to register manager with
161 */
162 private static String mBeanServerName;
163
164 /***
165 * Holds Stopwatch's properties (if any)
166 */
167 private static Properties stopwatchProperties = new Properties();
168
169 /***
170 * Holds reference to current stopwatch engine
171 */
172 private static StopwatchEngine engine;
173
174 /***
175 * Holds reference to current stopwatch JMX agent
176 */
177 private static StopwatchAgent agent;
178
179 /***
180 * Current persistence mode
181 */
182 private static String persistenceMode;
183
184
185
186
187 static {
188 init();
189 }
190
191
192 /***
193 * Starts new measurement. This method will do nothing and simply return a negative long if
194 * Stopwatch is not active.
195 *
196 * @param group the name of the group this measurement should be placed in
197 * @param label how this measurement should be labeled
198 * @return Unique ID representing current measurement.
199 */
200 public static long start(String group, String label) {
201 if (!isActive()) {
202 if (isDebug()) {
203 log.debug("Stopwatch.start(" + group + "," + label + ") ignored. Stopwatch is not active!");
204 }
205 return -1;
206 }
207 return engine.begin(group, label);
208 }
209
210
211 /***
212 * Starts new measurement and provides a {@link Meter} which can be later on stopped ({@link Meter#stop()})
213 * or canceled ({@link Meter#cancel()}).
214 *
215 * @param group the name of the group this measurement should be placed in
216 * @param label how this measurement should be labeled
217 * @return a {@link Meter} which can be later on stopped ({@link Meter#stop()}) or canceled ({@link Meter#cancel()})
218 * @since 0.4
219 */
220 public static Meter startMeter(String group, String label) {
221 return new Meter(start(group, label));
222 }
223
224
225 /***
226 * Stop measurement identified by <code>id</code>. This method will do nothing if Stopwatch
227 * is not active or measurement has been skipped already.
228 *
229 * @param id which measurement to stop
230 */
231 public static void stop(long id) {
232 if (!isActive()) {
233 if (isDebug()) {
234 log.debug("Stopwatch.stop(" + id + ") ignored. Stopwatch is not active!");
235 }
236 return;
237 }
238 engine.end(id);
239 };
240
241
242 /***
243 * Skip measurement identified by <code>id</code>. Method should be called if for some reason
244 * current measurement should be skipped. Default stopwatch engine will delete any information
245 * related to this <code>id</code> but other engines may behave differently (for example to
246 * provide a "skipped measurements" report).
247 *
248 * This method will do nothing if Stopwatch is not active or measurement has been stopped
249 * already.
250 *
251 * @param id which measurement to stop
252 */
253 public static void skip(long id) {
254
255 if (!isActive()) {
256 if (isDebug()) {
257 log.debug("Stopwatch.skip(" + id + ") ignored. Stopwatch is not active!");
258 }
259 return;
260 }
261 engine.skip(id);
262 };
263
264
265 /***
266 * Generates an array of reports which contains exactly 1 element for each combination of
267 * <b>group</b> and <b>label</b> If there is no enough data to produce reports, this method
268 * returns <code>null</code>
269 *
270 * @return array of reports of <code>null</code>.
271 */
272 public static Report[] getAllReports() {
273 return getAllReports(null);
274 }
275
276
277 /***
278 * Generates an array of reports which contains exactly 1 element for each combination of
279 * <b>group</b> and <b>label</b> If there is no enough data to produce reports, this method
280 * returns <code>null</code>
281 *
282 * @return array of reports of <code>null</code>.
283 */
284 public static Report[] getAllReports(ReportComparator comparator) {
285
286 if (!Stopwatch.initialised) {
287 log.warn("Stopwatch not propery initialised! Call to getAllReports() was ignored! Try to reset Stopwatch.");
288 return new Report[0];
289 }
290
291 Report[] reports = engine.getStorage().getReports();
292 Arrays.sort(reports, comparator);
293 return reports;
294 }
295
296
297 /***
298 *
299 * @return
300 */
301 public static Report[] getAllByGroupReports() {
302 return getAllByGroupReports(null);
303 }
304
305
306 /***
307 *
308 * @return
309 */
310 public static Report[] getAllByGroupReports(ReportComparator comparator) {
311
312 if (!Stopwatch.initialised) {
313 log.warn("Stopwatch not propery initialised! Call to getAllByGroupReports() was ignored! Try to reset Stopwatch.");
314 return new Report[0];
315 }
316
317 Report[] reports = engine.getStorage().getAllByGroupReports();
318 Arrays.sort(reports, comparator);
319 return reports;
320
321 }
322
323
324 /***
325 *
326 * @return
327 */
328 public static Report[] getAllByLabelReports() {
329 return getAllByLabelReports(null);
330 }
331
332
333 /***
334 *
335 * @return
336 */
337 public static Report[] getAllByLabelReports(ReportComparator comparator) {
338
339 if (!Stopwatch.initialised) {
340 log.warn("Stopwatch not propery initialised! Call to getAllByLabelReports() was ignored! Try to reset Stopwatch.");
341 return new Report[0];
342 }
343
344 Report[] reports = engine.getStorage().getAllByLabelReports();
345 Arrays.sort(reports, comparator);
346 return reports;
347 }
348
349
350 /***
351 * Generates an array of reports which contains exactly 1 element for each <b>group</b> If
352 * there is no enough data to produce the report, this method returns <code>null</code>
353 *
354 * @param group the group for which report should be generated
355 * @return array of reports of <code>null</code>.
356 */
357 public static Report[] getGroupReports(String group) {
358 return getGroupReports(group, null);
359 }
360
361
362 /***
363 * Generates an array of reports which contains exactly 1 element for each <b>group</b> If
364 * there is no enough data to produce the report, this method returns <code>null</code>
365 *
366 * @param group the group for which report should be generated
367 * @return array of reports of <code>null</code>.
368 */
369 public static Report[] getGroupReports(String group, ReportComparator comparator) {
370 if (!Stopwatch.initialised) {
371 log.warn("Stopwatch not propery initialised! Call to getGroupReports() was ignored! Try to reset Stopwatch.");
372 return new Report[0];
373 }
374 Report[] reports = engine.getStorage().getGroupReports(group);
375 Arrays.sort(reports, comparator);
376 return reports;
377 }
378
379
380 /***
381 * Generates an array of reports which contains exactly 1 element for each <b>label</b> If
382 * there is no enough data to produce the report, this method returns <code>null</code>
383 *
384 * @param label the label for which report should be generated
385 * @return array of reports or <code>null</code>.
386 */
387 public static Report[] getLabelReports(String label) {
388 return getLabelReports(label, null);
389 }
390
391
392 /***
393 * Generates an array of reports which contains exactly 1 element for each <b>label</b> If
394 * there is no enough data to produce the report, this method returns <code>null</code>
395 *
396 * @param label the label for which report should be generated
397 * @return array of reports or <code>null</code>.
398 */
399 public static Report[] getLabelReports(String label, ReportComparator comparator) {
400 if (!Stopwatch.initialised) {
401 log.warn("Stopwatch not propery initialised! Call to getLabelReports() was ignored! Try to reset Stopwatch.");
402 return new Report[0];
403 }
404
405 Report[] reports = engine.getStorage().getLabelReports(label);
406 Arrays.sort(reports, comparator);
407 return reports;
408 }
409
410
411 /***
412 * Generates a single report for provided <b>group</b> and <b>label</b> If there is no enough
413 * data to produce the report, this method returns <code>null</code>
414 *
415 * @param group the group for which report should be generated
416 * @param label the label for which report should be generated
417 * @return single report for provided <b>group</b> and <b>label</b> of <code>null</code>.
418 */
419 public static Report getSingleReport(String group, String label) {
420 if (!Stopwatch.initialised) {
421 log.warn("Stopwatch not propery initialised! Call to getSingleReport() was ignored! Try to reset Stopwatch.");
422 return null;
423 }
424 return engine.getStorage().getReport(group, label);
425 }
426
427
428 /***
429 * Returns information of how many instances of any measured code ware running for the last
430 * <code>numberOfPeriods</code> periods. Period length is defined by <code>periodField</code>
431 * which can be one of {@link java.util.Calendar#FIELD_NAME}
432 * <p>
433 * For example to see how many peaces of measured code were running per minute for the last 30
434 * minutes, one could use:
435 *
436 * <pre>
437 * long[] load = Stopwatch.getLoad({@link java.util.Calendar#MINUTE}, 30);
438 * </pre>
439 *
440 * In this case <code>load[0]</code> will contain the number of code instances running 30
441 * minutes ago and <code>load[29]</code> number of code instances running in the last minute.
442 *
443 * @param periodField can be one of {@link java.util.Calendar#FIELD_NAME}
444 * @param numberOfPeriods number of periods
445 * @return array of length <code>numberOfPeriods</code> where every element represents the
446 * load for given pariod.
447 */
448 public static long[] getLoad(int periodField, int numberOfPeriods) {
449 if (!Stopwatch.initialised) {
450 log.warn("Stopwatch not propery initialised! Call to getLoad() was ignored! Try to reset Stopwatch.");
451 return new long[0];
452 }
453 return engine.getStorage().getLoad(null, null, periodField, numberOfPeriods);
454 }
455
456
457 /***
458 * Returns information of how many instances of any measured code in group <code>group</code>
459 * ware running for the last <code>numberOfPeriods</code> periods. Period length is defined by
460 * <code>periodField</code> which can be one of {@link java.util.Calendar#FIELD_NAME}
461 * <p>
462 * For example to see how many peaces of measured code in group <code>g1</code> were running
463 * per day for the last 10 days, one could use:
464 *
465 * <pre>
466 * long[] load = Stopwatch.getLoad({@link java.util.Calendar#DAY_OF_MONTH}, 10);
467 * </pre>
468 *
469 * In this case <code>load[0]</code> will contain the number of code instances running 10 days
470 * ago and <code>load[9]</code> number of code instances running today.
471 *
472 * @param group the group for which report should be generated
473 * @param periodField can be one of {@link java.util.Calendar#FIELD_NAME}
474 * @param numberOfPeriods number of periods
475 * @return array of length <code>numberOfPeriods</code> where every element represents the
476 * load for given period.
477 */
478 public static long[] getGroupLoad(String group, int periodField, int numberOfPeriods) {
479 if (!Stopwatch.initialised) {
480 log.warn("Stopwatch not propery initialised! Call to getGroupLoad() was ignored! Try to reset Stopwatch.");
481 return new long[0];
482 }
483 return engine.getStorage().getLoad(group, null, periodField, numberOfPeriods);
484 }
485
486
487 /***
488 * Returns information of how many instances of any measured code labeled <code>label</code>
489 * ware running for the last <code>numberOfPeriods</code> periods. Period length is defined by
490 * <code>periodField</code> which can be one of {@link java.util.Calendar#FIELD_NAME}
491 * <p>
492 * For example to see how many peaces of measured code labeled <code>l1</code> were running
493 * per second for the last 15 seconds, one could use:
494 *
495 * <pre>
496 * long[] load = Stopwatch.getLoad({@link java.util.Calendar#SECOND}, 15);
497 * </pre>
498 *
499 * In this case <code>load[0]</code> will contain the number of code instances running 15
500 * seconds ago and <code>load[14]</code> number of code instances running in the last second.
501 *
502 * @param label the label for which report should be generated
503 * @param periodField can be one of {@link java.util.Calendar#FIELD_NAME}
504 * @param numberOfPeriods number of periods
505 * @return array of length <code>numberOfPeriods</code> where every element represents the
506 * load for given period.
507 */
508 public static long[] getLabelLoad(String label, int periodField, int numberOfPeriods) {
509 if (!Stopwatch.initialised) {
510 log.warn("Stopwatch not propery initialised! Call to getLoad() was ignored! Try to reset Stopwatch.");
511 return new long[0];
512 }
513 return engine.getStorage().getLoad(null, label, periodField, numberOfPeriods);
514 }
515
516
517 /***
518 * Returns information of how many instances of any measured code in group <code>group</code>
519 * labeled <code>label</code> ware running for the last <code>numberOfPeriods</code>
520 * periods. Period length is defined by <code>periodField</code> which can be one of
521 * {@link java.util.Calendar#FIELD_NAME}
522 * <p>
523 * For example to see how many peaces of measured code in group <code>g1</code> labeled
524 * <code>l1</code> were running per second for the last 3 weeks, one could use:
525 *
526 * <pre>
527 * long[] load = Stopwatch.getLoad({@link java.util.Calendar#WEEK_OF_YEAR}, 3);
528 * </pre>
529 *
530 * In this case <code>load[0]</code> will contain the number of code instances running 3 weeks
531 * ago and <code>load[2]</code> number of code instances running in the last week.
532 *
533 * @param group the group for which report should be generated
534 * @param label the label for which report should be generated
535 * @param periodField can be one of {@link java.util.Calendar#FIELD_NAME}
536 * @param numberOfPeriods number of periods
537 * @return array of length <code>numberOfPeriods</code> where every element represents the
538 * load for given period.
539 */
540 public static long[] getLoad(String group, String label, int periodField, int numberOfPeriods) {
541 if (!Stopwatch.initialised) {
542 log.warn("Stopwatch not propery initialised! Call to getLoad() was ignored! Try to reset Stopwatch.");
543 return new long[0];
544 }
545 return engine.getStorage().getLoad(group, label, periodField, numberOfPeriods);
546 }
547
548
549 /***
550 *
551 *
552 */
553 public static void reset() {
554 engine.stop();
555 init();
556 }
557
558
559 /***
560 * Called to check if Stopwatch is active. When this method returns <code>false</code> all
561 * calls to {@link #start(String, String)} and {@link #stop(long)} are ignored.
562 *
563 * @return Returns the Stopwatch's status.
564 */
565 public static boolean isActive() {
566 return active;
567 }
568
569
570 /***
571 * This method changes stopwatch's status Should be used to activate/deactivate Stopwatch at
572 * runtime.
573 *
574 * @param active the Stopwatch's status.
575 */
576 public static void setActive(boolean active) {
577
578
579 if (Stopwatch.active == active) return;
580
581 if (!Stopwatch.initialised) {
582 log.warn("Stopwatch not propery initialised! Call to setActive() was ignored! Try to reset Stopwatch.");
583 return;
584 }
585
586
587 if (active == false) {
588 engine.pause();
589 } else {
590 engine.resume();
591 }
592
593 Stopwatch.active = active;
594 }
595
596
597 /***
598 * Called to check if Stopwatch should produce debug information.
599 *
600 * @see #setDebugEnabled(boolean)
601 * @return Returns the <code>true</code> or <code>false</code>
602 */
603 public static boolean isDebugEnabled() {
604 return debugEnabled;
605 }
606
607
608 /***
609 * Used to disable/enable Stopwatch's debug information. The reason for this method to exist is
610 * to be able to minimize the performance impact Stopwatch may have on the measured application.
611 * Generating debug info consumes additional CPU units, which may become a problem if Stopwatch
612 * is heavily used.
613 *
614 * Setting this to false (is is false by default) will cause no debug info being generated by
615 * Stopwatch even when log4j's level is set to DEBUG.
616 *
617 * @param debugEnabled should debug information be generated
618 */
619 public static void setDebugEnabled(boolean debugEnabled) {
620 Stopwatch.debugEnabled = debugEnabled;
621 }
622
623
624 /***
625 * @return true if debug is enabled
626 */
627 private static boolean isDebug() {
628 return isDebugEnabled() && log.isDebugEnabled();
629 }
630
631
632 /***
633 * Tries to get the value of property <b>key</b>
634 *
635 * @param key
636 * @param defaultValue
637 * @return the value of property <b>key</b> of <code>defaultValue</code> if property not
638 * found.
639 */
640 public static String getProperty(String key, String defaultValue) {
641
642 String result = stopwatchProperties.getProperty(key, defaultValue);
643
644 result = System.getProperty(SYSTEM_PROPERTIES_PREFIX + key, result);
645
646 if (result != null && result.trim().length() > 0) return result.trim();
647 return defaultValue;
648 }
649
650
651 /***
652 * Loads properties from given location. Returns an empty instance of {@link Properties} if for
653 * any reason properties can not be read!
654 *
655 * @param location the URI to load properties from
656 * @return the actual properties or an empty instance of {@link Properties} on error
657 */
658 private static Properties readPropertiesFromLocation(String location) {
659 Properties result = new Properties();
660
661 if (location == null) {
662 if (isDebug()) {
663 log.debug("Missing properties location !");
664 }
665 return result;
666 }
667
668 URI uri;
669 try {
670 uri = new URI(location);
671 } catch (URISyntaxException e) {
672 log.warn("Invalid properties location " + location + "! Properties not set!", e);
673 return result;
674 }
675
676 InputStream propertiesStream;
677 if ("classpath".equalsIgnoreCase(uri.getScheme())) {
678 propertiesStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(uri.getSchemeSpecificPart());
679 if (propertiesStream == null) {
680 log.warn("Properties file " + uri.getSchemeSpecificPart() + " not found on classpath! Properties not set!");
681 return result;
682 }
683 } else if ("file".equalsIgnoreCase(uri.getScheme())) {
684 try {
685 propertiesStream = new FileInputStream(new File(uri.getSchemeSpecificPart()));
686 } catch (FileNotFoundException e) {
687 log.warn("Properties file " + uri.getSchemeSpecificPart() + " not found! Properties not set!");
688 return result;
689 }
690 } else {
691 log.warn("Unknown schema " + uri.getScheme() + " in properties location! Properties not set!");
692 return result;
693 }
694
695 try {
696 result.load(propertiesStream);
697 } catch (IOException e) {
698 log.warn("Error while loading properties! Properties not set!", e);
699 } finally {
700 try {
701 propertiesStream.close();
702 } catch (IOException e) {
703 log.warn("Error while loading properties!", e);
704 }
705 }
706 return result;
707 }
708
709
710 /***
711 *
712 */
713 private static void init() {
714 initialised = true;
715 InputStream propertiesInputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("stopwatch.properties");
716 if (propertiesInputStream != null) {
717 try {
718 stopwatchProperties.load(propertiesInputStream);
719 } catch (IOException e) {
720 log.warn("Problem loading 'stopwatch.properties' file!", e);
721 }
722 }
723
724 active = Boolean.valueOf(getProperty(PROPERTY_ACTIVE, Boolean.toString(false))).booleanValue();
725 debugEnabled = Boolean.valueOf(getProperty(PROPERTY_DEBUG, Boolean.toString(false))).booleanValue();
726 jmxManaged = Boolean.valueOf(getProperty(PROPERTY_JMX_MANAGED, Boolean.toString(false))).booleanValue();
727 mBeanServerName = getProperty(PROPERTY_MBEAN_SERVER_NAME, null);
728 String engineClass = getProperty(PROPERTY_ENGINE, DEFAULT_ENGINE);
729 String enginePropertiesLocation = getProperty(PROPERTY_ENGINE_PROPERTIES, DEFAULT_ENGINE_PROPERTIES);
730 String storageClass = getProperty(PROPERTY_STORAGE, null);
731 String storagePropertiesLocation = getProperty(PROPERTY_STORAGE_PROPERTIES, DEFAULT_STORAGE_PROPERTIES);
732 persistenceMode = getProperty(PROPERTY_MODE, null);
733 try {
734 engine = (StopwatchEngine) Class.forName(engineClass).newInstance();
735 engine.setDebugEnabled(debugEnabled);
736 engine.setProperties(readPropertiesFromLocation(enginePropertiesLocation));
737
738
739 if (storageClass != null && storageClass.trim().length() > 0) {
740 StopwatchStorage storage = (StopwatchStorage) Class.forName(storageClass).newInstance();
741 storage.setDebugEnabled(debugEnabled);
742 storage.setProperties(readPropertiesFromLocation(storagePropertiesLocation));
743 engine.setStorage(storage);
744 }
745
746
747 if ("NORMAL".equals(persistenceMode)) {
748 engine.setPersistenceMode(StorageManager.NORMAL_MODE);
749 } else if ("THREAD".equals(persistenceMode)) {
750 engine.setPersistenceMode(StorageManager.THREAD_MODE);
751 } else if ("DELAYED".equals(persistenceMode)) {
752 engine.setPersistenceMode(StorageManager.DELAYED_MODE);
753 } else {
754 if (persistenceMode != null) log.warn("Unknown persistence mode: " + persistenceMode + "! Using default !");
755 engine.setPersistenceMode(DEFAULT_MODE);
756 persistenceMode = "DELAYED";
757 }
758
759 engine.start();
760
761 if (jmxManaged) {
762 agent = new StopwatchAgent(mBeanServerName);
763 agent.start();
764 }
765
766 } catch (InstantiationException e) {
767 active = false;
768 initialised = false;
769 log.warn("Stopwatch was deactivated because an error(s) occurred during initialization!", e);
770 } catch (IllegalAccessException e) {
771 active = false;
772 initialised = false;
773 log.warn("Stopwatch was deactivated because an error(s) occurred during initialization!", e);
774 } catch (ClassNotFoundException e) {
775 active = false;
776 initialised = false;
777 log.warn("Stopwatch was deactivated because an error(s) occurred during initialization!", e);
778 }
779 }
780
781
782 public static String getEngineClass() {
783 return engine.getClass().getName();
784 }
785
786
787 public static String getStorageClass() {
788 return engine.getStorageClass();
789 }
790
791
792 public static String getPersistenceMode() {
793 return persistenceMode;
794 }
795
796
797 /***
798 * @return the initialised
799 */
800 public static boolean isInitialised() {
801 return initialised;
802 }
803
804 }