001: /**
002: * The XMOJO Project 5
003: * Copyright © 2003 XMOJO.org. All rights reserved.
004:
005: * NO WARRANTY
006:
007: * BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR
008: * THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
009: * OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
010: * PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
011: * OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
012: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
013: * TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE
014: * LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
015: * REPAIR OR CORRECTION.
016:
017: * IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL
018: * ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE
019: * THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
020: * GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
021: * USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF
022: * DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
023: * PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE),
024: * EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
025: * SUCH DAMAGES.
026: **/package javax.management.monitor;
027:
028: import javax.management.ObjectName;
029: import javax.management.MBeanServer;
030: import javax.management.MBeanNotificationInfo;
031: import javax.management.MBeanException;
032: import javax.management.AttributeNotFoundException;
033: import javax.management.InstanceNotFoundException;
034: import javax.management.ReflectionException;
035:
036: /**
037: * Defines a monitor MBean designed to observe the values of a gauge attribute.
038: * <P>
039: * A gauge monitor observes an attribute that is continuously variable with time.
040: * A gauge monitor sends notifications as follows:
041: * <UL>
042: * <LI> if the attribute value is increasing and becomes equal to or greater
043: * than the high threshold value,
044: * a {@link MonitorNotification#THRESHOLD_HIGH_VALUE_EXCEEDED threshold high notification}
045: * is sent. The notify high flag must be set to <CODE>true</CODE>
046: * <BR>Subsequent crossings of the high threshold value do not cause
047: * further notifications unless the attribute value becomes equal to or
048: * less than the low threshold value.
049: * <LI> if the attribute value is decreasing and becomes equal to or less than
050: * the low threshold value,
051: * a {@link MonitorNotification#THRESHOLD_LOW_VALUE_EXCEEDED threshold low notification}
052: * is sent. The notify low flag must be set to <CODE>true</CODE>.
053: * <BR>Subsequent crossings of the low threshold value do not cause
054: * further notifications unless the attribute value becomes equal to or
055: * greater than the high threshold value.
056: * </UL>
057: * This provides a hysteresis mechanism to avoid repeated triggering of
058: * notifications when the attribute value makes small oscillations around the
059: * high or low threshold value.
060: * <P>
061: * If the gauge difference mode is used, the value of the derived gauge is
062: * calculated as the difference between the observed gauge values for two
063: * successive observations.
064: * <BR>The derived gauge value (V[t]) is calculated using the following method:
065: * <UL>
066: * <LI>V[t] = gauge[t] - gauge[t-GP]
067: * </UL>
068: * This implementation of the gauge monitor requires the observed attribute to
069: * be of the type integer or floating-point (<CODE>Byte</CODE>,
070: * <CODE>Integer</CODE>, <CODE>Short</CODE>, <CODE>Long</CODE>,
071: * <CODE>Float</CODE>, <CODE>Double</CODE>).
072: */
073: public class GaugeMonitor extends Monitor implements GaugeMonitorMBean {
074: /**
075: * Derived gauge.
076: */
077: private Number derivedGauge = null;
078:
079: /**
080: * Flag indicating if the gauge difference mode is used.
081: * If the gauge difference mode is used, the derived gauge is the difference between two consecutive observed values.
082: * Otherwise, the derived gauge is directly the value of the observed attribute.
083: * <BR>The default value is set to <CODE>false</CODE>.
084: */
085: private boolean differenceMode = false;
086:
087: /**
088: * Gauge high threshold.
089: * <BR>The default value is a null Integer object.
090: */
091: private Number highThreshold = null;
092:
093: /**
094: * Gauge low threshold.
095: * <BR>The default value is a null Integer object.
096: */
097: private Number lowThreshold = null;
098:
099: /**
100: * Flag indicating if the gauge monitor notifies when exceeding the high threshold.
101: * <BR>The default value is set to <CODE>false</CODE>.
102: */
103: private boolean notifyHigh = true;
104:
105: /**
106: * Flag indicating if the gauge monitor notifies when exceeding the low threshold.
107: * <BR>The default value is set to <CODE>false</CODE>.
108: */
109: private boolean notifyLow = true;
110:
111: /**
112: * Previous derived gauge value.
113: */
114: private Number prevDerivedGauge = null;
115:
116: private long sequenceNumber = 1;
117: private Comparable comparableDerivedGauge = null;
118: private String observedAttributeType = null;
119: private Comparable comparableLowThreshold = null;
120: private Comparable comparableHighThreshold = null;
121: private ObjectName objName = null;
122: private Thread gaugeMonitorThread = null;
123: private int NO_NOTIF_SENT = 1;
124: private int HIGH_NOTIF_SENT = 2;
125: private int LOW_NOTIF_SENT = 3;
126: private int notifStatus;
127:
128: /**
129: * Default Constructor.
130: */
131: public GaugeMonitor() {
132: try {
133: objName = new ObjectName("Services:type=GaugeMonitor");
134: } catch (Exception e) {
135: }
136: //notifStatus = NO_NOTIF_SENT;
137: }
138:
139: /**
140: * Starts the Gauge monitor.
141: */
142: public void start() {
143: Object object = null;
144: gaugeMonitorThread = new Thread(new GaugeMonitorThread(this ));
145: isActive = true;
146: notifStatus = NO_NOTIF_SENT;
147: gaugeMonitorThread.setName("GaugeMonitorThread-"
148: + gaugeMonitorThread.getName());
149: gaugeMonitorThread.start();
150: }
151:
152: /**
153: * Stops the Gauge Monitor.
154: */
155: public void stop() {
156: isActive = false;
157: if (gaugeMonitorThread != null) {
158: if (gaugeMonitorThread.isAlive()) {
159: gaugeMonitorThread.stop();
160: }
161: }
162: }
163:
164: /**
165: * This method returns a NotificationInfo object containing the name of the
166: * Java class of the notification and the notification types sent by the
167: * counter monitor.
168: *
169: * @return An Array of MBeanNotificationInfo objects.
170: */
171: public MBeanNotificationInfo[] getNotificationInfo() {
172: //Check if this returns the correct values---------balaji.
173: MBeanNotificationInfo[] notifInfo = super .getNotificationInfo();
174:
175: MBeanNotificationInfo[] newNotifInfo = new MBeanNotificationInfo[notifInfo.length + 2];
176:
177: for (int i = 0; i < notifInfo.length; i++) {
178: newNotifInfo[i] = notifInfo[i];
179: }
180:
181: String[] types = { "jmx.monitor.error.threshold" };
182: newNotifInfo[newNotifInfo.length - 2] = new MBeanNotificationInfo(
183: types, "Monitor Threshold Error Notification",
184: "Emimitted for a error case in Threshold");
185:
186: String[] types1 = { "jmx.monitor.gauge.high",
187: "jmx.monitor.gauge.low" };
188: newNotifInfo[newNotifInfo.length - 1] = new MBeanNotificationInfo(
189: types1, "Monitor Threshold CrossOver Notification",
190: "Emimitted for a CrossOver in monitored attribute");
191:
192: return newNotifInfo;
193: }
194:
195: /**
196: * This method gets the value of the derived gauge. The derived gauge is
197: * either the exact value of the observed attribute, or the difference
198: * between the two consecutive observed values of the attribute.
199: *
200: * @return An instance of java.lang.Number giving the value of the derived gauge.
201: */
202: public java.lang.Number getDerivedGauge() {
203: return derivedGauge;
204: }
205:
206: /**
207: * This method gets the value of the derived gauge time stamp.The derived
208: * gauge time stamp* is the value(in the nearest miliseconds) when the
209: * notification was triggered.
210: *
211: * @return long value representing the time the notification was triggered.
212: */
213: public long getDerivedGaugeTimeStamp() {
214: return derivedGaugeTimeStamp;
215: }
216:
217: /**
218: * This method gets the value of the difference mode. If the difference
219: * mode is true, the difference mode option is set to calculate the value
220: * of the derived gauge.
221: *
222: * @return boolean value indicating whether the difference mode option is set.
223: */
224: public boolean getDifferenceMode() {
225: return differenceMode;
226: }
227:
228: /**
229: * This method sets the state of the difference mode.
230: *
231: * @param value boolean value representing the state of the difference mode.
232: */
233: public void setDifferenceMode(boolean value) {
234: this .differenceMode = value;
235: }
236:
237: /**
238: * This method gets the value of the high threshold.
239: *
240: * @return An instance of java.lang.Number giving the value of the high threshold.
241: */
242: public java.lang.Number getHighThreshold() {
243: return highThreshold;
244: }
245:
246: /**
247: * This method gets the value of the low threshold.
248: *
249: * @return An instance of java.lang.Number giving the value of the low threshold.
250: */
251: public java.lang.Number getLowThreshold() {
252: return lowThreshold;
253: }
254:
255: /**
256: * This method sets the high threshold and low threshold values.
257: *
258: * @param highValue - The high threshold value.
259: *
260: * @param lowValue - The low threshold value.
261: *
262: * @exception java.lang.IllegalArgumentException - The specified high/low
263: * threshold is null or the low threshold is greater than the
264: * high threshold or the high threshold and the low threshold
265: * are not of the same type.
266: */
267: public void setThresholds(Number highValue, Number lowValue)
268: throws IllegalArgumentException {
269: Object object = null;
270:
271: if (highValue == null || lowValue == null) {
272: throw new IllegalArgumentException(
273: "Threshold Values cannot be null");
274: }
275:
276: String highValueType = highValue.getClass().getName();
277: String lowValueType = lowValue.getClass().getName();
278:
279: //if the highValue and lowValue are not of the same type,throw exception.
280: this .highThreshold = highValue;
281: this .lowThreshold = lowValue;
282:
283: if (!(highValueType.equals(lowValueType))) {
284: sendNotification(new MonitorNotification(
285: MonitorNotification.THRESHOLD_ERROR, this ,
286: observedObject, attributeName, derivedGauge,
287: highValue, sequenceNumber++));
288: throw new IllegalArgumentException(
289: "Threshold values should be of the same type");
290: }
291:
292: if (getComparableValue(highValue).compareTo(
293: getComparableValue(lowValue)) < 0) {
294: /*sendNotification(new MonitorNotification(MonitorNotification.THRESHOLD_ERROR,this, observedObject,attributeName,derivedGauge, lowValue,sequenceNumber++));
295: */
296: throw new IllegalArgumentException(
297: "Low Threshold cannot be greater than High Threshold");
298: }
299:
300: //TODO --- if the HighThresholdDataType && LowThresholdDataType are not
301: //the same as ObservedAttribute DataType ....send a notificiaiton.
302:
303: //gets the instances of the thresholds as instances of Comparable interface.
304: comparableLowThreshold = getComparableValue(lowThreshold);
305: comparableHighThreshold = getComparableValue(highThreshold);
306: }
307:
308: /**
309: * This method gets the high notification's on/off switch value.
310: *
311: * @return true if the gauge monitor notifies when exceeding the high
312: * threshold, false otherwise.
313: */
314: public boolean getNotifyHigh() {
315: return notifyHigh;
316: }
317:
318: /**
319: * This method sets the high notification's on/off switch value.
320: *
321: * @param value - The high notification's on/off switch value.
322: */
323: public void setNotifyHigh(boolean value) {
324: this .notifyHigh = value;
325: }
326:
327: /**
328: * This method gets the low notification's on/off switch value.
329: *
330: * @return true if the gauge monitor notifies when exceeding the low
331: * threshold, false otherwise.
332: */
333: public boolean getNotifyLow() {
334: return notifyLow;
335: }
336:
337: /**
338: * This method sets the low notification's on/off switch value.
339: *
340: * @param value - The low notification's on/off switch value.
341: */
342: public void setNotifyLow(boolean value) {
343: this .notifyLow = value;
344: }
345:
346: /**
347: * Overriding the preRegister() of MBeanRegistration interface to store the
348: * ObjectName locally.
349: */
350: public ObjectName preRegister(MBeanServer server, ObjectName name)
351: throws Exception {
352: this .objName = name;
353: super .preRegister(server, name);
354: return name;
355: }
356:
357: //-------------------------- Private methods --------------------------//
358:
359: // Calculates the derived gauge according to the specifications when the
360: // difference mode is set.
361: private Number calculateDerivedGauge(Object derived,
362: Object prevDerived) {
363: Number toRet = null;
364: String temp = derived.getClass().getName();
365:
366: if (temp.equals("java.lang.Integer")) {
367: toRet = (Number) (new Integer(((Integer) derived)
368: .intValue()
369: - ((Integer) prevDerived).intValue()));
370: }
371: if (temp.equals("java.lang.Float")) {
372: toRet = (Number) (new Float(((Float) derived).floatValue()
373: - ((Float) prevDerived).floatValue()));
374: }
375: if (temp.equals("java.lang.Double")) {
376: toRet = (Number) (new Double(((Double) derived)
377: .doubleValue()
378: - ((Double) prevDerived).doubleValue()));
379: }
380: if (temp.equals("java.lang.Long")) {
381: toRet = (Number) (new Long(((Long) derived).longValue()
382: - ((Long) prevDerived).longValue()));
383: }
384:
385: return toRet;
386: }
387:
388: //checks whether the observed attribute is only of gauge monitor type.
389: private boolean isGaugeMonitorDataType(Object object) {
390: String temp = object.getClass().getName();
391:
392: if (temp.indexOf("Integer") != -1)
393: return true;
394: else if (temp.indexOf("Float") != -1)
395: return true;
396: else if (temp.indexOf("Double") != -1)
397: return true;
398: else if (temp.indexOf("Long") != -1)
399: return true;
400: else
401: return false;
402: }
403:
404: //This method checks whether the observed atttribute is of a gauge Monitor Type.
405: private Comparable getComparableValue(Object object) {
406: Comparable toRet = null;
407: String temp = object.getClass().getName();
408:
409: if (temp.indexOf("Integer") != -1)
410: toRet = (Integer) object;
411: else if (temp.indexOf("Float") != -1)
412: toRet = (Float) object;
413: else if (temp.indexOf("Double") != -1)
414: toRet = (Double) object;
415: else if (temp.indexOf("Long") != -1)
416: toRet = (Long) object;
417: return toRet;
418: }
419:
420: //---------------------------- Inner class -----------------------------//
421:
422: // This inner class implements Runnable and when the StringMonitor is
423: // started, the start method of this class is called and it periodically
424: // polls the Observed Attribute according to the granularity period and
425: // when there is a deviation from the configuration details, sends a notification.
426: class GaugeMonitorThread implements Runnable {
427: Object obj = null;
428: MonitorNotification notif = null;
429: GaugeMonitor monitor = null;
430: private boolean isNotifHighSent = false;
431: private boolean isNotifLowSent = false;
432:
433: GaugeMonitorThread(GaugeMonitor monitor) {
434: this .monitor = monitor;
435: }
436:
437: public void run() {
438: while (true) {
439: try {
440: obj = server.getAttribute(observedObject,
441: attributeName);
442: derivedGaugeTimeStamp = System.currentTimeMillis();
443: } catch (InstanceNotFoundException ine) {
444: if (Monitor.OBSERVED_OBJECT_ERROR_NOTIFIED == 1) {
445: sendNotification(new MonitorNotification(
446: MonitorNotification.OBSERVED_OBJECT_ERROR,
447: monitor, observedObject, attributeName,
448: null, null, sequenceNumber++));
449: Monitor.OBSERVED_OBJECT_ERROR_NOTIFIED = 0;
450: }
451: sleep();
452: continue;
453: } catch (AttributeNotFoundException ane) {
454: if (Monitor.OBSERVED_ATTRIBUTE_ERROR_NOTIFIED == 1) {
455: sendNotification(new MonitorNotification(
456: MonitorNotification.OBSERVED_ATTRIBUTE_ERROR,
457: monitor, observedObject, attributeName,
458: null, null, sequenceNumber++));
459: Monitor.OBSERVED_ATTRIBUTE_ERROR_NOTIFIED = 0;
460: }
461: sleep();
462: continue;
463: } catch (MBeanException mbe) {
464: if (Monitor.RUNTIME_ERROR_NOTIFIED == 1) {
465: sendNotification(new MonitorNotification(
466: MonitorNotification.RUNTIME_ERROR,
467: monitor, observedObject, attributeName,
468: null, null, sequenceNumber++));
469: Monitor.RUNTIME_ERROR_NOTIFIED = 0;
470: }
471: sleep();
472: continue;
473: } catch (ReflectionException re) {
474: if (Monitor.OBSERVED_ATTRIBUTE_ERROR_NOTIFIED == 1) {
475: sendNotification(new MonitorNotification(
476: MonitorNotification.OBSERVED_ATTRIBUTE_ERROR,
477: monitor, observedObject, attributeName,
478: null, null, sequenceNumber++));
479: Monitor.OBSERVED_ATTRIBUTE_ERROR_NOTIFIED = 0;
480: }
481: sleep();
482: continue;
483: } catch (Exception e) {
484: if (Monitor.RUNTIME_ERROR_NOTIFIED == 1) {
485: sendNotification(new MonitorNotification(
486: MonitorNotification.RUNTIME_ERROR,
487: monitor, observedObject, attributeName,
488: null, null, sequenceNumber++));
489: Monitor.RUNTIME_ERROR_NOTIFIED = 0;
490: }
491: sleep();
492: continue;
493: }
494:
495: if (obj == null) {
496: continue;
497: }
498:
499: //check if the attribute is of gaugemonitor type.
500: if (!isGaugeMonitorDataType(obj)) {
501: if (Monitor.OBSERVED_ATTRIBUTE_TYPE_ERROR_NOTIFIED == 1) {
502: sendNotification(new MonitorNotification(
503: MonitorNotification.OBSERVED_ATTRIBUTE_TYPE_ERROR,
504: monitor, observedObject, attributeName,
505: null, null, sequenceNumber++));
506: Monitor.OBSERVED_ATTRIBUTE_TYPE_ERROR_NOTIFIED = 0;
507: }
508: }
509:
510: derivedGauge = (Number) obj;
511:
512: comparableDerivedGauge = getComparableValue(derivedGauge);
513:
514: if (differenceMode) {
515: // calculate the derivedGauge Value for the difference Mode.
516: if (prevDerivedGauge == null) {
517: prevDerivedGauge = derivedGauge;
518: }
519:
520: derivedGauge = calculateDerivedGauge(derivedGauge,
521: prevDerivedGauge);
522: comparableDerivedGauge = getComparableValue(derivedGauge);
523: }
524:
525: /*if(comparableDerivedGauge.compareTo(comparableHighThreshold) >= 0)
526: {
527: if(notifyHigh)
528: {
529: notif = new MonitorNotification(MonitorNotification.THRESHOLD_HIGH_VALUE_EXCEEDED,monitor, observedObject,attributeName, derivedGauge,highThreshold, sequenceNumber++);
530: sendNotification(notif);
531:
532: notifyHigh = false;
533: notifyLow = true;
534: }
535: }
536:
537: if(comparableDerivedGauge.compareTo(comparableLowThreshold) <= 0)
538: {
539: if(notifyLow)
540: {
541: notif = new MonitorNotification(MonitorNotification.THRESHOLD_LOW_VALUE_EXCEEDED,monitor, observedObject,attributeName, derivedGauge,lowThreshold, sequenceNumber++);
542: sendNotification(notif);
543:
544: notifyLow = false;
545: notifyHigh = true;
546: }
547: }*/
548:
549: if (notifyHigh) {
550: if (isNotifHighSent) {
551: if (comparableDerivedGauge
552: .compareTo(comparableHighThreshold) < 0) {
553: isNotifHighSent = false;
554: if (!notifyLow)
555: notifStatus = LOW_NOTIF_SENT;
556: }
557: }
558:
559: if (notifStatus == NO_NOTIF_SENT
560: || notifStatus == LOW_NOTIF_SENT) {
561: /*
562: if(isNotifHighSent){
563: if(comparableDerivedGauge.compareTo(comparableHighThreshold) < 0){
564: isNotifHighSent = false;
565: if(!notifyLow)
566: notifStatus = LOW_NOTIF_SENT;
567: }
568: }
569: else{
570: */
571: if (comparableDerivedGauge
572: .compareTo(comparableHighThreshold) >= 0) {
573: notif = new MonitorNotification(
574: MonitorNotification.THRESHOLD_HIGH_VALUE_EXCEEDED,
575: monitor, observedObject,
576: attributeName, derivedGauge,
577: highThreshold, sequenceNumber++);
578: isNotifHighSent = true;
579:
580: sendNotification(notif);
581: notifStatus = HIGH_NOTIF_SENT;
582: }
583: //}
584: }
585: }
586:
587: if (notifyLow) {
588: if (isNotifLowSent) {
589: if (comparableDerivedGauge
590: .compareTo(comparableLowThreshold) > 0) {
591: isNotifLowSent = false;
592: if (!notifyHigh)
593: notifStatus = HIGH_NOTIF_SENT;
594: }
595: }
596:
597: if (notifStatus == NO_NOTIF_SENT
598: || notifStatus == HIGH_NOTIF_SENT) {
599: /*
600: if(isNotifLowSent){
601: if(comparableDerivedGauge.compareTo(comparableLowThreshold) >0){
602: isNotifLowSent = false;
603: if(!notifyHigh)
604: notifStatus = HIGH_NOTIF_SENT;
605: }
606: }
607: else {
608: */
609:
610: if (comparableDerivedGauge
611: .compareTo(comparableLowThreshold) <= 0) {
612: notif = new MonitorNotification(
613: MonitorNotification.THRESHOLD_LOW_VALUE_EXCEEDED,
614: monitor, observedObject,
615: attributeName, derivedGauge,
616: highThreshold, sequenceNumber++);
617: isNotifLowSent = true;
618: sendNotification(notif);
619: notifStatus = LOW_NOTIF_SENT;
620: }
621: //}
622: }
623: }
624:
625: try {
626: prevDerivedGauge = derivedGauge;
627: Thread.sleep(granularityPeriod);
628:
629: } catch (InterruptedException IE) {
630: //IE.printStackTrace();
631: }
632: }
633: }
634:
635: private void sleep() {
636: try {
637: Thread.sleep(granularityPeriod);
638: } catch (Exception e) {
639: }
640: }
641: }//End GaugeMonitor Thread class.
642: }//End GaugeMonitor Class.
|