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 26package javax.management.monitor; 27 28import static com.sun.jmx.defaults.JmxProperties.MONITOR_LOGGER; 29import com.sun.jmx.mbeanserver.GetPropertyAction; 30import com.sun.jmx.mbeanserver.Introspector; 31import java.io.IOException; 32import java.security.AccessControlContext; 33import java.security.AccessController; 34import java.security.PrivilegedAction; 35import java.security.ProtectionDomain; 36import java.util.List; 37import java.util.Map; 38import java.util.WeakHashMap; 39import java.util.concurrent.CopyOnWriteArrayList; 40import java.util.concurrent.Executors; 41import java.util.concurrent.Future; 42import java.util.concurrent.LinkedBlockingQueue; 43import java.util.concurrent.ScheduledExecutorService; 44import java.util.concurrent.ScheduledFuture; 45import java.util.concurrent.ThreadFactory; 46import java.util.concurrent.ThreadPoolExecutor; 47import java.util.concurrent.TimeUnit; 48import java.util.concurrent.atomic.AtomicInteger; 49import java.util.concurrent.atomic.AtomicLong; 50import java.lang.System.Logger.Level; 51import javax.management.AttributeNotFoundException; 52import javax.management.InstanceNotFoundException; 53import javax.management.IntrospectionException; 54import javax.management.MBeanAttributeInfo; 55import javax.management.MBeanException; 56import javax.management.MBeanInfo; 57import javax.management.MBeanRegistration; 58import javax.management.MBeanServer; 59import javax.management.MBeanServerConnection; 60import javax.management.NotificationBroadcasterSupport; 61import javax.management.ObjectName; 62import javax.management.ReflectionException; 63import static javax.management.monitor.MonitorNotification.*; 64 65/** 66 * Defines the part common to all monitor MBeans. 67 * A monitor MBean monitors values of an attribute common to a set of observed 68 * MBeans. The observed attribute is monitored at intervals specified by the 69 * granularity period. A gauge value (derived gauge) is derived from the values 70 * of the observed attribute. 71 * 72 * 73 * @since 1.5 74 */ 75public abstract class Monitor 76 extends NotificationBroadcasterSupport 77 implements MonitorMBean, MBeanRegistration { 78 79 /* 80 * ------------------------------------------ 81 * PACKAGE CLASSES 82 * ------------------------------------------ 83 */ 84 85 static class ObservedObject { 86 87 public ObservedObject(ObjectName observedObject) { 88 this.observedObject = observedObject; 89 } 90 91 public final ObjectName getObservedObject() { 92 return observedObject; 93 } 94 public final synchronized int getAlreadyNotified() { 95 return alreadyNotified; 96 } 97 public final synchronized void setAlreadyNotified(int alreadyNotified) { 98 this.alreadyNotified = alreadyNotified; 99 } 100 public final synchronized Object getDerivedGauge() { 101 return derivedGauge; 102 } 103 public final synchronized void setDerivedGauge(Object derivedGauge) { 104 this.derivedGauge = derivedGauge; 105 } 106 public final synchronized long getDerivedGaugeTimeStamp() { 107 return derivedGaugeTimeStamp; 108 } 109 public final synchronized void setDerivedGaugeTimeStamp( 110 long derivedGaugeTimeStamp) { 111 this.derivedGaugeTimeStamp = derivedGaugeTimeStamp; 112 } 113 114 private final ObjectName observedObject; 115 private int alreadyNotified; 116 private Object derivedGauge; 117 private long derivedGaugeTimeStamp; 118 } 119 120 /* 121 * ------------------------------------------ 122 * PRIVATE VARIABLES 123 * ------------------------------------------ 124 */ 125 126 /** 127 * Attribute to observe. 128 */ 129 private String observedAttribute; 130 131 /** 132 * Monitor granularity period (in milliseconds). 133 * The default value is set to 10 seconds. 134 */ 135 private long granularityPeriod = 10000; 136 137 /** 138 * Monitor state. 139 * The default value is set to <CODE>false</CODE>. 140 */ 141 private boolean isActive = false; 142 143 /** 144 * Monitor sequence number. 145 * The default value is set to 0. 146 */ 147 private final AtomicLong sequenceNumber = new AtomicLong(); 148 149 /** 150 * Complex type attribute flag. 151 * The default value is set to <CODE>false</CODE>. 152 */ 153 private boolean isComplexTypeAttribute = false; 154 155 /** 156 * First attribute name extracted from complex type attribute name. 157 */ 158 private String firstAttribute; 159 160 /** 161 * Remaining attribute names extracted from complex type attribute name. 162 */ 163 private final List<String> remainingAttributes = 164 new CopyOnWriteArrayList<String>(); 165 166 /** 167 * AccessControlContext of the Monitor.start() caller. 168 */ 169 private static final AccessControlContext noPermissionsACC = 170 new AccessControlContext( 171 new ProtectionDomain[] {new ProtectionDomain(null, null)}); 172 private volatile AccessControlContext acc = noPermissionsACC; 173 174 /** 175 * Scheduler Service. 176 */ 177 private static final ScheduledExecutorService scheduler = 178 Executors.newSingleThreadScheduledExecutor( 179 new DaemonThreadFactory("Scheduler")); 180 181 /** 182 * Map containing the thread pool executor per thread group. 183 */ 184 private static final Map<ThreadPoolExecutor, Void> executors = 185 new WeakHashMap<ThreadPoolExecutor, Void>(); 186 187 /** 188 * Lock for executors map. 189 */ 190 private static final Object executorsLock = new Object(); 191 192 /** 193 * Maximum Pool Size 194 */ 195 private static final int maximumPoolSize; 196 static { 197 final String maximumPoolSizeSysProp = "jmx.x.monitor.maximum.pool.size"; 198 final String maximumPoolSizeStr = AccessController.doPrivileged( 199 new GetPropertyAction(maximumPoolSizeSysProp)); 200 if (maximumPoolSizeStr == null || 201 maximumPoolSizeStr.trim().length() == 0) { 202 maximumPoolSize = 10; 203 } else { 204 int maximumPoolSizeTmp = 10; 205 try { 206 maximumPoolSizeTmp = Integer.parseInt(maximumPoolSizeStr); 207 } catch (NumberFormatException e) { 208 if (MONITOR_LOGGER.isLoggable(Level.TRACE)) { 209 MONITOR_LOGGER.log(Level.TRACE, 210 "Wrong value for " + maximumPoolSizeSysProp + 211 " system property", e); 212 MONITOR_LOGGER.log(Level.TRACE, 213 maximumPoolSizeSysProp + " defaults to 10"); 214 } 215 maximumPoolSizeTmp = 10; 216 } 217 if (maximumPoolSizeTmp < 1) { 218 maximumPoolSize = 1; 219 } else { 220 maximumPoolSize = maximumPoolSizeTmp; 221 } 222 } 223 } 224 225 /** 226 * Future associated to the current monitor task. 227 */ 228 private Future<?> monitorFuture; 229 230 /** 231 * Scheduler task to be executed by the Scheduler Service. 232 */ 233 private final SchedulerTask schedulerTask = new SchedulerTask(); 234 235 /** 236 * ScheduledFuture associated to the current scheduler task. 237 */ 238 private ScheduledFuture<?> schedulerFuture; 239 240 /* 241 * ------------------------------------------ 242 * PROTECTED VARIABLES 243 * ------------------------------------------ 244 */ 245 246 /** 247 * The amount by which the capacity of the monitor arrays are 248 * automatically incremented when their size becomes greater than 249 * their capacity. 250 */ 251 protected final static int capacityIncrement = 16; 252 253 /** 254 * The number of valid components in the vector of observed objects. 255 * 256 */ 257 protected int elementCount = 0; 258 259 /** 260 * Monitor errors that have already been notified. 261 * @deprecated equivalent to {@link #alreadyNotifieds}[0]. 262 */ 263 @Deprecated 264 protected int alreadyNotified = 0; 265 266 /** 267 * <p>Selected monitor errors that have already been notified.</p> 268 * 269 * <p>Each element in this array corresponds to an observed object 270 * in the vector. It contains a bit mask of the flags {@link 271 * #OBSERVED_OBJECT_ERROR_NOTIFIED} etc, indicating whether the 272 * corresponding notification has already been sent for the MBean 273 * being monitored.</p> 274 * 275 */ 276 protected int alreadyNotifieds[] = new int[capacityIncrement]; 277 278 /** 279 * Reference to the MBean server. This reference is null when the 280 * monitor MBean is not registered in an MBean server. This 281 * reference is initialized before the monitor MBean is registered 282 * in the MBean server. 283 * @see #preRegister(MBeanServer server, ObjectName name) 284 */ 285 protected MBeanServer server; 286 287 // Flags defining possible monitor errors. 288 // 289 290 /** 291 * This flag is used to reset the {@link #alreadyNotifieds 292 * alreadyNotifieds} monitor attribute. 293 */ 294 protected static final int RESET_FLAGS_ALREADY_NOTIFIED = 0; 295 296 /** 297 * Flag denoting that a notification has occurred after changing 298 * the observed object. This flag is used to check that the new 299 * observed object is registered in the MBean server at the time 300 * of the first notification. 301 */ 302 protected static final int OBSERVED_OBJECT_ERROR_NOTIFIED = 1; 303 304 /** 305 * Flag denoting that a notification has occurred after changing 306 * the observed attribute. This flag is used to check that the 307 * new observed attribute belongs to the observed object at the 308 * time of the first notification. 309 */ 310 protected static final int OBSERVED_ATTRIBUTE_ERROR_NOTIFIED = 2; 311 312 /** 313 * Flag denoting that a notification has occurred after changing 314 * the observed object or the observed attribute. This flag is 315 * used to check that the observed attribute type is correct 316 * (depending on the monitor in use) at the time of the first 317 * notification. 318 */ 319 protected static final int OBSERVED_ATTRIBUTE_TYPE_ERROR_NOTIFIED = 4; 320 321 /** 322 * Flag denoting that a notification has occurred after changing 323 * the observed object or the observed attribute. This flag is 324 * used to notify any exception (except the cases described above) 325 * when trying to get the value of the observed attribute at the 326 * time of the first notification. 327 */ 328 protected static final int RUNTIME_ERROR_NOTIFIED = 8; 329 330 /** 331 * This field is retained for compatibility but should not be referenced. 332 * 333 * @deprecated No replacement. 334 */ 335 @Deprecated 336 protected String dbgTag = Monitor.class.getName(); 337 338 /* 339 * ------------------------------------------ 340 * PACKAGE VARIABLES 341 * ------------------------------------------ 342 */ 343 344 /** 345 * List of ObservedObjects to which the attribute to observe belongs. 346 */ 347 final List<ObservedObject> observedObjects = 348 new CopyOnWriteArrayList<ObservedObject>(); 349 350 /** 351 * Flag denoting that a notification has occurred after changing 352 * the threshold. This flag is used to notify any exception 353 * related to invalid thresholds settings. 354 */ 355 static final int THRESHOLD_ERROR_NOTIFIED = 16; 356 357 /** 358 * Enumeration used to keep trace of the derived gauge type 359 * in counter and gauge monitors. 360 */ 361 enum NumericalType { BYTE, SHORT, INTEGER, LONG, FLOAT, DOUBLE }; 362 363 /** 364 * Constant used to initialize all the numeric values. 365 */ 366 static final Integer INTEGER_ZERO = 0; 367 368 369 /* 370 * ------------------------------------------ 371 * PUBLIC METHODS 372 * ------------------------------------------ 373 */ 374 375 /** 376 * Allows the monitor MBean to perform any operations it needs 377 * before being registered in the MBean server. 378 * <P> 379 * Initializes the reference to the MBean server. 380 * 381 * @param server The MBean server in which the monitor MBean will 382 * be registered. 383 * @param name The object name of the monitor MBean. 384 * 385 * @return The name of the monitor MBean registered. 386 * 387 * @exception Exception if something goes wrong 388 */ 389 public ObjectName preRegister(MBeanServer server, ObjectName name) 390 throws Exception { 391 392 MONITOR_LOGGER.log(Level.TRACE, 393 "initialize the reference on the MBean server"); 394 395 this.server = server; 396 return name; 397 } 398 399 /** 400 * Allows the monitor MBean to perform any operations needed after 401 * having been registered in the MBean server or after the 402 * registration has failed. 403 * <P> 404 * Not used in this context. 405 */ 406 public void postRegister(Boolean registrationDone) { 407 } 408 409 /** 410 * Allows the monitor MBean to perform any operations it needs 411 * before being unregistered by the MBean server. 412 * <P> 413 * Stops the monitor. 414 * 415 * @exception Exception if something goes wrong 416 */ 417 public void preDeregister() throws Exception { 418 419 MONITOR_LOGGER.log(Level.TRACE, "stop the monitor"); 420 421 // Stop the Monitor. 422 // 423 stop(); 424 } 425 426 /** 427 * Allows the monitor MBean to perform any operations needed after 428 * having been unregistered by the MBean server. 429 * <P> 430 * Not used in this context. 431 */ 432 public void postDeregister() { 433 } 434 435 /** 436 * Starts the monitor. 437 */ 438 public abstract void start(); 439 440 /** 441 * Stops the monitor. 442 */ 443 public abstract void stop(); 444 445 // GETTERS AND SETTERS 446 //-------------------- 447 448 /** 449 * Returns the object name of the first object in the set of observed 450 * MBeans, or <code>null</code> if there is no such object. 451 * 452 * @return The object being observed. 453 * 454 * @see #setObservedObject(ObjectName) 455 * 456 * @deprecated As of JMX 1.2, replaced by {@link #getObservedObjects} 457 */ 458 @Deprecated 459 public synchronized ObjectName getObservedObject() { 460 if (observedObjects.isEmpty()) { 461 return null; 462 } else { 463 return observedObjects.get(0).getObservedObject(); 464 } 465 } 466 467 /** 468 * Removes all objects from the set of observed objects, and then adds the 469 * specified object. 470 * 471 * @param object The object to observe. 472 * @exception IllegalArgumentException The specified 473 * object is null. 474 * 475 * @see #getObservedObject() 476 * 477 * @deprecated As of JMX 1.2, replaced by {@link #addObservedObject} 478 */ 479 @Deprecated 480 public synchronized void setObservedObject(ObjectName object) 481 throws IllegalArgumentException { 482 if (object == null) 483 throw new IllegalArgumentException("Null observed object"); 484 if (observedObjects.size() == 1 && containsObservedObject(object)) 485 return; 486 observedObjects.clear(); 487 addObservedObject(object); 488 } 489 490 /** 491 * Adds the specified object in the set of observed MBeans, if this object 492 * is not already present. 493 * 494 * @param object The object to observe. 495 * @exception IllegalArgumentException The specified object is null. 496 * 497 */ 498 public synchronized void addObservedObject(ObjectName object) 499 throws IllegalArgumentException { 500 501 if (object == null) { 502 throw new IllegalArgumentException("Null observed object"); 503 } 504 505 // Check that the specified object is not already contained. 506 // 507 if (containsObservedObject(object)) 508 return; 509 510 // Add the specified object in the list. 511 // 512 ObservedObject o = createObservedObject(object); 513 o.setAlreadyNotified(RESET_FLAGS_ALREADY_NOTIFIED); 514 o.setDerivedGauge(INTEGER_ZERO); 515 o.setDerivedGaugeTimeStamp(System.currentTimeMillis()); 516 observedObjects.add(o); 517 518 // Update legacy protected stuff. 519 // 520 createAlreadyNotified(); 521 } 522 523 /** 524 * Removes the specified object from the set of observed MBeans. 525 * 526 * @param object The object to remove. 527 * 528 */ 529 public synchronized void removeObservedObject(ObjectName object) { 530 // Check for null object. 531 // 532 if (object == null) 533 return; 534 535 final ObservedObject o = getObservedObject(object); 536 if (o != null) { 537 // Remove the specified object from the list. 538 // 539 observedObjects.remove(o); 540 // Update legacy protected stuff. 541 // 542 createAlreadyNotified(); 543 } 544 } 545 546 /** 547 * Tests whether the specified object is in the set of observed MBeans. 548 * 549 * @param object The object to check. 550 * @return <CODE>true</CODE> if the specified object is present, 551 * <CODE>false</CODE> otherwise. 552 * 553 */ 554 public synchronized boolean containsObservedObject(ObjectName object) { 555 return getObservedObject(object) != null; 556 } 557 558 /** 559 * Returns an array containing the objects being observed. 560 * 561 * @return The objects being observed. 562 * 563 */ 564 public synchronized ObjectName[] getObservedObjects() { 565 ObjectName[] names = new ObjectName[observedObjects.size()]; 566 for (int i = 0; i < names.length; i++) 567 names[i] = observedObjects.get(i).getObservedObject(); 568 return names; 569 } 570 571 /** 572 * Gets the attribute being observed. 573 * <BR>The observed attribute is not initialized by default (set to null). 574 * 575 * @return The attribute being observed. 576 * 577 * @see #setObservedAttribute 578 */ 579 public synchronized String getObservedAttribute() { 580 return observedAttribute; 581 } 582 583 /** 584 * Sets the attribute to observe. 585 * <BR>The observed attribute is not initialized by default (set to null). 586 * 587 * @param attribute The attribute to observe. 588 * @exception IllegalArgumentException The specified 589 * attribute is null. 590 * 591 * @see #getObservedAttribute 592 */ 593 public void setObservedAttribute(String attribute) 594 throws IllegalArgumentException { 595 596 if (attribute == null) { 597 throw new IllegalArgumentException("Null observed attribute"); 598 } 599 600 // Update alreadyNotified array. 601 // 602 synchronized (this) { 603 if (observedAttribute != null && 604 observedAttribute.equals(attribute)) 605 return; 606 observedAttribute = attribute; 607 608 // Reset the complex type attribute information 609 // such that it is recalculated again. 610 // 611 cleanupIsComplexTypeAttribute(); 612 613 int index = 0; 614 for (ObservedObject o : observedObjects) { 615 resetAlreadyNotified(o, index++, 616 OBSERVED_ATTRIBUTE_ERROR_NOTIFIED | 617 OBSERVED_ATTRIBUTE_TYPE_ERROR_NOTIFIED); 618 } 619 } 620 } 621 622 /** 623 * Gets the granularity period (in milliseconds). 624 * <BR>The default value of the granularity period is 10 seconds. 625 * 626 * @return The granularity period value. 627 * 628 * @see #setGranularityPeriod 629 */ 630 public synchronized long getGranularityPeriod() { 631 return granularityPeriod; 632 } 633 634 /** 635 * Sets the granularity period (in milliseconds). 636 * <BR>The default value of the granularity period is 10 seconds. 637 * 638 * @param period The granularity period value. 639 * @exception IllegalArgumentException The granularity 640 * period is less than or equal to zero. 641 * 642 * @see #getGranularityPeriod 643 */ 644 public synchronized void setGranularityPeriod(long period) 645 throws IllegalArgumentException { 646 647 if (period <= 0) { 648 throw new IllegalArgumentException("Nonpositive granularity " + 649 "period"); 650 } 651 652 if (granularityPeriod == period) 653 return; 654 granularityPeriod = period; 655 656 // Reschedule the scheduler task if the monitor is active. 657 // 658 if (isActive()) { 659 cleanupFutures(); 660 schedulerFuture = scheduler.schedule(schedulerTask, 661 period, 662 TimeUnit.MILLISECONDS); 663 } 664 } 665 666 /** 667 * Tests whether the monitor MBean is active. A monitor MBean is 668 * marked active when the {@link #start start} method is called. 669 * It becomes inactive when the {@link #stop stop} method is 670 * called. 671 * 672 * @return <CODE>true</CODE> if the monitor MBean is active, 673 * <CODE>false</CODE> otherwise. 674 */ 675 /* This method must be synchronized so that the monitoring thread will 676 correctly see modifications to the isActive variable. See the MonitorTask 677 action executed by the Scheduled Executor Service. */ 678 public synchronized boolean isActive() { 679 return isActive; 680 } 681 682 /* 683 * ------------------------------------------ 684 * PACKAGE METHODS 685 * ------------------------------------------ 686 */ 687 688 /** 689 * Starts the monitor. 690 */ 691 void doStart() { 692 MONITOR_LOGGER.log(Level.TRACE, "start the monitor"); 693 694 synchronized (this) { 695 if (isActive()) { 696 MONITOR_LOGGER.log(Level.TRACE, "the monitor is already active"); 697 return; 698 } 699 700 isActive = true; 701 702 // Reset the complex type attribute information 703 // such that it is recalculated again. 704 // 705 cleanupIsComplexTypeAttribute(); 706 707 // Cache the AccessControlContext of the Monitor.start() caller. 708 // The monitor tasks will be executed within this context. 709 // 710 acc = AccessController.getContext(); 711 712 // Start the scheduler. 713 // 714 cleanupFutures(); 715 schedulerTask.setMonitorTask(new MonitorTask()); 716 schedulerFuture = scheduler.schedule(schedulerTask, 717 getGranularityPeriod(), 718 TimeUnit.MILLISECONDS); 719 } 720 } 721 722 /** 723 * Stops the monitor. 724 */ 725 void doStop() { 726 MONITOR_LOGGER.log(Level.TRACE, "stop the monitor"); 727 728 synchronized (this) { 729 if (!isActive()) { 730 MONITOR_LOGGER.log(Level.TRACE, "the monitor is not active"); 731 return; 732 } 733 734 isActive = false; 735 736 // Cancel the scheduler task associated with the 737 // scheduler and its associated monitor task. 738 // 739 cleanupFutures(); 740 741 // Reset the AccessControlContext. 742 // 743 acc = noPermissionsACC; 744 745 // Reset the complex type attribute information 746 // such that it is recalculated again. 747 // 748 cleanupIsComplexTypeAttribute(); 749 } 750 } 751 752 /** 753 * Gets the derived gauge of the specified object, if this object is 754 * contained in the set of observed MBeans, or <code>null</code> otherwise. 755 * 756 * @param object the name of the object whose derived gauge is to 757 * be returned. 758 * 759 * @return The derived gauge of the specified object. 760 * 761 * @since 1.6 762 */ 763 synchronized Object getDerivedGauge(ObjectName object) { 764 final ObservedObject o = getObservedObject(object); 765 return o == null ? null : o.getDerivedGauge(); 766 } 767 768 /** 769 * Gets the derived gauge timestamp of the specified object, if 770 * this object is contained in the set of observed MBeans, or 771 * <code>0</code> otherwise. 772 * 773 * @param object the name of the object whose derived gauge 774 * timestamp is to be returned. 775 * 776 * @return The derived gauge timestamp of the specified object. 777 * 778 */ 779 synchronized long getDerivedGaugeTimeStamp(ObjectName object) { 780 final ObservedObject o = getObservedObject(object); 781 return o == null ? 0 : o.getDerivedGaugeTimeStamp(); 782 } 783 784 Object getAttribute(MBeanServerConnection mbsc, 785 ObjectName object, 786 String attribute) 787 throws AttributeNotFoundException, 788 InstanceNotFoundException, 789 MBeanException, 790 ReflectionException, 791 IOException { 792 // Check for "ObservedAttribute" replacement. 793 // This could happen if a thread A called setObservedAttribute() 794 // while other thread B was in the middle of the monitor() method 795 // and received the old observed attribute value. 796 // 797 final boolean lookupMBeanInfo; 798 synchronized (this) { 799 if (!isActive()) 800 throw new IllegalArgumentException( 801 "The monitor has been stopped"); 802 if (!attribute.equals(getObservedAttribute())) 803 throw new IllegalArgumentException( 804 "The observed attribute has been changed"); 805 lookupMBeanInfo = 806 (firstAttribute == null && attribute.indexOf('.') != -1); 807 } 808 809 // Look up MBeanInfo if needed 810 // 811 final MBeanInfo mbi; 812 if (lookupMBeanInfo) { 813 try { 814 mbi = mbsc.getMBeanInfo(object); 815 } catch (IntrospectionException e) { 816 throw new IllegalArgumentException(e); 817 } 818 } else { 819 mbi = null; 820 } 821 822 // Check for complex type attribute 823 // 824 final String fa; 825 synchronized (this) { 826 if (!isActive()) 827 throw new IllegalArgumentException( 828 "The monitor has been stopped"); 829 if (!attribute.equals(getObservedAttribute())) 830 throw new IllegalArgumentException( 831 "The observed attribute has been changed"); 832 if (firstAttribute == null) { 833 if (attribute.indexOf('.') != -1) { 834 MBeanAttributeInfo mbaiArray[] = mbi.getAttributes(); 835 for (MBeanAttributeInfo mbai : mbaiArray) { 836 if (attribute.equals(mbai.getName())) { 837 firstAttribute = attribute; 838 break; 839 } 840 } 841 if (firstAttribute == null) { 842 String tokens[] = attribute.split("\\.", -1); 843 firstAttribute = tokens[0]; 844 for (int i = 1; i < tokens.length; i++) 845 remainingAttributes.add(tokens[i]); 846 isComplexTypeAttribute = true; 847 } 848 } else { 849 firstAttribute = attribute; 850 } 851 } 852 fa = firstAttribute; 853 } 854 return mbsc.getAttribute(object, fa); 855 } 856 857 Comparable<?> getComparableFromAttribute(ObjectName object, 858 String attribute, 859 Object value) 860 throws AttributeNotFoundException { 861 if (isComplexTypeAttribute) { 862 Object v = value; 863 for (String attr : remainingAttributes) 864 v = Introspector.elementFromComplex(v, attr); 865 return (Comparable<?>) v; 866 } else { 867 return (Comparable<?>) value; 868 } 869 } 870 871 boolean isComparableTypeValid(ObjectName object, 872 String attribute, 873 Comparable<?> value) { 874 return true; 875 } 876 877 String buildErrorNotification(ObjectName object, 878 String attribute, 879 Comparable<?> value) { 880 return null; 881 } 882 883 void onErrorNotification(MonitorNotification notification) { 884 } 885 886 Comparable<?> getDerivedGaugeFromComparable(ObjectName object, 887 String attribute, 888 Comparable<?> value) { 889 return (Comparable<?>) value; 890 } 891 892 MonitorNotification buildAlarmNotification(ObjectName object, 893 String attribute, 894 Comparable<?> value){ 895 return null; 896 } 897 898 boolean isThresholdTypeValid(ObjectName object, 899 String attribute, 900 Comparable<?> value) { 901 return true; 902 } 903 904 static Class<? extends Number> classForType(NumericalType type) { 905 switch (type) { 906 case BYTE: 907 return Byte.class; 908 case SHORT: 909 return Short.class; 910 case INTEGER: 911 return Integer.class; 912 case LONG: 913 return Long.class; 914 case FLOAT: 915 return Float.class; 916 case DOUBLE: 917 return Double.class; 918 default: 919 throw new IllegalArgumentException( 920 "Unsupported numerical type"); 921 } 922 } 923 924 static boolean isValidForType(Object value, Class<? extends Number> c) { 925 return ((value == INTEGER_ZERO) || c.isInstance(value)); 926 } 927 928 /** 929 * Get the specified {@code ObservedObject} if this object is 930 * contained in the set of observed MBeans, or {@code null} 931 * otherwise. 932 * 933 * @param object the name of the {@code ObservedObject} to retrieve. 934 * 935 * @return The {@code ObservedObject} associated to the supplied 936 * {@code ObjectName}. 937 * 938 * @since 1.6 939 */ 940 synchronized ObservedObject getObservedObject(ObjectName object) { 941 for (ObservedObject o : observedObjects) 942 if (o.getObservedObject().equals(object)) 943 return o; 944 return null; 945 } 946 947 /** 948 * Factory method for ObservedObject creation. 949 * 950 * @since 1.6 951 */ 952 ObservedObject createObservedObject(ObjectName object) { 953 return new ObservedObject(object); 954 } 955 956 /** 957 * Create the {@link #alreadyNotified} array from 958 * the {@code ObservedObject} array list. 959 */ 960 synchronized void createAlreadyNotified() { 961 // Update elementCount. 962 // 963 elementCount = observedObjects.size(); 964 965 // Update arrays. 966 // 967 alreadyNotifieds = new int[elementCount]; 968 for (int i = 0; i < elementCount; i++) { 969 alreadyNotifieds[i] = observedObjects.get(i).getAlreadyNotified(); 970 } 971 updateDeprecatedAlreadyNotified(); 972 } 973 974 /** 975 * Update the deprecated {@link #alreadyNotified} field. 976 */ 977 synchronized void updateDeprecatedAlreadyNotified() { 978 if (elementCount > 0) 979 alreadyNotified = alreadyNotifieds[0]; 980 else 981 alreadyNotified = 0; 982 } 983 984 /** 985 * Update the {@link #alreadyNotifieds} array element at the given index 986 * with the already notified flag in the given {@code ObservedObject}. 987 * Ensure the deprecated {@link #alreadyNotified} field is updated 988 * if appropriate. 989 */ 990 synchronized void updateAlreadyNotified(ObservedObject o, int index) { 991 alreadyNotifieds[index] = o.getAlreadyNotified(); 992 if (index == 0) 993 updateDeprecatedAlreadyNotified(); 994 } 995 996 /** 997 * Check if the given bits in the given element of {@link #alreadyNotifieds} 998 * are set. 999 */ 1000 synchronized boolean isAlreadyNotified(ObservedObject o, int mask) { 1001 return ((o.getAlreadyNotified() & mask) != 0); 1002 } 1003 1004 /** 1005 * Set the given bits in the given element of {@link #alreadyNotifieds}. 1006 * Ensure the deprecated {@link #alreadyNotified} field is updated 1007 * if appropriate. 1008 */ 1009 synchronized void setAlreadyNotified(ObservedObject o, int index, 1010 int mask, int an[]) { 1011 final int i = computeAlreadyNotifiedIndex(o, index, an); 1012 if (i == -1) 1013 return; 1014 o.setAlreadyNotified(o.getAlreadyNotified() | mask); 1015 updateAlreadyNotified(o, i); 1016 } 1017 1018 /** 1019 * Reset the given bits in the given element of {@link #alreadyNotifieds}. 1020 * Ensure the deprecated {@link #alreadyNotified} field is updated 1021 * if appropriate. 1022 */ 1023 synchronized void resetAlreadyNotified(ObservedObject o, 1024 int index, int mask) { 1025 o.setAlreadyNotified(o.getAlreadyNotified() & ~mask); 1026 updateAlreadyNotified(o, index); 1027 } 1028 1029 /** 1030 * Reset all bits in the given element of {@link #alreadyNotifieds}. 1031 * Ensure the deprecated {@link #alreadyNotified} field is updated 1032 * if appropriate. 1033 */ 1034 synchronized void resetAllAlreadyNotified(ObservedObject o, 1035 int index, int an[]) { 1036 final int i = computeAlreadyNotifiedIndex(o, index, an); 1037 if (i == -1) 1038 return; 1039 o.setAlreadyNotified(RESET_FLAGS_ALREADY_NOTIFIED); 1040 updateAlreadyNotified(o, index); 1041 } 1042 1043 /** 1044 * Check if the {@link #alreadyNotifieds} array has been modified. 1045 * If true recompute the index for the given observed object. 1046 */ 1047 synchronized int computeAlreadyNotifiedIndex(ObservedObject o, 1048 int index, int an[]) { 1049 if (an == alreadyNotifieds) { 1050 return index; 1051 } else { 1052 return observedObjects.indexOf(o); 1053 } 1054 } 1055 1056 /* 1057 * ------------------------------------------ 1058 * PRIVATE METHODS 1059 * ------------------------------------------ 1060 */ 1061 1062 /** 1063 * This method is used by the monitor MBean to create and send a 1064 * monitor notification to all the listeners registered for this 1065 * kind of notification. 1066 * 1067 * @param type The notification type. 1068 * @param timeStamp The notification emission date. 1069 * @param msg The notification message. 1070 * @param derGauge The derived gauge. 1071 * @param trigger The threshold/string (depending on the monitor 1072 * type) that triggered off the notification. 1073 * @param object The ObjectName of the observed object that triggered 1074 * off the notification. 1075 * @param onError Flag indicating if this monitor notification is 1076 * an error notification or an alarm notification. 1077 */ 1078 private void sendNotification(String type, long timeStamp, String msg, 1079 Object derGauge, Object trigger, 1080 ObjectName object, boolean onError) { 1081 if (!isActive()) 1082 return; 1083 1084 if (MONITOR_LOGGER.isLoggable(Level.TRACE)) { 1085 MONITOR_LOGGER.log(Level.TRACE, "send notification: " + 1086 "\n\tNotification observed object = " + object + 1087 "\n\tNotification observed attribute = " + observedAttribute + 1088 "\n\tNotification derived gauge = " + derGauge); 1089 } 1090 1091 long seqno = sequenceNumber.getAndIncrement(); 1092 1093 MonitorNotification mn = 1094 new MonitorNotification(type, 1095 this, 1096 seqno, 1097 timeStamp, 1098 msg, 1099 object, 1100 observedAttribute, 1101 derGauge, 1102 trigger); 1103 if (onError) 1104 onErrorNotification(mn); 1105 sendNotification(mn); 1106 } 1107 1108 /** 1109 * This method is called by the monitor each time 1110 * the granularity period has been exceeded. 1111 * @param o The observed object. 1112 */ 1113 private void monitor(ObservedObject o, int index, int an[]) { 1114 1115 String attribute; 1116 String notifType = null; 1117 String msg = null; 1118 Object derGauge = null; 1119 Object trigger = null; 1120 ObjectName object; 1121 Comparable<?> value = null; 1122 MonitorNotification alarm = null; 1123 1124 if (!isActive()) 1125 return; 1126 1127 // Check that neither the observed object nor the 1128 // observed attribute are null. If the observed 1129 // object or observed attribute is null, this means 1130 // that the monitor started before a complete 1131 // initialization and nothing is done. 1132 // 1133 synchronized (this) { 1134 object = o.getObservedObject(); 1135 attribute = getObservedAttribute(); 1136 if (object == null || attribute == null) { 1137 return; 1138 } 1139 } 1140 1141 // Check that the observed object is registered in the 1142 // MBean server and that the observed attribute 1143 // belongs to the observed object. 1144 // 1145 Object attributeValue = null; 1146 try { 1147 attributeValue = getAttribute(server, object, attribute); 1148 if (attributeValue == null) 1149 if (isAlreadyNotified( 1150 o, OBSERVED_ATTRIBUTE_TYPE_ERROR_NOTIFIED)) 1151 return; 1152 else { 1153 notifType = OBSERVED_ATTRIBUTE_TYPE_ERROR; 1154 setAlreadyNotified( 1155 o, index, OBSERVED_ATTRIBUTE_TYPE_ERROR_NOTIFIED, an); 1156 msg = "The observed attribute value is null."; 1157 MONITOR_LOGGER.log(Level.TRACE, msg); 1158 } 1159 } catch (NullPointerException np_ex) { 1160 if (isAlreadyNotified(o, RUNTIME_ERROR_NOTIFIED)) 1161 return; 1162 else { 1163 notifType = RUNTIME_ERROR; 1164 setAlreadyNotified(o, index, RUNTIME_ERROR_NOTIFIED, an); 1165 msg = 1166 "The monitor must be registered in the MBean " + 1167 "server or an MBeanServerConnection must be " + 1168 "explicitly supplied."; 1169 MONITOR_LOGGER.log(Level.TRACE, msg); 1170 MONITOR_LOGGER.log(Level.TRACE, np_ex::toString); 1171 } 1172 } catch (InstanceNotFoundException inf_ex) { 1173 if (isAlreadyNotified(o, OBSERVED_OBJECT_ERROR_NOTIFIED)) 1174 return; 1175 else { 1176 notifType = OBSERVED_OBJECT_ERROR; 1177 setAlreadyNotified( 1178 o, index, OBSERVED_OBJECT_ERROR_NOTIFIED, an); 1179 msg = 1180 "The observed object must be accessible in " + 1181 "the MBeanServerConnection."; 1182 MONITOR_LOGGER.log(Level.TRACE, msg); 1183 MONITOR_LOGGER.log(Level.TRACE, inf_ex::toString); 1184 } 1185 } catch (AttributeNotFoundException anf_ex) { 1186 if (isAlreadyNotified(o, OBSERVED_ATTRIBUTE_ERROR_NOTIFIED)) 1187 return; 1188 else { 1189 notifType = OBSERVED_ATTRIBUTE_ERROR; 1190 setAlreadyNotified( 1191 o, index, OBSERVED_ATTRIBUTE_ERROR_NOTIFIED, an); 1192 msg = 1193 "The observed attribute must be accessible in " + 1194 "the observed object."; 1195 MONITOR_LOGGER.log(Level.TRACE, msg); 1196 MONITOR_LOGGER.log(Level.TRACE, anf_ex::toString); 1197 } 1198 } catch (MBeanException mb_ex) { 1199 if (isAlreadyNotified(o, RUNTIME_ERROR_NOTIFIED)) 1200 return; 1201 else { 1202 notifType = RUNTIME_ERROR; 1203 setAlreadyNotified(o, index, RUNTIME_ERROR_NOTIFIED, an); 1204 msg = mb_ex.getMessage() == null ? "" : mb_ex.getMessage(); 1205 MONITOR_LOGGER.log(Level.TRACE, msg); 1206 MONITOR_LOGGER.log(Level.TRACE, mb_ex::toString); 1207 } 1208 } catch (ReflectionException ref_ex) { 1209 if (isAlreadyNotified(o, RUNTIME_ERROR_NOTIFIED)) { 1210 return; 1211 } else { 1212 notifType = RUNTIME_ERROR; 1213 setAlreadyNotified(o, index, RUNTIME_ERROR_NOTIFIED, an); 1214 msg = ref_ex.getMessage() == null ? "" : ref_ex.getMessage(); 1215 MONITOR_LOGGER.log(Level.TRACE, msg); 1216 MONITOR_LOGGER.log(Level.TRACE, ref_ex::toString); 1217 } 1218 } catch (IOException io_ex) { 1219 if (isAlreadyNotified(o, RUNTIME_ERROR_NOTIFIED)) 1220 return; 1221 else { 1222 notifType = RUNTIME_ERROR; 1223 setAlreadyNotified(o, index, RUNTIME_ERROR_NOTIFIED, an); 1224 msg = io_ex.getMessage() == null ? "" : io_ex.getMessage(); 1225 MONITOR_LOGGER.log(Level.TRACE, msg); 1226 MONITOR_LOGGER.log(Level.TRACE, io_ex::toString); 1227 } 1228 } catch (RuntimeException rt_ex) { 1229 if (isAlreadyNotified(o, RUNTIME_ERROR_NOTIFIED)) 1230 return; 1231 else { 1232 notifType = RUNTIME_ERROR; 1233 setAlreadyNotified(o, index, RUNTIME_ERROR_NOTIFIED, an); 1234 msg = rt_ex.getMessage() == null ? "" : rt_ex.getMessage(); 1235 MONITOR_LOGGER.log(Level.TRACE, msg); 1236 MONITOR_LOGGER.log(Level.TRACE, rt_ex::toString); 1237 } 1238 } 1239 1240 synchronized (this) { 1241 1242 // Check if the monitor has been stopped. 1243 // 1244 if (!isActive()) 1245 return; 1246 1247 // Check if the observed attribute has been changed. 1248 // 1249 // Avoid race condition where mbs.getAttribute() succeeded but 1250 // another thread replaced the observed attribute meanwhile. 1251 // 1252 // Avoid setting computed derived gauge on erroneous attribute. 1253 // 1254 if (!attribute.equals(getObservedAttribute())) 1255 return; 1256 1257 // Derive a Comparable object from the ObservedAttribute value 1258 // if the type of the ObservedAttribute value is a complex type. 1259 // 1260 if (msg == null) { 1261 try { 1262 value = getComparableFromAttribute(object, 1263 attribute, 1264 attributeValue); 1265 } catch (ClassCastException e) { 1266 if (isAlreadyNotified( 1267 o, OBSERVED_ATTRIBUTE_TYPE_ERROR_NOTIFIED)) 1268 return; 1269 else { 1270 notifType = OBSERVED_ATTRIBUTE_TYPE_ERROR; 1271 setAlreadyNotified(o, index, 1272 OBSERVED_ATTRIBUTE_TYPE_ERROR_NOTIFIED, an); 1273 msg = 1274 "The observed attribute value does not " + 1275 "implement the Comparable interface."; 1276 MONITOR_LOGGER.log(Level.TRACE, msg); 1277 MONITOR_LOGGER.log(Level.TRACE, e::toString); 1278 } 1279 } catch (AttributeNotFoundException e) { 1280 if (isAlreadyNotified(o, OBSERVED_ATTRIBUTE_ERROR_NOTIFIED)) 1281 return; 1282 else { 1283 notifType = OBSERVED_ATTRIBUTE_ERROR; 1284 setAlreadyNotified( 1285 o, index, OBSERVED_ATTRIBUTE_ERROR_NOTIFIED, an); 1286 msg = 1287 "The observed attribute must be accessible in " + 1288 "the observed object."; 1289 MONITOR_LOGGER.log(Level.TRACE, msg); 1290 MONITOR_LOGGER.log(Level.TRACE, e::toString); 1291 } 1292 } catch (RuntimeException e) { 1293 if (isAlreadyNotified(o, RUNTIME_ERROR_NOTIFIED)) 1294 return; 1295 else { 1296 notifType = RUNTIME_ERROR; 1297 setAlreadyNotified(o, index, 1298 RUNTIME_ERROR_NOTIFIED, an); 1299 msg = e.getMessage() == null ? "" : e.getMessage(); 1300 MONITOR_LOGGER.log(Level.TRACE, msg); 1301 MONITOR_LOGGER.log(Level.TRACE, e::toString); 1302 } 1303 } 1304 } 1305 1306 // Check that the observed attribute type is supported by this 1307 // monitor. 1308 // 1309 if (msg == null) { 1310 if (!isComparableTypeValid(object, attribute, value)) { 1311 if (isAlreadyNotified( 1312 o, OBSERVED_ATTRIBUTE_TYPE_ERROR_NOTIFIED)) 1313 return; 1314 else { 1315 notifType = OBSERVED_ATTRIBUTE_TYPE_ERROR; 1316 setAlreadyNotified(o, index, 1317 OBSERVED_ATTRIBUTE_TYPE_ERROR_NOTIFIED, an); 1318 msg = "The observed attribute type is not valid."; 1319 MONITOR_LOGGER.log(Level.TRACE, msg); 1320 } 1321 } 1322 } 1323 1324 // Check that threshold type is supported by this monitor. 1325 // 1326 if (msg == null) { 1327 if (!isThresholdTypeValid(object, attribute, value)) { 1328 if (isAlreadyNotified(o, THRESHOLD_ERROR_NOTIFIED)) 1329 return; 1330 else { 1331 notifType = THRESHOLD_ERROR; 1332 setAlreadyNotified(o, index, 1333 THRESHOLD_ERROR_NOTIFIED, an); 1334 msg = "The threshold type is not valid."; 1335 MONITOR_LOGGER.log(Level.TRACE, msg); 1336 } 1337 } 1338 } 1339 1340 // Let someone subclassing the monitor to perform additional 1341 // monitor consistency checks and report errors if necessary. 1342 // 1343 if (msg == null) { 1344 msg = buildErrorNotification(object, attribute, value); 1345 if (msg != null) { 1346 if (isAlreadyNotified(o, RUNTIME_ERROR_NOTIFIED)) 1347 return; 1348 else { 1349 notifType = RUNTIME_ERROR; 1350 setAlreadyNotified(o, index, 1351 RUNTIME_ERROR_NOTIFIED, an); 1352 MONITOR_LOGGER.log(Level.TRACE, msg); 1353 } 1354 } 1355 } 1356 1357 // If no errors were found then clear all error flags and 1358 // let the monitor decide if a notification must be sent. 1359 // 1360 if (msg == null) { 1361 // Clear all already notified flags. 1362 // 1363 resetAllAlreadyNotified(o, index, an); 1364 1365 // Get derived gauge from comparable value. 1366 // 1367 derGauge = getDerivedGaugeFromComparable(object, 1368 attribute, 1369 value); 1370 1371 o.setDerivedGauge(derGauge); 1372 o.setDerivedGaugeTimeStamp(System.currentTimeMillis()); 1373 1374 // Check if an alarm must be fired. 1375 // 1376 alarm = buildAlarmNotification(object, 1377 attribute, 1378 (Comparable<?>) derGauge); 1379 } 1380 1381 } 1382 1383 // Notify monitor errors 1384 // 1385 if (msg != null) 1386 sendNotification(notifType, 1387 System.currentTimeMillis(), 1388 msg, 1389 derGauge, 1390 trigger, 1391 object, 1392 true); 1393 1394 // Notify monitor alarms 1395 // 1396 if (alarm != null && alarm.getType() != null) 1397 sendNotification(alarm.getType(), 1398 System.currentTimeMillis(), 1399 alarm.getMessage(), 1400 derGauge, 1401 alarm.getTrigger(), 1402 object, 1403 false); 1404 } 1405 1406 /** 1407 * Cleanup the scheduler and monitor tasks futures. 1408 */ 1409 private synchronized void cleanupFutures() { 1410 if (schedulerFuture != null) { 1411 schedulerFuture.cancel(false); 1412 schedulerFuture = null; 1413 } 1414 if (monitorFuture != null) { 1415 monitorFuture.cancel(false); 1416 monitorFuture = null; 1417 } 1418 } 1419 1420 /** 1421 * Cleanup the "is complex type attribute" info. 1422 */ 1423 private synchronized void cleanupIsComplexTypeAttribute() { 1424 firstAttribute = null; 1425 remainingAttributes.clear(); 1426 isComplexTypeAttribute = false; 1427 } 1428 1429 /** 1430 * SchedulerTask nested class: This class implements the Runnable interface. 1431 * 1432 * The SchedulerTask is executed periodically with a given fixed delay by 1433 * the Scheduled Executor Service. 1434 */ 1435 private class SchedulerTask implements Runnable { 1436 1437 private MonitorTask task; 1438 1439 /* 1440 * ------------------------------------------ 1441 * CONSTRUCTORS 1442 * ------------------------------------------ 1443 */ 1444 1445 public SchedulerTask() { 1446 } 1447 1448 /* 1449 * ------------------------------------------ 1450 * GETTERS/SETTERS 1451 * ------------------------------------------ 1452 */ 1453 1454 public void setMonitorTask(MonitorTask task) { 1455 this.task = task; 1456 } 1457 1458 /* 1459 * ------------------------------------------ 1460 * PUBLIC METHODS 1461 * ------------------------------------------ 1462 */ 1463 1464 public void run() { 1465 synchronized (Monitor.this) { 1466 Monitor.this.monitorFuture = task.submit(); 1467 } 1468 } 1469 } 1470 1471 /** 1472 * MonitorTask nested class: This class implements the Runnable interface. 1473 * 1474 * The MonitorTask is executed periodically with a given fixed delay by the 1475 * Scheduled Executor Service. 1476 */ 1477 private class MonitorTask implements Runnable { 1478 1479 private ThreadPoolExecutor executor; 1480 1481 /* 1482 * ------------------------------------------ 1483 * CONSTRUCTORS 1484 * ------------------------------------------ 1485 */ 1486 1487 public MonitorTask() { 1488 // Find out if there's already an existing executor for the calling 1489 // thread and reuse it. Otherwise, create a new one and store it in 1490 // the executors map. If there is a SecurityManager, the group of 1491 // System.getSecurityManager() is used, else the group of the thread 1492 // instantiating this MonitorTask, i.e. the group of the thread that 1493 // calls "Monitor.start()". 1494 SecurityManager s = System.getSecurityManager(); 1495 ThreadGroup group = (s != null) ? s.getThreadGroup() : 1496 Thread.currentThread().getThreadGroup(); 1497 synchronized (executorsLock) { 1498 for (ThreadPoolExecutor e : executors.keySet()) { 1499 DaemonThreadFactory tf = 1500 (DaemonThreadFactory) e.getThreadFactory(); 1501 ThreadGroup tg = tf.getThreadGroup(); 1502 if (tg == group) { 1503 executor = e; 1504 break; 1505 } 1506 } 1507 if (executor == null) { 1508 executor = new ThreadPoolExecutor( 1509 maximumPoolSize, 1510 maximumPoolSize, 1511 60L, 1512 TimeUnit.SECONDS, 1513 new LinkedBlockingQueue<Runnable>(), 1514 new DaemonThreadFactory("ThreadGroup<" + 1515 group.getName() + "> Executor", group)); 1516 executor.allowCoreThreadTimeOut(true); 1517 executors.put(executor, null); 1518 } 1519 } 1520 } 1521 1522 /* 1523 * ------------------------------------------ 1524 * PUBLIC METHODS 1525 * ------------------------------------------ 1526 */ 1527 1528 public Future<?> submit() { 1529 return executor.submit(this); 1530 } 1531 1532 public void run() { 1533 final ScheduledFuture<?> sf; 1534 final AccessControlContext ac; 1535 synchronized (Monitor.this) { 1536 sf = Monitor.this.schedulerFuture; 1537 ac = Monitor.this.acc; 1538 } 1539 PrivilegedAction<Void> action = new PrivilegedAction<Void>() { 1540 public Void run() { 1541 if (Monitor.this.isActive()) { 1542 final int an[] = alreadyNotifieds; 1543 int index = 0; 1544 for (ObservedObject o : Monitor.this.observedObjects) { 1545 if (Monitor.this.isActive()) { 1546 Monitor.this.monitor(o, index++, an); 1547 } 1548 } 1549 } 1550 return null; 1551 } 1552 }; 1553 if (ac == null) { 1554 throw new SecurityException("AccessControlContext cannot be null"); 1555 } 1556 AccessController.doPrivileged(action, ac); 1557 synchronized (Monitor.this) { 1558 if (Monitor.this.isActive() && 1559 Monitor.this.schedulerFuture == sf) { 1560 Monitor.this.monitorFuture = null; 1561 Monitor.this.schedulerFuture = 1562 scheduler.schedule(Monitor.this.schedulerTask, 1563 Monitor.this.getGranularityPeriod(), 1564 TimeUnit.MILLISECONDS); 1565 } 1566 } 1567 } 1568 } 1569 1570 /** 1571 * Daemon thread factory used by the monitor executors. 1572 * <P> 1573 * This factory creates all new threads used by an Executor in 1574 * the same ThreadGroup. If there is a SecurityManager, it uses 1575 * the group of System.getSecurityManager(), else the group of 1576 * the thread instantiating this DaemonThreadFactory. Each new 1577 * thread is created as a daemon thread with priority 1578 * Thread.NORM_PRIORITY. New threads have names accessible via 1579 * Thread.getName() of "{@literal JMX Monitor <pool-name> Pool [Thread-M]}", 1580 * where M is the sequence number of the thread created by this 1581 * factory. 1582 */ 1583 private static class DaemonThreadFactory implements ThreadFactory { 1584 final ThreadGroup group; 1585 final AtomicInteger threadNumber = new AtomicInteger(1); 1586 final String namePrefix; 1587 static final String nameSuffix = "]"; 1588 1589 public DaemonThreadFactory(String poolName) { 1590 SecurityManager s = System.getSecurityManager(); 1591 group = (s != null) ? s.getThreadGroup() : 1592 Thread.currentThread().getThreadGroup(); 1593 namePrefix = "JMX Monitor " + poolName + " Pool [Thread-"; 1594 } 1595 1596 public DaemonThreadFactory(String poolName, ThreadGroup threadGroup) { 1597 group = threadGroup; 1598 namePrefix = "JMX Monitor " + poolName + " Pool [Thread-"; 1599 } 1600 1601 public ThreadGroup getThreadGroup() { 1602 return group; 1603 } 1604 1605 public Thread newThread(Runnable r) { 1606 Thread t = new Thread( 1607 group, 1608 r, 1609 namePrefix + threadNumber.getAndIncrement() + nameSuffix, 1610 0, 1611 false 1612 ); 1613 1614 t.setDaemon(true); 1615 if (t.getPriority() != Thread.NORM_PRIORITY) 1616 t.setPriority(Thread.NORM_PRIORITY); 1617 return t; 1618 } 1619 } 1620} 1621