1 /*
2  * Copyright (c) 1999, 2017, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 package javax.management.monitor;
27 
28 import static com.sun.jmx.defaults.JmxProperties.MONITOR_LOGGER;
29 import java.lang.System.Logger.Level;
30 import javax.management.MBeanNotificationInfo;
31 import javax.management.ObjectName;
32 import static javax.management.monitor.Monitor.NumericalType.*;
33 import static javax.management.monitor.MonitorNotification.*;
34 
35 /**
36  * Defines a monitor MBean designed to observe the values of a gauge attribute.
37  *
38  * <P> A gauge monitor observes an attribute that is continuously
39  * variable with time. A gauge monitor sends notifications as
40  * follows:
41  *
42  * <UL>
43  *
44  * <LI> if the attribute value is increasing and becomes equal to or
45  * greater than the high threshold value, a {@link
46  * MonitorNotification#THRESHOLD_HIGH_VALUE_EXCEEDED threshold high
47  * notification} is sent. The notify high flag must be set to
48  * <CODE>true</CODE>.
49  *
50  * <BR>Subsequent crossings of the high threshold value do not cause
51  * further notifications unless the attribute value becomes equal to
52  * or less than the low threshold value.</LI>
53  *
54  * <LI> if the attribute value is decreasing and becomes equal to or
55  * less than the low threshold value, a {@link
56  * MonitorNotification#THRESHOLD_LOW_VALUE_EXCEEDED threshold low
57  * notification} is sent. The notify low flag must be set to
58  * <CODE>true</CODE>.
59  *
60  * <BR>Subsequent crossings of the low threshold value do not cause
61  * further notifications unless the attribute value becomes equal to
62  * or greater than the high threshold value.</LI>
63  *
64  * </UL>
65  *
66  * This provides a hysteresis mechanism to avoid repeated triggering
67  * of notifications when the attribute value makes small oscillations
68  * around the high or low threshold value.
69  *
70  * <P> If the gauge difference mode is used, the value of the derived
71  * gauge is calculated as the difference between the observed gauge
72  * values for two successive observations.
73  *
74  * <BR>The derived gauge value (V[t]) is calculated using the following method:
75  * <UL>
76  * <LI>V[t] = gauge[t] - gauge[t-GP]</LI>
77  * </UL>
78  *
79  * This implementation of the gauge monitor requires the observed
80  * attribute to be of the type integer or floating-point
81  * (<CODE>Byte</CODE>, <CODE>Integer</CODE>, <CODE>Short</CODE>,
82  * <CODE>Long</CODE>, <CODE>Float</CODE>, <CODE>Double</CODE>).
83  *
84  *
85  * @since 1.5
86  */
87 public class GaugeMonitor extends Monitor implements GaugeMonitorMBean {
88 
89     /*
90      * ------------------------------------------
91      *  PACKAGE CLASSES
92      * ------------------------------------------
93      */
94 
95     static class GaugeMonitorObservedObject extends ObservedObject {
96 
GaugeMonitorObservedObject(ObjectName observedObject)97         public GaugeMonitorObservedObject(ObjectName observedObject) {
98             super(observedObject);
99         }
100 
getDerivedGaugeValid()101         public final synchronized boolean getDerivedGaugeValid() {
102             return derivedGaugeValid;
103         }
setDerivedGaugeValid( boolean derivedGaugeValid)104         public final synchronized void setDerivedGaugeValid(
105                                                  boolean derivedGaugeValid) {
106             this.derivedGaugeValid = derivedGaugeValid;
107         }
getType()108         public final synchronized NumericalType getType() {
109             return type;
110         }
setType(NumericalType type)111         public final synchronized void setType(NumericalType type) {
112             this.type = type;
113         }
getPreviousScanGauge()114         public final synchronized Number getPreviousScanGauge() {
115             return previousScanGauge;
116         }
setPreviousScanGauge( Number previousScanGauge)117         public final synchronized void setPreviousScanGauge(
118                                                   Number previousScanGauge) {
119             this.previousScanGauge = previousScanGauge;
120         }
getStatus()121         public final synchronized int getStatus() {
122             return status;
123         }
setStatus(int status)124         public final synchronized void setStatus(int status) {
125             this.status = status;
126         }
127 
128         private boolean derivedGaugeValid;
129         private NumericalType type;
130         private Number previousScanGauge;
131         private int status;
132     }
133 
134     /*
135      * ------------------------------------------
136      *  PRIVATE VARIABLES
137      * ------------------------------------------
138      */
139 
140     /**
141      * Gauge high threshold.
142      *
143      * <BR>The default value is a null Integer object.
144      */
145     private Number highThreshold = INTEGER_ZERO;
146 
147     /**
148      * Gauge low threshold.
149      *
150      * <BR>The default value is a null Integer object.
151      */
152     private Number lowThreshold = INTEGER_ZERO;
153 
154     /**
155      * Flag indicating if the gauge monitor notifies when exceeding
156      * the high threshold.
157      *
158      * <BR>The default value is <CODE>false</CODE>.
159      */
160     private boolean notifyHigh = false;
161 
162     /**
163      * Flag indicating if the gauge monitor notifies when exceeding
164      * the low threshold.
165      *
166      * <BR>The default value is <CODE>false</CODE>.
167      */
168     private boolean notifyLow = false;
169 
170     /**
171      * Flag indicating if the gauge difference mode is used.  If the
172      * gauge difference mode is used, the derived gauge is the
173      * difference between two consecutive observed values.  Otherwise,
174      * the derived gauge is directly the value of the observed
175      * attribute.
176      *
177      * <BR>The default value is set to <CODE>false</CODE>.
178      */
179     private boolean differenceMode = false;
180 
181     private static final String[] types = {
182         RUNTIME_ERROR,
183         OBSERVED_OBJECT_ERROR,
184         OBSERVED_ATTRIBUTE_ERROR,
185         OBSERVED_ATTRIBUTE_TYPE_ERROR,
186         THRESHOLD_ERROR,
187         THRESHOLD_HIGH_VALUE_EXCEEDED,
188         THRESHOLD_LOW_VALUE_EXCEEDED
189     };
190 
191     private static final MBeanNotificationInfo[] notifsInfo = {
192         new MBeanNotificationInfo(
193             types,
194             "javax.management.monitor.MonitorNotification",
195             "Notifications sent by the GaugeMonitor MBean")
196     };
197 
198     // Flags needed to implement the hysteresis mechanism.
199     //
200     private static final int RISING             = 0;
201     private static final int FALLING            = 1;
202     private static final int RISING_OR_FALLING  = 2;
203 
204     /*
205      * ------------------------------------------
206      *  CONSTRUCTORS
207      * ------------------------------------------
208      */
209 
210     /**
211      * Default constructor.
212      */
GaugeMonitor()213     public GaugeMonitor() {
214     }
215 
216     /*
217      * ------------------------------------------
218      *  PUBLIC METHODS
219      * ------------------------------------------
220      */
221 
222     /**
223      * Starts the gauge monitor.
224      */
start()225     public synchronized void start() {
226         if (isActive()) {
227             MONITOR_LOGGER.log(Level.TRACE, "the monitor is already active");
228             return;
229         }
230         // Reset values.
231         //
232         for (ObservedObject o : observedObjects) {
233             final GaugeMonitorObservedObject gmo =
234                 (GaugeMonitorObservedObject) o;
235             gmo.setStatus(RISING_OR_FALLING);
236             gmo.setPreviousScanGauge(null);
237         }
238         doStart();
239     }
240 
241     /**
242      * Stops the gauge monitor.
243      */
stop()244     public synchronized void stop() {
245         doStop();
246     }
247 
248     // GETTERS AND SETTERS
249     //--------------------
250 
251     /**
252      * Gets the derived gauge of the specified object, if this object is
253      * contained in the set of observed MBeans, or <code>null</code> otherwise.
254      *
255      * @param object the name of the MBean.
256      *
257      * @return The derived gauge of the specified object.
258      *
259      */
260     @Override
getDerivedGauge(ObjectName object)261     public synchronized Number getDerivedGauge(ObjectName object) {
262         return (Number) super.getDerivedGauge(object);
263     }
264 
265     /**
266      * Gets the derived gauge timestamp of the specified object, if
267      * this object is contained in the set of observed MBeans, or
268      * <code>0</code> otherwise.
269      *
270      * @param object the name of the object whose derived gauge
271      * timestamp is to be returned.
272      *
273      * @return The derived gauge timestamp of the specified object.
274      *
275      */
276     @Override
getDerivedGaugeTimeStamp(ObjectName object)277     public synchronized long getDerivedGaugeTimeStamp(ObjectName object) {
278         return super.getDerivedGaugeTimeStamp(object);
279     }
280 
281     /**
282      * Returns the derived gauge of the first object in the set of
283      * observed MBeans.
284      *
285      * @return The derived gauge.
286      *
287      * @deprecated As of JMX 1.2, replaced by
288      * {@link #getDerivedGauge(ObjectName)}
289      */
290     @Deprecated
getDerivedGauge()291     public synchronized Number getDerivedGauge() {
292         if (observedObjects.isEmpty()) {
293             return null;
294         } else {
295             return (Number) observedObjects.get(0).getDerivedGauge();
296         }
297     }
298 
299     /**
300      * Gets the derived gauge timestamp of the first object in the set
301      * of observed MBeans.
302      *
303      * @return The derived gauge timestamp.
304      *
305      * @deprecated As of JMX 1.2, replaced by
306      * {@link #getDerivedGaugeTimeStamp(ObjectName)}
307      */
308     @Deprecated
getDerivedGaugeTimeStamp()309     public synchronized long getDerivedGaugeTimeStamp() {
310         if (observedObjects.isEmpty()) {
311             return 0;
312         } else {
313             return observedObjects.get(0).getDerivedGaugeTimeStamp();
314         }
315     }
316 
317     /**
318      * Gets the high threshold value common to all observed MBeans.
319      *
320      * @return The high threshold value.
321      *
322      * @see #setThresholds
323      */
getHighThreshold()324     public synchronized Number getHighThreshold() {
325         return highThreshold;
326     }
327 
328     /**
329      * Gets the low threshold value common to all observed MBeans.
330      *
331      * @return The low threshold value.
332      *
333      * @see #setThresholds
334      */
getLowThreshold()335     public synchronized Number getLowThreshold() {
336         return lowThreshold;
337     }
338 
339     /**
340      * Sets the high and the low threshold values common to all
341      * observed MBeans.
342      *
343      * @param highValue The high threshold value.
344      * @param lowValue The low threshold value.
345      *
346      * @exception IllegalArgumentException The specified high/low
347      * threshold is null or the low threshold is greater than the high
348      * threshold or the high threshold and the low threshold are not
349      * of the same type.
350      *
351      * @see #getHighThreshold
352      * @see #getLowThreshold
353      */
setThresholds(Number highValue, Number lowValue)354     public synchronized void setThresholds(Number highValue, Number lowValue)
355         throws IllegalArgumentException {
356 
357         if ((highValue == null) || (lowValue == null)) {
358             throw new IllegalArgumentException("Null threshold value");
359         }
360 
361         if (highValue.getClass() != lowValue.getClass()) {
362             throw new IllegalArgumentException("Different type " +
363                                                "threshold values");
364         }
365 
366         if (isFirstStrictlyGreaterThanLast(lowValue, highValue,
367                                            highValue.getClass().getName())) {
368             throw new IllegalArgumentException("High threshold less than " +
369                                                "low threshold");
370         }
371 
372         if (highThreshold.equals(highValue) && lowThreshold.equals(lowValue))
373             return;
374         highThreshold = highValue;
375         lowThreshold = lowValue;
376 
377         // Reset values.
378         //
379         int index = 0;
380         for (ObservedObject o : observedObjects) {
381             resetAlreadyNotified(o, index++, THRESHOLD_ERROR_NOTIFIED);
382             final GaugeMonitorObservedObject gmo =
383                 (GaugeMonitorObservedObject) o;
384             gmo.setStatus(RISING_OR_FALLING);
385         }
386     }
387 
388     /**
389      * Gets the high notification's on/off switch value common to all
390      * observed MBeans.
391      *
392      * @return <CODE>true</CODE> if the gauge monitor notifies when
393      * exceeding the high threshold, <CODE>false</CODE> otherwise.
394      *
395      * @see #setNotifyHigh
396      */
getNotifyHigh()397     public synchronized boolean getNotifyHigh() {
398         return notifyHigh;
399     }
400 
401     /**
402      * Sets the high notification's on/off switch value common to all
403      * observed MBeans.
404      *
405      * @param value The high notification's on/off switch value.
406      *
407      * @see #getNotifyHigh
408      */
setNotifyHigh(boolean value)409     public synchronized void setNotifyHigh(boolean value) {
410         if (notifyHigh == value)
411             return;
412         notifyHigh = value;
413     }
414 
415     /**
416      * Gets the low notification's on/off switch value common to all
417      * observed MBeans.
418      *
419      * @return <CODE>true</CODE> if the gauge monitor notifies when
420      * exceeding the low threshold, <CODE>false</CODE> otherwise.
421      *
422      * @see #setNotifyLow
423      */
getNotifyLow()424     public synchronized boolean getNotifyLow() {
425         return notifyLow;
426     }
427 
428     /**
429      * Sets the low notification's on/off switch value common to all
430      * observed MBeans.
431      *
432      * @param value The low notification's on/off switch value.
433      *
434      * @see #getNotifyLow
435      */
setNotifyLow(boolean value)436     public synchronized void setNotifyLow(boolean value) {
437         if (notifyLow == value)
438             return;
439         notifyLow = value;
440     }
441 
442     /**
443      * Gets the difference mode flag value common to all observed MBeans.
444      *
445      * @return <CODE>true</CODE> if the difference mode is used,
446      * <CODE>false</CODE> otherwise.
447      *
448      * @see #setDifferenceMode
449      */
getDifferenceMode()450     public synchronized boolean getDifferenceMode() {
451         return differenceMode;
452     }
453 
454     /**
455      * Sets the difference mode flag value common to all observed MBeans.
456      *
457      * @param value The difference mode flag value.
458      *
459      * @see #getDifferenceMode
460      */
setDifferenceMode(boolean value)461     public synchronized void setDifferenceMode(boolean value) {
462         if (differenceMode == value)
463             return;
464         differenceMode = value;
465 
466         // Reset values.
467         //
468         for (ObservedObject o : observedObjects) {
469             final GaugeMonitorObservedObject gmo =
470                 (GaugeMonitorObservedObject) o;
471             gmo.setStatus(RISING_OR_FALLING);
472             gmo.setPreviousScanGauge(null);
473         }
474     }
475 
476    /**
477      * Returns a <CODE>NotificationInfo</CODE> object containing the
478      * name of the Java class of the notification and the notification
479      * types sent by the gauge monitor.
480      */
481     @Override
getNotificationInfo()482     public MBeanNotificationInfo[] getNotificationInfo() {
483         return notifsInfo.clone();
484     }
485 
486     /*
487      * ------------------------------------------
488      *  PRIVATE METHODS
489      * ------------------------------------------
490      */
491 
492     /**
493      * Updates the derived gauge attribute of the observed object.
494      *
495      * @param scanGauge The value of the observed attribute.
496      * @param o The observed object.
497      * @return <CODE>true</CODE> if the derived gauge value is valid,
498      * <CODE>false</CODE> otherwise.  The derived gauge value is
499      * invalid when the differenceMode flag is set to
500      * <CODE>true</CODE> and it is the first notification (so we
501      * haven't 2 consecutive values to update the derived gauge).
502      */
updateDerivedGauge( Object scanGauge, GaugeMonitorObservedObject o)503     private synchronized boolean updateDerivedGauge(
504         Object scanGauge, GaugeMonitorObservedObject o) {
505 
506         boolean is_derived_gauge_valid;
507 
508         // The gauge difference mode is used.
509         //
510         if (differenceMode) {
511 
512             // The previous scan gauge has been initialized.
513             //
514             if (o.getPreviousScanGauge() != null) {
515                 setDerivedGaugeWithDifference((Number)scanGauge, o);
516                 is_derived_gauge_valid = true;
517             }
518             // The previous scan gauge has not been initialized.
519             // We cannot update the derived gauge...
520             //
521             else {
522                 is_derived_gauge_valid = false;
523             }
524             o.setPreviousScanGauge((Number)scanGauge);
525         }
526         // The gauge difference mode is not used.
527         //
528         else {
529             o.setDerivedGauge((Number)scanGauge);
530             is_derived_gauge_valid = true;
531         }
532 
533         return is_derived_gauge_valid;
534     }
535 
536     /**
537      * Updates the notification attribute of the observed object
538      * and notifies the listeners only once if the notify flag
539      * is set to <CODE>true</CODE>.
540      * @param o The observed object.
541      */
updateNotifications( GaugeMonitorObservedObject o)542     private synchronized MonitorNotification updateNotifications(
543         GaugeMonitorObservedObject o) {
544 
545         MonitorNotification n = null;
546 
547         // Send high notification if notifyHigh is true.
548         // Send low notification if notifyLow is true.
549         //
550         if (o.getStatus() == RISING_OR_FALLING) {
551             if (isFirstGreaterThanLast((Number)o.getDerivedGauge(),
552                                        highThreshold,
553                                        o.getType())) {
554                 if (notifyHigh) {
555                     n = new MonitorNotification(
556                             THRESHOLD_HIGH_VALUE_EXCEEDED,
557                             this,
558                             0,
559                             0,
560                             "",
561                             null,
562                             null,
563                             null,
564                             highThreshold);
565                 }
566                 o.setStatus(FALLING);
567             } else if (isFirstGreaterThanLast(lowThreshold,
568                                               (Number)o.getDerivedGauge(),
569                                               o.getType())) {
570                 if (notifyLow) {
571                     n = new MonitorNotification(
572                             THRESHOLD_LOW_VALUE_EXCEEDED,
573                             this,
574                             0,
575                             0,
576                             "",
577                             null,
578                             null,
579                             null,
580                             lowThreshold);
581                 }
582                 o.setStatus(RISING);
583             }
584         } else {
585             if (o.getStatus() == RISING) {
586                 if (isFirstGreaterThanLast((Number)o.getDerivedGauge(),
587                                            highThreshold,
588                                            o.getType())) {
589                     if (notifyHigh) {
590                         n = new MonitorNotification(
591                                 THRESHOLD_HIGH_VALUE_EXCEEDED,
592                                 this,
593                                 0,
594                                 0,
595                                 "",
596                                 null,
597                                 null,
598                                 null,
599                                 highThreshold);
600                     }
601                     o.setStatus(FALLING);
602                 }
603             } else if (o.getStatus() == FALLING) {
604                 if (isFirstGreaterThanLast(lowThreshold,
605                                            (Number)o.getDerivedGauge(),
606                                            o.getType())) {
607                     if (notifyLow) {
608                         n = new MonitorNotification(
609                                 THRESHOLD_LOW_VALUE_EXCEEDED,
610                                 this,
611                                 0,
612                                 0,
613                                 "",
614                                 null,
615                                 null,
616                                 null,
617                                 lowThreshold);
618                     }
619                     o.setStatus(RISING);
620                 }
621             }
622         }
623 
624         return n;
625     }
626 
627     /**
628      * Sets the derived gauge when the differenceMode flag is set to
629      * <CODE>true</CODE>.  Both integer and floating-point types are
630      * allowed.
631      *
632      * @param scanGauge The value of the observed attribute.
633      * @param o The observed object.
634      */
setDerivedGaugeWithDifference( Number scanGauge, GaugeMonitorObservedObject o)635     private synchronized void setDerivedGaugeWithDifference(
636         Number scanGauge, GaugeMonitorObservedObject o) {
637         Number prev = o.getPreviousScanGauge();
638         Number der;
639         switch (o.getType()) {
640         case INTEGER:
641             der = Integer.valueOf(((Integer)scanGauge).intValue() -
642                                   ((Integer)prev).intValue());
643             break;
644         case BYTE:
645             der = Byte.valueOf((byte)(((Byte)scanGauge).byteValue() -
646                                       ((Byte)prev).byteValue()));
647             break;
648         case SHORT:
649             der = Short.valueOf((short)(((Short)scanGauge).shortValue() -
650                                         ((Short)prev).shortValue()));
651             break;
652         case LONG:
653             der = Long.valueOf(((Long)scanGauge).longValue() -
654                                ((Long)prev).longValue());
655             break;
656         case FLOAT:
657             der = Float.valueOf(((Float)scanGauge).floatValue() -
658                                 ((Float)prev).floatValue());
659             break;
660         case DOUBLE:
661             der = Double.valueOf(((Double)scanGauge).doubleValue() -
662                                  ((Double)prev).doubleValue());
663             break;
664         default:
665             // Should never occur...
666             MONITOR_LOGGER.log(Level.TRACE,
667                     "the threshold type is invalid");
668             return;
669         }
670         o.setDerivedGauge(der);
671     }
672 
673     /**
674      * Tests if the first specified Number is greater than or equal to
675      * the last.  Both integer and floating-point types are allowed.
676      *
677      * @param greater The first Number to compare with the second.
678      * @param less The second Number to compare with the first.
679      * @param type The number type.
680      * @return <CODE>true</CODE> if the first specified Number is
681      * greater than or equal to the last, <CODE>false</CODE>
682      * otherwise.
683      */
isFirstGreaterThanLast(Number greater, Number less, NumericalType type)684     private boolean isFirstGreaterThanLast(Number greater,
685                                            Number less,
686                                            NumericalType type) {
687 
688         switch (type) {
689         case INTEGER:
690         case BYTE:
691         case SHORT:
692         case LONG:
693             return (greater.longValue() >= less.longValue());
694         case FLOAT:
695         case DOUBLE:
696             return (greater.doubleValue() >= less.doubleValue());
697         default:
698             // Should never occur...
699             MONITOR_LOGGER.log(Level.TRACE,
700                     "the threshold type is invalid");
701             return false;
702         }
703     }
704 
705     /**
706      * Tests if the first specified Number is strictly greater than the last.
707      * Both integer and floating-point types are allowed.
708      *
709      * @param greater The first Number to compare with the second.
710      * @param less The second Number to compare with the first.
711      * @param className The number class name.
712      * @return <CODE>true</CODE> if the first specified Number is
713      * strictly greater than the last, <CODE>false</CODE> otherwise.
714      */
isFirstStrictlyGreaterThanLast(Number greater, Number less, String className)715     private boolean isFirstStrictlyGreaterThanLast(Number greater,
716                                                    Number less,
717                                                    String className) {
718 
719         if (className.equals("java.lang.Integer") ||
720             className.equals("java.lang.Byte") ||
721             className.equals("java.lang.Short") ||
722             className.equals("java.lang.Long")) {
723 
724             return (greater.longValue() > less.longValue());
725         }
726         else if (className.equals("java.lang.Float") ||
727                  className.equals("java.lang.Double")) {
728 
729             return (greater.doubleValue() > less.doubleValue());
730         }
731         else {
732             // Should never occur...
733             MONITOR_LOGGER.log(Level.TRACE,
734                     "the threshold type is invalid");
735             return false;
736         }
737     }
738 
739     /*
740      * ------------------------------------------
741      *  PACKAGE METHODS
742      * ------------------------------------------
743      */
744 
745     /**
746      * Factory method for ObservedObject creation.
747      *
748      * @since 1.6
749      */
750     @Override
createObservedObject(ObjectName object)751     ObservedObject createObservedObject(ObjectName object) {
752         final GaugeMonitorObservedObject gmo =
753             new GaugeMonitorObservedObject(object);
754         gmo.setStatus(RISING_OR_FALLING);
755         gmo.setPreviousScanGauge(null);
756         return gmo;
757     }
758 
759     /**
760      * This method globally sets the derived gauge type for the given
761      * "object" and "attribute" after checking that the type of the
762      * supplied observed attribute value is one of the value types
763      * supported by this monitor.
764      */
765     @Override
isComparableTypeValid(ObjectName object, String attribute, Comparable<?> value)766     synchronized boolean isComparableTypeValid(ObjectName object,
767                                                String attribute,
768                                                Comparable<?> value) {
769         final GaugeMonitorObservedObject o =
770             (GaugeMonitorObservedObject) getObservedObject(object);
771         if (o == null)
772             return false;
773 
774         // Check that the observed attribute is either of type
775         // "Integer" or "Float".
776         //
777         if (value instanceof Integer) {
778             o.setType(INTEGER);
779         } else if (value instanceof Byte) {
780             o.setType(BYTE);
781         } else if (value instanceof Short) {
782             o.setType(SHORT);
783         } else if (value instanceof Long) {
784             o.setType(LONG);
785         } else if (value instanceof Float) {
786             o.setType(FLOAT);
787         } else if (value instanceof Double) {
788             o.setType(DOUBLE);
789         } else {
790             return false;
791         }
792         return true;
793     }
794 
795     @Override
getDerivedGaugeFromComparable( ObjectName object, String attribute, Comparable<?> value)796     synchronized Comparable<?> getDerivedGaugeFromComparable(
797                                                   ObjectName object,
798                                                   String attribute,
799                                                   Comparable<?> value) {
800         final GaugeMonitorObservedObject o =
801             (GaugeMonitorObservedObject) getObservedObject(object);
802         if (o == null)
803             return null;
804 
805         // Update the derived gauge attributes and check the
806         // validity of the new value. The derived gauge value
807         // is invalid when the differenceMode flag is set to
808         // true and it is the first notification, i.e. we
809         // haven't got 2 consecutive values to update the
810         // derived gauge.
811         //
812         o.setDerivedGaugeValid(updateDerivedGauge(value, o));
813 
814         return (Comparable<?>) o.getDerivedGauge();
815     }
816 
817     @Override
onErrorNotification(MonitorNotification notification)818     synchronized void onErrorNotification(MonitorNotification notification) {
819         final GaugeMonitorObservedObject o = (GaugeMonitorObservedObject)
820             getObservedObject(notification.getObservedObject());
821         if (o == null)
822             return;
823 
824         // Reset values.
825         //
826         o.setStatus(RISING_OR_FALLING);
827         o.setPreviousScanGauge(null);
828     }
829 
830     @Override
buildAlarmNotification( ObjectName object, String attribute, Comparable<?> value)831     synchronized MonitorNotification buildAlarmNotification(
832                                                ObjectName object,
833                                                String attribute,
834                                                Comparable<?> value) {
835         final GaugeMonitorObservedObject o =
836             (GaugeMonitorObservedObject) getObservedObject(object);
837         if (o == null)
838             return null;
839 
840         // Notify the listeners if the updated derived
841         // gauge value is valid.
842         //
843         final MonitorNotification alarm;
844         if (o.getDerivedGaugeValid())
845             alarm = updateNotifications(o);
846         else
847             alarm = null;
848         return alarm;
849     }
850 
851     /**
852      * Tests if the threshold high and threshold low are both of the
853      * same type as the gauge.  Both integer and floating-point types
854      * are allowed.
855      *
856      * Note:
857      *   If the optional lowThreshold or highThreshold have not been
858      *   initialized, their default value is an Integer object with
859      *   a value equal to zero.
860      *
861      * @param object The observed object.
862      * @param attribute The observed attribute.
863      * @param value The sample value.
864      * @return <CODE>true</CODE> if type is the same,
865      * <CODE>false</CODE> otherwise.
866      */
867     @Override
isThresholdTypeValid(ObjectName object, String attribute, Comparable<?> value)868     synchronized boolean isThresholdTypeValid(ObjectName object,
869                                               String attribute,
870                                               Comparable<?> value) {
871         final GaugeMonitorObservedObject o =
872             (GaugeMonitorObservedObject) getObservedObject(object);
873         if (o == null)
874             return false;
875 
876         Class<? extends Number> c = classForType(o.getType());
877         return (isValidForType(highThreshold, c) &&
878                 isValidForType(lowThreshold, c));
879     }
880 }
881