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

Save This Page
Home » openjdk-7 » javax » management » monitor » [javadoc | source]