FileDocCategorySizeDatePackage
GaugeMonitor.javaAPI DocJava SE 5 API34519Fri Aug 26 14:57:36 BST 2005javax.management.monitor

GaugeMonitor

public class GaugeMonitor extends Monitor implements GaugeMonitorMBean
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:

  • if the attribute value is increasing and becomes equal to or greater than the high threshold value, a {@link MonitorNotification#THRESHOLD_HIGH_VALUE_EXCEEDED threshold high notification} is sent. The notify high flag must be set to true
    Subsequent crossings of the high threshold value do not cause further notifications unless the attribute value becomes equal to or less than the low threshold value.
  • if the attribute value is decreasing and becomes equal to or less than the low threshold value, a {@link MonitorNotification#THRESHOLD_LOW_VALUE_EXCEEDED threshold low notification} is sent. The notify low flag must be set to true.
    Subsequent crossings of the low threshold value do not cause further notifications unless the attribute value becomes equal to or greater than the high threshold value.
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:

  • V[t] = gauge[t] - gauge[t-GP]
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

Fields Summary
private static final Integer
INTEGER_ZERO
private Number
highThreshold
Gauge high threshold.
The default value is a null Integer object.
private Number
lowThreshold
Gauge low threshold.
The default value is a null Integer object.
private boolean
notifyHigh
Flag indicating if the gauge monitor notifies when exceeding the high threshold.
The default value is set to false.
private boolean
notifyLow
Flag indicating if the gauge monitor notifies when exceeding the low threshold.
The default value is set to false.
private boolean
differenceMode
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 Number[]
derivedGauge
Derived gauges.
Each element in this array corresponds to an observed object in the list.
private long[]
derivedGaugeTimestamp
Derived gauge timestamps.
Each element in this array corresponds to an observed object in the list.
private Number[]
previousScanGauge
Scan gauge values captured by the previous observation.
Each element in this array corresponds to an observed object in the list.
private int[]
status
This attribute is used to handle the hysteresis mechanism.
Each element in this array corresponds to an observed object in the list.
private int[]
type
This attribute is used to keep the derived gauge type.
Each element in this array corresponds to an observed object in the list.
private static final int
RISING
private static final int
FALLING
private static final int
RISING_OR_FALLING
private static final int
INTEGER
private static final int
BYTE
private static final int
SHORT
private static final int
LONG
private static final int
FLOAT
private static final int
DOUBLE
private static final int
THRESHOLD_ERROR_NOTIFIED
private Timer
timer
Timer.
Constructors Summary
public GaugeMonitor()
Default constructor.

      dbgTag = makeDebugTag();
    
Methods Summary
public synchronized java.lang.NumbergetDerivedGauge(javax.management.ObjectName object)
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

        int index = indexOf(object);
        if (index != -1)
            return derivedGauge[index];
        else
            return null;
    
public synchronized java.lang.NumbergetDerivedGauge()
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)}

        return derivedGauge[0];
    
public synchronized longgetDerivedGaugeTimeStamp(javax.management.ObjectName object)
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

        int index = indexOf(object);
        if (index != -1)
            return derivedGaugeTimestamp[index];
        else
            return 0;
    
public synchronized longgetDerivedGaugeTimeStamp()
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)}

        return derivedGaugeTimestamp[0];
    
public synchronized booleangetDifferenceMode()
Gets the difference mode flag value common to all observed MBeans.

return
true if the difference mode is used, false otherwise.
see
#setDifferenceMode

        return differenceMode;
    
public synchronized java.lang.NumbergetHighThreshold()
Gets the high threshold value common to all observed MBeans.

return
The high threshold value.

        return highThreshold;
    
public synchronized java.lang.NumbergetLowThreshold()
Gets the low threshold value common to all observed MBeans.

return
The low threshold value.

        return lowThreshold;
    
public javax.management.MBeanNotificationInfo[]getNotificationInfo()
Returns a NotificationInfo object containing the name of the Java class of the notification and the notification types sent by the gauge monitor.

        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;
    
public synchronized booleangetNotifyHigh()
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.

        return notifyHigh;
    
public synchronized booleangetNotifyLow()
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

        return notifyLow;
    
synchronized voidinsertSpecificElementAt(int 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.

        // 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;
    
private booleanisFirstGreaterThanLast(java.lang.Number greater, java.lang.Number less, int type)
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.


        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;
        }
    
private booleanisFirstStrictlyGreaterThanLast(java.lang.Number greater, java.lang.Number less, java.lang.String className)
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.


        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;
        }
    
private synchronized booleanisThresholdTypeValid(int 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.


        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;
        }
    
java.lang.StringmakeDebugTag()




    // TRACES & DEBUG
    //---------------

      
        return "GaugeMonitor";
    
voidnotifyAlarmClock(int index)
This method is called by the gauge monitor each time the granularity period has been exceeded.

param
index The index of the observed object.

	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);
	}
    
synchronized voidremoveSpecificElementAt(int index)
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.

	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);
    
private synchronized voidsetDerivedGaugeWithDifference(java.lang.Number scanGauge, int index)
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.

	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;
    
public synchronized voidsetDifferenceMode(boolean value)
Sets the difference mode flag value common to all observed MBeans.

param
value The difference mode flag value.
see
#getDifferenceMode

        differenceMode = value;

        // Reset values.
        //
        for (int i = 0; i < elementCount; i++) {
            status[i] = RISING_OR_FALLING;
            previousScanGauge[i] = null;
        }
    
public synchronized voidsetGranularityPeriod(long period)
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)

        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());
        }
    
public synchronized voidsetNotifyHigh(boolean value)
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

        notifyHigh = value;
    
public synchronized voidsetNotifyLow(boolean value)
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

        notifyLow = value;
    
public synchronized voidsetThresholds(java.lang.Number highValue, java.lang.Number lowValue)
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.


        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;
        }
    
public voidstart()
Starts the gauge monitor.


        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());
	}
    
public voidstop()
Stops the gauge monitor.

	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;
            }
	}
    
private synchronized booleanupdateDerivedGauge(java.lang.Object scanGauge, int index)
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).


        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;
    
private voidupdateNotifications(int index)
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.

	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);
	}