001: /*
002: * JBoss, Home of Professional Open Source.
003: * Copyright 2006, Red Hat Middleware LLC, and individual contributors
004: * as indicated by the @author tags. See the copyright.txt file in the
005: * distribution for a full listing of individual contributors.
006: *
007: * This is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as
009: * published by the Free Software Foundation; either version 2.1 of
010: * the License, or (at your option) any later version.
011: *
012: * This software is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this software; if not, write to the Free
019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021: */
022: package javax.management.monitor;
023:
024: import java.util.Iterator;
025:
026: import javax.management.MBeanAttributeInfo;
027: import javax.management.MBeanNotificationInfo;
028: import javax.management.ObjectName;
029:
030: import org.jboss.mx.util.MonitorRunnable;
031: import org.jboss.mx.util.ObservedObject;
032: import org.jboss.mx.util.MonitorCallback;
033:
034: /**
035: * The gauge monitor service.
036: *
037: * @author <a href="mailto:Adrian.Brock@HappeningTimes.com">Adrian Brock</a>
038: * @version $Revision: 57200 $
039: *
040: */
041: public class GaugeMonitor extends Monitor implements GaugeMonitorMBean {
042: // Constants -----------------------------------------------------
043:
044: /**
045: * The gauge high threshold exceeded has been notified.
046: */
047: int THRESHOLD_HIGH_EXCEEDED_NOTIFIED = 16;
048:
049: /**
050: * The gauge low threshold exceeded has been notified.
051: */
052: int THRESHOLD_LOW_EXCEEDED_NOTIFIED = 32;
053:
054: /**
055: * The threshold type error has been notified.
056: */
057: int THRESHOLD_ERROR_NOTIFIED = 64;
058:
059: // Attributes ----------------------------------------------------
060:
061: /**
062: * Difference mode.
063: */
064: boolean differenceMode = false;
065:
066: /**
067: * The high threshold.
068: */
069: Number highThreshold = new Integer(0);
070:
071: /**
072: * The low threshold.
073: */
074: Number lowThreshold = new Integer(0);
075:
076: /**
077: * High Notify.
078: */
079: boolean notifyHigh = false;
080:
081: /**
082: * Low Notify.
083: */
084: boolean notifyLow = false;
085: /**
086: * The runnable monitor.
087: */
088: private MonitorRunnable monitorRunnable;
089:
090: // Static --------------------------------------------------------
091:
092: // Constructors --------------------------------------------------
093:
094: /**
095: * Default Constructor
096: */
097: public GaugeMonitor() {
098: }
099:
100: // Public --------------------------------------------------------
101:
102: public MBeanNotificationInfo[] getNotificationInfo() {
103: MBeanNotificationInfo[] result = new MBeanNotificationInfo[1];
104: String[] types = new String[] {
105: MonitorNotification.RUNTIME_ERROR,
106: MonitorNotification.OBSERVED_OBJECT_ERROR,
107: MonitorNotification.OBSERVED_ATTRIBUTE_ERROR,
108: MonitorNotification.OBSERVED_ATTRIBUTE_TYPE_ERROR,
109: MonitorNotification.THRESHOLD_ERROR,
110: MonitorNotification.THRESHOLD_HIGH_VALUE_EXCEEDED,
111: MonitorNotification.THRESHOLD_LOW_VALUE_EXCEEDED };
112: result[0] = new MBeanNotificationInfo(types,
113: "javax.management.monitor.MonitorNotification",
114: "Notifications sent by the Gauge Monitor Service MBean");
115: return result;
116: }
117:
118: // GaugeMonitorMBean implementation ------------------------------
119:
120: public Number getDerivedGauge() {
121: ObservedObject object = getFirstObservedObject();
122: if (object != null)
123: return (Number) object.getDerivedGauge();
124: else
125: return null;
126: }
127:
128: public Number getDerivedGauge(ObjectName name) {
129: ObservedObject object = retrieveObservedObject(name);
130: if (object != null)
131: return (Number) object.getDerivedGauge();
132: else
133: return null;
134: }
135:
136: public long getDerivedGaugeTimeStamp() {
137: ObservedObject object = getFirstObservedObject();
138: if (object != null)
139: return object.getDerivedGaugeTimeStamp();
140: else
141: return 0L;
142: }
143:
144: public long getDerivedGaugeTimeStamp(ObjectName name) {
145: ObservedObject object = retrieveObservedObject(name);
146: if (object != null)
147: return object.getDerivedGaugeTimeStamp();
148: else
149: return 0L;
150: }
151:
152: public boolean getDifferenceMode() {
153: return differenceMode;
154: }
155:
156: public void setDifferenceMode(boolean value) {
157: differenceMode = value;
158: }
159:
160: public boolean getNotifyHigh() {
161: return notifyHigh;
162: }
163:
164: public void setNotifyHigh(boolean value) {
165: notifyHigh = value;
166: }
167:
168: public boolean getNotifyLow() {
169: return notifyLow;
170: }
171:
172: public void setNotifyLow(boolean value) {
173: notifyLow = value;
174: }
175:
176: public Number getHighThreshold() {
177: return highThreshold;
178: }
179:
180: public Number getLowThreshold() {
181: return lowThreshold;
182: }
183:
184: public void setThresholds(Number highValue, Number lowValue)
185: throws IllegalArgumentException {
186: if (highValue == null)
187: throw new IllegalArgumentException("Null high threshold");
188: if (lowValue == null)
189: throw new IllegalArgumentException("Null low threshold");
190: if (highValue.getClass() != lowValue.getClass())
191: throw new IllegalArgumentException(
192: "High and low different types");
193: if (highValue.doubleValue() < lowValue.doubleValue())
194: throw new IllegalArgumentException(
195: "High less than low threshold");
196: highThreshold = highValue;
197: lowThreshold = lowValue;
198: }
199:
200: public synchronized void start() {
201: // Ignore if already active
202: if (active)
203: return;
204: active = true;
205:
206: for (Iterator i = retrieveObservedObjects().values().iterator(); i
207: .hasNext();) {
208: ObservedObject object = (ObservedObject) i.next();
209: initObservedObject(object);
210: }
211:
212: // Start the monitor runnable
213: MonitorCallback callback = new MonitorCallback() {
214: public void monitorCallback(ObservedObject object,
215: MBeanAttributeInfo attributeInfo, Object value)
216: throws Exception {
217: monitor(object, attributeInfo, value);
218: }
219:
220: public MonitorNotification createNotification(String type,
221: Object source, long timeStamp, String message,
222: Object derivedGauge, String observedAttribute,
223: ObjectName observedObject, Object trigger) {
224: return new MonitorNotification(type, source,
225: nextSeqNo(), timeStamp, message, derivedGauge,
226: observedAttribute, observedObject, trigger);
227: }
228: };
229: monitorRunnable = new MonitorRunnable(this , objectName,
230: callback, observedObjects, server);
231: }
232:
233: public synchronized void stop() {
234: // Ignore if not active
235: if (!active)
236: return;
237:
238: // Stop the monitor runnable
239: active = false;
240: monitorRunnable.setScheduler(null);
241: monitorRunnable = null;
242: }
243:
244: // Package protected ---------------------------------------------
245:
246: void initObservedObject(ObservedObject object) {
247: super .initObservedObject(object);
248: object.setDerivedGauge(new Integer(0));
249: object.setLastValue(null);
250: }
251:
252: // REVIEW: This works but needs tidying up!
253: void monitor(ObservedObject object,
254: MBeanAttributeInfo attributeInfo, Object value)
255: throws Exception {
256: // Wrong type of attribute
257: if (!(value instanceof Number)) {
258: sendAttributeTypeErrorNotification(object,
259: "Attribute is not a number");
260: return;
261: }
262:
263: // Wrong threshold types
264: if (highThreshold.getClass() != value.getClass()
265: || lowThreshold.getClass() != value.getClass()) {
266: sendThresholdErrorNotification(object, value);
267: return;
268: }
269:
270: // Cast the gauge to a Number
271: Number number = (Number) value;
272: Number lastValue = (Number) object.getLastValue();
273: Number derivedGauge = (Number) object.getDerivedGauge();
274:
275: // Get the gauge and record when we got it.
276: if (differenceMode) {
277: if (lastValue == null)
278: derivedGauge = getZero(number);
279: else
280: derivedGauge = sub(number, lastValue);
281: } else
282: derivedGauge = number;
283: object.setDerivedGauge(derivedGauge);
284: object.setDerivedGaugeTimeStamp(System.currentTimeMillis());
285:
286: // Fire the event if the low threshold has been exceeded
287: if (derivedGauge.doubleValue() <= lowThreshold.doubleValue()) {
288: if (object
289: .notAlreadyNotified(THRESHOLD_LOW_EXCEEDED_NOTIFIED)) {
290: // Reset high threshold
291: object
292: .setNotAlreadyNotified(THRESHOLD_HIGH_EXCEEDED_NOTIFIED);
293:
294: // Send the notification once
295: sendThresholdLowExceededNotification(object,
296: derivedGauge);
297: }
298: }
299:
300: // Fire the event if the high threshold has been exceeded
301: if (derivedGauge.doubleValue() >= highThreshold.doubleValue()) {
302: if (object
303: .notAlreadyNotified(THRESHOLD_HIGH_EXCEEDED_NOTIFIED)) {
304: // Reset low threshold
305: object
306: .setNotAlreadyNotified(THRESHOLD_LOW_EXCEEDED_NOTIFIED);
307:
308: // Send the notification once
309: sendThresholdHighExceededNotification(object,
310: derivedGauge);
311: }
312: }
313:
314: // Remember the last value
315: object.setLastValue(number);
316: }
317:
318: /**
319: * Get zero for the type passed.
320: *
321: * @param value reference object
322: * @return zero for the correct type
323: */
324: Number getZero(Number value) {
325: if (value instanceof Byte)
326: return new Byte((byte) 0);
327: if (value instanceof Integer)
328: return new Integer(0);
329: if (value instanceof Long)
330: return new Long(0);
331: if (value instanceof Short)
332: return new Short((short) 0);
333: if (value instanceof Float)
334: return new Float(0);
335: return new Double(0);
336: }
337:
338: /**
339: * Subtract two numbers.
340: * @param value1 the first value.
341: * @param value2 the second value.
342: * @return value1 - value2 of the correct type
343: */
344: Number sub(Number value1, Number value2) {
345: if (value1 instanceof Byte)
346: return new Byte((byte) (value1.byteValue() - value2
347: .byteValue()));
348: if (value1 instanceof Integer)
349: return new Integer(value1.intValue() - value2.intValue());
350: if (value1 instanceof Long)
351: return new Long((value1.longValue() - value2.longValue()));
352: if (value1 instanceof Short)
353: return new Short((short) (value1.shortValue() - value2
354: .shortValue()));
355: if (value1 instanceof Float)
356: return new Float(
357: (value1.floatValue() - value2.floatValue()));
358: return new Double(value1.doubleValue() - value2.doubleValue());
359: }
360:
361: /**
362: * Send a threshold low exceeded event.<p>
363: *
364: * This is only performed when requested and it has not already been sent.
365: *
366: * @param value the attribute value.
367: */
368: void sendThresholdLowExceededNotification(ObservedObject object,
369: Object value) {
370: if (notifyLow) {
371: sendNotification(object,
372: MonitorNotification.THRESHOLD_LOW_VALUE_EXCEEDED,
373: object.getDerivedGaugeTimeStamp(),
374: "low threshold exceeded", observedAttribute, value,
375: lowThreshold);
376: }
377: }
378:
379: /**
380: * Send a high threshold exceeded event.<p>
381: *
382: * This is only performed when requested and it has not already been sent.
383: *
384: * @param value the attribute value.
385: */
386: void sendThresholdHighExceededNotification(ObservedObject object,
387: Object value) {
388: if (notifyHigh) {
389: sendNotification(object,
390: MonitorNotification.THRESHOLD_HIGH_VALUE_EXCEEDED,
391: object.getDerivedGaugeTimeStamp(),
392: "high threshold exceeded", observedAttribute,
393: value, highThreshold);
394: }
395: }
396:
397: /**
398: * Send a threshold error event.<p>
399: *
400: * This is only performed when requested and it has not already been sent.
401: *
402: * @param value the attribute value.
403: */
404: void sendThresholdErrorNotification(ObservedObject object,
405: Object value) {
406: if (object.notAlreadyNotified(THRESHOLD_ERROR_NOTIFIED))
407: sendNotification(object,
408: MonitorNotification.THRESHOLD_ERROR, object
409: .getDerivedGaugeTimeStamp(),
410: "High or Low Threshold not the correct type",
411: observedAttribute, null, null);
412: }
413:
414: // Protected -----------------------------------------------------
415:
416: // Private -------------------------------------------------------
417:
418: // Inner classes -------------------------------------------------
419: }
|