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