1 /* 2 * Copyright (c) 1999, 2008, Oracle and/or its affiliates. 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package javax.management.monitor; 27 28 import static com.sun.jmx.defaults.JmxProperties.MONITOR_LOGGER; 29 import java.util.logging.Level; 30 import javax.management.ObjectName; 31 import javax.management.MBeanNotificationInfo; 32 import static javax.management.monitor.Monitor.NumericalType.*; 33 import 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 */ 79 public 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 @Override 269 public synchronized Number getDerivedGauge(ObjectName object) { 270 return (Number) super.getDerivedGauge(object); 271 } 272 273 /** 274 * Gets the derived gauge timestamp of the specified object, if 275 * this object is contained in the set of observed MBeans, or 276 * <code>0</code> otherwise. 277 * 278 * @param object the name of the object whose derived gauge 279 * timestamp is to be returned. 280 * 281 * @return The derived gauge timestamp of the specified object. 282 * 283 */ 284 @Override 285 public synchronized long getDerivedGaugeTimeStamp(ObjectName object) { 286 return super.getDerivedGaugeTimeStamp(object); 287 } 288 289 /** 290 * Gets the current threshold value of the specified object, if 291 * this object is contained in the set of observed MBeans, or 292 * <code>null</code> otherwise. 293 * 294 * @param object the name of the object whose threshold is to be 295 * returned. 296 * 297 * @return The threshold value of the specified object. 298 * 299 */ 300 public synchronized Number getThreshold(ObjectName object) { 301 final CounterMonitorObservedObject o = 302 (CounterMonitorObservedObject) getObservedObject(object); 303 if (o == null) 304 return null; 305 306 // If the counter that is monitored rolls over when it reaches a 307 // maximum value, then the modulus value needs to be set to that 308 // maximum value. The threshold will then also roll over whenever 309 // it strictly exceeds the modulus value. When the threshold rolls 310 // over, it is reset to the value that was specified through the 311 // latest call to the monitor's setInitThreshold method, before 312 // any offsets were applied. 313 // 314 if (offset.longValue() > 0L && 315 modulus.longValue() > 0L && 316 o.getThreshold().longValue() > modulus.longValue()) { 317 return initThreshold; 318 } else { 319 return o.getThreshold(); 320 } 321 } 322 323 /** 324 * Gets the initial threshold value common to all observed objects. 325 * 326 * @return The initial threshold. 327 * 328 * @see #setInitThreshold 329 * 330 */ 331 public synchronized Number getInitThreshold() { 332 return initThreshold; 333 } 334 335 /** 336 * Sets the initial threshold value common to all observed objects. 337 * 338 * <BR>The current threshold of every object in the set of 339 * observed MBeans is updated consequently. 340 * 341 * @param value The initial threshold value. 342 * 343 * @exception IllegalArgumentException The specified 344 * threshold is null or the threshold value is less than zero. 345 * 346 * @see #getInitThreshold 347 * 348 */ 349 public synchronized void setInitThreshold(Number value) 350 throws IllegalArgumentException { 351 352 if (value == null) { 353 throw new IllegalArgumentException("Null threshold"); 354 } 355 if (value.longValue() < 0L) { 356 throw new IllegalArgumentException("Negative threshold"); 357 } 358 359 if (initThreshold.equals(value)) 360 return; 361 initThreshold = value; 362 363 // Reset values. 364 // 365 int index = 0; 366 for (ObservedObject o : observedObjects) { 367 resetAlreadyNotified(o, index++, THRESHOLD_ERROR_NOTIFIED); 368 final CounterMonitorObservedObject cmo = 369 (CounterMonitorObservedObject) o; 370 cmo.setThreshold(value); 371 cmo.setModulusExceeded(false); 372 cmo.setEventAlreadyNotified(false); 373 } 374 } 375 376 /** 377 * Returns the derived gauge of the first object in the set of 378 * observed MBeans. 379 * 380 * @return The derived gauge. 381 * 382 * @deprecated As of JMX 1.2, replaced by 383 * {@link #getDerivedGauge(ObjectName)} 384 */ 385 @Deprecated 386 public synchronized Number getDerivedGauge() { 387 if (observedObjects.isEmpty()) { 388 return null; 389 } else { 390 return (Number) observedObjects.get(0).getDerivedGauge(); 391 } 392 } 393 394 /** 395 * Gets the derived gauge timestamp of the first object in the set 396 * of observed MBeans. 397 * 398 * @return The derived gauge timestamp. 399 * 400 * @deprecated As of JMX 1.2, replaced by 401 * {@link #getDerivedGaugeTimeStamp(ObjectName)} 402 */ 403 @Deprecated 404 public synchronized long getDerivedGaugeTimeStamp() { 405 if (observedObjects.isEmpty()) { 406 return 0; 407 } else { 408 return observedObjects.get(0).getDerivedGaugeTimeStamp(); 409 } 410 } 411 412 /** 413 * Gets the threshold value of the first object in the set of 414 * observed MBeans. 415 * 416 * @return The threshold value. 417 * 418 * @see #setThreshold 419 * 420 * @deprecated As of JMX 1.2, replaced by {@link #getThreshold(ObjectName)} 421 */ 422 @Deprecated 423 public synchronized Number getThreshold() { 424 return getThreshold(getObservedObject()); 425 } 426 427 /** 428 * Sets the initial threshold value. 429 * 430 * @param value The initial threshold value. 431 * 432 * @exception IllegalArgumentException The specified threshold is 433 * null or the threshold value is less than zero. 434 * 435 * @see #getThreshold() 436 * 437 * @deprecated As of JMX 1.2, replaced by {@link #setInitThreshold} 438 */ 439 @Deprecated 440 public synchronized void setThreshold(Number value) 441 throws IllegalArgumentException { 442 setInitThreshold(value); 443 } 444 445 /** 446 * Gets the offset value common to all observed MBeans. 447 * 448 * @return The offset value. 449 * 450 * @see #setOffset 451 */ 452 public synchronized Number getOffset() { 453 return offset; 454 } 455 456 /** 457 * Sets the offset value common to all observed MBeans. 458 * 459 * @param value The offset value. 460 * 461 * @exception IllegalArgumentException The specified 462 * offset is null or the offset value is less than zero. 463 * 464 * @see #getOffset 465 */ 466 public synchronized void setOffset(Number value) 467 throws IllegalArgumentException { 468 469 if (value == null) { 470 throw new IllegalArgumentException("Null offset"); 471 } 472 if (value.longValue() < 0L) { 473 throw new IllegalArgumentException("Negative offset"); 474 } 475 476 if (offset.equals(value)) 477 return; 478 offset = value; 479 480 int index = 0; 481 for (ObservedObject o : observedObjects) { 482 resetAlreadyNotified(o, index++, THRESHOLD_ERROR_NOTIFIED); 483 } 484 } 485 486 /** 487 * Gets the modulus value common to all observed MBeans. 488 * 489 * @see #setModulus 490 * 491 * @return The modulus value. 492 */ 493 public synchronized Number getModulus() { 494 return modulus; 495 } 496 497 /** 498 * Sets the modulus value common to all observed MBeans. 499 * 500 * @param value The modulus value. 501 * 502 * @exception IllegalArgumentException The specified 503 * modulus is null or the modulus value is less than zero. 504 * 505 * @see #getModulus 506 */ 507 public synchronized void setModulus(Number value) 508 throws IllegalArgumentException { 509 510 if (value == null) { 511 throw new IllegalArgumentException("Null modulus"); 512 } 513 if (value.longValue() < 0L) { 514 throw new IllegalArgumentException("Negative modulus"); 515 } 516 517 if (modulus.equals(value)) 518 return; 519 modulus = value; 520 521 // Reset values. 522 // 523 int index = 0; 524 for (ObservedObject o : observedObjects) { 525 resetAlreadyNotified(o, index++, THRESHOLD_ERROR_NOTIFIED); 526 final CounterMonitorObservedObject cmo = 527 (CounterMonitorObservedObject) o; 528 cmo.setModulusExceeded(false); 529 } 530 } 531 532 /** 533 * Gets the notification's on/off switch value common to all 534 * observed MBeans. 535 * 536 * @return <CODE>true</CODE> if the counter monitor notifies when 537 * exceeding the threshold, <CODE>false</CODE> otherwise. 538 * 539 * @see #setNotify 540 */ 541 public synchronized boolean getNotify() { 542 return notify; 543 } 544 545 /** 546 * Sets the notification's on/off switch value common to all 547 * observed MBeans. 548 * 549 * @param value The notification's on/off switch value. 550 * 551 * @see #getNotify 552 */ 553 public synchronized void setNotify(boolean value) { 554 if (notify == value) 555 return; 556 notify = value; 557 } 558 559 /** 560 * Gets the difference mode flag value common to all observed MBeans. 561 * 562 * @return <CODE>true</CODE> if the difference mode is used, 563 * <CODE>false</CODE> otherwise. 564 * 565 * @see #setDifferenceMode 566 */ 567 public synchronized boolean getDifferenceMode() { 568 return differenceMode; 569 } 570 571 /** 572 * Sets the difference mode flag value common to all observed MBeans. 573 * 574 * @param value The difference mode flag value. 575 * 576 * @see #getDifferenceMode 577 */ 578 public synchronized void setDifferenceMode(boolean value) { 579 if (differenceMode == value) 580 return; 581 differenceMode = value; 582 583 // Reset values. 584 // 585 for (ObservedObject o : observedObjects) { 586 final CounterMonitorObservedObject cmo = 587 (CounterMonitorObservedObject) o; 588 cmo.setThreshold(initThreshold); 589 cmo.setModulusExceeded(false); 590 cmo.setEventAlreadyNotified(false); 591 cmo.setPreviousScanCounter(null); 592 } 593 } 594 595 /** 596 * Returns a <CODE>NotificationInfo</CODE> object containing the 597 * name of the Java class of the notification and the notification 598 * types sent by the counter monitor. 599 */ 600 @Override 601 public MBeanNotificationInfo[] getNotificationInfo() { 602 return notifsInfo.clone(); 603 } 604 605 /* 606 * ------------------------------------------ 607 * PRIVATE METHODS 608 * ------------------------------------------ 609 */ 610 611 /** 612 * Updates the derived gauge attribute of the observed object. 613 * 614 * @param scanCounter The value of the observed attribute. 615 * @param o The observed object. 616 * @return <CODE>true</CODE> if the derived gauge value is valid, 617 * <CODE>false</CODE> otherwise. The derived gauge value is 618 * invalid when the differenceMode flag is set to 619 * <CODE>true</CODE> and it is the first notification (so we 620 * haven't 2 consecutive values to update the derived gauge). 621 */ 622 private synchronized boolean updateDerivedGauge( 623 Object scanCounter, CounterMonitorObservedObject o) { 624 625 boolean is_derived_gauge_valid; 626 627 // The counter difference mode is used. 628 // 629 if (differenceMode) { 630 631 // The previous scan counter has been initialized. 632 // 633 if (o.getPreviousScanCounter() != null) { 634 setDerivedGaugeWithDifference((Number)scanCounter, null, o); 635 636 // If derived gauge is negative it means that the 637 // counter has wrapped around and the value of the 638 // threshold needs to be reset to its initial value. 639 // 640 if (((Number)o.getDerivedGauge()).longValue() < 0L) { 641 if (modulus.longValue() > 0L) { 642 setDerivedGaugeWithDifference((Number)scanCounter, 643 modulus, o); 644 } 645 o.setThreshold(initThreshold); 646 o.setEventAlreadyNotified(false); 647 } 648 is_derived_gauge_valid = true; 649 } 650 // The previous scan counter has not been initialized. 651 // We cannot update the derived gauge... 652 // 653 else { 654 is_derived_gauge_valid = false; 655 } 656 o.setPreviousScanCounter((Number)scanCounter); 657 } 658 // The counter difference mode is not used. 659 // 660 else { 661 o.setDerivedGauge((Number)scanCounter); 662 is_derived_gauge_valid = true; 663 } 664 return is_derived_gauge_valid; 665 } 666 667 /** 668 * Updates the notification attribute of the observed object 669 * and notifies the listeners only once if the notify flag 670 * is set to <CODE>true</CODE>. 671 * @param o The observed object. 672 */ 673 private synchronized MonitorNotification updateNotifications( 674 CounterMonitorObservedObject o) { 675 676 MonitorNotification n = null; 677 678 // Send notification if notify is true. 679 // 680 if (!o.getEventAlreadyNotified()) { 681 if (((Number)o.getDerivedGauge()).longValue() >= 682 o.getThreshold().longValue()) { 683 if (notify) { 684 n = new MonitorNotification(THRESHOLD_VALUE_EXCEEDED, 685 this, 686 0, 687 0, 688 "", 689 null, 690 null, 691 null, 692 o.getThreshold()); 693 } 694 if (!differenceMode) { 695 o.setEventAlreadyNotified(true); 696 } 697 } 698 } else { 699 if (MONITOR_LOGGER.isLoggable(Level.FINER)) { 700 final StringBuilder strb = new StringBuilder() 701 .append("The notification:") 702 .append("\n\tNotification observed object = ") 703 .append(o.getObservedObject()) 704 .append("\n\tNotification observed attribute = ") 705 .append(getObservedAttribute()) 706 .append("\n\tNotification threshold level = ") 707 .append(o.getThreshold()) 708 .append("\n\tNotification derived gauge = ") 709 .append(o.getDerivedGauge()) 710 .append("\nhas already been sent"); 711 MONITOR_LOGGER.logp(Level.FINER, CounterMonitor.class.getName(), 712 "updateNotifications", strb.toString()); 713 } 714 } 715 716 return n; 717 } 718 719 /** 720 * Updates the threshold attribute of the observed object. 721 * @param o The observed object. 722 */ 723 private synchronized void updateThreshold(CounterMonitorObservedObject o) { 724 725 // Calculate the new threshold value if the threshold has been 726 // exceeded and if the offset value is greater than zero. 727 // 728 if (((Number)o.getDerivedGauge()).longValue() >= 729 o.getThreshold().longValue()) { 730 731 if (offset.longValue() > 0L) { 732 733 // Increment the threshold until its value is greater 734 // than the one for the current derived gauge. 735 // 736 long threshold_value = o.getThreshold().longValue(); 737 while (((Number)o.getDerivedGauge()).longValue() >= 738 threshold_value) { 739 threshold_value += offset.longValue(); 740 } 741 742 // Set threshold attribute. 743 // 744 switch (o.getType()) { 745 case INTEGER: 746 o.setThreshold(Integer.valueOf((int)threshold_value)); 747 break; 748 case BYTE: 749 o.setThreshold(Byte.valueOf((byte)threshold_value)); 750 break; 751 case SHORT: 752 o.setThreshold(Short.valueOf((short)threshold_value)); 753 break; 754 case LONG: 755 o.setThreshold(Long.valueOf(threshold_value)); 756 break; 757 default: 758 // Should never occur... 759 MONITOR_LOGGER.logp(Level.FINEST, 760 CounterMonitor.class.getName(), 761 "updateThreshold", 762 "the threshold type is invalid"); 763 break; 764 } 765 766 // If the counter can wrap around when it reaches 767 // its maximum and we are not dealing with counter 768 // differences then we need to reset the threshold 769 // to its initial value too. 770 // 771 if (!differenceMode) { 772 if (modulus.longValue() > 0L) { 773 if (o.getThreshold().longValue() > 774 modulus.longValue()) { 775 o.setModulusExceeded(true); 776 o.setDerivedGaugeExceeded( 777 (Number) o.getDerivedGauge()); 778 } 779 } 780 } 781 782 // Threshold value has been modified so we can notify again. 783 // 784 o.setEventAlreadyNotified(false); 785 } else { 786 o.setModulusExceeded(true); 787 o.setDerivedGaugeExceeded((Number) o.getDerivedGauge()); 788 } 789 } 790 } 791 792 /** 793 * Sets the derived gauge of the specified observed object when the 794 * differenceMode flag is set to <CODE>true</CODE>. Integer types 795 * only are allowed. 796 * 797 * @param scanCounter The value of the observed attribute. 798 * @param mod The counter modulus value. 799 * @param o The observed object. 800 */ 801 private synchronized void setDerivedGaugeWithDifference( 802 Number scanCounter, Number mod, CounterMonitorObservedObject o) { 803 /* We do the arithmetic using longs here even though the 804 result may end up in a smaller type. Since 805 l == (byte)l (mod 256) for any long l, 806 (byte) ((byte)l1 + (byte)l2) == (byte) (l1 + l2), 807 and likewise for subtraction. So it's the same as if 808 we had done the arithmetic in the smaller type.*/ 809 810 long derived = 811 scanCounter.longValue() - o.getPreviousScanCounter().longValue(); 812 if (mod != null) 813 derived += modulus.longValue(); 814 815 switch (o.getType()) { 816 case INTEGER: o.setDerivedGauge(Integer.valueOf((int) derived)); break; 817 case BYTE: o.setDerivedGauge(Byte.valueOf((byte) derived)); break; 818 case SHORT: o.setDerivedGauge(Short.valueOf((short) derived)); break; 819 case LONG: o.setDerivedGauge(Long.valueOf(derived)); break; 820 default: 821 // Should never occur... 822 MONITOR_LOGGER.logp(Level.FINEST, CounterMonitor.class.getName(), 823 "setDerivedGaugeWithDifference", 824 "the threshold type is invalid"); 825 break; 826 } 827 } 828 829 /* 830 * ------------------------------------------ 831 * PACKAGE METHODS 832 * ------------------------------------------ 833 */ 834 835 /** 836 * Factory method for ObservedObject creation. 837 * 838 * @since 1.6 839 */ 840 @Override 841 ObservedObject createObservedObject(ObjectName object) { 842 final CounterMonitorObservedObject cmo = 843 new CounterMonitorObservedObject(object); 844 cmo.setThreshold(initThreshold); 845 cmo.setModulusExceeded(false); 846 cmo.setEventAlreadyNotified(false); 847 cmo.setPreviousScanCounter(null); 848 return cmo; 849 } 850 851 /** 852 * This method globally sets the derived gauge type for the given 853 * "object" and "attribute" after checking that the type of the 854 * supplied observed attribute value is one of the value types 855 * supported by this monitor. 856 */ 857 @Override 858 synchronized boolean isComparableTypeValid(ObjectName object, 859 String attribute, 860 Comparable<?> value) { 861 final CounterMonitorObservedObject o = 862 (CounterMonitorObservedObject) getObservedObject(object); 863 if (o == null) 864 return false; 865 866 // Check that the observed attribute is of type "Integer". 867 // 868 if (value instanceof Integer) { 869 o.setType(INTEGER); 870 } else if (value instanceof Byte) { 871 o.setType(BYTE); 872 } else if (value instanceof Short) { 873 o.setType(SHORT); 874 } else if (value instanceof Long) { 875 o.setType(LONG); 876 } else { 877 return false; 878 } 879 return true; 880 } 881 882 @Override 883 synchronized Comparable<?> getDerivedGaugeFromComparable( 884 ObjectName object, 885 String attribute, 886 Comparable<?> value) { 887 final CounterMonitorObservedObject o = 888 (CounterMonitorObservedObject) getObservedObject(object); 889 if (o == null) 890 return null; 891 892 // Check if counter has wrapped around. 893 // 894 if (o.getModulusExceeded()) { 895 if (((Number)o.getDerivedGauge()).longValue() < 896 o.getDerivedGaugeExceeded().longValue()) { 897 o.setThreshold(initThreshold); 898 o.setModulusExceeded(false); 899 o.setEventAlreadyNotified(false); 900 } 901 } 902 903 // Update the derived gauge attributes and check the 904 // validity of the new value. The derived gauge value 905 // is invalid when the differenceMode flag is set to 906 // true and it is the first notification, i.e. we 907 // haven't got 2 consecutive values to update the 908 // derived gauge. 909 // 910 o.setDerivedGaugeValid(updateDerivedGauge(value, o)); 911 912 return (Comparable<?>) o.getDerivedGauge(); 913 } 914 915 @Override 916 synchronized void onErrorNotification(MonitorNotification notification) { 917 final CounterMonitorObservedObject o = (CounterMonitorObservedObject) 918 getObservedObject(notification.getObservedObject()); 919 if (o == null) 920 return; 921 922 // Reset values. 923 // 924 o.setModulusExceeded(false); 925 o.setEventAlreadyNotified(false); 926 o.setPreviousScanCounter(null); 927 } 928 929 @Override 930 synchronized MonitorNotification buildAlarmNotification( 931 ObjectName object, 932 String attribute, 933 Comparable<?> value) { 934 final CounterMonitorObservedObject o = 935 (CounterMonitorObservedObject) getObservedObject(object); 936 if (o == null) 937 return null; 938 939 // Notify the listeners and update the threshold if 940 // the updated derived gauge value is valid. 941 // 942 final MonitorNotification alarm; 943 if (o.getDerivedGaugeValid()) { 944 alarm = updateNotifications(o); 945 updateThreshold(o); 946 } else { 947 alarm = null; 948 } 949 return alarm; 950 } 951 952 /** 953 * Tests if the threshold, offset and modulus of the specified observed 954 * object are of the same type as the counter. Only integer types are 955 * allowed. 956 * 957 * Note: 958 * If the optional offset or modulus have not been initialized, their 959 * default value is an Integer object with a value equal to zero. 960 * 961 * @param object The observed object. 962 * @param attribute The observed attribute. 963 * @param value The sample value. 964 * @return <CODE>true</CODE> if type is the same, 965 * <CODE>false</CODE> otherwise. 966 */ 967 @Override 968 synchronized boolean isThresholdTypeValid(ObjectName object, 969 String attribute, 970 Comparable<?> value) { 971 final CounterMonitorObservedObject o = 972 (CounterMonitorObservedObject) getObservedObject(object); 973 if (o == null) 974 return false; 975 976 Class<? extends Number> c = classForType(o.getType()); 977 return (c.isInstance(o.getThreshold()) && 978 isValidForType(offset, c) && 979 isValidForType(modulus, c)); 980 } 981 }