/* * @(#)CounterMonitor.java 1.74 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; // jmx 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 counter * attribute. * *

A counter monitor sends a {@link * MonitorNotification#THRESHOLD_VALUE_EXCEEDED threshold * notification} when the value of the counter reaches or exceeds a * threshold known as the comparison level. The notify flag must be * set to true. * *

In addition, an offset mechanism enables particular counting * intervals to be detected. If the offset value is not zero, * whenever the threshold is triggered by the counter value reaching a * comparison level, that comparison level is incremented by the * offset value. This is regarded as taking place instantaneously, * that is, before the count is incremented. Thus, for each level, * the threshold triggers an event notification every time the count * increases by an interval equal to the offset value. * *

If the counter can wrap around its maximum value, the modulus * needs to be specified. The modulus is the value at which the * counter is reset to zero. * *

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

* * This implementation of the counter monitor requires the observed * attribute to be of the type integer (Byte, * Integer, Short, Long). * * @version 1.74 05/18/04 * @author Sun Microsystems, Inc * * @since 1.5 */ public class CounterMonitor extends Monitor implements CounterMonitorMBean { /* * ------------------------------------------ * PRIVATE VARIABLES * ------------------------------------------ */ private static final Integer INTEGER_ZERO = new Integer(0); /** * Counter thresholds. *
Each element in this array corresponds to an observed * object in the list. */ private Number threshold[] = new Number[capacityIncrement]; /** * Counter modulus. *
The default value is a null Integer object. */ private Number modulus = INTEGER_ZERO; /** * Counter offset. *
The default value is a null Integer object. */ private Number offset = INTEGER_ZERO; /** * Flag indicating if the counter monitor notifies when exceeding * the threshold. The default value is set to * false. */ private boolean notify = false; /** * Flag indicating if the counter difference mode is used. If the * counter 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; /** * Initial counter threshold. This value is used to initialize * the threshold when a new object is added to the list and reset * the threshold to its initial value each time the counter * resets. */ private Number initThreshold = INTEGER_ZERO; /** * Derived gauges. * *
Each element in this array corresponds to an observed * object in the list. */ private Number derivedGauge[] = new Number[capacityIncrement]; /** * Derived gauge timestamp. *
Each element in this array corresponds to an observed * object in the list. */ private long derivedGaugeTimestamp[] = new long[capacityIncrement]; /** * Scan counter value captured by the previous observation. *
Each element in this array corresponds to an observed * object in the list. */ private Number previousScanCounter[] = new Number[capacityIncrement]; /** * Flag indicating if the modulus has been exceeded by the * threshold. This flag is used to reset the threshold once we * are sure that the counter has been resetted. *
Each element in this array corresponds to an observed * object in the list. */ private boolean modulusExceeded[] = new boolean[capacityIncrement]; /** * Derived gauge captured when the modulus has been exceeded by * the threshold. This value is used to check if the counter has * been resetted (in order to reset the threshold). *
Each element in this array corresponds to an observed * object in the list. */ private Number derivedGaugeExceeded[] = new Number[capacityIncrement]; /** * This flag is used to notify only once between two granularity * periods. *
Each element in this array corresponds to an observed * object in the list. */ private boolean eventAlreadyNotified[] = new boolean[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 keep trace of the derived gauge type. // Integer types only 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; // New flags defining possible counter monitor errors. // Flag denoting that a notification has occured after changing // the threshold. // This flag is used to check that the threshold, offset and // modulus types are the same as the counter. // private static final int THRESHOLD_ERROR_NOTIFIED = 16; /** * Timer. */ private Timer timer = null; // TRACES & DEBUG //--------------- String makeDebugTag() { return "CounterMonitor"; } /* * ------------------------------------------ * CONSTRUCTORS * ------------------------------------------ */ /** * Default constructor. */ public CounterMonitor() { dbgTag = makeDebugTag(); } /* * ------------------------------------------ * PUBLIC METHODS * ------------------------------------------ */ /** * Allows the counter monitor MBean to perform any operations it * needs before being unregistered by the MBean server. * *

Resets the threshold values. * * @exception java.lang.Exception */ public void preDeregister() throws java.lang.Exception { // Stop the CounterMonitor. // super.preDeregister(); if (isTraceOn()) { trace("preDeregister", "reset the threshold values"); } // Reset values for serialization. // synchronized (this) { for (int i = 0; i < elementCount; i++) { threshold[i] = initThreshold; } } } /** * Starts the counter monitor. */ public synchronized void start() { if (isTraceOn()) { trace("start", "start the counter monitor"); } if (isActive()) { if (isTraceOn()) { trace("start", "the counter monitor is already activated"); } return; } isActive = true; // Reset values. // for (int i = 0; i < elementCount; i++) { threshold[i] = initThreshold; modulusExceeded[i] = false; eventAlreadyNotified[i] = false; previousScanCounter[i] = null; } // Start the timer. // timer = new Timer(); timer.schedule(new CounterAlarmClock(this), getGranularityPeriod(), getGranularityPeriod()); } /** * Stops the counter 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 synchronized void stop() { if (isTraceOn()) { trace("stop", "stop the counter monitor"); } if (isTraceOn()) { trace("stop", "the counter monitor is not started"); return; } isActive = false; // Stop the timer. // 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 CounterAlarmClock(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 object whose derived gauge is to * be returned. * * @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 object whose derived gauge * timestamp is to be returned. * * @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; } /** * Gets the current threshold value of the specified object, if * this object is contained in the set of observed MBeans, or * null otherwise. * * @param object the name of the object whose threshold is to be * returned. * * @return The threshold value of the specified object. * * @see #setThreshold * * @since.unbundled JMX 1.2 */ public synchronized Number getThreshold(ObjectName object) { int index = indexOf(object); if (index != -1) return threshold[index]; else return null; } /** * Gets the initial threshold value common to all observed objects. * * @return The initial threshold. * * @see #setInitThreshold * * @since.unbundled JMX 1.2 */ public synchronized Number getInitThreshold() { return initThreshold; } /** * Sets the initial threshold value common to all observed objects. * *
The current threshold of every object in the set of * observed MBeans is updated consequently. * * @param value The initial threshold value. * @exception java.lang.IllegalArgumentException The specified * threshold is null or the threshold value is less than zero. * * @see #getInitThreshold * * @since.unbundled JMX 1.2 */ public synchronized void setInitThreshold(Number value) throws IllegalArgumentException { if (value == null) { throw new IllegalArgumentException("Null threshold"); } if (value.longValue() < 0L) { throw new IllegalArgumentException("Negative threshold"); } initThreshold = value; for (int i = 0; i < elementCount; i++) { threshold[i] = value; resetAlreadyNotified(i, THRESHOLD_ERROR_NOTIFIED); // Reset values. // modulusExceeded[i] = false; eventAlreadyNotified[i] = false; } } /** * 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 threshold value of the first object in the set of * observed MBeans. * * @return The threshold value. * * @see #setThreshold(Number) * * @deprecated As of JMX 1.2, replaced by {@link #getThreshold(ObjectName)} */ @Deprecated public synchronized Number getThreshold() { return threshold[0]; } /** * Sets the initial threshold value. * * @param value The initial threshold value. * @exception IllegalArgumentException The specified threshold is * null or the threshold value is less than zero. * * @see #getThreshold() * * @deprecated As of JMX 1.2, replaced by {@link #setInitThreshold} */ @Deprecated public synchronized void setThreshold(Number value) throws IllegalArgumentException { setInitThreshold(value); } /** * Gets the offset value common to all observed MBeans. * * @return The offset value. * * @see #setOffset */ public synchronized Number getOffset() { return offset; } /** * Sets the offset value common to all observed MBeans. * * @param value The offset value. * @exception java.lang.IllegalArgumentException The specified * offset is null or the offset value is less than zero. * * @see #getOffset */ public synchronized void setOffset(Number value) throws IllegalArgumentException { if (value == null) { throw new IllegalArgumentException("Null offset"); } if (value.longValue() < 0L) { throw new IllegalArgumentException("Negative offset"); } offset = value; for (int i = 0; i < elementCount; i++) { resetAlreadyNotified(i, THRESHOLD_ERROR_NOTIFIED); } } /** * Gets the modulus value common to all observed MBeans. * * @see #setModulus * * @return The modulus value. */ public synchronized Number getModulus() { return modulus; } /** * Sets the modulus value common to all observed MBeans. * * @param value The modulus value. * @exception java.lang.IllegalArgumentException The specified * modulus is null or the modulus value is less than zero. * * @see #getModulus */ public synchronized void setModulus(Number value) throws IllegalArgumentException { if (value == null) { throw new IllegalArgumentException("Null modulus"); } if (value.longValue() < 0L) { throw new IllegalArgumentException("Negative modulus"); } modulus = value; for (int i = 0; i < elementCount; i++) { resetAlreadyNotified(i, THRESHOLD_ERROR_NOTIFIED); // Reset values. // modulusExceeded[i] = false; } } /** * Gets the notification's on/off switch value common to all * observed MBeans. * * @return true if the counter monitor notifies when * exceeding the threshold, false otherwise. * * @see #setNotify */ public synchronized boolean getNotify() { return notify; } /** * Sets the notification's on/off switch value common to all * observed MBeans. * * @param value The notification's on/off switch value. * * @see #getNotify */ public synchronized void setNotify(boolean value) { notify = 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; for (int i = 0; i < elementCount; i++) { // Reset values. // threshold[i] = initThreshold; modulusExceeded[i] = false; eventAlreadyNotified[i] = false; previousScanCounter[i] = null; } } /** * Returns a NotificationInfo object containing the * name of the Java class of the notification and the notification * types sent by the counter 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_VALUE_EXCEEDED}; MBeanNotificationInfo[] notifsInfo = { new MBeanNotificationInfo(types, "javax.management.monitor.MonitorNotification", "Notifications sent by the CounterMonitor MBean") }; return notifsInfo; } /* * ------------------------------------------ * PRIVATE METHODS * ------------------------------------------ */ /** * Updates the derived gauge and the derived gauge timestamp attributes * of the observed object at the specified index. * * @param scanCounter 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 scanCounter, int index) { boolean is_derived_gauge_valid; derivedGaugeTimestamp[index] = System.currentTimeMillis(); // The counter difference mode is used. // if (differenceMode) { // The previous scan counter has been initialized. // if (previousScanCounter[index] != null) { setDerivedGaugeWithDifference((Number)scanCounter, null, index); // If derived gauge is negative it means that the // counter has wrapped around and the value of the // threshold needs to be reset to its initial value. // if (derivedGauge[index].longValue() < 0L) { if (modulus.longValue() > 0L) { setDerivedGaugeWithDifference((Number)scanCounter, (Number)modulus, index); } threshold[index] = initThreshold; eventAlreadyNotified[index] = false; } is_derived_gauge_valid = true; } // The previous scan counter has not been initialized. // We cannot update the derived gauge... // else { is_derived_gauge_valid = false; } previousScanCounter[index] = (Number)scanCounter; } // The counter difference mode is not used. // else { derivedGauge[index] = (Number)scanCounter; 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 sendNotif = false; String notifType = null; long timeStamp = 0; String msg = null; Object derGauge = null; Object trigger = null; synchronized(this) { // Send notification if notify is true. // if (!eventAlreadyNotified[index]) { if (derivedGauge[index].longValue() >= threshold[index].longValue()) { if (notify) { sendNotif = true; notifType = MonitorNotification.THRESHOLD_VALUE_EXCEEDED; timeStamp = derivedGaugeTimestamp[index]; msg = ""; derGauge = derivedGauge[index]; trigger = threshold[index]; } if (!differenceMode) { eventAlreadyNotified[index] = true; } } } else { if (isTraceOn()) { trace("updateNotifications", "the notification:" + "\n\tNotification observed object = " + getObservedObject(index) + "\n\tNotification observed attribute = " + getObservedAttribute() + "\n\tNotification derived gauge = " + derivedGauge[index] + "\nhas already been sent"); } } } if (sendNotif) { sendNotification(notifType, timeStamp, msg, derGauge, trigger, index); } } /** * Updates the threshold attribute of the observed object at the * specified index. * @param index The index of the observed object. */ private synchronized void updateThreshold(int index) { // Calculate the new threshold value if the threshold has been // exceeded and if the offset value is greater than zero. // if (derivedGauge[index].longValue() >= threshold[index].longValue()) { if (offset.longValue() > 0L) { // Increment the threshold until its value is greater // than the one for the current derived gauge. // long threshold_value = threshold[index].longValue(); while (derivedGauge[index].longValue() >= threshold_value) { threshold_value += offset.longValue(); } // Set threshold attribute. // switch(type[index]) { case INTEGER: threshold[index] = new Integer((int)threshold_value); break; case BYTE: threshold[index] = new Byte((byte)threshold_value); break; case SHORT: threshold[index] = new Short((short)threshold_value); break; case LONG: threshold[index] = new Long((long)threshold_value); break; default: // Should never occur... if (isDebugOn()) { debug("updateThreshold", "the threshold type is invalid"); } break; } // If the counter can wrap around when it reaches its maximum // and we are not dealing with counter differences then we need // to reset the threshold to its initial value too. // if (!differenceMode) { if (modulus.longValue() > 0L) { if (threshold[index].longValue() > modulus.longValue()) { modulusExceeded[index] = true; derivedGaugeExceeded[index] = derivedGauge[index]; } } } // Threshold value has been modified so we can notify again. // eventAlreadyNotified[index] = false; } else { modulusExceeded[index] = true; derivedGaugeExceeded[index] = derivedGauge[index]; } } } /** * Tests if the threshold, offset and modulus of the specified index are * of the same type as the counter. Only integer types are allowed. * * Note: * If the optional offset or modulus 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 ((threshold[index] instanceof Integer) && ((offset == INTEGER_ZERO) || (offset instanceof Integer)) && ((modulus == INTEGER_ZERO) || (modulus instanceof Integer))); case BYTE: return ((threshold[index] instanceof Byte) && ((offset == INTEGER_ZERO) || (offset instanceof Byte)) && ((modulus == INTEGER_ZERO) || (modulus instanceof Byte))); case SHORT: return ((threshold[index] instanceof Short) && ((offset == INTEGER_ZERO) || (offset instanceof Short)) && ((modulus == INTEGER_ZERO) || (modulus instanceof Short))); case LONG: return ((threshold[index] instanceof Long) && ((offset == INTEGER_ZERO) || (offset instanceof Long)) && ((modulus == INTEGER_ZERO) || (modulus instanceof Long))); default: // Should never occured... if (isDebugOn()) { debug("isThresholdTypeValid", "The threshold type is invalid"); } return false; } } /** * Sets the derived gauge of the specified index when the * differenceMode flag is set to true. Integer types * only are allowed. * * @param scanCounter The value of the observed attribute. * @param mod The counter modulus value. * @param index The index of the observed object. */ private synchronized void setDerivedGaugeWithDifference(Number scanCounter, Number mod, int index) { /* We do the arithmetic using longs here even though the result may end up in a smaller type. Since l == (byte)l (mod 256) for any long l, (byte) ((byte)l1 + (byte)l2) == (byte) (l1 + l2), and likewise for subtraction. So it's the same as if we had done the arithmetic in the smaller type.*/ long derived = scanCounter.longValue() - previousScanCounter[index].longValue(); if (mod != null) derived += modulus.longValue(); switch (type[index]) { case INTEGER: derivedGauge[index] = new Integer((int) derived); break; case BYTE: derivedGauge[index] = new Byte((byte) derived); break; case SHORT: derivedGauge[index] = new Short((short) derived); break; case LONG: derivedGauge[index] = new Long(derived); break; default: // Should never occur... if (isDebugOn()) { debug("setDerivedGaugeWithDifference", "the threshold type is invalid"); } break; } } /* * ------------------------------------------ * PACKAGE METHODS * ------------------------------------------ */ /** * This method is called by the counter 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_counter = 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_counter = server.getAttribute(getObservedObject(index), getObservedAttribute()); if (scan_counter == 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 counter 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 of type "Integer". // if (scan_counter instanceof Integer) { type[index] = INTEGER; } else if (scan_counter instanceof Byte) { type[index] = BYTE; } else if (scan_counter instanceof Short) { type[index] = SHORT; } else if (scan_counter instanceof Long) { type[index] = LONG; } 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."; } } } if (msg == null) { // Check that threshold, offset and modulus have // values that fit in the counter's type // if (!isThresholdTypeValid(index)) { if (alreadyNotified(index, THRESHOLD_ERROR_NOTIFIED)) return; else { notif_type = MonitorNotification.THRESHOLD_ERROR; setAlreadyNotified(index, THRESHOLD_ERROR_NOTIFIED); msg = "The threshold, offset and modulus must " + "be of the same type as the counter."; } } } if (msg == null) { // Clear all already notified flags. // resetAllAlreadyNotified(index); // Check if counter has wrapped around. // if (modulusExceeded[index]) { if (derivedGauge[index].longValue() < derivedGaugeExceeded[index].longValue()) { threshold[index] = initThreshold; modulusExceeded[index] = false; eventAlreadyNotified[index] = false; } } // 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_counter, index); // Notify the listeners and update the threshold if // the updated derived gauge value is valid. // if (is_derived_gauge_valid) { updateNotifications(index); updateThreshold(index); } } else { // msg != null, will send an error notification timeStamp = derivedGaugeTimestamp[index]; derGauge = derivedGauge[index]; // Reset values. // modulusExceeded[index] = false; eventAlreadyNotified[index] = false; previousScanCounter[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 counter specific arrays. * @param index The index of the observed object. */ synchronized void insertSpecificElementAt(int index) { // Update threshold, derivedGauge, derivedGaugeTimestamp, // previousScanCounter, modulusExceeded, derivedGaugeExceeded, // eventAlreadyNotified and type values. if (index != elementCount) throw new Error("Internal error: index != elementCount"); if (elementCount >= threshold.length) { threshold = expandArray(threshold); derivedGauge = expandArray(derivedGauge); previousScanCounter = expandArray(previousScanCounter); derivedGaugeExceeded = expandArray(derivedGaugeExceeded); derivedGaugeTimestamp = expandArray(derivedGaugeTimestamp); modulusExceeded = expandArray(modulusExceeded); eventAlreadyNotified = expandArray(eventAlreadyNotified); type = expandArray(type); } threshold[index] = INTEGER_ZERO; derivedGauge[index] = INTEGER_ZERO; previousScanCounter[index] = null; derivedGaugeExceeded[index] = null; derivedGaugeTimestamp[index] = System.currentTimeMillis(); modulusExceeded[index] = false; eventAlreadyNotified[index] = false; type[index] = INTEGER; } /** * This method is called when removing an observed object from the vector. * It updates all the counter specific arrays. * @param index The index of the observed object. */ synchronized void removeSpecificElementAt(int index) { // Update threshold, derivedGauge, derivedGaugeTimestamp, // previousScanCounter, modulusExceeded, derivedGaugeExceeded, // eventAlreadyNotified and type values. // removeElementAt(threshold, index); removeElementAt(derivedGauge, index); removeElementAt(previousScanCounter, index); removeElementAt(derivedGaugeExceeded, index); removeElementAt(derivedGaugeTimestamp, index); removeElementAt(modulusExceeded, index); removeElementAt(eventAlreadyNotified, index); removeElementAt(type, index); } /** * CounterAlarmClock 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 counter monitor every * granularity period. */ private static class CounterAlarmClock extends TimerTask { CounterMonitor listener = null; /* * ------------------------------------------ * CONSTRUCTORS * ------------------------------------------ */ public CounterAlarmClock(CounterMonitor listener) { this.listener = listener; } /* * ------------------------------------------ * PUBLIC METHODS * ------------------------------------------ */ /** * This method is called by the CounterAlarmClock thread when * it is started. */ public void run() { if (listener.isActive()) { for (int i = 0; i < listener.elementCount; i++) { listener.notifyAlarmClock(i); } } } } }