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 java.util.Iterator;
011: import javax.management.MBeanNotificationInfo;
012: import javax.management.ObjectName;
013:
014: /**
015: * Defines a monitor MBean designed to observe the values of a counter attribute.
016: * <P>
017: * A counter monitor sends a {@link MonitorNotification#THRESHOLD_VALUE_EXCEEDED threshold notification}
018: * when the value of the counter reaches or exceeds a threshold known as the comparison level.
019: * The notify flag must be set to <CODE>true</CODE>.
020: * <BR>In addition, an offset mechanism enables particular counting intervals to be detected.
021: * <P>
022: * If the offset value is not zero, whenever the threshold is triggered by the counter value
023: * reaching a comparison level, that comparison level is incremented by the offset value.
024: * This is regarded as taking place instantaneously, that is before the count is incremented.
025: * Thus, for each level, the threshold triggers an event notification every time the count increases
026: * by an interval equal to the offset value.
027: * <P>
028: * If the counter can wrap around its maximum value, the modulus needs to be specified.
029: * The modulus is the value at which the counter is reset to zero.
030: * <P>
031: * If the counter difference mode is used, the value of the derived gauge is calculated
032: * as the difference between the observed counter values for two successive observations.
033: * If this difference is negative, the value of the derived gauge is incremented by the value of the modulus.
034: * <BR>The derived gauge value (V[t]) is calculated using the following method:
035: * <UL>
036: * <LI>if (counter[t] - counter[t-GP]) is positive then V[t] = counter[t] - counter[t-GP]
037: * <LI>if (counter[t] - counter[t-GP]) is negative then V[t] = counter[t] - counter[t-GP] + MODULUS
038: * </UL>
039: * This implementation of the counter monitor requires the observed attribute to be of the type integer
040: * (<CODE>Byte</CODE>, <CODE>Integer</CODE>, <CODE>Short</CODE>, <CODE>Long</CODE>).
041: *
042: * @author <a href="mailto:young_yy@hotmail.org">Young Yang</a>
043: */
044:
045: public class CounterMonitor extends Monitor implements
046: CounterMonitorMBean {
047: private boolean notify = false;
048: private boolean differenceMode = false;
049: private long modulus = 0L;
050: private long offset = 0L;
051: // private long threshold = 0L;
052: private long initThreshold = 0L;
053: // private long derivedGauge = 0L;
054: // private long lastDerivedGauge = 0L;
055: // private long maxDerivedGauge = 0L;
056:
057: private Class counterClass = null;
058:
059: // private long derivedGaugeTimestamp = System.currentTimeMillis();
060:
061: // private boolean isModulusExceeded = false;
062:
063: // private boolean wasNotified = false;
064:
065: public synchronized void start() {
066: _start();
067: }
068:
069: public synchronized void stop() {
070: _stop();
071: }
072:
073: public Number getDerivedGauge(ObjectName observedObjectName) {
074: return getNumber(((CounterMonitorData) getMonitorData(observedObjectName)).derivedGauge);
075: }
076:
077: public long getDerivedGaugeTimeStamp(ObjectName observedObjectName) {
078: return ((CounterMonitorData) getMonitorData(observedObjectName)).derivedGaugeTimestamp;
079: }
080:
081: public Number getThreshold(ObjectName observedObjectName) {
082: return getNumber(((CounterMonitorData) getMonitorData(observedObjectName)).threshold);
083: }
084:
085: public Number getInitThreshold() {
086: return getNumber(initThreshold);
087: }
088:
089: public void setInitThreshold(Number value)
090: throws java.lang.IllegalArgumentException {
091: if (value == null || value.longValue() < 0L) {
092: throw new IllegalArgumentException(
093: "The threshold must be greater than or equal to zero.");
094: }
095: checkNumber(value);
096:
097: initThreshold = value.longValue();
098: // threshold = initThreshold;
099: // wasNotified = false;
100: setAllThreshold(initThreshold);
101: // setAllNotified(false);
102: }
103:
104: private void setAllThreshold(long value) {
105: Iterator iter = observedObjects.values().iterator();
106: synchronized (iter) {
107: while (iter.hasNext()) {
108: CounterMonitorData data = (CounterMonitorData) iter
109: .next();
110: data.threshold = value;
111: data.wasNotified = false;
112: }
113: }
114: }
115:
116: public Number getOffset() {
117: return getNumber(offset);
118: }
119:
120: public void setOffset(Number value)
121: throws java.lang.IllegalArgumentException {
122: if (value == null || value.longValue() < 0L) {
123: throw new IllegalArgumentException(
124: "The offset must be greater than or equal to zero.");
125: }
126: checkNumber(value);
127: offset = value.longValue();
128: // wasNotified = false;
129: setAllNotified(false);
130: }
131:
132: public Number getModulus() {
133: return getNumber(modulus);
134: }
135:
136: public void setModulus(Number value)
137: throws java.lang.IllegalArgumentException {
138: if (value == null || value.longValue() < 0L) {
139: throw new IllegalArgumentException(
140: "The threshold value has to be a valid number higher than 0");
141: }
142: checkNumber(value);
143: modulus = value.longValue();
144: // wasNotified = false;
145: setAllNotified(false);
146: }
147:
148: public boolean getNotify() {
149: return notify;
150: }
151:
152: public void setNotify(boolean value) {
153: notify = value;
154: }
155:
156: public boolean getDifferenceMode() {
157: return differenceMode;
158: }
159:
160: public void setDifferenceMode(boolean value) {
161: differenceMode = value;
162: }
163:
164: public MBeanNotificationInfo[] getNotificationInfo() {
165: MBeanNotificationInfo[] notificationInfos = { new MBeanNotificationInfo(
166: new String[] {
167: MonitorNotification.RUNTIME_ERROR,
168: MonitorNotification.OBSERVED_OBJECT_ERROR,
169: MonitorNotification.OBSERVED_ATTRIBUTE_ERROR,
170: MonitorNotification.OBSERVED_ATTRIBUTE_TYPE_ERROR,
171: MonitorNotification.THRESHOLD_ERROR,
172: MonitorNotification.THRESHOLD_VALUE_EXCEEDED },
173: "javax.management.monitor.MonitorNotification",
174: "Notifications sent by the CounterMonitor MBean") };
175: return notificationInfos;
176: }
177:
178: // implemented by every entity monitor
179: protected void doMonitor(ObjectName observedObject, Object value) {
180:
181: CounterMonitorData data = (CounterMonitorData) observedObjects
182: .get(observedObject);
183: try {
184: long derivedGaugeTimestamp = System.currentTimeMillis(); // update timestamp
185: data.derivedGaugeTimestamp = derivedGaugeTimestamp;
186: if (data.threshold == 0) {
187: sendNotification(MonitorNotification.THRESHOLD_ERROR,
188: derivedGaugeTimestamp,
189: "threshold value must not be null or zero.",
190: null, null, observedObject);
191: return;
192: }
193:
194: if (!counterClass.isInstance(value)) { // type check
195: sendNotification(
196: MonitorNotification.OBSERVED_ATTRIBUTE_TYPE_ERROR,
197: derivedGaugeTimestamp,
198: "The threshold, offset and modulus must be of the same type as the counter(java.lang.Integer).",
199: null, null, observedObject);
200: return;
201: }
202:
203: // updateDerivedGauge((Number)value);
204: // roll over
205: if (data.isModulusExceeded
206: && data.derivedGauge < data.maxDerivedGauge) {
207: data.threshold = initThreshold;
208: data.wasNotified = false;
209: }
210:
211: if (!differenceMode) { // not differenceMode
212: data.derivedGauge = ((Number) value).longValue();
213: } else { // is defferenceMode
214: data.derivedGauge = ((Number) value).longValue()
215: - data.lastDerivedGauge;
216: data.lastDerivedGauge = ((Number) value).longValue();
217:
218: // If derived gauge is negative it means that the counter has wrapped around and
219: // the value of the threshold needs to be reset to its initial value.
220: //
221: if (data.derivedGauge < 0L) {
222: if (isModulusSet())
223: data.derivedGauge += modulus;
224: data.threshold = initThreshold;
225: data.wasNotified = false;
226: }
227: }
228:
229: if (notify && !(data.wasNotified)
230: && data.derivedGauge >= data.threshold) { // send notification
231: sendNotification(
232: MonitorNotification.THRESHOLD_VALUE_EXCEEDED,
233: derivedGaugeTimestamp, "",
234: getDerivedGauge(observedObject),
235: getThreshold(observedObject), observedObject);
236: data.wasNotified = true;
237: }
238:
239: // updateThreshold();
240:
241: if (data.derivedGauge >= data.threshold) { // update threshold etc.
242:
243: if (offset > 0L) {
244:
245: // Increment the threshold until its value is greater than the one for the current derived gauge.
246: while (data.derivedGauge >= data.threshold) {
247: data.threshold += offset;
248: }
249:
250: // If the counter can wrap around when it reaches its maximum
251: // and we are not dealing with counter differences then we need
252: // to reset the threshold to its initial value too.
253: //
254: if (!differenceMode && isModulusSet()
255: && data.threshold > modulus) {
256: data.isModulusExceeded = true;
257: data.maxDerivedGauge = data.derivedGauge;
258: }
259:
260: // Threshold value has been modified so we must notify again.
261: data.wasNotified = false;
262: } else {
263: data.isModulusExceeded = true;
264: data.maxDerivedGauge = data.derivedGauge;
265: }
266: }
267: } catch (Exception e) {
268: sendNotification(MonitorNotification.RUNTIME_ERROR,
269: data.derivedGaugeTimestamp, e.getMessage(), null,
270: null, observedObject);
271: }
272: }
273:
274: public void addObservedObject(ObjectName objectName)
275: throws IllegalArgumentException {
276: if (objectName == null)
277: throw new IllegalArgumentException(
278: "The object to observe cannot be null.");
279: observedObjects.put(objectName, new CounterMonitorData(
280: objectName));
281:
282: // System.out.println("addObservedObject: " + objectName);
283: }
284:
285: private Number getNumber(long value) {
286: if (counterClass == null)
287: counterClass = java.lang.Integer.class;
288: try {
289: return (Number) (counterClass
290: .getConstructor(new Class[] { java.lang.String.class })
291: .newInstance(new Object[] { "" + value }));
292: } catch (Exception e) {
293: e.printStackTrace();
294: return null;
295: }
296: }
297:
298: private void checkNumber(Number value) {
299: if (counterClass != null && !counterClass.isInstance(value)) {
300: throw new java.lang.IllegalArgumentException(
301: "The threshold, offset and modulus must be of the same type as the counter.");
302: }
303: counterClass = value.getClass();
304:
305: }
306:
307: private boolean isModulusSet() {
308: return modulus > 0L;
309: }
310:
311: private void setAllNotified(boolean value) {
312: Iterator iter = observedObjects.values().iterator();
313: synchronized (iter) {
314: while (iter.hasNext()) {
315: CounterMonitorData data = (CounterMonitorData) iter
316: .next();
317: data.wasNotified = value;
318: }
319: }
320: }
321:
322: class CounterMonitorData extends MonitorData {
323: long threshold = initThreshold;
324: long derivedGauge = 0L;
325: long lastDerivedGauge = 0L;
326: long maxDerivedGauge = 0L;
327: boolean isModulusExceeded = false;
328: boolean wasNotified = false;
329:
330: public CounterMonitorData(ObjectName objectName) {
331: super (objectName);
332: threshold = initThreshold;
333: }
334:
335: public ObjectName getObjectName() {
336: return super.getObjectName();
337: }
338: }
339: }
|