/* * @(#)GaugeMonitor.java 1.73 04/05/18 * * Copyright 2004 Sun Microsystems, Inc. All rights reserved. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. */ package javax.management.monitor; // java imports // import java.util.Date; import java.util.Timer; import java.util.TimerTask; // RI imports // import javax.management.ObjectName; import javax.management.MBeanNotificationInfo; import javax.management.AttributeNotFoundException; import javax.management.InstanceNotFoundException; import javax.management.MBeanException; import javax.management.ReflectionException; /** * Defines a monitor MBean designed to observe the values of a gauge attribute. * *

A gauge monitor observes an attribute that is continuously * variable with time. A gauge monitor sends notifications as * follows: * *

* * This provides a hysteresis mechanism to avoid repeated triggering * of notifications when the attribute value makes small oscillations * around the high or low threshold value. * *

If the gauge difference mode is used, the value of the derived * gauge is calculated as the difference between the observed gauge * values for two successive observations. * *
The derived gauge value (V[t]) is calculated using the following method: *

* * This implementation of the gauge monitor requires the observed * attribute to be of the type integer or floating-point * (Byte, Integer, Short, * Long, Float, Double). * * @version 1.73 05/18/04 * @author Sun Microsystems, Inc * * @since 1.5 */ public class GaugeMonitor extends Monitor implements GaugeMonitorMBean { /* * ------------------------------------------ * PRIVATE VARIABLES * ------------------------------------------ */ private static final Integer INTEGER_ZERO = new Integer(0); /** * Gauge high threshold. *
The default value is a null Integer object. */ private Number highThreshold = INTEGER_ZERO; /** * Gauge low threshold. *
The default value is a null Integer object. */ private Number lowThreshold = INTEGER_ZERO; /** * Flag indicating if the gauge monitor notifies when exceeding * the high threshold. * *
The default value is set to false. */ private boolean notifyHigh = false; /** * Flag indicating if the gauge monitor notifies when exceeding * the low threshold. * *
The default value is set to false. */ private boolean notifyLow = false; /** * Flag indicating if the gauge difference mode is used. If the * gauge difference mode is used, the derived gauge is the * difference between two consecutive observed values. Otherwise, * the derived gauge is directly the value of the observed * attribute. * *
The default value is set to false. */ private boolean differenceMode = false; /** * Derived gauges. *
Each element in this array corresponds to an observed * object in the list. */ private Number derivedGauge[] = new Number[capacityIncrement]; /** * Derived gauge timestamps. *
Each element in this array corresponds to an observed * object in the list. */ private long derivedGaugeTimestamp[] = new long[capacityIncrement]; /** * Scan gauge values captured by the previous observation. *
Each element in this array corresponds to an observed * object in the list. */ private Number previousScanGauge[] = new Number[capacityIncrement]; /** * This attribute is used to handle the hysteresis mechanism. *
Each element in this array corresponds to an observed * object in the list. */ private int status[] = new int[capacityIncrement]; /** * This attribute is used to keep the derived gauge type. *
Each element in this array corresponds to an observed * object in the list. */ private int type[] = new int[capacityIncrement]; // Flags needed to implement the hysteresis mechanism. // private static final int RISING = 0; private static final int FALLING = 1; private static final int RISING_OR_FALLING = 2; // Flags needed to keep trace of the derived gauge type. // Integer + floating-point types are allowed. // private static final int INTEGER = 0; private static final int BYTE = 1; private static final int SHORT = 2; private static final int LONG = 3; private static final int FLOAT = 4; private static final int DOUBLE = 5; // New flags defining possible gauge monitor errors. // Flag denoting that a notification has occurred after changing // the high/low threshold. This flag is used to check that the // high/low threshold type is the same as the gauge and that the // threshold high value is greater than the threshold low value at // the first notification time. // private static final int THRESHOLD_ERROR_NOTIFIED = 16; /** * Timer. */ private Timer timer = null; // TRACES & DEBUG //--------------- String makeDebugTag() { return "GaugeMonitor"; } /* * ------------------------------------------ * CONSTRUCTORS * ------------------------------------------ */ /** * Default constructor. */ public GaugeMonitor() { dbgTag = makeDebugTag(); } /* * ------------------------------------------ * PUBLIC METHODS * ------------------------------------------ */ /** * Starts the gauge monitor. */ public void start() { if (isTraceOn()) { trace("start", "start the gauge monitor"); } synchronized(this) { if (isActive) { if (isTraceOn()) { trace("start", "the gauge monitor is already activated"); } return; } isActive = true; // Reset values. // for (int i = 0; i < elementCount; i++) { status[i] = RISING_OR_FALLING; previousScanGauge[i] = null; } // Start the AlarmClock. // timer = new Timer(); timer.schedule(new GaugeAlarmClock(this), getGranularityPeriod(), getGranularityPeriod()); } } /** * Stops the gauge monitor. */ /* This method is not synchronized, because if it were there could be a deadlock with a thread that attempted to get the lock on the monitor before being interrupted or noticing that it had been interrupted. */ public void stop() { trace("stop", "stop the gauge monitor"); synchronized(this) { if (!isActive) { if (isTraceOn()) { trace("stop", "the counter monitor is already started"); } return; } isActive = false; // Stop the AlarmClock. // if (timer != null) { timer.cancel(); timer = null; } } } // GETTERS AND SETTERS //-------------------- /** * Sets the granularity period (in milliseconds). *
The default value of the granularity period is 10 seconds. * * @param period The granularity period value. * @exception java.lang.IllegalArgumentException The granularity * period is less than or equal to zero. * * @see Monitor#setGranularityPeriod(long) */ public synchronized void setGranularityPeriod(long period) throws IllegalArgumentException { super.setGranularityPeriod(period); // Reschedule timer task if timer is already running // if (isActive()) { timer.cancel(); timer = new Timer(); timer.schedule(new GaugeAlarmClock(this), getGranularityPeriod(), getGranularityPeriod()); } } /** * Gets the derived gauge of the specified object, if this object is * contained in the set of observed MBeans, or null otherwise. * * @param object the name of the MBean. * * @return The derived gauge of the specified object. * * @since.unbundled JMX 1.2 */ public synchronized Number getDerivedGauge(ObjectName object) { int index = indexOf(object); if (index != -1) return derivedGauge[index]; else return null; } /** * Gets the derived gauge timestamp of the specified object, if * this object is contained in the set of observed MBeans, or * null otherwise. * * @param object the name of the MBean. * * @return The derived gauge timestamp of the specified object. * * @since.unbundled JMX 1.2 */ public synchronized long getDerivedGaugeTimeStamp(ObjectName object) { int index = indexOf(object); if (index != -1) return derivedGaugeTimestamp[index]; else return 0; } /** * Returns the derived gauge of the first object in the set of * observed MBeans. * * @return The derived gauge. * @deprecated As of JMX 1.2, replaced by {@link #getDerivedGauge(ObjectName)} */ @Deprecated public synchronized Number getDerivedGauge() { return derivedGauge[0]; } /** * Gets the derived gauge timestamp of the first object in the set * of observed MBeans. * * @return The derived gauge timestamp. * @deprecated As of JMX 1.2, replaced by * {@link #getDerivedGaugeTimeStamp(ObjectName)} */ @Deprecated public synchronized long getDerivedGaugeTimeStamp() { return derivedGaugeTimestamp[0]; } /** * Gets the high threshold value common to all observed MBeans. * * @return The high threshold value. */ public synchronized Number getHighThreshold() { return highThreshold; } /** * Gets the low threshold value common to all observed MBeans. * * @return The low threshold value. */ public synchronized Number getLowThreshold() { return lowThreshold; } /** * Sets the high and the low threshold values common to all * observed MBeans. * * @param highValue The high threshold value. * @param lowValue The low threshold value. * * @exception IllegalArgumentException The specified high/low * threshold is null or the low threshold is greater than the high * threshold or the high threshold and the low threshold are not * of the same type. */ public synchronized void setThresholds(Number highValue, Number lowValue) throws IllegalArgumentException { if ((highValue == null) || (lowValue == null)) { throw new IllegalArgumentException("Null threshold value"); } if (highValue.getClass() != lowValue.getClass()) { throw new IllegalArgumentException("Different type " + "threshold values"); } if (isFirstStrictlyGreaterThanLast(lowValue, highValue, highValue.getClass().getName())) { throw new IllegalArgumentException("High threshold less than " + "low threshold"); } highThreshold = highValue; lowThreshold = lowValue; for (int i = 0; i < elementCount; i++) { resetAlreadyNotified(i, THRESHOLD_ERROR_NOTIFIED); // Reset values. // status[i] = RISING_OR_FALLING; } } /** * Gets the high notification's on/off switch value common to all * observed MBeans. * * @see #setNotifyHigh * * @return true if the gauge monitor notifies when * exceeding the high threshold, false otherwise. */ public synchronized boolean getNotifyHigh() { return notifyHigh; } /** * Sets the high notification's on/off switch value common to all * observed MBeans. * * @param value The high notification's on/off switch value. * * @see #getNotifyHigh */ public synchronized void setNotifyHigh(boolean value) { notifyHigh = value; } /** * Gets the low notification's on/off switch value common to all * observed MBeans. * * @return true if the gauge monitor notifies when * exceeding the low threshold, false otherwise. * * @see #setNotifyLow */ public synchronized boolean getNotifyLow() { return notifyLow; } /** * Sets the low notification's on/off switch value common to all * observed MBeans. * * @param value The low notification's on/off switch value. * * @see #getNotifyLow */ public synchronized void setNotifyLow(boolean value) { notifyLow = value; } /** * Gets the difference mode flag value common to all observed MBeans. * * @return true if the difference mode is used, * false otherwise. * * @see #setDifferenceMode */ public synchronized boolean getDifferenceMode() { return differenceMode; } /** * Sets the difference mode flag value common to all observed MBeans. * * @param value The difference mode flag value. * * @see #getDifferenceMode */ public synchronized void setDifferenceMode(boolean value) { differenceMode = value; // Reset values. // for (int i = 0; i < elementCount; i++) { status[i] = RISING_OR_FALLING; previousScanGauge[i] = null; } } /** * Returns a NotificationInfo object containing the * name of the Java class of the notification and the notification * types sent by the gauge monitor. */ public MBeanNotificationInfo[] getNotificationInfo() { String[] types = { MonitorNotification.RUNTIME_ERROR, MonitorNotification.OBSERVED_OBJECT_ERROR, MonitorNotification.OBSERVED_ATTRIBUTE_ERROR, MonitorNotification.OBSERVED_ATTRIBUTE_TYPE_ERROR, MonitorNotification.THRESHOLD_ERROR, MonitorNotification.THRESHOLD_HIGH_VALUE_EXCEEDED, MonitorNotification.THRESHOLD_LOW_VALUE_EXCEEDED}; MBeanNotificationInfo[] notifsInfo = { new MBeanNotificationInfo(types, "javax.management.monitor.MonitorNotification", "Notifications sent by the GaugeMonitor MBean") }; return notifsInfo; } /* * ------------------------------------------ * PRIVATE METHODS * ------------------------------------------ */ /** * Updates the derived gauge and the derived gauge timestamp attributes * of the observed object at the specified index. * * @param scanGauge The value of the observed attribute. * @param index The index of the observed object. * @return true if the derived gauge value is valid, * false otherwise. The derived gauge value is * invalid when the differenceMode flag is set to * true and it is the first notification (so we * haven't 2 consecutive values to update the derived gauge). */ private synchronized boolean updateDerivedGauge(Object scanGauge, int index) { boolean is_derived_gauge_valid; derivedGaugeTimestamp[index] = System.currentTimeMillis(); // The gauge difference mode is used. // if (differenceMode) { // The previous scan gauge has been initialized. // if (previousScanGauge[index] != null) { setDerivedGaugeWithDifference((Number)scanGauge, index); is_derived_gauge_valid = true; } // The previous scan gauge has not been initialized. // We cannot update the derived gauge... // else { is_derived_gauge_valid = false; } previousScanGauge[index] = (Number)scanGauge; } // The gauge difference mode is not used. // else { derivedGauge[index] = (Number)scanGauge; is_derived_gauge_valid = true; } return is_derived_gauge_valid; } /** * Updates the notification attribute of the observed object at the * specified index and notifies the listeners only once if the notify flag * is set to true. * @param index The index of the observed object. */ private void updateNotifications(int index) { boolean sendNotify = false; String notifType = null; long timeStamp = 0; String msg = null; Object derGauge = null; Object trigger = null; // Send high notification if notifyHigh is true. // Send low notification if notifyLow is true. // synchronized(this) { if (status[index] == RISING_OR_FALLING) { if (isFirstGreaterThanLast(derivedGauge[index], highThreshold, type[index])) { if (notifyHigh) { sendNotify = true; notifType = MonitorNotification.THRESHOLD_HIGH_VALUE_EXCEEDED; timeStamp = derivedGaugeTimestamp[index]; msg = ""; derGauge = derivedGauge[index]; trigger = highThreshold; } status[index] = FALLING; } else if (isFirstGreaterThanLast(lowThreshold, derivedGauge[index], type[index])) { if (notifyLow) { sendNotify = true; notifType = MonitorNotification.THRESHOLD_LOW_VALUE_EXCEEDED; timeStamp = derivedGaugeTimestamp[index]; msg =""; derGauge = derivedGauge[index]; trigger = lowThreshold; } status[index] = RISING; } } else { if (status[index] == RISING) { if (isFirstGreaterThanLast(derivedGauge[index], highThreshold, type[index])) { if (notifyHigh) { sendNotify = true; notifType = MonitorNotification.THRESHOLD_HIGH_VALUE_EXCEEDED; timeStamp = derivedGaugeTimestamp[index]; msg = ""; derGauge = derivedGauge[index]; trigger = highThreshold; } status[index] = FALLING; } } else if (status[index] == FALLING) { if (isFirstGreaterThanLast(lowThreshold, derivedGauge[index], type[index])) { if (notifyLow) { sendNotify = true; notifType = MonitorNotification.THRESHOLD_LOW_VALUE_EXCEEDED; timeStamp = derivedGaugeTimestamp[index]; msg = ""; derGauge = derivedGauge[index]; trigger = lowThreshold; } status[index] = RISING; } } } } if (sendNotify) { sendNotification(notifType, timeStamp, msg, derGauge, trigger, index); } } /** * Tests if the threshold high and threshold low are both of the * same type as the gauge. Both integer and floating-point types * are allowed. * * Note: * If the optional lowThreshold or highThreshold have not been * initialized, their default value is an Integer object with * a value equal to zero. * * @param index The index of the observed object. * @return true if type is the same, * false otherwise. */ private synchronized boolean isThresholdTypeValid(int index) { switch(type[index]) { case INTEGER: return (((highThreshold == INTEGER_ZERO) || (highThreshold instanceof Integer)) && ((lowThreshold == INTEGER_ZERO) || (lowThreshold instanceof Integer))); case BYTE: return (((highThreshold == INTEGER_ZERO) || (highThreshold instanceof Byte)) && ((lowThreshold == INTEGER_ZERO) || (lowThreshold instanceof Byte))); case SHORT: return (((highThreshold == INTEGER_ZERO) || (highThreshold instanceof Short)) && ((lowThreshold == INTEGER_ZERO) || (lowThreshold instanceof Short))); case LONG: return (((highThreshold == INTEGER_ZERO) || (highThreshold instanceof Long)) && ((lowThreshold == INTEGER_ZERO) || (lowThreshold instanceof Long))); case FLOAT: return (((highThreshold == INTEGER_ZERO) || (highThreshold instanceof Float)) && ((lowThreshold == INTEGER_ZERO) || (lowThreshold instanceof Float))); case DOUBLE: return (((highThreshold == INTEGER_ZERO) || (highThreshold instanceof Double)) && ((lowThreshold == INTEGER_ZERO) || (lowThreshold instanceof Double))); default: // Should never occur... if (isDebugOn()) { debug("isThresholdTypeValid", "The threshold type is invalid"); } return false; } } /** * Sets the derived gauge when the differenceMode flag is set to * true. Both integer and floating-point types are * allowed. * * @param scanGauge The value of the observed attribute. * @param index The index of the observed object. */ private synchronized void setDerivedGaugeWithDifference(Number scanGauge, int index) { Number prev = previousScanGauge[index]; Number der; switch (type[index]) { case INTEGER: der = new Integer(((Integer)scanGauge).intValue() - ((Integer)prev).intValue()); break; case BYTE: der = new Byte((byte)(((Byte)scanGauge).byteValue() - ((Byte)prev).byteValue())); break; case SHORT: der = new Short((short)(((Short)scanGauge).shortValue() - ((Short)prev).shortValue())); break; case LONG: der = new Long(((Long)scanGauge).longValue() - ((Long)prev).longValue()); break; case FLOAT: der = new Float(((Float)scanGauge).floatValue() - ((Float)prev).floatValue()); break; case DOUBLE: der = new Double(((Double)scanGauge).doubleValue() - ((Double)prev).doubleValue()); default: // Should never occur... if (isDebugOn()) { debug("setDerivedGaugeWithDifference", "the threshold type is invalid"); } return; } derivedGauge[index] = der; } /** * Tests if the first specified Number is greater than or equal to * the last. Both integer and floating-point types are allowed. * * @param greater The first Number to compare with the second. * @param less The second Number to compare with the first. * @param type The number type. * @return true if the first specified Number is * greater than or equal to the last, false * otherwise. */ private boolean isFirstGreaterThanLast(Number greater, Number less, int type) { switch(type) { case INTEGER: case BYTE: case SHORT: case LONG: return (greater.longValue() >= less.longValue()); case FLOAT: case DOUBLE: return (greater.doubleValue() >= less.doubleValue()); default: // Should never occur... if (isDebugOn()) { debug("isFirstGreaterThanLast", "the threshold type is invalid"); } return false; } } /** * Tests if the first specified Number is strictly greater than the last. * Both integer and floating-point types are allowed. * * @param greater The first Number to compare with the second. * @param less The second Number to compare with the first. * @param className The number class name. * @return true if the first specified Number is * strictly greater than the last, false otherwise. */ private boolean isFirstStrictlyGreaterThanLast(Number greater, Number less, String className) { if (className.equals("java.lang.Integer") || className.equals("java.lang.Byte") || className.equals("java.lang.Short") || className.equals("java.lang.Long")) { return (greater.longValue() > less.longValue()); } else if (className.equals("java.lang.Float") || className.equals("java.lang.Double")) { return (greater.doubleValue() > less.doubleValue()); } else { // Should never occur... if (isDebugOn()) { debug("isFirstStrictlyGreaterThanLast", "the threshold type is invalid"); } return false; } } /* * ------------------------------------------ * PACKAGE METHODS * ------------------------------------------ */ /** * This method is called by the gauge monitor each time * the granularity period has been exceeded. * @param index The index of the observed object. */ void notifyAlarmClock(int index) { long timeStamp = 0; String msg = null; Object derGauge = null; Object scan_gauge = null; String notif_type = null; synchronized(this) { if (!isActive()) return; // Check if the observed object and observed attribute are valid. // // Check that neither the observed object nor the observed // attribute are null. If the observed object or observed // attribute is null, this means that the monitor started // before a complete initialization and nothing is done. // if ((getObservedObject(index) == null) || (getObservedAttribute() == null)) return; // Check that the observed object is registered in the // MBean server and that the observed attribute belongs to // the observed object. // try { scan_gauge = server.getAttribute(getObservedObject(index), getObservedAttribute()); if (scan_gauge == null) return; } catch (NullPointerException np_ex) { if (alreadyNotified(index, RUNTIME_ERROR_NOTIFIED)) return; else { notif_type = MonitorNotification.RUNTIME_ERROR; setAlreadyNotified(index, RUNTIME_ERROR_NOTIFIED); msg = "The gauge monitor must be registered in " + "the MBean server."; } } catch (InstanceNotFoundException inf_ex) { if (alreadyNotified(index, OBSERVED_OBJECT_ERROR_NOTIFIED)) return; else { notif_type = MonitorNotification.OBSERVED_OBJECT_ERROR; setAlreadyNotified(index, OBSERVED_OBJECT_ERROR_NOTIFIED); msg = "The observed object must be registered in " + "the MBean server."; } } catch (AttributeNotFoundException anf_ex) { if (alreadyNotified(index, OBSERVED_ATTRIBUTE_ERROR_NOTIFIED)) return; else { notif_type = MonitorNotification.OBSERVED_ATTRIBUTE_ERROR; setAlreadyNotified(index, OBSERVED_ATTRIBUTE_ERROR_NOTIFIED); msg = "The observed attribute must be accessible in " + "the observed object."; } } catch (MBeanException mb_ex) { if (alreadyNotified(index, RUNTIME_ERROR_NOTIFIED)) return; else { notif_type = MonitorNotification.RUNTIME_ERROR; setAlreadyNotified(index, RUNTIME_ERROR_NOTIFIED); msg = mb_ex.getMessage(); } } catch (ReflectionException ref_ex) { if (alreadyNotified(index, OBSERVED_ATTRIBUTE_ERROR_NOTIFIED)) return; else { notif_type = MonitorNotification.OBSERVED_ATTRIBUTE_ERROR; setAlreadyNotified(index, OBSERVED_ATTRIBUTE_ERROR_NOTIFIED); msg = ref_ex.getMessage(); } } if (msg == null) { // Check that the observed attribute is either of type // "Integer" or "Float". // if (scan_gauge instanceof Integer) { type[index] = INTEGER; } else if (scan_gauge instanceof Byte) { type[index] = BYTE; } else if (scan_gauge instanceof Short) { type[index] = SHORT; } else if (scan_gauge instanceof Long) { type[index] = LONG; } else if (scan_gauge instanceof Float) { type[index] = FLOAT; } else if (scan_gauge instanceof Double) { type[index] = DOUBLE; } else { if (alreadyNotified(index, OBSERVED_ATTRIBUTE_TYPE_ERROR_NOTIFIED)) return; else { notif_type = MonitorNotification.OBSERVED_ATTRIBUTE_TYPE_ERROR; setAlreadyNotified(index, OBSERVED_ATTRIBUTE_TYPE_ERROR_NOTIFIED); msg = "The observed attribute type must be an " + "integer type or a floating-point type."; } } } if (msg == null) { // Check that threshold high and threshold low are of // the same type as the gauge. // if (!isThresholdTypeValid(index)) { if (alreadyNotified(index, THRESHOLD_ERROR_NOTIFIED)) return; else { notif_type = MonitorNotification.THRESHOLD_ERROR; setAlreadyNotified(index, THRESHOLD_ERROR_NOTIFIED); msg = "The threshold high and threshold low must be " + "of the same type as the gauge."; } } } if (msg == null) { // Clear all already notified flags. // resetAllAlreadyNotified(index); // Update the derived gauge attributes and check // the validity of the new value. The derived // gauge value is invalid when the differenceMode // flag is set to true and it is the first // notification (so we haven't 2 consecutive // values to update the derived gauge). // boolean is_derived_gauge_valid = updateDerivedGauge(scan_gauge, index); // Notify the listeners if the updated derived // gauge value is valid. // if (is_derived_gauge_valid) updateNotifications(index); } else { // msg != null, will send an error notification timeStamp = derivedGaugeTimestamp[index]; derGauge = derivedGauge[index]; // Reset values. // status[index] = RISING_OR_FALLING; previousScanGauge[index] = null; } } if (msg != null) { sendNotification(notif_type, timeStamp, msg, derGauge, null, index); } } /** * This method is called when adding a new observed object in the vector. * It updates all the gauge specific arrays. * @param index The index of the observed object. */ synchronized void insertSpecificElementAt(int index) { // Update derivedGauge, derivedGaugeTimestamp, previousScanGauge, // status and type values. if (index != elementCount) throw new Error("Internal error: index != elementCount"); if (elementCount >= derivedGauge.length) { derivedGauge = expandArray(derivedGauge); previousScanGauge = expandArray(previousScanGauge); derivedGaugeTimestamp = expandArray(derivedGaugeTimestamp); status = expandArray(status); type = expandArray(type); } derivedGauge[index] = INTEGER_ZERO; previousScanGauge[index] = null; derivedGaugeTimestamp[index] = System.currentTimeMillis(); status[index] = RISING_OR_FALLING; type[index] = INTEGER; } /** * This method is called when removing an observed object from the vector. * It updates all the gauge specific arrays. * @param index The index of the observed object. */ synchronized void removeSpecificElementAt(int index) { if (index < 0 || index >= elementCount) return; // Update derivedGauge, derivedGaugeTimestamp, previousScanGauge, // status and type arrays. // removeElementAt(derivedGauge, index); removeElementAt(previousScanGauge, index); removeElementAt(derivedGaugeTimestamp, index); removeElementAt(status, index); removeElementAt(type, index); } /** * GaugeAlarmClock inner class: * This class provides a simple implementation of an alarm clock MBean. * The aim of this MBean is to set up an alarm which wakes up the * gauge monitor every granularity period. */ private static class GaugeAlarmClock extends TimerTask { GaugeMonitor listener = null; /* * ------------------------------------------ * CONSTRUCTORS * ------------------------------------------ */ public GaugeAlarmClock(GaugeMonitor listener) { this.listener = listener; } /* * ------------------------------------------ * PUBLIC METHODS * ------------------------------------------ */ /** * This method is called by the GaugeAlarmClock thread when it * is started. */ public void run() { if (listener.isActive()) { for (int i = 0; i < listener.elementCount; i++) { listener.notifyAlarmClock(i); } } } } }