blob: 567bf2c47febd57e6bb9b38f0acc6f340a5e639c [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 1999-2007 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package javax.management.monitor;
27
28import static com.sun.jmx.defaults.JmxProperties.MONITOR_LOGGER;
29import java.util.logging.Level;
30import javax.management.ObjectName;
31import javax.management.MBeanNotificationInfo;
32import static javax.management.monitor.Monitor.NumericalType.*;
33import static javax.management.monitor.MonitorNotification.*;
34
35/**
36 * Defines a monitor MBean designed to observe the values of a counter
37 * attribute.
38 *
39 * <P> A counter monitor sends a {@link
40 * MonitorNotification#THRESHOLD_VALUE_EXCEEDED threshold
41 * notification} when the value of the counter reaches or exceeds a
42 * threshold known as the comparison level. The notify flag must be
43 * set to <CODE>true</CODE>.
44 *
45 * <P> In addition, an offset mechanism enables particular counting
46 * intervals to be detected. If the offset value is not zero,
47 * whenever the threshold is triggered by the counter value reaching a
48 * comparison level, that comparison level is incremented by the
49 * offset value. This is regarded as taking place instantaneously,
50 * that is, before the count is incremented. Thus, for each level,
51 * the threshold triggers an event notification every time the count
52 * increases by an interval equal to the offset value.
53 *
54 * <P> If the counter can wrap around its maximum value, the modulus
55 * needs to be specified. The modulus is the value at which the
56 * counter is reset to zero.
57 *
58 * <P> If the counter difference mode is used, the value of the
59 * derived gauge is calculated as the difference between the observed
60 * counter values for two successive observations. If this difference
61 * is negative, the value of the derived gauge is incremented by the
62 * value of the modulus. The derived gauge value (V[t]) is calculated
63 * using the following method:
64 *
65 * <UL>
66 * <LI>if (counter[t] - counter[t-GP]) is positive then
67 * V[t] = counter[t] - counter[t-GP]
68 * <LI>if (counter[t] - counter[t-GP]) is negative then
69 * V[t] = counter[t] - counter[t-GP] + MODULUS
70 * </UL>
71 *
72 * This implementation of the counter monitor requires the observed
73 * attribute to be of the type integer (<CODE>Byte</CODE>,
74 * <CODE>Integer</CODE>, <CODE>Short</CODE>, <CODE>Long</CODE>).
75 *
76 *
77 * @since 1.5
78 */
79public class CounterMonitor extends Monitor implements CounterMonitorMBean {
80
81 /*
82 * ------------------------------------------
83 * PACKAGE CLASSES
84 * ------------------------------------------
85 */
86
87 static class CounterMonitorObservedObject extends ObservedObject {
88
89 public CounterMonitorObservedObject(ObjectName observedObject) {
90 super(observedObject);
91 }
92
93 public final synchronized Number getThreshold() {
94 return threshold;
95 }
96 public final synchronized void setThreshold(Number threshold) {
97 this.threshold = threshold;
98 }
99 public final synchronized Number getPreviousScanCounter() {
100 return previousScanCounter;
101 }
102 public final synchronized void setPreviousScanCounter(
103 Number previousScanCounter) {
104 this.previousScanCounter = previousScanCounter;
105 }
106 public final synchronized boolean getModulusExceeded() {
107 return modulusExceeded;
108 }
109 public final synchronized void setModulusExceeded(
110 boolean modulusExceeded) {
111 this.modulusExceeded = modulusExceeded;
112 }
113 public final synchronized Number getDerivedGaugeExceeded() {
114 return derivedGaugeExceeded;
115 }
116 public final synchronized void setDerivedGaugeExceeded(
117 Number derivedGaugeExceeded) {
118 this.derivedGaugeExceeded = derivedGaugeExceeded;
119 }
120 public final synchronized boolean getDerivedGaugeValid() {
121 return derivedGaugeValid;
122 }
123 public final synchronized void setDerivedGaugeValid(
124 boolean derivedGaugeValid) {
125 this.derivedGaugeValid = derivedGaugeValid;
126 }
127 public final synchronized boolean getEventAlreadyNotified() {
128 return eventAlreadyNotified;
129 }
130 public final synchronized void setEventAlreadyNotified(
131 boolean eventAlreadyNotified) {
132 this.eventAlreadyNotified = eventAlreadyNotified;
133 }
134 public final synchronized NumericalType getType() {
135 return type;
136 }
137 public final synchronized void setType(NumericalType type) {
138 this.type = type;
139 }
140
141 private Number threshold;
142 private Number previousScanCounter;
143 private boolean modulusExceeded;
144 private Number derivedGaugeExceeded;
145 private boolean derivedGaugeValid;
146 private boolean eventAlreadyNotified;
147 private NumericalType type;
148 }
149
150 /*
151 * ------------------------------------------
152 * PRIVATE VARIABLES
153 * ------------------------------------------
154 */
155
156 /**
157 * Counter modulus.
158 * <BR>The default value is a null Integer object.
159 */
160 private Number modulus = INTEGER_ZERO;
161
162 /**
163 * Counter offset.
164 * <BR>The default value is a null Integer object.
165 */
166 private Number offset = INTEGER_ZERO;
167
168 /**
169 * Flag indicating if the counter monitor notifies when exceeding
170 * the threshold. The default value is set to
171 * <CODE>false</CODE>.
172 */
173 private boolean notify = false;
174
175 /**
176 * Flag indicating if the counter difference mode is used. If the
177 * counter difference mode is used, the derived gauge is the
178 * difference between two consecutive observed values. Otherwise,
179 * the derived gauge is directly the value of the observed
180 * attribute. The default value is set to <CODE>false</CODE>.
181 */
182 private boolean differenceMode = false;
183
184 /**
185 * Initial counter threshold. This value is used to initialize
186 * the threshold when a new object is added to the list and reset
187 * the threshold to its initial value each time the counter
188 * resets.
189 */
190 private Number initThreshold = INTEGER_ZERO;
191
192 private static final String[] types = {
193 RUNTIME_ERROR,
194 OBSERVED_OBJECT_ERROR,
195 OBSERVED_ATTRIBUTE_ERROR,
196 OBSERVED_ATTRIBUTE_TYPE_ERROR,
197 THRESHOLD_ERROR,
198 THRESHOLD_VALUE_EXCEEDED
199 };
200
201 private static final MBeanNotificationInfo[] notifsInfo = {
202 new MBeanNotificationInfo(
203 types,
204 "javax.management.monitor.MonitorNotification",
205 "Notifications sent by the CounterMonitor MBean")
206 };
207
208 /*
209 * ------------------------------------------
210 * CONSTRUCTORS
211 * ------------------------------------------
212 */
213
214 /**
215 * Default constructor.
216 */
217 public CounterMonitor() {
218 }
219
220 /*
221 * ------------------------------------------
222 * PUBLIC METHODS
223 * ------------------------------------------
224 */
225
226 /**
227 * Starts the counter monitor.
228 */
229 public synchronized void start() {
230 if (isActive()) {
231 MONITOR_LOGGER.logp(Level.FINER, CounterMonitor.class.getName(),
232 "start", "the monitor is already active");
233 return;
234 }
235 // Reset values.
236 //
237 for (ObservedObject o : observedObjects) {
238 final CounterMonitorObservedObject cmo =
239 (CounterMonitorObservedObject) o;
240 cmo.setThreshold(initThreshold);
241 cmo.setModulusExceeded(false);
242 cmo.setEventAlreadyNotified(false);
243 cmo.setPreviousScanCounter(null);
244 }
245 doStart();
246 }
247
248 /**
249 * Stops the counter monitor.
250 */
251 public synchronized void stop() {
252 doStop();
253 }
254
255 // GETTERS AND SETTERS
256 //--------------------
257
258 /**
259 * Gets the derived gauge of the specified object, if this object is
260 * contained in the set of observed MBeans, or <code>null</code> otherwise.
261 *
262 * @param object the name of the object whose derived gauge is to
263 * be returned.
264 *
265 * @return The derived gauge of the specified object.
266 *
267 */
268 public synchronized Number getDerivedGauge(ObjectName object) {
269 return (Number) super.getDerivedGauge(object);
270 }
271
272 /**
273 * Gets the derived gauge timestamp of the specified object, if
274 * this object is contained in the set of observed MBeans, or
275 * <code>0</code> otherwise.
276 *
277 * @param object the name of the object whose derived gauge
278 * timestamp is to be returned.
279 *
280 * @return The derived gauge timestamp of the specified object.
281 *
282 */
283 public synchronized long getDerivedGaugeTimeStamp(ObjectName object) {
284 return super.getDerivedGaugeTimeStamp(object);
285 }
286
287 /**
288 * Gets the current threshold value of the specified object, if
289 * this object is contained in the set of observed MBeans, or
290 * <code>null</code> otherwise.
291 *
292 * @param object the name of the object whose threshold is to be
293 * returned.
294 *
295 * @return The threshold value of the specified object.
296 *
297 */
298 public synchronized Number getThreshold(ObjectName object) {
299 final CounterMonitorObservedObject o =
300 (CounterMonitorObservedObject) getObservedObject(object);
301 if (o == null)
302 return null;
303
304 // If the counter that is monitored rolls over when it reaches a
305 // maximum value, then the modulus value needs to be set to that
306 // maximum value. The threshold will then also roll over whenever
307 // it strictly exceeds the modulus value. When the threshold rolls
308 // over, it is reset to the value that was specified through the
309 // latest call to the monitor's setInitThreshold method, before
310 // any offsets were applied.
311 //
312 if (offset.longValue() > 0L &&
313 modulus.longValue() > 0L &&
314 o.getThreshold().longValue() > modulus.longValue()) {
315 return initThreshold;
316 } else {
317 return o.getThreshold();
318 }
319 }
320
321 /**
322 * Gets the initial threshold value common to all observed objects.
323 *
324 * @return The initial threshold.
325 *
326 * @see #setInitThreshold
327 *
328 */
329 public synchronized Number getInitThreshold() {
330 return initThreshold;
331 }
332
333 /**
334 * Sets the initial threshold value common to all observed objects.
335 *
336 * <BR>The current threshold of every object in the set of
337 * observed MBeans is updated consequently.
338 *
339 * @param value The initial threshold value.
340 *
341 * @exception IllegalArgumentException The specified
342 * threshold is null or the threshold value is less than zero.
343 *
344 * @see #getInitThreshold
345 *
346 */
347 public synchronized void setInitThreshold(Number value)
348 throws IllegalArgumentException {
349
350 if (value == null) {
351 throw new IllegalArgumentException("Null threshold");
352 }
353 if (value.longValue() < 0L) {
354 throw new IllegalArgumentException("Negative threshold");
355 }
356
357 if (initThreshold.equals(value))
358 return;
359 initThreshold = value;
360
361 // Reset values.
362 //
363 int index = 0;
364 for (ObservedObject o : observedObjects) {
365 resetAlreadyNotified(o, index++, THRESHOLD_ERROR_NOTIFIED);
366 final CounterMonitorObservedObject cmo =
367 (CounterMonitorObservedObject) o;
368 cmo.setThreshold(value);
369 cmo.setModulusExceeded(false);
370 cmo.setEventAlreadyNotified(false);
371 }
372 }
373
374 /**
375 * Returns the derived gauge of the first object in the set of
376 * observed MBeans.
377 *
378 * @return The derived gauge.
379 *
380 * @deprecated As of JMX 1.2, replaced by
381 * {@link #getDerivedGauge(ObjectName)}
382 */
383 @Deprecated
384 public synchronized Number getDerivedGauge() {
385 if (observedObjects.isEmpty()) {
386 return null;
387 } else {
388 return (Number) observedObjects.get(0).getDerivedGauge();
389 }
390 }
391
392 /**
393 * Gets the derived gauge timestamp of the first object in the set
394 * of observed MBeans.
395 *
396 * @return The derived gauge timestamp.
397 *
398 * @deprecated As of JMX 1.2, replaced by
399 * {@link #getDerivedGaugeTimeStamp(ObjectName)}
400 */
401 @Deprecated
402 public synchronized long getDerivedGaugeTimeStamp() {
403 if (observedObjects.isEmpty()) {
404 return 0;
405 } else {
406 return observedObjects.get(0).getDerivedGaugeTimeStamp();
407 }
408 }
409
410 /**
411 * Gets the threshold value of the first object in the set of
412 * observed MBeans.
413 *
414 * @return The threshold value.
415 *
416 * @see #setThreshold
417 *
418 * @deprecated As of JMX 1.2, replaced by {@link #getThreshold(ObjectName)}
419 */
420 @Deprecated
421 public synchronized Number getThreshold() {
422 return getThreshold(getObservedObject());
423 }
424
425 /**
426 * Sets the initial threshold value.
427 *
428 * @param value The initial threshold value.
429 *
430 * @exception IllegalArgumentException The specified threshold is
431 * null or the threshold value is less than zero.
432 *
433 * @see #getThreshold()
434 *
435 * @deprecated As of JMX 1.2, replaced by {@link #setInitThreshold}
436 */
437 @Deprecated
438 public synchronized void setThreshold(Number value)
439 throws IllegalArgumentException {
440 setInitThreshold(value);
441 }
442
443 /**
444 * Gets the offset value common to all observed MBeans.
445 *
446 * @return The offset value.
447 *
448 * @see #setOffset
449 */
450 public synchronized Number getOffset() {
451 return offset;
452 }
453
454 /**
455 * Sets the offset value common to all observed MBeans.
456 *
457 * @param value The offset value.
458 *
459 * @exception IllegalArgumentException The specified
460 * offset is null or the offset value is less than zero.
461 *
462 * @see #getOffset
463 */
464 public synchronized void setOffset(Number value)
465 throws IllegalArgumentException {
466
467 if (value == null) {
468 throw new IllegalArgumentException("Null offset");
469 }
470 if (value.longValue() < 0L) {
471 throw new IllegalArgumentException("Negative offset");
472 }
473
474 if (offset.equals(value))
475 return;
476 offset = value;
477
478 int index = 0;
479 for (ObservedObject o : observedObjects) {
480 resetAlreadyNotified(o, index++, THRESHOLD_ERROR_NOTIFIED);
481 }
482 }
483
484 /**
485 * Gets the modulus value common to all observed MBeans.
486 *
487 * @see #setModulus
488 *
489 * @return The modulus value.
490 */
491 public synchronized Number getModulus() {
492 return modulus;
493 }
494
495 /**
496 * Sets the modulus value common to all observed MBeans.
497 *
498 * @param value The modulus value.
499 *
500 * @exception IllegalArgumentException The specified
501 * modulus is null or the modulus value is less than zero.
502 *
503 * @see #getModulus
504 */
505 public synchronized void setModulus(Number value)
506 throws IllegalArgumentException {
507
508 if (value == null) {
509 throw new IllegalArgumentException("Null modulus");
510 }
511 if (value.longValue() < 0L) {
512 throw new IllegalArgumentException("Negative modulus");
513 }
514
515 if (modulus.equals(value))
516 return;
517 modulus = value;
518
519 // Reset values.
520 //
521 int index = 0;
522 for (ObservedObject o : observedObjects) {
523 resetAlreadyNotified(o, index++, THRESHOLD_ERROR_NOTIFIED);
524 final CounterMonitorObservedObject cmo =
525 (CounterMonitorObservedObject) o;
526 cmo.setModulusExceeded(false);
527 }
528 }
529
530 /**
531 * Gets the notification's on/off switch value common to all
532 * observed MBeans.
533 *
534 * @return <CODE>true</CODE> if the counter monitor notifies when
535 * exceeding the threshold, <CODE>false</CODE> otherwise.
536 *
537 * @see #setNotify
538 */
539 public synchronized boolean getNotify() {
540 return notify;
541 }
542
543 /**
544 * Sets the notification's on/off switch value common to all
545 * observed MBeans.
546 *
547 * @param value The notification's on/off switch value.
548 *
549 * @see #getNotify
550 */
551 public synchronized void setNotify(boolean value) {
552 if (notify == value)
553 return;
554 notify = value;
555 }
556
557 /**
558 * Gets the difference mode flag value common to all observed MBeans.
559 *
560 * @return <CODE>true</CODE> if the difference mode is used,
561 * <CODE>false</CODE> otherwise.
562 *
563 * @see #setDifferenceMode
564 */
565 public synchronized boolean getDifferenceMode() {
566 return differenceMode;
567 }
568
569 /**
570 * Sets the difference mode flag value common to all observed MBeans.
571 *
572 * @param value The difference mode flag value.
573 *
574 * @see #getDifferenceMode
575 */
576 public synchronized void setDifferenceMode(boolean value) {
577 if (differenceMode == value)
578 return;
579 differenceMode = value;
580
581 // Reset values.
582 //
583 for (ObservedObject o : observedObjects) {
584 final CounterMonitorObservedObject cmo =
585 (CounterMonitorObservedObject) o;
586 cmo.setThreshold(initThreshold);
587 cmo.setModulusExceeded(false);
588 cmo.setEventAlreadyNotified(false);
589 cmo.setPreviousScanCounter(null);
590 }
591 }
592
593 /**
594 * Returns a <CODE>NotificationInfo</CODE> object containing the
595 * name of the Java class of the notification and the notification
596 * types sent by the counter monitor.
597 */
598 public MBeanNotificationInfo[] getNotificationInfo() {
599 return notifsInfo;
600 }
601
602 /*
603 * ------------------------------------------
604 * PRIVATE METHODS
605 * ------------------------------------------
606 */
607
608 /**
609 * Updates the derived gauge attribute of the observed object.
610 *
611 * @param scanCounter The value of the observed attribute.
612 * @param o The observed object.
613 * @return <CODE>true</CODE> if the derived gauge value is valid,
614 * <CODE>false</CODE> otherwise. The derived gauge value is
615 * invalid when the differenceMode flag is set to
616 * <CODE>true</CODE> and it is the first notification (so we
617 * haven't 2 consecutive values to update the derived gauge).
618 */
619 private synchronized boolean updateDerivedGauge(
620 Object scanCounter, CounterMonitorObservedObject o) {
621
622 boolean is_derived_gauge_valid;
623
624 // The counter difference mode is used.
625 //
626 if (differenceMode) {
627
628 // The previous scan counter has been initialized.
629 //
630 if (o.getPreviousScanCounter() != null) {
631 setDerivedGaugeWithDifference((Number)scanCounter, null, o);
632
633 // If derived gauge is negative it means that the
634 // counter has wrapped around and the value of the
635 // threshold needs to be reset to its initial value.
636 //
637 if (((Number)o.getDerivedGauge()).longValue() < 0L) {
638 if (modulus.longValue() > 0L) {
639 setDerivedGaugeWithDifference((Number)scanCounter,
640 modulus, o);
641 }
642 o.setThreshold(initThreshold);
643 o.setEventAlreadyNotified(false);
644 }
645 is_derived_gauge_valid = true;
646 }
647 // The previous scan counter has not been initialized.
648 // We cannot update the derived gauge...
649 //
650 else {
651 is_derived_gauge_valid = false;
652 }
653 o.setPreviousScanCounter((Number)scanCounter);
654 }
655 // The counter difference mode is not used.
656 //
657 else {
658 o.setDerivedGauge((Number)scanCounter);
659 is_derived_gauge_valid = true;
660 }
661 return is_derived_gauge_valid;
662 }
663
664 /**
665 * Updates the notification attribute of the observed object
666 * and notifies the listeners only once if the notify flag
667 * is set to <CODE>true</CODE>.
668 * @param o The observed object.
669 */
670 private synchronized MonitorNotification updateNotifications(
671 CounterMonitorObservedObject o) {
672
673 MonitorNotification n = null;
674
675 // Send notification if notify is true.
676 //
677 if (!o.getEventAlreadyNotified()) {
678 if (((Number)o.getDerivedGauge()).longValue() >=
679 o.getThreshold().longValue()) {
680 if (notify) {
681 n = new MonitorNotification(THRESHOLD_VALUE_EXCEEDED,
682 this,
683 0,
684 0,
685 "",
686 null,
687 null,
688 null,
689 o.getThreshold());
690 }
691 if (!differenceMode) {
692 o.setEventAlreadyNotified(true);
693 }
694 }
695 } else {
696 if (MONITOR_LOGGER.isLoggable(Level.FINER)) {
697 final StringBuilder strb = new StringBuilder()
698 .append("The notification:")
699 .append("\n\tNotification observed object = ")
700 .append(o.getObservedObject())
701 .append("\n\tNotification observed attribute = ")
702 .append(getObservedAttribute())
703 .append("\n\tNotification threshold level = ")
704 .append(o.getThreshold())
705 .append("\n\tNotification derived gauge = ")
706 .append(o.getDerivedGauge())
707 .append("\nhas already been sent");
708 MONITOR_LOGGER.logp(Level.FINER, CounterMonitor.class.getName(),
709 "updateNotifications", strb.toString());
710 }
711 }
712
713 return n;
714 }
715
716 /**
717 * Updates the threshold attribute of the observed object.
718 * @param o The observed object.
719 */
720 private synchronized void updateThreshold(CounterMonitorObservedObject o) {
721
722 // Calculate the new threshold value if the threshold has been
723 // exceeded and if the offset value is greater than zero.
724 //
725 if (((Number)o.getDerivedGauge()).longValue() >=
726 o.getThreshold().longValue()) {
727
728 if (offset.longValue() > 0L) {
729
730 // Increment the threshold until its value is greater
731 // than the one for the current derived gauge.
732 //
733 long threshold_value = o.getThreshold().longValue();
734 while (((Number)o.getDerivedGauge()).longValue() >=
735 threshold_value) {
736 threshold_value += offset.longValue();
737 }
738
739 // Set threshold attribute.
740 //
741 switch (o.getType()) {
742 case INTEGER:
743 o.setThreshold(new Integer((int)threshold_value));
744 break;
745 case BYTE:
746 o.setThreshold(new Byte((byte)threshold_value));
747 break;
748 case SHORT:
749 o.setThreshold(new Short((short)threshold_value));
750 break;
751 case LONG:
752 o.setThreshold(new Long(threshold_value));
753 break;
754 default:
755 // Should never occur...
756 MONITOR_LOGGER.logp(Level.FINEST,
757 CounterMonitor.class.getName(),
758 "updateThreshold",
759 "the threshold type is invalid");
760 break;
761 }
762
763 // If the counter can wrap around when it reaches
764 // its maximum and we are not dealing with counter
765 // differences then we need to reset the threshold
766 // to its initial value too.
767 //
768 if (!differenceMode) {
769 if (modulus.longValue() > 0L) {
770 if (o.getThreshold().longValue() >
771 modulus.longValue()) {
772 o.setModulusExceeded(true);
773 o.setDerivedGaugeExceeded(
774 (Number) o.getDerivedGauge());
775 }
776 }
777 }
778
779 // Threshold value has been modified so we can notify again.
780 //
781 o.setEventAlreadyNotified(false);
782 } else {
783 o.setModulusExceeded(true);
784 o.setDerivedGaugeExceeded((Number) o.getDerivedGauge());
785 }
786 }
787 }
788
789 /**
790 * Sets the derived gauge of the specified observed object when the
791 * differenceMode flag is set to <CODE>true</CODE>. Integer types
792 * only are allowed.
793 *
794 * @param scanCounter The value of the observed attribute.
795 * @param mod The counter modulus value.
796 * @param o The observed object.
797 */
798 private synchronized void setDerivedGaugeWithDifference(
799 Number scanCounter, Number mod, CounterMonitorObservedObject o) {
800 /* We do the arithmetic using longs here even though the
801 result may end up in a smaller type. Since
802 l == (byte)l (mod 256) for any long l,
803 (byte) ((byte)l1 + (byte)l2) == (byte) (l1 + l2),
804 and likewise for subtraction. So it's the same as if
805 we had done the arithmetic in the smaller type.*/
806
807 long derived =
808 scanCounter.longValue() - o.getPreviousScanCounter().longValue();
809 if (mod != null)
810 derived += modulus.longValue();
811
812 switch (o.getType()) {
813 case INTEGER: o.setDerivedGauge(new Integer((int) derived)); break;
814 case BYTE: o.setDerivedGauge(new Byte((byte) derived)); break;
815 case SHORT: o.setDerivedGauge(new Short((short) derived)); break;
816 case LONG: o.setDerivedGauge(new Long(derived)); break;
817 default:
818 // Should never occur...
819 MONITOR_LOGGER.logp(Level.FINEST, CounterMonitor.class.getName(),
820 "setDerivedGaugeWithDifference",
821 "the threshold type is invalid");
822 break;
823 }
824 }
825
826 /*
827 * ------------------------------------------
828 * PACKAGE METHODS
829 * ------------------------------------------
830 */
831
832 /**
833 * Factory method for ObservedObject creation.
834 *
835 * @since 1.6
836 */
837 @Override
838 ObservedObject createObservedObject(ObjectName object) {
839 final CounterMonitorObservedObject cmo =
840 new CounterMonitorObservedObject(object);
841 cmo.setThreshold(initThreshold);
842 cmo.setModulusExceeded(false);
843 cmo.setEventAlreadyNotified(false);
844 cmo.setPreviousScanCounter(null);
845 return cmo;
846 }
847
848 /**
849 * This method globally sets the derived gauge type for the given
850 * "object" and "attribute" after checking that the type of the
851 * supplied observed attribute value is one of the value types
852 * supported by this monitor.
853 */
854 @Override
855 synchronized boolean isComparableTypeValid(ObjectName object,
856 String attribute,
857 Comparable<?> value) {
858 final CounterMonitorObservedObject o =
859 (CounterMonitorObservedObject) getObservedObject(object);
860 if (o == null)
861 return false;
862
863 // Check that the observed attribute is of type "Integer".
864 //
865 if (value instanceof Integer) {
866 o.setType(INTEGER);
867 } else if (value instanceof Byte) {
868 o.setType(BYTE);
869 } else if (value instanceof Short) {
870 o.setType(SHORT);
871 } else if (value instanceof Long) {
872 o.setType(LONG);
873 } else {
874 return false;
875 }
876 return true;
877 }
878
879 @Override
880 synchronized Comparable<?> getDerivedGaugeFromComparable(
881 ObjectName object,
882 String attribute,
883 Comparable<?> value) {
884 final CounterMonitorObservedObject o =
885 (CounterMonitorObservedObject) getObservedObject(object);
886 if (o == null)
887 return null;
888
889 // Check if counter has wrapped around.
890 //
891 if (o.getModulusExceeded()) {
892 if (((Number)o.getDerivedGauge()).longValue() <
893 o.getDerivedGaugeExceeded().longValue()) {
894 o.setThreshold(initThreshold);
895 o.setModulusExceeded(false);
896 o.setEventAlreadyNotified(false);
897 }
898 }
899
900 // Update the derived gauge attributes and check the
901 // validity of the new value. The derived gauge value
902 // is invalid when the differenceMode flag is set to
903 // true and it is the first notification, i.e. we
904 // haven't got 2 consecutive values to update the
905 // derived gauge.
906 //
907 o.setDerivedGaugeValid(updateDerivedGauge(value, o));
908
909 return (Comparable<?>) o.getDerivedGauge();
910 }
911
912 @Override
913 synchronized void onErrorNotification(MonitorNotification notification) {
914 final CounterMonitorObservedObject o = (CounterMonitorObservedObject)
915 getObservedObject(notification.getObservedObject());
916 if (o == null)
917 return;
918
919 // Reset values.
920 //
921 o.setModulusExceeded(false);
922 o.setEventAlreadyNotified(false);
923 o.setPreviousScanCounter(null);
924 }
925
926 @Override
927 synchronized MonitorNotification buildAlarmNotification(
928 ObjectName object,
929 String attribute,
930 Comparable<?> value) {
931 final CounterMonitorObservedObject o =
932 (CounterMonitorObservedObject) getObservedObject(object);
933 if (o == null)
934 return null;
935
936 // Notify the listeners and update the threshold if
937 // the updated derived gauge value is valid.
938 //
939 final MonitorNotification alarm;
940 if (o.getDerivedGaugeValid()) {
941 alarm = updateNotifications(o);
942 updateThreshold(o);
943 } else {
944 alarm = null;
945 }
946 return alarm;
947 }
948
949 /**
950 * Tests if the threshold, offset and modulus of the specified observed
951 * object are of the same type as the counter. Only integer types are
952 * allowed.
953 *
954 * Note:
955 * If the optional offset or modulus have not been initialized, their
956 * default value is an Integer object with a value equal to zero.
957 *
958 * @param object The observed object.
959 * @param attribute The observed attribute.
960 * @param value The sample value.
961 * @return <CODE>true</CODE> if type is the same,
962 * <CODE>false</CODE> otherwise.
963 */
964 @Override
965 synchronized boolean isThresholdTypeValid(ObjectName object,
966 String attribute,
967 Comparable<?> value) {
968 final CounterMonitorObservedObject o =
969 (CounterMonitorObservedObject) getObservedObject(object);
970 if (o == null)
971 return false;
972
973 Class<? extends Number> c = classForType(o.getType());
974 return (c.isInstance(o.getThreshold()) &&
975 isValidForType(offset, c) &&
976 isValidForType(modulus, c));
977 }
978}