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 counter monitor service.
036: *
037: * <p><b>Revisions:</b>
038: * <p><b>20020319 Adrian Brock:</b>
039: * <ul>
040: * <li>Reset the threshold when the value becomes negative in difference mode
041: * </ul>
042: * <p><b>20020326 Adrian Brock:</b>
043: * <ul>
044: * <li>The spec says the modulus should be *strictly* exceeded. It appears
045: * from testing the RI, it is a mathematical definition of modulus. e.g.
046: * 10 exceeds a modulus of 10
047: * </ul>
048: *
049: * @author <a href="mailto:Adrian.Brock@HappeningTimes.com">Adrian Brock</a>
050: * @version $Revision: 57200 $
051: *
052: */
053: public class CounterMonitor extends Monitor implements
054: CounterMonitorMBean {
055: // Constants -----------------------------------------------------
056:
057: /**
058: * The counter threshold exceeded has been notified.
059: */
060: int THRESHOLD_EXCEEDED_NOTIFIED = 16;
061:
062: /**
063: * The threshold type error has been notified.
064: */
065: int THRESHOLD_ERROR_NOTIFIED = 32;
066:
067: // Attributes ----------------------------------------------------
068:
069: /**
070: * The offset.
071: */
072: Number offset = new Integer(0);
073:
074: /**
075: * The modulus.
076: */
077: Number modulus = new Integer(0);
078:
079: /**
080: * The last stated threshold.
081: */
082: Number initThreshold = new Integer(0);
083:
084: /**
085: * Difference mode.
086: */
087: boolean differenceMode = false;
088:
089: /**
090: * Notify.
091: */
092: boolean notify = false;
093: /**
094: * The runnable monitor.
095: */
096: private MonitorRunnable monitorRunnable;
097:
098: // Static --------------------------------------------------------
099:
100: // Constructors --------------------------------------------------
101:
102: /**
103: * Default Constructor
104: */
105: public CounterMonitor() {
106: }
107:
108: // Public --------------------------------------------------------
109:
110: public MBeanNotificationInfo[] getNotificationInfo() {
111: MBeanNotificationInfo[] result = new MBeanNotificationInfo[1];
112: String[] types = new String[] {
113: MonitorNotification.RUNTIME_ERROR,
114: MonitorNotification.OBSERVED_OBJECT_ERROR,
115: MonitorNotification.OBSERVED_ATTRIBUTE_ERROR,
116: MonitorNotification.OBSERVED_ATTRIBUTE_TYPE_ERROR,
117: MonitorNotification.THRESHOLD_ERROR,
118: MonitorNotification.THRESHOLD_VALUE_EXCEEDED };
119: result[0] = new MBeanNotificationInfo(types,
120: "javax.management.monitor.MonitorNotification",
121: "Notifications sent by the Counter Monitor Service MBean");
122: return result;
123: }
124:
125: // CounterMonitorMBean implementation ----------------------------
126:
127: public Number getDerivedGauge() {
128: ObservedObject object = getFirstObservedObject();
129: if (object != null)
130: return (Number) object.getDerivedGauge();
131: else
132: return null;
133: }
134:
135: public Number getDerivedGauge(ObjectName name) {
136: ObservedObject object = retrieveObservedObject(name);
137: if (object != null)
138: return (Number) object.getDerivedGauge();
139: else
140: return null;
141: }
142:
143: public long getDerivedGaugeTimeStamp() {
144: ObservedObject object = getFirstObservedObject();
145: if (object != null)
146: return object.getDerivedGaugeTimeStamp();
147: else
148: return 0L;
149: }
150:
151: public long getDerivedGaugeTimeStamp(ObjectName name) {
152: ObservedObject object = retrieveObservedObject(name);
153: if (object != null)
154: return object.getDerivedGaugeTimeStamp();
155: else
156: return 0L;
157: }
158:
159: public boolean getDifferenceMode() {
160: return differenceMode;
161: }
162:
163: public void setDifferenceMode(boolean value) {
164: differenceMode = value;
165: }
166:
167: public Number getInitThreshold() {
168: return initThreshold;
169: }
170:
171: public void setInitThreshold(Number threshold)
172: throws IllegalArgumentException {
173: if (threshold == null)
174: throw new IllegalArgumentException("Null threshold");
175: if (threshold.longValue() < 0)
176: throw new IllegalArgumentException("Negative threshold");
177: initThreshold = threshold;
178: }
179:
180: public Number getModulus() {
181: return modulus;
182: }
183:
184: public void setModulus(Number value)
185: throws IllegalArgumentException {
186: if (value == null)
187: throw new IllegalArgumentException("Null modulus");
188: if (value.longValue() < 0)
189: throw new IllegalArgumentException("Negative modulus");
190: modulus = value;
191: }
192:
193: public boolean getNotify() {
194: return notify;
195: }
196:
197: public void setNotify(boolean value) {
198: notify = value;
199: }
200:
201: public Number getOffset() {
202: return offset;
203: }
204:
205: public void setOffset(Number value) throws IllegalArgumentException {
206: if (value == null)
207: throw new IllegalArgumentException("Null offset");
208: if (value.longValue() < 0)
209: throw new IllegalArgumentException("Negative offset");
210: offset = value;
211: }
212:
213: public Number getThreshold() {
214: ObservedObject object = getFirstObservedObject();
215: if (object != null)
216: return (Number) object.getThreshold();
217: else
218: return null;
219: }
220:
221: public Number getThreshold(ObjectName name) {
222: ObservedObject object = retrieveObservedObject(name);
223: if (object != null)
224: return (Number) object.getThreshold();
225: else
226: return null;
227: }
228:
229: public void setThreshold(Number value)
230: throws IllegalArgumentException {
231: setInitThreshold(value);
232: }
233:
234: public synchronized void start() {
235: // Ignore if already active
236: if (active)
237: return;
238: active = true;
239:
240: for (Iterator i = retrieveObservedObjects().values().iterator(); i
241: .hasNext();) {
242: ObservedObject object = (ObservedObject) i.next();
243: initObservedObject(object);
244: }
245:
246: // Start the monitor runnable
247: MonitorCallback callback = new MonitorCallback() {
248: public void monitorCallback(ObservedObject object,
249: MBeanAttributeInfo attributeInfo, Object value)
250: throws Exception {
251: monitor(object, attributeInfo, value);
252: }
253:
254: public MonitorNotification createNotification(String type,
255: Object source, long timeStamp, String message,
256: Object derivedGauge, String observedAttribute,
257: ObjectName observedObject, Object trigger) {
258: return new MonitorNotification(type, source,
259: nextSeqNo(), timeStamp, message, derivedGauge,
260: observedAttribute, observedObject, trigger);
261: }
262: };
263: monitorRunnable = new MonitorRunnable(this , objectName,
264: callback, observedObjects, server);
265: }
266:
267: public synchronized void stop() {
268: // Ignore if not active
269: if (!active)
270: return;
271:
272: // Stop the monitor runnable
273: active = false;
274: monitorRunnable.setScheduler(null);
275: monitorRunnable = null;
276: }
277:
278: // Package protected ---------------------------------------------
279:
280: void initObservedObject(ObservedObject object) {
281: super .initObservedObject(object);
282: object.setDerivedGauge(new Integer(0));
283: object.setThreshold(initThreshold);
284: object.setLastValue(null);
285: }
286:
287: // REVIEW: This works but needs tidying up!
288: void monitor(ObservedObject object,
289: MBeanAttributeInfo attributeInfo, Object value)
290: throws Exception {
291: // Wrong type of attribute
292: if (!(value instanceof Byte) && !(value instanceof Integer)
293: && !(value instanceof Short)
294: && !(value instanceof Long)) {
295: sendAttributeTypeErrorNotification(object,
296: "Attribute is not an integer type");
297: return;
298: }
299:
300: Number threshold = (Number) object.getThreshold();
301:
302: // Wrong threshold types
303: if (threshold.getClass() != value.getClass()
304: || offset.longValue() != 0
305: && offset.getClass() != value.getClass()
306: || modulus.longValue() != 0
307: && modulus.getClass() != value.getClass()) {
308: sendThresholdErrorNotification(object, value);
309: return;
310: }
311:
312: // Cast the counter to a Number
313: Number number = (Number) value;
314: Number lastValue = (Number) object.getLastValue();
315: Number derivedGauge = (Number) object.getDerivedGauge();
316:
317: // Get the gauge and record when we got it.
318: if (differenceMode) {
319: if (lastValue == null)
320: derivedGauge = getZero(number);
321: else
322: derivedGauge = sub(number, lastValue);
323: if (derivedGauge.longValue() < 0
324: && modulus.longValue() != 0) {
325: derivedGauge = add(derivedGauge, modulus);
326: threshold = initThreshold;
327: object.setThreshold(threshold);
328: object
329: .setNotAlreadyNotified(THRESHOLD_EXCEEDED_NOTIFIED);
330: }
331: } else
332: derivedGauge = number;
333:
334: object.setDerivedGauge(derivedGauge);
335: object.setDerivedGaugeTimeStamp(System.currentTimeMillis());
336:
337: // Have we wrapped?
338: if (lastValue != null && modulus.longValue() != 0
339: && offset.longValue() != 0
340: && derivedGauge.longValue() < lastValue.longValue()) {
341: object.setNotAlreadyNotified(THRESHOLD_EXCEEDED_NOTIFIED);
342: }
343:
344: // Fire the event if the threshold has been exceeded
345: if (derivedGauge.longValue() >= threshold.longValue()) {
346: if (object.notAlreadyNotified(THRESHOLD_EXCEEDED_NOTIFIED)) {
347: sendThresholdExceededNotification(object, derivedGauge);
348:
349: // Add any offsets required to get a new threshold
350: if (offset.longValue() != 0) {
351: while (threshold.longValue() <= derivedGauge
352: .longValue())
353: threshold = add(threshold, offset);
354: object.setThreshold(threshold);
355: object
356: .setNotAlreadyNotified(THRESHOLD_EXCEEDED_NOTIFIED);
357: }
358: }
359: } else {
360: // Reset notfication when it becomes less than threshold
361: if (derivedGauge.longValue() < threshold.longValue()
362: && offset.longValue() == 0)
363: object
364: .setNotAlreadyNotified(THRESHOLD_EXCEEDED_NOTIFIED);
365: }
366:
367: // Restart when modulus exceeded
368: if (modulus.longValue() != 0
369: && number.longValue() >= modulus.longValue()) {
370: object.setThreshold(initThreshold);
371: object.setAlreadyNotified(THRESHOLD_EXCEEDED_NOTIFIED);
372: }
373:
374: // Remember the last value
375: object.setLastValue(number);
376: }
377:
378: /**
379: * Get zero for the type passed.
380: *
381: * @param value - the reference object
382: * @return zero for the correct type
383: */
384: Number getZero(Number value) {
385: if (value instanceof Byte)
386: return new Byte((byte) 0);
387: if (value instanceof Integer)
388: return new Integer(0);
389: if (value instanceof Short)
390: return new Short((short) 0);
391: return new Long(0);
392: }
393:
394: /**
395: * Add two numbers together.
396: * @param value1 the first value.
397: * @param value2 the second value.
398: * @return value1 + value2 of the correct type
399: */
400: Number add(Number value1, Number value2) {
401: if (value1 instanceof Byte)
402: return new Byte((byte) (value1.byteValue() + value2
403: .byteValue()));
404: if (value1 instanceof Integer)
405: return new Integer(value1.intValue() + value2.intValue());
406: if (value1 instanceof Short)
407: return new Short((short) (value1.shortValue() + value2
408: .shortValue()));
409: return new Long(value1.longValue() + value2.longValue());
410: }
411:
412: /**
413: * Subtract two numbers.
414: * @param value1 the first value.
415: * @param value2 the second value.
416: * @return value1 - value2 of the correct type
417: */
418: Number sub(Number value1, Number value2) {
419: if (value1 instanceof Byte)
420: return new Byte((byte) (value1.byteValue() - value2
421: .byteValue()));
422: if (value1 instanceof Integer)
423: return new Integer(value1.intValue() - value2.intValue());
424: if (value1 instanceof Short)
425: return new Short((short) (value1.shortValue() - value2
426: .shortValue()));
427: return new Long(value1.longValue() - value2.longValue());
428: }
429:
430: /**
431: * Send a threshold exceeded event.<p>
432: *
433: * This is only performed when requested and it has not already been sent.
434: *
435: * @param value the attribute value.
436: */
437: void sendThresholdExceededNotification(ObservedObject object,
438: Object value) {
439: if (notify) {
440: sendNotification(object,
441: MonitorNotification.THRESHOLD_VALUE_EXCEEDED,
442: object.getDerivedGaugeTimeStamp(),
443: "threshold exceeded", observedAttribute, value,
444: object.getThreshold());
445: }
446: }
447:
448: /**
449: * Send a threshold error event.<p>
450: *
451: * This is only performed when requested and it has not already been sent.
452: *
453: * @param value the attribute value.
454: */
455: void sendThresholdErrorNotification(ObservedObject object,
456: Object value) {
457: if (object.notAlreadyNotified(THRESHOLD_ERROR_NOTIFIED))
458: sendNotification(
459: object,
460: MonitorNotification.THRESHOLD_ERROR,
461: object.getDerivedGaugeTimeStamp(),
462: "Threshold, offset or modulus not the correct type",
463: observedAttribute, null, null);
464: }
465:
466: // Protected -----------------------------------------------------
467:
468: // Private -------------------------------------------------------
469:
470: // Inner classes -------------------------------------------------
471: }
|