001: /* JFox, the OpenSource J2EE Application Server
002: *
003: * Copyright (C) 2002 huihoo.org
004: * Distributable under GNU LGPL license
005: * See the GNU Lesser General Public License for more details.
006: */
007:
008: package javax.management.monitor;
009:
010: import javax.management.MBeanNotificationInfo;
011: import javax.management.ObjectName;
012:
013: /**
014: * Defines a monitor MBean designed to observe the values of a gauge attribute.
015: * <P>
016: * A gauge monitor observes an attribute that is continuously variable with time.
017: * A gauge monitor sends notifications as follows:
018: * <UL>
019: * <LI> if the attribute value is increasing and becomes equal to or greater than the high threshold value,
020: * a {@link MonitorNotification#THRESHOLD_HIGH_VALUE_EXCEEDED threshold high notification} is sent.
021: * The notify high flag must be set to <CODE>true</CODE>
022: * <BR>Subsequent crossings of the high threshold value do not cause further notifications unless
023: * the attribute value becomes equal to or less than the low threshold value.
024: * <LI> if the attribute value is decreasing and becomes equal to or less than the low threshold value,
025: * a {@link MonitorNotification#THRESHOLD_LOW_VALUE_EXCEEDED threshold low notification} is sent.
026: * The notify low flag must be set to <CODE>true</CODE>.
027: * <BR>Subsequent crossings of the low threshold value do not cause further notifications unless
028: * the attribute value becomes equal to or greater than the high threshold value.
029: * </UL>
030: * This provides a hysteresis mechanism to avoid repeated triggering of notifications when
031: * the attribute value makes small oscillations around the high or low threshold value.
032: * <P>
033: * If the gauge difference mode is used, the value of the derived gauge is calculated
034: * as the difference between the observed gauge values for two successive observations.
035: * <BR>The derived gauge value (V[t]) is calculated using the following method:
036: * <UL>
037: * <LI>V[t] = gauge[t] - gauge[t-GP]
038: * </UL>
039: * This implementation of the gauge monitor requires the observed attribute to be of the type integer or floating-point
040: * (<CODE>Byte</CODE>, <CODE>Integer</CODE>, <CODE>Short</CODE>, <CODE>Long</CODE>, <CODE>Float</CODE>, <CODE>Double</CODE>).
041: *
042: * @author <a href="mailto:young_yy@hotmail.org">Young Yang</a>
043: */
044:
045: public class GaugeMonitor extends Monitor implements GaugeMonitorMBean {
046: private double highThreshold = 0.0f;
047: private double lowThreshold = 0.0f;
048: private boolean notifyHigh = false;
049: private boolean notifyLow = false;
050: private boolean differenceMode = false;
051: private boolean highNotified = false;
052: private boolean lowNotified = false;
053: private Class gaugeClass = null;
054:
055: public void start() {
056: _start();
057: }
058:
059: public void stop() {
060: _stop();
061: }
062:
063: public Number getDerivedGauge(ObjectName observedObject) {
064: return getNumber(((GaugeMonitorData) getMonitorData(observedObject)).derivedGauge);
065: }
066:
067: public long getDerivedGaugeTimeStamp(ObjectName observedObject) {
068: return ((GaugeMonitorData) getMonitorData(observedObject)).derivedGaugeTimestamp;
069: }
070:
071: public Number getHighThreshold() {
072: return getNumber(highThreshold);
073: }
074:
075: public Number getLowThreshold() {
076: return getNumber(lowThreshold);
077: }
078:
079: public void setThresholds(Number highValue, Number lowValue)
080: throws java.lang.IllegalArgumentException {
081: if (highValue == null || lowValue == null) {
082: throw new IllegalArgumentException(
083: "Threshold values cannot be null");
084: }
085: if (!highValue.getClass().equals(lowValue.getClass())) {
086: throw new IllegalArgumentException(
087: "The high and the low thresholds must be of the same type.");
088: }
089: if (highValue.doubleValue() < lowValue.doubleValue()) {
090: throw new IllegalArgumentException(
091: "The threshold high value must be greater than or equal to threshold low value.");
092: }
093:
094: checkNumber(highValue);
095:
096: highThreshold = highValue.doubleValue();
097: lowThreshold = lowValue.doubleValue();
098: highNotified = false;
099: lowNotified = false;
100: }
101:
102: public boolean getNotifyHigh() {
103: return notifyHigh;
104: }
105:
106: public void setNotifyHigh(boolean value) {
107: this .notifyHigh = value;
108: highNotified = false;
109: }
110:
111: public boolean getNotifyLow() {
112: return notifyLow;
113: }
114:
115: public void setNotifyLow(boolean value) {
116: this .notifyLow = value;
117: lowNotified = false;
118: }
119:
120: public boolean getDifferenceMode() {
121: return differenceMode;
122: }
123:
124: public void setDifferenceMode(boolean value) {
125: this .differenceMode = value;
126: }
127:
128: public MBeanNotificationInfo[] getNotificationInfo() {
129: String[] types = { MonitorNotification.RUNTIME_ERROR,
130: MonitorNotification.OBSERVED_OBJECT_ERROR,
131: MonitorNotification.OBSERVED_ATTRIBUTE_ERROR,
132: MonitorNotification.OBSERVED_ATTRIBUTE_TYPE_ERROR,
133: MonitorNotification.THRESHOLD_ERROR,
134: MonitorNotification.THRESHOLD_HIGH_VALUE_EXCEEDED,
135: MonitorNotification.THRESHOLD_LOW_VALUE_EXCEEDED };
136: MBeanNotificationInfo[] notifsInfo = { new MBeanNotificationInfo(
137: types, "javax.management.monitor.MonitorNotification",
138: "Notifications sent by the GaugeMonitor MBean") };
139: return notifsInfo;
140: }
141:
142: // implemented by every entity monitor
143: protected void doMonitor(ObjectName observedObject, Object value) {
144: GaugeMonitorData data = (GaugeMonitorData) getMonitorData(observedObject);
145: try {
146: long derivedGaugeTimestamp = System.currentTimeMillis(); // update timestamp
147: data.derivedGaugeTimestamp = derivedGaugeTimestamp;
148:
149: if (!gaugeClass.isInstance(value)) {
150: sendNotification(
151: MonitorNotification.OBSERVED_ATTRIBUTE_TYPE_ERROR,
152: derivedGaugeTimestamp,
153: "The observed attribute type must be an integer type or a floating-point type.",
154: null, null, observedObject);
155: return;
156: }
157:
158: if (highThreshold == 0.0f || lowThreshold == 0.0f) {
159: sendNotification(
160: MonitorNotification.THRESHOLD_ERROR,
161: derivedGaugeTimestamp,
162: "The threshold high and threshold low must not be zero",
163: null, null, observedObject);
164: return;
165: }
166:
167: // update derived gauge
168: if (!differenceMode) { // is difference mode
169: data.derivedGauge = ((Number) value).doubleValue();
170: } else { // not difference mode
171: data.derivedGauge = ((Number) value).doubleValue()
172: - data.lastDerivedGauge;
173: data.lastDerivedGauge = ((Number) value).doubleValue();
174: }
175:
176: // send notification
177: if (notifyHigh && !highNotified
178: && data.derivedGauge > highThreshold) {
179: sendNotification(
180: MonitorNotification.THRESHOLD_HIGH_VALUE_EXCEEDED,
181: derivedGaugeTimestamp, "",
182: getDerivedGauge(observedObject),
183: getHighThreshold(), observedObject);
184: highNotified = true;
185: lowNotified = false;
186: }
187: if (notifyLow && !lowNotified
188: && data.derivedGauge < lowThreshold) {
189: sendNotification(
190: MonitorNotification.THRESHOLD_LOW_VALUE_EXCEEDED,
191: derivedGaugeTimestamp, "",
192: getDerivedGauge(observedObject),
193: getLowThreshold(), observedObject);
194: lowNotified = true;
195: highNotified = false;
196: }
197: } catch (Exception e) {
198: e.printStackTrace();
199: sendNotification(MonitorNotification.RUNTIME_ERROR,
200: data.derivedGaugeTimestamp, e.getMessage(), null,
201: null, observedObject);
202: }
203:
204: }
205:
206: public void addObservedObject(ObjectName objectName)
207: throws IllegalArgumentException {
208: if (objectName == null)
209: throw new IllegalArgumentException(
210: "The object to observe cannot be null.");
211: observedObjects.put(objectName,
212: new GaugeMonitorData(objectName));
213: }
214:
215: // decide the type according the gaugeClass
216: private Number getNumber(double value) {
217: if (gaugeClass == null)
218: return null;
219: try {
220: if (gaugeClass == java.lang.Float.class
221: || gaugeClass == java.lang.Double.class) { // float type
222: return (Number) (gaugeClass
223: .getConstructor(new Class[] { java.lang.String.class })
224: .newInstance(new Object[] { "" + value }));
225: } else { // integer type
226: return (Number) (gaugeClass
227: .getConstructor(new Class[] { java.lang.String.class })
228: .newInstance(new Object[] { "" + (long) value }));
229: }
230: } catch (Exception e) {
231: e.printStackTrace();
232: return null;
233: }
234: }
235:
236: private void checkNumber(Number value) {
237: if (gaugeClass != null && !gaugeClass.isInstance(value)) {
238: throw new java.lang.IllegalArgumentException(
239: "The threshold, offset and modulus must be of the same type as the counter.");
240: }
241: gaugeClass = value.getClass();
242:
243: }
244:
245: class GaugeMonitorData extends MonitorData {
246: double derivedGauge = 0.0f;
247: double lastDerivedGauge = 0.0f;
248: long derivedGaugeTimestamp = System.currentTimeMillis();
249:
250: public GaugeMonitorData(ObjectName objectName) {
251: super (objectName);
252: }
253:
254: public ObjectName getObjectName() {
255: return super.getObjectName();
256: }
257: }
258: }
|