mx4j/src/core/mx4j/monitor MX4JCounterMonitor.java,NONE,1.1 MX4JCounterMonitorMBean.java,NONE,1.1 MX4JGaugeMonitor.java,NONE,1.1 MX4JGaugeMonitorMBean.java,NONE,1.1 MX4JMonitor.java,NONE,1.1 MX4JMonitorMBean.java,NONE,1.1 MX4JMonitorNotification.java,NONE,1.1 MX4JStringMonitor.java,NONE,1.1 MX4JStringMonitorMBean.java,NONE,1.1
Simone Bordet <[email protected]> Sat, 04 Sep 2004 13:55:36 +0000
| Newsgroups | gmane.comp.java.mx4j.cvs |
|---|---|
| Message-ID | <[email protected]> |
Update of /cvsroot/mx4j/mx4j/src/core/mx4j/monitor In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv8483/src/core/mx4j/monitor Added Files: MX4JCounterMonitor.java MX4JCounterMonitorMBean.java MX4JGaugeMonitor.java MX4JGaugeMonitorMBean.java MX4JMonitor.java MX4JMonitorMBean.java MX4JMonitorNotification.java MX4JStringMonitor.java MX4JStringMonitorMBean.java Log Message: Rewritten the monitor package and its tests --- NEW FILE: MX4JStringMonitor.java --- /* * Copyright (C) The MX4J Contributors. * All rights reserved. * * This software is distributed under the terms of the MX4J License version 1.0. * See the terms of the MX4J License in the documentation provided with this software. */ package mx4j.monitor; import javax.management.MBeanNotificationInfo; import javax.management.NotCompliantMBeanException; import javax.management.ObjectName; import javax.management.monitor.MonitorNotification; import mx4j.log.Logger; /** * @author <a href="mailto:[email protected]">Simone Bordet</a> * @version $Revision: 1.1 $ */ public class MX4JStringMonitor extends MX4JMonitor implements MX4JStringMonitorMBean { private static final String EMPTY = ""; private String stringToCompare = EMPTY; private boolean notifyMatch; private boolean notifyDiffer; public MX4JStringMonitor() throws NotCompliantMBeanException { super(MX4JStringMonitorMBean.class); } public MX4JStringMonitor(Class management) throws NotCompliantMBeanException { super(management); } public MBeanNotificationInfo[] getNotificationInfo() { // TODO return new MBeanNotificationInfo[0]; } public synchronized String getStringToCompare() { return stringToCompare; } public synchronized void setStringToCompare(String value) throws IllegalArgumentException { if (value == null) throw new IllegalArgumentException("String to compare cannot be null"); this.stringToCompare = value; } public synchronized boolean getNotifyMatch() { return notifyMatch; } public synchronized void setNotifyMatch(boolean notifyMatch) { this.notifyMatch = notifyMatch; } public synchronized boolean getNotifyDiffer() { return notifyDiffer; } public synchronized void setNotifyDiffer(boolean notifyDiffer) { this.notifyDiffer = notifyDiffer; } public String getDerivedGauge(ObjectName objectName) { StringMonitorInfo info = (StringMonitorInfo)getMonitorInfo(objectName); return info.getGauge(); } public long getDerivedGaugeTimeStamp(ObjectName objectName) { StringMonitorInfo info = (StringMonitorInfo)getMonitorInfo(objectName); return info.getTimestamp(); } protected MonitorInfo createMonitorInfo() { return new StringMonitorInfo(); } protected int compare(String left, String right) { return left == null ? right == null ? 0 : -1 : right == null ? 1 : left.compareTo(right); } protected void monitor(ObjectName name, String attribute, Object value, MonitorInfo monitorInfo) { if (!(value instanceof String)) { sendErrorNotification(monitorInfo, MonitorNotification.OBSERVED_ATTRIBUTE_TYPE_ERROR, "Attribute type must be a String, not " + value.getClass(), name, attribute); return; } String gauge = (String)value; String reference = null; synchronized (this) { reference = getStringToCompare(); } Logger logger = getLogger(); StringMonitorInfo info = (StringMonitorInfo)monitorInfo; if (logger.isEnabledFor(Logger.DEBUG)) { logger.debug("Computing gauge, previous values are: " + info); logger.debug("Current values are: gauge=" + gauge + ", stringToCompare=" + reference); } compareAndSendNotification(gauge, reference, info, name, attribute); info.setGauge(gauge); info.setTimestamp(System.currentTimeMillis()); } private void compareAndSendNotification(String gauge, String reference, StringMonitorInfo info, ObjectName name, String attribute) { Logger logger = getLogger(); boolean equals = compare(gauge, reference) == 0; if (info.isDifferNotified() && !equals) { if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("Difference already notified, gauge=" + gauge + ", string-to-compare=" + reference); return; } if (info.isMatchNotified() && equals) { if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("Match already notified, gauge=" + gauge + ", string-to-compare=" + reference); return; } if (equals) { if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("Gauge matches, gauge=" + gauge + ", string-to-compare=" + reference); info.setDifferNotified(false); if (getNotifyMatch()) { if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("Sending string match notification"); info.setMatchNotified(true); sendNotification(MonitorNotification.STRING_TO_COMPARE_VALUE_MATCHED, "Gauge " + gauge + " matched " + reference, name, attribute, gauge, reference); } else { info.setMatchNotified(false); if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("StringMonitor is configured in non-match-notification mode"); } } else { if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("Gauge differs, gauge=" + gauge + ", string-to-compare=" + reference); info.setMatchNotified(false); if (getNotifyDiffer()) { if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("Sending string differ notification"); info.setDifferNotified(true); sendNotification(MonitorNotification.STRING_TO_COMPARE_VALUE_DIFFERED, "Gauge " + gauge + " differs from " + reference, name, attribute, gauge, reference); } else { info.setDifferNotified(false); if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("StringMonitor is configured in non-differ-notification mode"); } } } protected class StringMonitorInfo extends MonitorInfo { private String gauge; private long timestamp; private boolean matchNotified; private boolean differNotified; public String getGauge() { return gauge; } public void setGauge(String gauge) { this.gauge = gauge; } public long getTimestamp() { return timestamp; } public void setTimestamp(long timestamp) { this.timestamp = timestamp; } public boolean isMatchNotified() { return matchNotified; } public void setMatchNotified(boolean matchNotified) { this.matchNotified = matchNotified; } public boolean isDifferNotified() { return differNotified; } public void setDifferNotified(boolean differNotified) { this.differNotified = differNotified; } public String toString() { StringBuffer buffer = new StringBuffer(super.toString()); buffer.append(", gauge=").append(getGauge()); buffer.append(", matchNotified=").append(isMatchNotified()); buffer.append(", differNotified=").append(isDifferNotified()); return buffer.toString(); } } } --- NEW FILE: MX4JGaugeMonitorMBean.java --- /* * Copyright (C) The MX4J contributors. * All rights reserved. * * This software is distributed under the terms of the MX4J License version 1.0. * See the terms of the MX4J License in the documentation provided with this software. */ package mx4j.monitor; import javax.management.ObjectName; /** * @author <a href="mailto:[email protected]">Carlos Quiroz</a> * @version $Revision: 1.1 $ */ public interface MX4JGaugeMonitorMBean extends MX4JMonitorMBean { public Number getDerivedGauge(ObjectName objectName); public long getDerivedGaugeTimeStamp(ObjectName objectName); public Number getHighThreshold(); public Number getLowThreshold(); public void setThresholds(Number highValue, Number lowValue) throws IllegalArgumentException; public boolean getNotifyHigh(); public void setNotifyHigh(boolean value); public boolean getNotifyLow(); public void setNotifyLow(boolean value); public boolean getDifferenceMode(); public void setDifferenceMode(boolean value); } --- NEW FILE: MX4JCounterMonitor.java --- /* * Copyright (C) The MX4J contributors. * All rights reserved. * * This software is distributed under the terms of the MX4J License version 1.0. * See the terms of the MX4J License in the documentation provided with this software. */ package mx4j.monitor; import java.math.BigInteger; import javax.management.MBeanNotificationInfo; import javax.management.NotCompliantMBeanException; import javax.management.ObjectName; import javax.management.monitor.MonitorNotification; import mx4j.log.Logger; /** * @author <a href="mailto:[email protected]">Simone Bordet</a> * @version $Revision: 1.1 $ */ public class MX4JCounterMonitor extends MX4JMonitor implements MX4JCounterMonitorMBean { private static Integer ZERO = new Integer(0); private Number threshold = ZERO; private Number offset = ZERO; private Number modulus = ZERO; private boolean notify; private boolean differenceMode; public MX4JCounterMonitor() throws NotCompliantMBeanException { super(MX4JCounterMonitorMBean.class); } protected MX4JCounterMonitor(Class management) throws NotCompliantMBeanException { super(management); } public MBeanNotificationInfo[] getNotificationInfo() { // TODO return new MBeanNotificationInfo[0]; } public synchronized Number getInitThreshold() { return threshold; } public void setInitThreshold(Number threshold) throws IllegalArgumentException { if (threshold == null || compare(threshold, ZERO) < 0) throw new IllegalArgumentException("Threshold cannot be " + threshold); this.threshold = threshold; } public synchronized Number getOffset() { return offset; } public void setOffset(Number offset) throws IllegalArgumentException { if (offset == null || compare(offset, ZERO) < 0) throw new IllegalArgumentException("Offset cannot be " + offset); this.offset = offset; } public Number getModulus() { return modulus; } public void setModulus(Number modulus) throws IllegalArgumentException { if (modulus == null || compare(modulus, ZERO) < 0) throw new IllegalArgumentException("Modulus cannot be " + modulus); this.modulus = modulus; } public boolean getNotify() { return notify; } public void setNotify(boolean notify) { this.notify = notify; } public boolean getDifferenceMode() { return differenceMode; } public void setDifferenceMode(boolean mode) { this.differenceMode = mode; } public Number getDerivedGauge(ObjectName name) { CounterMonitorInfo info = (CounterMonitorInfo)getMonitorInfo(name); return info.getGauge(); } public long getDerivedGaugeTimeStamp(ObjectName name) { CounterMonitorInfo info = (CounterMonitorInfo)getMonitorInfo(name); return info.getTimestamp(); } public Number getThreshold(ObjectName name) { CounterMonitorInfo info = (CounterMonitorInfo)getMonitorInfo(name); return info.getThreshold(); } protected int compare(Number left, Number right) { if (left instanceof BigInteger && right instanceof BigInteger) return ((BigInteger)left).compareTo((BigInteger)right); if (left.longValue() == right.longValue()) return 0; return left.longValue() > right.longValue() ? 1 : -1; } protected Number sum(Number left, Number right) { if (left instanceof BigInteger && right instanceof BigInteger) return ((BigInteger)left).add((BigInteger)right); if (left instanceof BigInteger) return ((BigInteger)left).add(BigInteger.valueOf(right.longValue())); if (right instanceof BigInteger) return ((BigInteger)right).add(BigInteger.valueOf(left.longValue())); if (left instanceof Long || right instanceof Long) return new Long(left.longValue() + right.longValue()); if (left instanceof Integer || right instanceof Integer) return new Integer(left.intValue() + right.intValue()); if (left instanceof Short || right instanceof Short) return new Short((short)(left.shortValue() + right.shortValue())); if (left instanceof Byte || right instanceof Byte) return new Byte((byte)(left.byteValue() + right.byteValue())); return null; } protected Number sub(Number left, Number right) { if (left instanceof BigInteger && right instanceof BigInteger) return ((BigInteger)left).subtract((BigInteger)right); if (left instanceof BigInteger) return ((BigInteger)left).subtract(BigInteger.valueOf(right.longValue())); if (left instanceof Long || right instanceof Long) return new Long(left.longValue() - right.longValue()); if (left instanceof Integer || right instanceof Integer) return new Integer(left.intValue() - right.intValue()); if (left instanceof Short || right instanceof Short) return new Short((short)(left.shortValue() - right.shortValue())); if (left instanceof Byte || right instanceof Byte) return new Byte((byte)(left.byteValue() - right.byteValue())); return null; } protected void monitor(ObjectName name, String attribute, Object value, MonitorInfo monitorInfo) { if (!(value instanceof Number)) { sendErrorNotification(monitorInfo, MonitorNotification.OBSERVED_ATTRIBUTE_TYPE_ERROR, "Attribute type must be a Number, not " + value.getClass(), name, attribute); return; } Number gauge = (Number)value; if (compare(gauge, ZERO) < 0) { // Spec requires counter monitor values not be negative sendErrorNotification(monitorInfo, MonitorNotification.THRESHOLD_ERROR, "Attribute value cannot be negative " + gauge, name, attribute); return; } // Spec requires that types of gauge, threshold, offset and modulus be affine Number threshold = null; Number offset = null; Number modulus = null; synchronized (this) { threshold = getThreshold(name); offset = getOffset(); modulus = getModulus(); } Class gaugeClass = gauge.getClass(); if (threshold != ZERO && threshold.getClass() != gaugeClass) { sendErrorNotification(monitorInfo, MonitorNotification.THRESHOLD_ERROR, "Threshold type " + threshold.getClass() + " must be of same type of the attribute " + gaugeClass, name, attribute); return; } if (offset != ZERO && offset.getClass() != gaugeClass) { sendErrorNotification(monitorInfo, MonitorNotification.THRESHOLD_ERROR, "Offset type " + offset.getClass() + " must be of same type of the attribute " + gaugeClass, name, attribute); return; } if (modulus != ZERO && modulus.getClass() != gaugeClass) { sendErrorNotification(monitorInfo, MonitorNotification.THRESHOLD_ERROR, "Modulus type " + modulus.getClass() + " must be of same type of the attribute " + gaugeClass, name, attribute); return; } Logger logger = getLogger(); // Contains previous gauge and threshold CounterMonitorInfo info = (CounterMonitorInfo)monitorInfo; if (logger.isEnabledFor(Logger.DEBUG)) { logger.debug("Computing gauge, previous values are: " + info); logger.debug("Current values are: threshold=" + threshold + ", offset=" + offset + ", modulus=" + modulus); } boolean updateThreshold = false; if (getDifferenceMode()) { Number diffGauge = sub(gauge, info.getGauge()); if (compare(diffGauge, ZERO) < 0) diffGauge = sum(diffGauge, getModulus()); if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("CounterMonitor in difference mode, difference gauge=" + diffGauge); updateThreshold = compareAndSendNotification(diffGauge, threshold, info, name, attribute); } else { if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("CounterMonitor in absolute mode, gauge=" + gauge); updateThreshold = compareAndSendNotification(gauge, threshold, info, name, attribute); } if (updateThreshold) { if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("Updating threshold, old value = " + threshold); // Offset the threshold until exceeds the gauge if (compare(offset, ZERO) != 0) while (compare(threshold, gauge) <= 0) threshold = sum(threshold, offset); if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("Threshold has been offset, new value = " + threshold); // Check for rollover if (getModulus() != ZERO && compare(threshold, getModulus()) > 0) threshold = getInitThreshold(); if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("Threshold has been rolled over, new value = " + threshold); } else { if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("No need to update the threshold, value remains = " + threshold); } CounterMonitorInfo newInfo = (CounterMonitorInfo)createMonitorInfo(); newInfo.setThresholdNotified(info.isThresholdNotified()); newInfo.setGauge(gauge); newInfo.setTimestamp(System.currentTimeMillis()); newInfo.setThreshold(threshold); putMonitorInfo(name, newInfo); } private boolean compareAndSendNotification(Number gauge, Number threshold, CounterMonitorInfo info, ObjectName name, String attribute) { Logger logger = getLogger(); if (info.isThresholdNotified() && compare(gauge, info.getGauge()) == 0) { if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("Threshold exceeded already notified, gauge did not change: " + gauge); return false; } if (compare(gauge, threshold) >= 0) { if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("Gauge above threshold: gauge=" + gauge + ", threshold=" + threshold); if (getNotify()) { if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("Sending threshold exceeded notification"); info.setThresholdNotified(true); sendNotification(MonitorNotification.THRESHOLD_VALUE_EXCEEDED, "Threshold " + threshold + " exceeded: " + gauge, name, attribute, gauge, threshold); } else { info.setThresholdNotified(false); if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("CounterMonitor is configured in non-notification mode"); } return true; } else { info.setThresholdNotified(false); if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("Gauge below threshold: gauge=" + gauge + ", threshold=" + threshold); return false; } } protected MonitorInfo createMonitorInfo() { return new CounterMonitorInfo(); } protected class CounterMonitorInfo extends MonitorInfo { private boolean thresholdNotified; private Number gauge = ZERO; private long timestamp; private Number threshold = ZERO; public void setThresholdNotified(boolean thresholdNotified) { this.thresholdNotified = thresholdNotified; } public void setGauge(Number gauge) { this.gauge = gauge; } public void setTimestamp(long timestamp) { this.timestamp = timestamp; } public void setThreshold(Number threshold) { this.threshold = threshold; } public boolean isThresholdNotified() { return thresholdNotified; } public Number getGauge() { return gauge; } public long getTimestamp() { return timestamp; } public Number getThreshold() { if (threshold == ZERO) return getInitThreshold(); return threshold; } public String toString() { StringBuffer buffer = new StringBuffer(super.toString()); buffer.append(", thresholdNotified=").append(isThresholdNotified()); buffer.append(", gauge=").append(getGauge()); buffer.append(", threshold=").append(threshold); return buffer.toString(); } } } --- NEW FILE: MX4JStringMonitorMBean.java --- /* * Copyright (C) The MX4J contributors. * All rights reserved. * * This software is distributed under the terms of the MX4J License version 1.0. * See the terms of the MX4J License in the documentation provided with this software. */ package mx4j.monitor; import javax.management.ObjectName; /** * @author <a href="mailto:[email protected]">Carlos Quiroz</a> * @version $Revision: 1.1 $ */ public interface MX4JStringMonitorMBean extends MX4JMonitorMBean { public String getDerivedGauge(ObjectName objectName); public long getDerivedGaugeTimeStamp(ObjectName objectName); public String getStringToCompare(); public void setStringToCompare(String value) throws IllegalArgumentException; public boolean getNotifyMatch(); public void setNotifyMatch(boolean value); public boolean getNotifyDiffer(); public void setNotifyDiffer(boolean value); } --- NEW FILE: MX4JMonitorNotification.java --- /* * Copyright (C) The MX4J contributors. * All rights reserved. * * This software is distributed under the terms of the MX4J License version 1.0. * See the terms of the MX4J License in the documentation provided with this software. */ package mx4j.monitor; import javax.management.Notification; import javax.management.ObjectName; /** * @author <a href="mailto:[email protected]">Carlos Quiroz</a> * @version $Revision: 1.1 $ */ public class MX4JMonitorNotification extends Notification { private final ObjectName observedObject; private final String observedAttribute; private final Object derivedGauge; private final Object trigger; public MX4JMonitorNotification(String type, Object source, long sequenceNumber, long timeStamp, String message, ObjectName monitoredName, String attribute, Object gauge, Object trigger) { super(type, source, sequenceNumber, timeStamp, message); this.observedObject = monitoredName; this.observedAttribute = attribute; this.derivedGauge = gauge; this.trigger = trigger; } public ObjectName getObservedObject() { return observedObject; } public Object getDerivedGauge() { return derivedGauge; } public String getObservedAttribute() { return observedAttribute; } public Object getTrigger() { return trigger; } public String toString() { StringBuffer buffer = new StringBuffer("["); buffer.append(super.toString()).append(", "); buffer.append("observed=").append(getObservedObject()).append(", "); buffer.append("gauge=").append(getDerivedGauge()).append(", "); buffer.append("attribute=").append(getObservedAttribute()).append(", "); buffer.append("trigger=").append(getTrigger()).append("]"); return buffer.toString(); } } --- NEW FILE: MX4JMonitorMBean.java --- /* * Copyright (C) The MX4J Contributors. * All rights reserved. * * This software is distributed under the terms of the MX4J License version 1.0. * See the terms of the MX4J License in the documentation provided with this software. */ package mx4j.monitor; import javax.management.ObjectName; /** * @author <a href="mailto:[email protected]">Simone Bordet</a> * @version $Revision: 1.1 $ */ public interface MX4JMonitorMBean { public void start(); public void stop(); public boolean isActive(); public void addObservedObject(ObjectName object) throws IllegalArgumentException; public void removeObservedObject(ObjectName object); public boolean containsObservedObject(ObjectName object); public ObjectName[] getObservedObjects(); public String getObservedAttribute(); public void setObservedAttribute(String attribute); public long getGranularityPeriod(); public void setGranularityPeriod(long period) throws java.lang.IllegalArgumentException; } --- NEW FILE: MX4JGaugeMonitor.java --- /* * Copyright (C) The MX4J Contributors. * All rights reserved. * * This software is distributed under the terms of the MX4J License version 1.0. * See the terms of the MX4J License in the documentation provided with this software. */ package mx4j.monitor; import java.math.BigDecimal; import java.math.BigInteger; import javax.management.MBeanNotificationInfo; import javax.management.NotCompliantMBeanException; import javax.management.ObjectName; import javax.management.monitor.MonitorNotification; import mx4j.log.Logger; /** * @author <a href="mailto:[email protected]">Simone Bordet</a> * @version $Revision: 1.1 $ */ public class MX4JGaugeMonitor extends MX4JMonitor implements MX4JGaugeMonitorMBean { private static Integer ZERO = new Integer(0); private Number highThreshold = ZERO; private Number lowThreshold = ZERO; private boolean notifyHigh; private boolean notifyLow; private boolean differenceMode; public MX4JGaugeMonitor() throws NotCompliantMBeanException { super(MX4JGaugeMonitorMBean.class); } protected MX4JGaugeMonitor(Class management) throws NotCompliantMBeanException { super(management); } public MBeanNotificationInfo[] getNotificationInfo() { // TODO return new MBeanNotificationInfo[0]; } public synchronized Number getHighThreshold() { return highThreshold; } public synchronized Number getLowThreshold() { return lowThreshold; } public void setThresholds(Number highValue, Number lowValue) throws IllegalArgumentException { if (highValue == null) throw new IllegalArgumentException("High Threshold cannot be null"); if (lowValue == null) throw new IllegalArgumentException("Low Threshold cannot be null"); if (highValue.getClass() != lowValue.getClass()) throw new IllegalArgumentException("Thresholds must be of the same type"); if (compare(highValue, lowValue) < 0) throw new IllegalArgumentException("High threshold cannot be lower than low threshold"); highThreshold = highValue; lowThreshold = lowValue; } public synchronized boolean getNotifyHigh() { return notifyHigh; } public synchronized boolean getNotifyLow() { return notifyLow; } public synchronized void setNotifyHigh(boolean notifyHigh) { this.notifyHigh = notifyHigh; } public synchronized void setNotifyLow(boolean notifyLow) { this.notifyLow = notifyLow; } public synchronized boolean getDifferenceMode() { return differenceMode; } public synchronized void setDifferenceMode(boolean differenceMode) { this.differenceMode = differenceMode; } public Number getDerivedGauge(ObjectName objectName) { GaugeMonitorInfo info = (GaugeMonitorInfo)getMonitorInfo(objectName); return info.getGauge(); } public long getDerivedGaugeTimeStamp(ObjectName objectName) { GaugeMonitorInfo info = (GaugeMonitorInfo)getMonitorInfo(objectName); return info.getTimestamp(); } protected MonitorInfo createMonitorInfo() { return new GaugeMonitorInfo(); } protected int compare(Number left, Number right) { if (left instanceof BigDecimal && right instanceof BigDecimal) return ((BigDecimal)left).compareTo((BigDecimal)right); if (left instanceof BigInteger && right instanceof BigInteger) return ((BigInteger)left).compareTo((BigInteger)right); return new Double(left.doubleValue()).compareTo(new Double(right.doubleValue())); } protected Number sub(Number left, Number right) { if (left instanceof BigDecimal && right instanceof BigDecimal) return ((BigDecimal)left).subtract((BigDecimal)right); if (left instanceof BigDecimal) return ((BigDecimal)left).subtract(new BigDecimal(right.doubleValue())); if (left instanceof BigInteger && right instanceof BigInteger) return ((BigInteger)left).subtract((BigInteger)right); if (left instanceof BigInteger) return ((BigInteger)left).subtract(BigInteger.valueOf(right.longValue())); if (left instanceof Double || right instanceof Double) return new Double(left.doubleValue() - right.doubleValue()); if (left instanceof Float || right instanceof Float) return new Float(left.floatValue() - right.floatValue()); if (left instanceof Long || right instanceof Long) return new Long(left.longValue() - right.longValue()); if (left instanceof Integer || right instanceof Integer) return new Integer(left.intValue() - right.intValue()); if (left instanceof Short || right instanceof Short) return new Short((short)(left.shortValue() - right.shortValue())); if (left instanceof Byte || right instanceof Byte) return new Byte((byte)(left.byteValue() - right.byteValue())); return null; } protected void monitor(ObjectName name, String attribute, Object value, MonitorInfo monitorInfo) { if (!(value instanceof Number)) { sendErrorNotification(monitorInfo, MonitorNotification.OBSERVED_ATTRIBUTE_TYPE_ERROR, "Attribute type must be a Number, not " + value.getClass(), name, attribute); return; } Number gauge = (Number)value; // Spec requires that types of gauge, high threshold and low threshold be affine Number high = null; Number low = null; synchronized (this) { high = getHighThreshold(); low = getLowThreshold(); } Class gaugeClass = gauge.getClass(); if (high != ZERO && high.getClass() != gaugeClass) { sendErrorNotification(monitorInfo, MonitorNotification.THRESHOLD_ERROR, "Threshold type " + high.getClass() + " must be of same type of the attribute " + gaugeClass, name, attribute); return; } if (low != ZERO && low.getClass() != gaugeClass) { sendErrorNotification(monitorInfo, MonitorNotification.THRESHOLD_ERROR, "Offset type " + low.getClass() + " must be of same type of the attribute " + gaugeClass, name, attribute); return; } Logger logger = getLogger(); // Contains previous gauge GaugeMonitorInfo info = (GaugeMonitorInfo)monitorInfo; if (logger.isEnabledFor(Logger.DEBUG)) { logger.debug("Computing gauge, previous values are: " + info); logger.debug("Current values are: gauge=" + gauge + ", highThreshold=" + high + ", lowThreshold=" + low); } if (getDifferenceMode()) { Number diffGauge = sub(gauge, info.getGauge()); if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("CounterMonitor in difference mode, difference gauge=" + diffGauge); compareAndSendNotification(diffGauge, low, high, info, name, attribute); } else { if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("CounterMonitor in absolute mode, gauge=" + gauge); compareAndSendNotification(gauge, low, high, info, name, attribute); } info.setGauge(gauge); info.setTimestamp(System.currentTimeMillis()); } private void compareAndSendNotification(Number gauge, Number low, Number high, GaugeMonitorInfo info, ObjectName name, String attribute) { Logger logger = getLogger(); if (info.isHighNotified() && compare(gauge, low) > 0) { if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("High threshold " + high + " already notified, gauge " + gauge + " not below low threshold " + low); return; } if (info.isLowNotified() && compare(gauge, high) < 0) { if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("Low threshold " + low + " already notified, gauge " + gauge + " not above high threshold " + high); return; } if (compare(gauge, high) >= 0) { if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("Gauge above high threshold: gauge=" + gauge + ", high threshold=" + high + ", low threshold=" + low); info.setLowNotified(false); if (getNotifyHigh()) { if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("Sending high threshold exceeded notification"); info.setHighNotified(true); sendNotification(MonitorNotification.THRESHOLD_HIGH_VALUE_EXCEEDED, "High threshold " + high + " exceeded: " + gauge, name, attribute, gauge, high); } else { info.setHighNotified(false); if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("GaugeMonitor is configured in non-high-notification mode"); } } else if (compare(gauge, low) <= 0) { if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("Gauge below low threshold: gauge=" + gauge + ", low threshold=" + low + ", high threshold=" + high); info.setHighNotified(false); if (getNotifyLow()) { if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("Sending low threshold exceeded notification"); info.setLowNotified(true); sendNotification(MonitorNotification.THRESHOLD_LOW_VALUE_EXCEEDED, "Low threshold " + low + " exceeded: " + gauge, name, attribute, gauge, low); } else { info.setLowNotified(false); if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("GaugeMonitor is configured in non-low-notification mode"); } } else { info.setHighNotified(false); info.setLowNotified(false); if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("Gauge between thresholds: gauge=" + gauge + ", low threshold=" + low + ", high threshold=" + high); } } protected class GaugeMonitorInfo extends MonitorInfo { private Number gauge = ZERO; private long timestamp; private boolean highNotified; private boolean lowNotified; public Number getGauge() { return gauge; } public void setGauge(Number gauge) { this.gauge = gauge; } public long getTimestamp() { return timestamp; } public void setTimestamp(long timestamp) { this.timestamp = timestamp; } public boolean isHighNotified() { return highNotified; } public void setHighNotified(boolean highNotified) { this.highNotified = highNotified; } public boolean isLowNotified() { return lowNotified; } public void setLowNotified(boolean lowNotified) { this.lowNotified = lowNotified; } public String toString() { StringBuffer buffer = new StringBuffer(super.toString()); buffer.append(", gauge=").append(getGauge()); buffer.append(", lowNotified=").append(isLowNotified()); buffer.append(", highNotified=").append(isHighNotified()); return buffer.toString(); } } } --- NEW FILE: MX4JCounterMonitorMBean.java --- /* * Copyright (C) The MX4J contributors. * All rights reserved. * * This software is distributed under the terms of the MX4J License version 1.0. * See the terms of the MX4J License in the documentation provided with this software. */ package mx4j.monitor; import javax.management.ObjectName; /** * @author <a href="mailto:[email protected]">Carlos Quiroz</a> * @version $Revision: 1.1 $ */ public interface MX4JCounterMonitorMBean extends MX4JMonitorMBean { public Number getDerivedGauge(ObjectName objectName); public long getDerivedGaugeTimeStamp(ObjectName objectName); public Number getThreshold(ObjectName objectName); public Number getInitThreshold(); public void setInitThreshold(Number value) throws IllegalArgumentException; public Number getOffset(); public void setOffset(Number value) throws IllegalArgumentException; public Number getModulus(); public void setModulus(Number value) throws IllegalArgumentException; public boolean getNotify(); public void setNotify(boolean value); public boolean getDifferenceMode(); public void setDifferenceMode(boolean value); } --- NEW FILE: MX4JMonitor.java --- /* * Copyright (C) The MX4J contributors. * All rights reserved. * * This software is distributed under the terms of the MX4J License version 1.0. * See the terms of the MX4J License in the documentation provided with this software. */ package mx4j.monitor; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.management.AttributeNotFoundException; import javax.management.InstanceNotFoundException; import javax.management.ListenerNotFoundException; import javax.management.MBeanException; import javax.management.MBeanRegistration; import javax.management.MBeanServer; import javax.management.NotCompliantMBeanException; import javax.management.Notification; import javax.management.NotificationBroadcasterSupport; import javax.management.NotificationEmitter; import javax.management.NotificationFilter; import javax.management.NotificationListener; import javax.management.ObjectName; import javax.management.ReflectionException; import javax.management.StandardMBean; import javax.management.monitor.MonitorNotification; import mx4j.log.Log; import mx4j.log.Logger; import mx4j.timer.TimeQueue; import mx4j.timer.TimeTask; /** * The class that implements the Monitor behavior of the JMX specification. * IMPLEMENTATION NOTE: * There is one single thread that handles monitoring, for all monitor objects. * There is one single task per each monitor object that runs. * The queue will have possibly many tasks per each monitor type. * Each monitor handles many MBeans, but only one attribute; however, both MBeans and attribute can be changed, * though it would be a strange way to use the monitor. * * @author <a href="mailto:[email protected]">Simone Bordet</a> * @version $Revision: 1.1 $ */ public abstract class MX4JMonitor extends StandardMBean implements MX4JMonitorMBean, MBeanRegistration, NotificationEmitter { private static TimeQueue queue = new TimeQueue(); private static int sequenceNumber; private NotificationBroadcasterSupport emitter; private MBeanServer server; private boolean active; private List observeds = new ArrayList(); private volatile String attribute; private volatile long granularity = 10 * 1000; // Spec says default is 10 seconds private boolean errorNotified; static { queue.start(); } private final TimeTask task = new MonitorTask(); private final Map infos = new HashMap(); protected MX4JMonitor(Class management) throws NotCompliantMBeanException { super(management); } // TODO: override descriptions for this MBean public ObjectName preRegister(MBeanServer server, ObjectName name) { this.server = server; return name; } public void postRegister(Boolean registrationDone) { } public void preDeregister() { stop(); } public void postDeregister() { server = null; } protected NotificationBroadcasterSupport createNotificationEmitter() { return new NotificationBroadcasterSupport(); } public void addNotificationListener(NotificationListener listener, NotificationFilter filter, Object handback) throws IllegalArgumentException { emitter.addNotificationListener(listener, filter, handback); } public void removeNotificationListener(NotificationListener listener) throws ListenerNotFoundException { emitter.removeNotificationListener(listener); } public void removeNotificationListener(NotificationListener listener, NotificationFilter filter, Object handback) throws ListenerNotFoundException { emitter.removeNotificationListener(listener, filter, handback); } public void sendNotification(Notification notification) { emitter.sendNotification(notification); } public synchronized void start() { if (isActive()) return; active = true; startMonitor(); } public synchronized void stop() { if (!isActive()) return; active = false; stopMonitor(); } public synchronized boolean isActive() { return active; } public synchronized void addObservedObject(ObjectName name) throws IllegalArgumentException { if (name == null) throw new IllegalArgumentException("Observed ObjectName cannot be null"); if (!containsObservedObject(name)) { observeds.add(name); putMonitorInfo(name, createMonitorInfo()); } } public synchronized void removeObservedObject(ObjectName name) { observeds.remove(name); removeMonitorInfo(name); } public synchronized boolean containsObservedObject(ObjectName name) { return observeds.contains(name); } public synchronized ObjectName[] getObservedObjects() { return (ObjectName[])observeds.toArray(new ObjectName[observeds.size()]); } public synchronized void clearObservedObjects() { observeds.clear(); } public synchronized String getObservedAttribute() { return attribute; } public synchronized void setObservedAttribute(String attribute) { this.attribute = attribute; } public synchronized long getGranularityPeriod() { return granularity; } public synchronized void setGranularityPeriod(long granularity) throws IllegalArgumentException { if (granularity <= 0) throw new IllegalArgumentException("Granularity must be greater than zero"); this.granularity = granularity; } protected void startMonitor() { if (emitter == null) this.emitter = createNotificationEmitter(); queue.schedule(task); } protected void stopMonitor() { queue.unschedule(task); } protected Logger getLogger() { return Log.getLogger(getClass().getName()); } protected void sendNotification(String type, String message, ObjectName name, String attribute, Object gauge, Object trigger) { int sequence = 0; synchronized (MX4JMonitor.class) { sequence = ++sequenceNumber; } Notification notification = createMonitorNotification(type, sequence, message, name, attribute, gauge, trigger); sendNotification(notification); } protected Notification createMonitorNotification(String type, long sequence, String message, ObjectName observed, String attribute, Object gauge, Object trigger) { return new MX4JMonitorNotification(type, this, sequence, System.currentTimeMillis(), message, observed, attribute, gauge, trigger); } protected abstract void monitor(ObjectName name, String attribute, Object value, MonitorInfo info); protected abstract MonitorInfo createMonitorInfo(); protected synchronized MonitorInfo getMonitorInfo(ObjectName name) { return (MonitorInfo)infos.get(name); } protected synchronized void putMonitorInfo(ObjectName name, MonitorInfo info) { infos.put(name, info); } protected synchronized void removeMonitorInfo(ObjectName name) { infos.remove(name); } protected void sendErrorNotification(MonitorInfo info, String type, String message, ObjectName observed, String attribute) { if (!info.isErrorNotified()) { info.setErrorNotified(true); sendNotification(type, message, observed, attribute, null, null); } } private class MonitorTask extends TimeTask { protected boolean isPeriodic() { return true; } protected long getPeriod() { return getGranularityPeriod(); } public boolean getFixedRate() { return true; } public void run() { if (!isActive()) return; long start = System.currentTimeMillis(); String attribute = getObservedAttribute(); if (server == null) { if (!errorNotified) { errorNotified = true; sendNotification(MonitorNotification.RUNTIME_ERROR, "Monitors must be registered in the MBeanServer", null, attribute, null, null); } } else { errorNotified = false; // If no attribute, sleep and try again if (attribute != null) { ObjectName[] names = getObservedObjects(); // If no names, sleep and try again for (int i = 0; i < names.length; i++) { ObjectName name = names[i]; MonitorInfo info = getMonitorInfo(name); if (info == null) continue; try { Object value = server.getAttribute(name, attribute); // If no value, sleep and try again if (value != null) { monitor(name, attribute, value, info); } } catch (InstanceNotFoundException x) { sendErrorNotification(info, MonitorNotification.OBSERVED_OBJECT_ERROR, "Could not find observed MBean", name, attribute); } catch (AttributeNotFoundException x) { sendErrorNotification(info, MonitorNotification.OBSERVED_ATTRIBUTE_ERROR, "Could not find observed attribute " + attribute, name, attribute); } catch (MBeanException x) { sendErrorNotification(info, MonitorNotification.RUNTIME_ERROR, x.toString(), name, attribute); } catch (ReflectionException x) { sendErrorNotification(info, MonitorNotification.RUNTIME_ERROR, x.toString(), name, attribute); } } } } long end = System.currentTimeMillis(); long elapsed = end - start; Logger logger = getLogger(); if (logger.isEnabledFor(Logger.DEBUG)) logger.debug("Monitored attribute " + attribute + " in " + elapsed + " ms"); } } protected class MonitorInfo { private boolean errorNotified; public boolean isErrorNotified() { return errorNotified; } public void setErrorNotified(boolean errorNotified) { this.errorNotified = errorNotified; } public String toString() { return "errorNotified=" + isErrorNotified(); } } } ------------------------------------------------------- This SF.Net email is sponsored by BEA Weblogic Workshop FREE Java Enterprise J2EE developer tools! Get your free copy of BEA WebLogic Workshop 8.1 today. http://ads.osdn.com/?ad_id=5047&alloc_id=10808&op=click