001: package com.jamonapi;
002:
003: /**
004: * Used to interact with monitor objects. I would have preferred to make this an
005: *interface, but didn't do that as jamon 1.0 code would have broken. Live and learn
006: *
007: * Created on December 11, 2005, 10:19 PM
008: */
009:
010: import java.util.Date;
011:
012: import com.jamonapi.utils.ToArray;
013:
014: // Note this was done as an empty abstract class so a recompile isn't needed
015: // to go to jamon 2.0. I had originally tried to make Monitor an interface.
016: // public abstract class Monitor extends BaseStatsImp implements MonitorInt {
017: public abstract class Monitor implements MonitorInt {
018:
019: /** Used in call to addListener(...). i.e. addListener(Monitor.MAX, ...) */
020: public static final String VALUE = "value";
021: public static final String MAX = "max";
022: public static final String MIN = "min";
023: public static final String MAXACTIVE = "maxactive";
024:
025: // Internal data passed from monitor to monitor.
026: MonInternals monData;
027:
028: Monitor(MonInternals monData) {
029: this .monData = monData;
030: }
031:
032: Monitor() {
033: this (new MonInternals());
034: }
035:
036: final MonInternals getMonInternals() {
037: return monData;
038: }
039:
040: public MonKey getMonKey() {
041: return monData.key;
042: }
043:
044: /** Returns the label for the monitor */
045: public String getLabel() {
046: return (String) getMonKey().getValue(MonKey.LABEL_HEADER);
047: }
048:
049: /** Returns the units for the monitor */
050: public String getUnits() {
051: return (String) getMonKey().getValue(MonKey.UNITS_HEADER);
052: }
053:
054: public void setAccessStats(long now) {
055: if (monData.enabled) {
056: synchronized (monData) {
057: // set the first and last access times.
058: if (monData.firstAccess == 0)
059: monData.firstAccess = now;
060:
061: monData.lastAccess = now;
062: }
063: }
064: }
065:
066: public void reset() {
067: if (monData.enabled) {
068: synchronized (monData) {
069: monData.reset();
070: }
071: }
072:
073: }
074:
075: public double getTotal() {
076: if (monData.enabled) {
077: synchronized (monData) {
078: return monData.total;
079: }
080: } else
081: return 0;
082: }
083:
084: public void setTotal(double value) {
085: if (monData.enabled) {
086: synchronized (monData) {
087: monData.total = value;
088: }
089: }
090: }
091:
092: public double getAvg() {
093: if (monData.enabled)
094: return avg(monData.total);
095: else
096: return 0;
097: }
098:
099: public double getMin() {
100: if (monData.enabled) {
101: synchronized (monData) {
102: return monData.min;
103: }
104: } else
105: return 0;
106: }
107:
108: public void setMin(double value) {
109: if (monData.enabled) {
110: synchronized (monData) {
111: monData.min = value;
112: }
113: }
114: }
115:
116: public double getMax() {
117: if (monData.enabled) {
118: synchronized (monData) {
119: return monData.max;
120: }
121: } else
122: return 0;
123: }
124:
125: public void setMax(double value) {
126: if (monData.enabled) {
127: synchronized (monData) {
128: monData.max = value;
129: }
130: }
131: }
132:
133: public double getHits() {
134: if (monData.enabled) {
135: synchronized (monData) {
136: return monData.hits;
137: }
138: } else
139: return 0;
140: }
141:
142: public void setHits(double value) {
143: if (monData.enabled) {
144: synchronized (monData) {
145: monData.hits = value;
146: }
147: }
148: }
149:
150: public double getStdDev() {
151:
152: if (monData.enabled) {
153: synchronized (monData) {
154: double stdDeviation = 0;
155: if (monData.hits != 0) {
156: double sumOfX = monData.total;
157: double n = monData.hits;
158: double nMinus1 = (n <= 1) ? 1 : n - 1; // avoid 0 divides;
159:
160: double numerator = monData.sumOfSquares
161: - ((sumOfX * sumOfX) / n);
162: stdDeviation = java.lang.Math.sqrt(numerator
163: / nMinus1);
164: }
165:
166: return stdDeviation;
167: }
168: } else
169: return 0;
170: }
171:
172: public void setFirstAccess(Date date) {
173: if (monData.enabled) {
174: synchronized (monData) {
175: monData.firstAccess = date.getTime();
176: }
177: }
178: }
179:
180: private static final Date NULL_DATE = new Date(0);
181:
182: public Date getFirstAccess() {
183: if (monData.enabled) {
184: synchronized (monData) {
185: return new Date(monData.firstAccess);
186: }
187: } else
188: return NULL_DATE;
189:
190: }
191:
192: public void setLastAccess(Date date) {
193: if (monData.enabled) {
194: synchronized (monData) {
195: monData.lastAccess = date.getTime();
196: }
197: }
198: }
199:
200: public Date getLastAccess() {
201: if (monData.enabled) {
202: synchronized (monData) {
203: return new Date(monData.lastAccess);
204: }
205: } else
206: return NULL_DATE;
207: }
208:
209: public double getLastValue() {
210: if (monData.enabled) {
211: synchronized (monData) {
212: return monData.lastValue;
213: }
214: } else
215: return 0;
216:
217: }
218:
219: public void setLastValue(double value) {
220: if (monData.enabled) {
221: synchronized (monData) {
222: monData.lastValue = value;
223: }
224: }
225: }
226:
227: // new methods. not sure about them
228: public void disable() {
229: monData.enabled = false;
230: }
231:
232: public void enable() {
233: monData.enabled = true;
234:
235: }
236:
237: public boolean isEnabled() {
238: return monData.enabled;
239: }
240:
241: Listeners getListeners() {
242: return monData.listeners;
243: }
244:
245: /** new jamon 2.4 stuff */
246:
247: /**
248: * Add a listener that receives notification every time this monitors add
249: * method is called. If null is passed all associated Listeners will be
250: * detached.
251: */
252:
253: // Some jamon 2.4 introduced methods. Mostly listener related.
254: public ListenerType getListenerType(String listenerType) {
255: return getListeners().getListenerType(listenerType);
256: }
257:
258: public Monitor start() {
259: if (monData.enabled) {
260:
261: synchronized (monData) {
262:
263: monData.activityStats.allActive.increment();
264:
265: if (monData.isPrimary) {
266: monData.activityStats.primaryActive.increment();
267: }
268:
269: // tracking current active/avg active/max active for this
270: // instance
271: double active = monData.activityStats.this Active
272: .incrementAndReturn();
273:
274: monData.totalActive += active;// allows us to track the
275: // average active for THIS
276: // instance.
277: if (active >= monData.maxActive) {
278: monData.maxActive = active;
279:
280: if (monData.listeners.listenerArray[Listeners.MAXACTIVE_LISTENER_INDEX].listener != null
281: && active > 1)
282: monData.listeners.listenerArray[Listeners.MAXACTIVE_LISTENER_INDEX].listener
283: .processEvent(this );
284: }
285:
286: // The only way activity tracking need be done is if start has
287: // been entered.
288: if (!monData.startHasBeenCalled) {
289: monData.startHasBeenCalled = true;
290: if (monData.range != null)
291: monData.range.setActivityTracking(true);
292: }
293:
294: } // end synchronized
295: } // end enabled
296:
297: return this ;
298:
299: }
300:
301: public Monitor stop() {
302: if (monData.enabled) {
303: synchronized (monData) {
304: monData.activityStats.this Active.decrement();
305:
306: if (monData.isPrimary) {
307: monData.activityStats.primaryActive.decrement();
308: }
309:
310: monData.activityStats.allActive.decrement();
311: }
312:
313: }
314:
315: return this ;
316:
317: }
318:
319: public Monitor add(double value) {
320: if (monData.enabled) {
321: synchronized (monData) {
322: // Being as TimeMonitors already have the current time and are
323: // passing it in
324: // the value (casted as long) for last access need not be
325: // recalculated.
326: // Using this admittedly ugly approach saved about 20%
327: // performance
328: // overhead on timing monitors.
329: if (!monData.isTimeMonitor)
330: setAccessStats(System.currentTimeMillis());
331:
332: // most recent value
333: monData.lastValue = value;
334:
335: // calculate hits i.e. n
336: monData.hits++;
337:
338: // calculate total i.e. sumofX's
339: monData.total += value;
340:
341: // used in std deviation
342: monData.sumOfSquares += value * value;
343:
344: // tracking activity is only done if start was called on the
345: // monitor
346: // there is no need to synchronize and perform activity tracking
347: // if this
348: // monitor doesn't have a start and stop called.
349: if (monData.trackActivity) {
350: // total of this monitors active
351: monData.this ActiveTotal += monData.activityStats.this Active
352: .getCount();
353: // total of primary actives
354: monData.primaryActiveTotal += monData.activityStats.primaryActive
355: .getCount();
356: // total of all monitors actives
357: monData.allActiveTotal += monData.activityStats.allActive
358: .getCount();
359: }
360:
361: // calculate min. note saving min if it is a tie
362: // so listener will be called and checking to see if the new
363: // min was less than the current min seemed to cost
364: // more. Same for max below
365: if (value <= monData.min) {
366: monData.min = value;
367:
368: if (monData.listeners.listenerArray[Listeners.MIN_LISTENER_INDEX].listener != null)
369: monData.listeners.listenerArray[Listeners.MIN_LISTENER_INDEX].listener
370: .processEvent(this );
371: }
372:
373: // calculate max
374: if (value >= monData.max) {
375: monData.max = value;
376:
377: if (monData.listeners.listenerArray[Listeners.MAX_LISTENER_INDEX].listener != null)
378: monData.listeners.listenerArray[Listeners.MAX_LISTENER_INDEX].listener
379: .processEvent(this );
380: }
381:
382: if (monData.listeners.listenerArray[Listeners.VALUE_LISTENER_INDEX].listener != null)
383: monData.listeners.listenerArray[Listeners.VALUE_LISTENER_INDEX].listener
384: .processEvent(this );
385:
386: if (monData.range != null)
387: monData.range.processEvent(this );
388:
389: }
390:
391: }
392:
393: return this ;
394:
395: }
396:
397: public Range getRange() {
398: return monData.range;
399: }
400:
401: public double getActive() {
402: if (monData.enabled) {
403: synchronized (monData) {
404: return monData.activityStats.this Active.getCount();
405: }
406: } else
407: return 0;
408: }
409:
410: public void setActive(double value) {
411: if (monData.enabled) {
412: synchronized (monData) {
413: monData.activityStats.this Active.setCount(value);
414: }
415: }
416: }
417:
418: public double getMaxActive() {
419: if (monData.enabled) {
420: synchronized (monData) {
421: return monData.maxActive;
422: }
423: } else
424: return 0;
425: }
426:
427: public void setMaxActive(double value) {
428: if (monData.enabled) {
429: synchronized (monData) {
430: monData.maxActive = value;
431: }
432: }
433: }
434:
435: /** Neeed to reset this to 0.0 to remove avg active numbers */
436: public void setTotalActive(double value) {
437: if (monData.enabled) {
438: synchronized (monData) {
439: monData.totalActive = value;
440: }
441: }
442: }
443:
444: public boolean isPrimary() {
445: return monData.isPrimary;
446: }
447:
448: public void setPrimary(boolean isPrimary) {
449: if (monData.enabled) {
450: this .monData.isPrimary = isPrimary;
451: }
452: }
453:
454: public boolean hasListeners() {
455: synchronized (monData) {
456: return monData.listeners.hasListeners();
457: }
458: }
459:
460: public String toString() {
461: if (monData.enabled) {
462: // This character string is about 275 characters now, but made
463: // the default a little bigger, so the JVM doesn't have to grow
464: // the StringBuffer should I add more info.
465:
466: StringBuffer b = new StringBuffer(400);
467: b.append(getMonKey() + ": (");
468: b.append("LastValue=");
469: b.append(getLastValue());
470: b.append(", Hits=");
471: b.append(getHits());
472: b.append(", Avg=");
473: b.append(getAvg());
474: b.append(", Total=");
475: b.append(getTotal());
476: b.append(", Min=");
477: b.append(getMin());
478: b.append(", Max=");
479: b.append(getMax());
480: b.append(", Active=");
481: b.append(getActive());
482: b.append(", Avg Active=");
483: b.append(getAvgActive());
484: b.append(", Max Active=");
485: b.append(getMaxActive());
486: b.append(", First Access=");
487: b.append(getFirstAccess());
488: b.append(", Last Access=");
489: b.append(getLastAccess());
490: b.append(")");
491:
492: return b.toString();
493: } else
494: return "";
495:
496: }
497:
498: /** FROM frequencydistimp */
499: public void setActivityTracking(boolean trackActivity) {
500: this .monData.trackActivity = trackActivity;
501: }
502:
503: public boolean isActivityTracking() {
504: return monData.trackActivity;
505: }
506:
507: private double avg(double value) {
508: synchronized (monData) {
509: if (monData.hits == 0)
510: return 0;
511: else
512: return value / monData.hits;
513: }
514: }
515:
516: public double getAvgActive() {
517: if (monData.enabled) {
518: // can be two ways to get active. For ranges
519: // thisActiveTotal is used and for nonranges
520: // totalActive is used.
521: if (monData.trackActivity) {
522: return avg(monData.this ActiveTotal);
523: } else
524: return avg(monData.totalActive);
525: } else
526: return 0;
527:
528: }
529:
530: public double getAvgGlobalActive() {
531: return avg(monData.allActiveTotal);
532: }
533:
534: public double getAvgPrimaryActive() {
535: return avg(monData.primaryActiveTotal);
536: }
537:
538: public JAMonDetailValue getJAMonDetailRow() {
539: if (monData.enabled) {
540: synchronized (monData) {
541: return new JAMonDetailValue(getMonKey(),
542: monData.lastValue,
543: monData.activityStats.this Active.getCount(),
544: monData.lastAccess);
545: // return new JAMonDetailValue(getMonKey().getDetailLabel(),
546: // monData.lastValue, monData.activityStats.thisActive.getCount(), monData.lastAccess);
547: }
548: } else
549: return JAMonDetailValue.NULL_VALUE;
550: }
551:
552: }
|