Home » openjdk-7 » javax » management » modelmbean » [javadoc | source]

    1   /*
    2    * Copyright (c) 2000, 2008, Oracle and/or its affiliates. All rights reserved.
    3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    4    *
    5    * This code is free software; you can redistribute it and/or modify it
    6    * under the terms of the GNU General Public License version 2 only, as
    7    * published by the Free Software Foundation.  Oracle designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Oracle in the LICENSE file that accompanied this code.
   10    *
   11    * This code is distributed in the hope that it will be useful, but WITHOUT
   12    * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   13    * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   14    * version 2 for more details (a copy is included in the LICENSE file that
   15    * accompanied this code).
   16    *
   17    * You should have received a copy of the GNU General Public License version
   18    * 2 along with this work; if not, write to the Free Software Foundation,
   19    * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   20    *
   21    * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   22    * or visit www.oracle.com if you need additional information or have any
   23    * questions.
   24    */
   25   /*
   26    * @author    IBM Corp.
   27    *
   28    * Copyright IBM Corp. 1999-2000.  All rights reserved.
   29    */
   30   
   31   
   32   package javax.management.modelmbean;
   33   
   34   /* java imports */
   35   
   36   import static com.sun.jmx.defaults.JmxProperties.MODELMBEAN_LOGGER;
   37   import java.io.FileOutputStream;
   38   import java.io.PrintStream;
   39   import java.lang.reflect.InvocationTargetException;
   40   
   41   import java.lang.reflect.Method;
   42   
   43   import java.util.Date;
   44   import java.util.HashMap;
   45   import java.util.HashSet;
   46   import java.util.Iterator;
   47   import java.util.logging.Level;
   48   import java.util.Map;
   49   import java.util.Set;
   50   
   51   import java.util.Vector;
   52   import javax.management.Attribute;
   53   import javax.management.AttributeChangeNotification;
   54   import javax.management.AttributeChangeNotificationFilter;
   55   import javax.management.AttributeList;
   56   import javax.management.AttributeNotFoundException;
   57   import javax.management.Descriptor;
   58   import javax.management.InstanceNotFoundException;
   59   import javax.management.InvalidAttributeValueException;
   60   import javax.management.ListenerNotFoundException;
   61   import javax.management.MBeanAttributeInfo;
   62   import javax.management.MBeanConstructorInfo;
   63   import javax.management.MBeanException;
   64   import javax.management.MBeanInfo;
   65   import javax.management.MBeanNotificationInfo;
   66   import javax.management.MBeanOperationInfo;
   67   import javax.management.MBeanRegistration;
   68   import javax.management.MBeanServer;
   69   import javax.management.MBeanServerFactory;
   70   import javax.management.Notification;
   71   import javax.management.NotificationBroadcasterSupport;
   72   import javax.management.NotificationEmitter;
   73   import javax.management.NotificationFilter;
   74   import javax.management.NotificationListener;
   75   import javax.management.ObjectName;
   76   import javax.management.ReflectionException;
   77   import javax.management.RuntimeErrorException;
   78   import javax.management.RuntimeOperationsException;
   79   import javax.management.ServiceNotFoundException;
   80   import javax.management.loading.ClassLoaderRepository;
   81   
   82   import sun.reflect.misc.MethodUtil;
   83   import sun.reflect.misc.ReflectUtil;
   84   
   85   /**
   86    * This class is the implementation of a ModelMBean. An appropriate
   87    * implementation of a ModelMBean must be shipped with every JMX Agent
   88    * and the class must be named RequiredModelMBean.
   89    * <P>
   90    * Java resources wishing to be manageable instantiate the
   91    * RequiredModelMBean using the MBeanServer's createMBean method.
   92    * The resource then sets the MBeanInfo and Descriptors for the
   93    * RequiredModelMBean instance. The attributes and operations exposed
   94    * via the ModelMBeanInfo for the ModelMBean are accessible
   95    * from MBeans, connectors/adaptors like other MBeans. Through the
   96    * Descriptors, values and methods in the managed application can be
   97    * defined and mapped to attributes and operations of the ModelMBean.
   98    * This mapping can be defined in an XML formatted file or dynamically and
   99    * programmatically at runtime.
  100    * <P>
  101    * Every RequiredModelMBean which is instantiated in the MBeanServer
  102    * becomes manageable:<br>
  103    * its attributes and operations become remotely accessible through the
  104    * connectors/adaptors connected to that MBeanServer.
  105    * <P>
  106    * A Java object cannot be registered in the MBeanServer unless it is a
  107    * JMX compliant MBean. By instantiating a RequiredModelMBean, resources
  108    * are guaranteed that the MBean is valid.
  109    *
  110    * MBeanException and RuntimeOperationsException must be thrown on every
  111    * public method.  This allows for wrapping exceptions from distributed
  112    * communications (RMI, EJB, etc.)
  113    *
  114    * @since 1.5
  115    */
  116   
  117   public class RequiredModelMBean
  118       implements ModelMBean, MBeanRegistration, NotificationEmitter {
  119   
  120       /*************************************/
  121       /* attributes                        */
  122       /*************************************/
  123       ModelMBeanInfo modelMBeanInfo;
  124   
  125       /* Notification broadcaster for any notification to be sent
  126        * from the application through the RequiredModelMBean.  */
  127       private NotificationBroadcasterSupport generalBroadcaster = null;
  128   
  129       /* Notification broadcaster for attribute change notifications */
  130       private NotificationBroadcasterSupport attributeBroadcaster = null;
  131   
  132       /* handle, name, or reference for instance on which the actual invoke
  133        * and operations will be executed */
  134       private Object managedResource = null;
  135   
  136   
  137       /* records the registering in MBeanServer */
  138       private boolean registered = false;
  139       private transient MBeanServer server = null;
  140   
  141       /*************************************/
  142       /* constructors                      */
  143       /*************************************/
  144   
  145       /**
  146        * Constructs an <CODE>RequiredModelMBean</CODE> with an empty
  147        * ModelMBeanInfo.
  148        * <P>
  149        * The RequiredModelMBean's MBeanInfo and Descriptors
  150        * can be customized using the {@link #setModelMBeanInfo} method.
  151        * After the RequiredModelMBean's MBeanInfo and Descriptors are
  152        * customized, the RequiredModelMBean can be registered with
  153        * the MBeanServer.
  154        *
  155        * @exception MBeanException Wraps a distributed communication Exception.
  156        *
  157        * @exception RuntimeOperationsException Wraps a {@link
  158        * RuntimeException} during the construction of the object.
  159        **/
  160       public RequiredModelMBean()
  161           throws MBeanException, RuntimeOperationsException {
  162           if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
  163               MODELMBEAN_LOGGER.logp(Level.FINER,
  164                       RequiredModelMBean.class.getName(),
  165                       "RequiredModelMBean()", "Entry");
  166           }
  167           modelMBeanInfo = createDefaultModelMBeanInfo();
  168           if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
  169               MODELMBEAN_LOGGER.logp(Level.FINER,
  170                       RequiredModelMBean.class.getName(),
  171                       "RequiredModelMBean()", "Exit");
  172           }
  173       }
  174   
  175       /**
  176        * Constructs a RequiredModelMBean object using ModelMBeanInfo passed in.
  177        * As long as the RequiredModelMBean is not registered
  178        * with the MBeanServer yet, the RequiredModelMBean's MBeanInfo and
  179        * Descriptors can be customized using the {@link #setModelMBeanInfo}
  180        * method.
  181        * After the RequiredModelMBean's MBeanInfo and Descriptors are
  182        * customized, the RequiredModelMBean can be registered with the
  183        * MBeanServer.
  184        *
  185        * @param mbi The ModelMBeanInfo object to be used by the
  186        *            RequiredModelMBean. The given ModelMBeanInfo is cloned
  187        *            and modified as specified by {@link #setModelMBeanInfo}
  188        *
  189        * @exception MBeanException Wraps a distributed communication Exception.
  190        * @exception RuntimeOperationsException Wraps an
  191        *    {link java.lang.IllegalArgumentException}:
  192        *          The MBeanInfo passed in parameter is null.
  193        *
  194        **/
  195       public RequiredModelMBean(ModelMBeanInfo mbi)
  196           throws MBeanException, RuntimeOperationsException {
  197   
  198           if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
  199               MODELMBEAN_LOGGER.logp(Level.FINER,
  200                       RequiredModelMBean.class.getName(),
  201                       "RequiredModelMBean(MBeanInfo)", "Entry");
  202           }
  203           setModelMBeanInfo(mbi);
  204   
  205           if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
  206               MODELMBEAN_LOGGER.logp(Level.FINER,
  207                       RequiredModelMBean.class.getName(),
  208                       "RequiredModelMBean(MBeanInfo)", "Exit");
  209           }
  210       }
  211   
  212   
  213       /*************************************/
  214       /* initializers                      */
  215       /*************************************/
  216   
  217       /**
  218        * Initializes a ModelMBean object using ModelMBeanInfo passed in.
  219        * This method makes it possible to set a customized ModelMBeanInfo on
  220        * the ModelMBean as long as it is not registered with the MBeanServer.
  221        * <br>
  222        * Once the ModelMBean's ModelMBeanInfo (with Descriptors) are
  223        * customized and set on the ModelMBean, the  ModelMBean be
  224        * registered with the MBeanServer.
  225        * <P>
  226        * If the ModelMBean is currently registered, this method throws
  227        * a {@link javax.management.RuntimeOperationsException} wrapping an
  228        * {@link IllegalStateException}
  229        * <P>
  230        * If the given <var>inModelMBeanInfo</var> does not contain any
  231        * {@link ModelMBeanNotificationInfo} for the <code>GENERIC</code>
  232        * or <code>ATTRIBUTE_CHANGE</code> notifications, then the
  233        * RequiredModelMBean will supply its own default
  234        * {@link ModelMBeanNotificationInfo ModelMBeanNotificationInfo}s for
  235        * those missing notifications.
  236        *
  237        * @param mbi The ModelMBeanInfo object to be used
  238        *        by the ModelMBean.
  239        *
  240        * @exception MBeanException Wraps a distributed communication
  241        *        Exception.
  242        * @exception RuntimeOperationsException
  243        * <ul><li>Wraps an {@link IllegalArgumentException} if
  244        *         the MBeanInfo passed in parameter is null.</li>
  245        *     <li>Wraps an {@link IllegalStateException} if the ModelMBean
  246        *         is currently registered in the MBeanServer.</li>
  247        * </ul>
  248        *
  249        **/
  250       public void setModelMBeanInfo(ModelMBeanInfo mbi)
  251           throws MBeanException, RuntimeOperationsException {
  252   
  253           if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
  254               MODELMBEAN_LOGGER.logp(Level.FINER,
  255                       RequiredModelMBean.class.getName(),
  256                   "setModelMBeanInfo(ModelMBeanInfo)","Entry");
  257           }
  258   
  259           if (mbi == null) {
  260               if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
  261                   MODELMBEAN_LOGGER.logp(Level.FINER,
  262                           RequiredModelMBean.class.getName(),
  263                       "setModelMBeanInfo(ModelMBeanInfo)",
  264                       "ModelMBeanInfo is null: Raising exception.");
  265               }
  266               final RuntimeException x = new
  267                   IllegalArgumentException("ModelMBeanInfo must not be null");
  268               final String exceptionText =
  269                   "Exception occurred trying to initialize the " +
  270                   "ModelMBeanInfo of the RequiredModelMBean";
  271               throw new RuntimeOperationsException(x,exceptionText);
  272           }
  273   
  274           if (registered) {
  275               if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
  276                   MODELMBEAN_LOGGER.logp(Level.FINER,
  277                           RequiredModelMBean.class.getName(),
  278                       "setModelMBeanInfo(ModelMBeanInfo)",
  279                       "RequiredMBean is registered: Raising exception.");
  280               }
  281               final String exceptionText =
  282                   "Exception occurred trying to set the " +
  283                   "ModelMBeanInfo of the RequiredModelMBean";
  284               final RuntimeException x = new IllegalStateException(
  285                "cannot call setModelMBeanInfo while ModelMBean is registered");
  286               throw new RuntimeOperationsException(x,exceptionText);
  287           }
  288   
  289           if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
  290               MODELMBEAN_LOGGER.logp(Level.FINER,
  291                       RequiredModelMBean.class.getName(),
  292                   "setModelMBeanInfo(ModelMBeanInfo)",
  293                   "Setting ModelMBeanInfo to " + printModelMBeanInfo(mbi));
  294               MODELMBEAN_LOGGER.logp(Level.FINER,
  295                       RequiredModelMBean.class.getName(),
  296                   "setModelMBeanInfo(ModelMBeanInfo)",
  297                   "ModelMBeanInfo notifications has " +
  298                   (mbi.getNotifications()).length + " elements");
  299           }
  300   
  301           modelMBeanInfo = (ModelMBeanInfo)mbi.clone();
  302   
  303           if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
  304               MODELMBEAN_LOGGER.logp(Level.FINER,
  305                       RequiredModelMBean.class.getName(),
  306                   "setModelMBeanInfo(ModelMBeanInfo)","set mbeanInfo to: "+
  307                    printModelMBeanInfo(modelMBeanInfo));
  308               MODELMBEAN_LOGGER.logp(Level.FINER,
  309                       RequiredModelMBean.class.getName(),
  310                   "setModelMBeanInfo(ModelMBeanInfo)","Exit");
  311           }
  312       }
  313   
  314   
  315       /**
  316        * Sets the instance handle of the object against which to
  317        * execute all methods in this ModelMBean management interface
  318        * (MBeanInfo and Descriptors).
  319        *
  320        * @param mr Object that is the managed resource
  321        * @param mr_type The type of reference for the managed resource.
  322        *     <br>Can be: "ObjectReference", "Handle", "IOR", "EJBHandle",
  323        *         or "RMIReference".
  324        *     <br>In this implementation only "ObjectReference" is supported.
  325        *
  326        * @exception MBeanException The initializer of the object has
  327        *            thrown an exception.
  328        * @exception InstanceNotFoundException The managed resource
  329        *            object could not be found
  330        * @exception InvalidTargetObjectTypeException The managed
  331        *            resource type should be "ObjectReference".
  332        * @exception RuntimeOperationsException Wraps a {@link
  333        *            RuntimeException} when setting the resource.
  334        **/
  335       public void setManagedResource(Object mr, String mr_type)
  336           throws MBeanException, RuntimeOperationsException,
  337                  InstanceNotFoundException, InvalidTargetObjectTypeException {
  338           if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
  339               MODELMBEAN_LOGGER.logp(Level.FINER,
  340                       RequiredModelMBean.class.getName(),
  341                   "setManagedResource(Object,String)","Entry");
  342           }
  343   
  344           // check that the mr_type is supported by this JMXAgent
  345           // only "objectReference" is supported
  346           if ((mr_type == null) ||
  347               (! mr_type.equalsIgnoreCase("objectReference"))) {
  348               if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
  349                   MODELMBEAN_LOGGER.logp(Level.FINER,
  350                           RequiredModelMBean.class.getName(),
  351                       "setManagedResource(Object,String)",
  352                       "Managed Resouce Type is not supported: " + mr_type);
  353               }
  354               throw new InvalidTargetObjectTypeException(mr_type);
  355           }
  356   
  357           if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
  358               MODELMBEAN_LOGGER.logp(Level.FINER,
  359                       RequiredModelMBean.class.getName(),
  360                   "setManagedResource(Object,String)",
  361                   "Managed Resouce is valid");
  362           }
  363           managedResource = mr;
  364   
  365           if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
  366               MODELMBEAN_LOGGER.logp(Level.FINER,
  367                       RequiredModelMBean.class.getName(),
  368                   "setManagedResource(Object, String)", "Exit");
  369           }
  370       }
  371   
  372       /**
  373        * <p>Instantiates this MBean instance with the data found for
  374        * the MBean in the persistent store.  The data loaded could include
  375        * attribute and operation values.</p>
  376        *
  377        * <p>This method should be called during construction or
  378        * initialization of this instance, and before the MBean is
  379        * registered with the MBeanServer.</p>
  380        *
  381        * <p>If the implementation of this class does not support
  382        * persistence, an {@link MBeanException} wrapping a {@link
  383        * ServiceNotFoundException} is thrown.</p>
  384        *
  385        * @exception MBeanException Wraps another exception, or
  386        * persistence is not supported
  387        * @exception RuntimeOperationsException Wraps exceptions from the
  388        * persistence mechanism
  389        * @exception InstanceNotFoundException Could not find or load
  390        * this MBean from persistent storage
  391        */
  392       public void load()
  393           throws MBeanException, RuntimeOperationsException,
  394                  InstanceNotFoundException {
  395           final ServiceNotFoundException x = new ServiceNotFoundException(
  396                                   "Persistence not supported for this MBean");
  397           throw new MBeanException(x, x.getMessage());
  398       }
  399   
  400           /**
  401        * <p>Captures the current state of this MBean instance and writes
  402        * it out to the persistent store.  The state stored could include
  403        * attribute and operation values.</p>
  404        *
  405        * <p>If the implementation of this class does not support
  406        * persistence, an {@link MBeanException} wrapping a {@link
  407        * ServiceNotFoundException} is thrown.</p>
  408        *
  409        * <p>Persistence policy from the MBean and attribute descriptor
  410        * is used to guide execution of this method. The MBean should be
  411        * stored if 'persistPolicy' field is:</p>
  412        *
  413        * <PRE>  != "never"
  414        *   = "always"
  415        *   = "onTimer" and now > 'lastPersistTime' + 'persistPeriod'
  416        *   = "NoMoreOftenThan" and now > 'lastPersistTime' + 'persistPeriod'
  417        *   = "onUnregister"
  418        * </PRE>
  419        *
  420        * <p>Do not store the MBean if 'persistPolicy' field is:</p>
  421        * <PRE>
  422        *    = "never"
  423        *    = "onUpdate"
  424        *    = "onTimer" && now < 'lastPersistTime' + 'persistPeriod'
  425        * </PRE>
  426        *
  427        * @exception MBeanException Wraps another exception, or
  428        * persistence is not supported
  429        * @exception RuntimeOperationsException Wraps exceptions from the
  430        * persistence mechanism
  431        * @exception InstanceNotFoundException Could not find/access the
  432        * persistent store
  433        */
  434       public void store()
  435           throws MBeanException, RuntimeOperationsException,
  436                  InstanceNotFoundException {
  437           final ServiceNotFoundException x = new ServiceNotFoundException(
  438                                   "Persistence not supported for this MBean");
  439           throw new MBeanException(x, x.getMessage());
  440       }
  441   
  442       /*************************************/
  443       /* DynamicMBean Interface            */
  444       /*************************************/
  445   
  446       /**
  447        * The resolveForCacheValue method checks the descriptor passed in to
  448        * see if there is a valid cached value in the descriptor.
  449        * The valid value will be in the 'value' field if there is one.
  450        * If the 'currencyTimeLimit' field in the descriptor is:
  451        * <ul>
  452        *   <li><b>&lt;0</b> Then the value is not cached and is never valid.
  453        *         Null is returned. The 'value' and 'lastUpdatedTimeStamp'
  454        *         fields are cleared.</li>
  455        *   <li><b>=0</b> Then the value is always cached and always valid.
  456        *         The 'value' field is returned.
  457        *         The 'lastUpdatedTimeStamp' field is not checked.</li>
  458        *   <li><b>&gt;0</b> Represents the number of seconds that the
  459        *         'value' field is valid.
  460        *         The 'value' field is no longer valid when
  461        *         'lastUpdatedTimeStamp' + 'currencyTimeLimit' &gt; Now.</li>
  462        * </ul>
  463        * <li>When 'value' is valid, 'valid' is returned.</li>
  464        * <li>When 'value' is no longer valid then null is returned and
  465        *     'value' and 'lastUpdatedTimeStamp' fields are cleared.</li>
  466        *
  467        **/
  468       private Object resolveForCacheValue(Descriptor descr)
  469           throws MBeanException, RuntimeOperationsException {
  470   
  471           final boolean tracing = MODELMBEAN_LOGGER.isLoggable(Level.FINER);
  472           final String mth = "resolveForCacheValue(Descriptor)";
  473           if (tracing) {
  474               MODELMBEAN_LOGGER.logp(Level.FINER,
  475                       RequiredModelMBean.class.getName(),mth,"Entry");
  476           }
  477   
  478           Object response = null;
  479           boolean resetValue = false, returnCachedValue = true;
  480           long currencyPeriod = 0;
  481   
  482           if (descr == null) {
  483               if (tracing) {
  484                   MODELMBEAN_LOGGER.logp(Level.FINER,
  485                           RequiredModelMBean.class.getName(),mth,
  486                       "Input Descriptor is null");
  487               }
  488               return response;
  489           }
  490   
  491           if (tracing) {
  492               MODELMBEAN_LOGGER.logp(Level.FINER,
  493                       RequiredModelMBean.class.getName(),
  494                       mth, "descriptor is " + descr);
  495           }
  496   
  497           final Descriptor mmbDescr = modelMBeanInfo.getMBeanDescriptor();
  498           if (mmbDescr == null) {
  499               if (tracing) {
  500                   MODELMBEAN_LOGGER.logp(Level.FINER,
  501                       RequiredModelMBean.class.getName(),
  502                           mth,"MBean Descriptor is null");
  503               }
  504               //return response;
  505           }
  506   
  507           Object objExpTime = descr.getFieldValue("currencyTimeLimit");
  508   
  509           String expTime;
  510           if (objExpTime != null) {
  511               expTime = objExpTime.toString();
  512           } else {
  513               expTime = null;
  514           }
  515   
  516           if ((expTime == null) && (mmbDescr != null)) {
  517               objExpTime = mmbDescr.getFieldValue("currencyTimeLimit");
  518               if (objExpTime != null) {
  519                   expTime = objExpTime.toString();
  520               } else {
  521                   expTime = null;
  522               }
  523           }
  524   
  525           if (expTime != null) {
  526               if (tracing) {
  527                   MODELMBEAN_LOGGER.logp(Level.FINER,
  528                       RequiredModelMBean.class.getName(),
  529                           mth,"currencyTimeLimit: " + expTime);
  530               }
  531   
  532               // convert seconds to milliseconds for time comparison
  533               currencyPeriod = ((new Long(expTime)).longValue()) * 1000;
  534               if (currencyPeriod < 0) {
  535                   /* if currencyTimeLimit is -1 then value is never cached */
  536                   returnCachedValue = false;
  537                   resetValue = true;
  538                   if (tracing) {
  539                       MODELMBEAN_LOGGER.logp(Level.FINER,
  540                               RequiredModelMBean.class.getName(),mth,
  541                           currencyPeriod + ": never Cached");
  542                   }
  543               } else if (currencyPeriod == 0) {
  544                   /* if currencyTimeLimit is 0 then value is always cached */
  545                   returnCachedValue = true;
  546                   resetValue = false;
  547                   if (tracing) {
  548                       MODELMBEAN_LOGGER.logp(Level.FINER,
  549                               RequiredModelMBean.class.getName(),mth,
  550                           "always valid Cache");
  551                   }
  552               } else {
  553                   Object objtStamp =
  554                       descr.getFieldValue("lastUpdatedTimeStamp");
  555   
  556                   String tStamp;
  557                   if (objtStamp != null) tStamp = objtStamp.toString();
  558                   else tStamp = null;
  559   
  560                   if (tracing) {
  561                       MODELMBEAN_LOGGER.logp(Level.FINER,
  562                               RequiredModelMBean.class.getName(),mth,
  563                           "lastUpdatedTimeStamp: " + tStamp);
  564                   }
  565   
  566                   if (tStamp == null)
  567                       tStamp = "0";
  568   
  569                   long lastTime = (new Long(tStamp)).longValue();
  570   
  571                   if (tracing) {
  572                       MODELMBEAN_LOGGER.logp(Level.FINER,
  573                               RequiredModelMBean.class.getName(),mth,
  574                           "currencyPeriod:" + currencyPeriod +
  575                           " lastUpdatedTimeStamp:" + lastTime);
  576                   }
  577   
  578                   long now = (new Date()).getTime();
  579   
  580                   if (now < (lastTime + currencyPeriod)) {
  581                       returnCachedValue = true;
  582                       resetValue = false;
  583                       if (tracing) {
  584                           MODELMBEAN_LOGGER.logp(Level.FINER,
  585                                   RequiredModelMBean.class.getName(),mth,
  586                               " timed valid Cache for " + now + " < " +
  587                               (lastTime + currencyPeriod));
  588                       }
  589                   } else { /* value is expired */
  590                       returnCachedValue = false;
  591                       resetValue = true;
  592                       if (tracing) {
  593                           MODELMBEAN_LOGGER.logp(Level.FINER,
  594                                   RequiredModelMBean.class.getName(),mth,
  595                               "timed expired cache for " + now + " > " +
  596                               (lastTime + currencyPeriod));
  597                       }
  598                   }
  599               }
  600               if (tracing) {
  601                   MODELMBEAN_LOGGER.logp(Level.FINER,
  602                           RequiredModelMBean.class.getName(),mth,
  603                       "returnCachedValue:" + returnCachedValue +
  604                       " resetValue: " + resetValue);
  605               }
  606   
  607               if (returnCachedValue == true) {
  608                   Object currValue = descr.getFieldValue("value");
  609                   if (currValue != null) {
  610                       /* error/validity check return value here */
  611                       response = currValue;
  612                       /* need to cast string cached value to type */
  613                       if (tracing) {
  614                           MODELMBEAN_LOGGER.logp(Level.FINER,
  615                                   RequiredModelMBean.class.getName(),mth,
  616                               "valid Cache value: " + currValue);
  617                       }
  618   
  619                   } else {
  620                       response = null;
  621                       if (tracing) {
  622                           MODELMBEAN_LOGGER.logp(Level.FINER,
  623                               RequiredModelMBean.class.getName(),
  624                                   mth,"no Cached value");
  625                       }
  626                   }
  627               }
  628   
  629               if (resetValue == true) {
  630                   /* value is not current, so remove it */
  631                   descr.removeField("lastUpdatedTimeStamp");
  632                   descr.removeField("value");
  633                   response = null;
  634                   modelMBeanInfo.setDescriptor(descr,null);
  635                   if (tracing) {
  636                       MODELMBEAN_LOGGER.logp(Level.FINER,
  637                           RequiredModelMBean.class.getName(),
  638                               mth,"reset cached value to null");
  639                   }
  640               }
  641           }
  642   
  643           if (tracing) {
  644               MODELMBEAN_LOGGER.logp(Level.FINER,
  645                       RequiredModelMBean.class.getName(),mth,"Exit");
  646           }
  647   
  648           return response;
  649       }
  650   
  651       /**
  652        * Returns the attributes, operations, constructors and notifications
  653        * that this RequiredModelMBean exposes for management.
  654        *
  655        * @return  An instance of ModelMBeanInfo allowing retrieval all
  656        *          attributes, operations, and Notifications of this MBean.
  657        *
  658        **/
  659       public MBeanInfo getMBeanInfo() {
  660   
  661           if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
  662               MODELMBEAN_LOGGER.logp(Level.FINER,
  663                       RequiredModelMBean.class.getName(),
  664                       "getMBeanInfo()","Entry");
  665           }
  666   
  667           if (modelMBeanInfo == null) {
  668               if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
  669                   MODELMBEAN_LOGGER.logp(Level.FINER,
  670                           RequiredModelMBean.class.getName(),
  671                       "getMBeanInfo()","modelMBeanInfo is null");
  672               }
  673               modelMBeanInfo = createDefaultModelMBeanInfo();
  674               //return new ModelMBeanInfo(" ", "", null, null, null, null);
  675           }
  676   
  677           if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
  678               MODELMBEAN_LOGGER.logp(Level.FINER,
  679                       RequiredModelMBean.class.getName(),
  680                   "getMBeanInfo()","ModelMBeanInfo is " +
  681                     modelMBeanInfo.getClassName() + " for " +
  682                     modelMBeanInfo.getDescription());
  683               MODELMBEAN_LOGGER.logp(Level.FINER,
  684                       RequiredModelMBean.class.getName(),
  685                   "getMBeanInfo()",printModelMBeanInfo(modelMBeanInfo));
  686           }
  687   
  688           return((MBeanInfo) modelMBeanInfo.clone());
  689       }
  690   
  691       private String printModelMBeanInfo(ModelMBeanInfo info) {
  692           final StringBuilder retStr = new StringBuilder();
  693           if (info == null) {
  694               if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
  695                   MODELMBEAN_LOGGER.logp(Level.FINER,
  696                           RequiredModelMBean.class.getName(),
  697                           "printModelMBeanInfo(ModelMBeanInfo)",
  698                           "ModelMBeanInfo to print is null, " +
  699                           "printing local ModelMBeanInfo");
  700               }
  701               info = modelMBeanInfo;
  702           }
  703   
  704           retStr.append("\nMBeanInfo for ModelMBean is:");
  705           retStr.append("\nCLASSNAME: \t"+ info.getClassName());
  706           retStr.append("\nDESCRIPTION: \t"+ info.getDescription());
  707   
  708   
  709           try {
  710               retStr.append("\nMBEAN DESCRIPTOR: \t"+
  711                             info.getMBeanDescriptor());
  712           } catch (Exception e) {
  713               retStr.append("\nMBEAN DESCRIPTOR: \t" + " is invalid");
  714           }
  715   
  716           retStr.append("\nATTRIBUTES");
  717   
  718           final MBeanAttributeInfo[] attrInfo = info.getAttributes();
  719           if ((attrInfo != null) && (attrInfo.length>0)) {
  720               for (int i=0; i<attrInfo.length; i++) {
  721                   final ModelMBeanAttributeInfo attInfo =
  722                       (ModelMBeanAttributeInfo)attrInfo[i];
  723                   retStr.append(" ** NAME: \t"+ attInfo.getName());
  724                   retStr.append("    DESCR: \t"+ attInfo.getDescription());
  725                   retStr.append("    TYPE: \t"+ attInfo.getType() +
  726                                 "    READ: \t"+ attInfo.isReadable() +
  727                                 "    WRITE: \t"+ attInfo.isWritable());
  728                   retStr.append("    DESCRIPTOR: " +
  729                                 attInfo.getDescriptor().toString());
  730               }
  731           } else {
  732               retStr.append(" ** No attributes **");
  733           }
  734   
  735           retStr.append("\nCONSTRUCTORS");
  736           final MBeanConstructorInfo[] constrInfo = info.getConstructors();
  737           if ((constrInfo != null) && (constrInfo.length > 0 )) {
  738               for (int i=0; i<constrInfo.length; i++) {
  739                   final ModelMBeanConstructorInfo ctorInfo =
  740                       (ModelMBeanConstructorInfo)constrInfo[i];
  741                   retStr.append(" ** NAME: \t"+ ctorInfo.getName());
  742                   retStr.append("    DESCR: \t"+
  743                                 ctorInfo.getDescription());
  744                   retStr.append("    PARAM: \t"+
  745                                 ctorInfo.getSignature().length +
  746                                 " parameter(s)");
  747                   retStr.append("    DESCRIPTOR: " +
  748                                 ctorInfo.getDescriptor().toString());
  749               }
  750           } else {
  751               retStr.append(" ** No Constructors **");
  752           }
  753   
  754           retStr.append("\nOPERATIONS");
  755           final MBeanOperationInfo[] opsInfo = info.getOperations();
  756           if ((opsInfo != null) && (opsInfo.length>0)) {
  757               for (int i=0; i<opsInfo.length; i++) {
  758                   final ModelMBeanOperationInfo operInfo =
  759                       (ModelMBeanOperationInfo)opsInfo[i];
  760                   retStr.append(" ** NAME: \t"+ operInfo.getName());
  761                   retStr.append("    DESCR: \t"+ operInfo.getDescription());
  762                   retStr.append("    PARAM: \t"+
  763                                 operInfo.getSignature().length +
  764                                 " parameter(s)");
  765                   retStr.append("    DESCRIPTOR: " +
  766                                 operInfo.getDescriptor().toString());
  767               }
  768           } else {
  769               retStr.append(" ** No operations ** ");
  770           }
  771   
  772           retStr.append("\nNOTIFICATIONS");
  773   
  774           MBeanNotificationInfo[] notifInfo = info.getNotifications();
  775           if ((notifInfo != null) && (notifInfo.length>0)) {
  776               for (int i=0; i<notifInfo.length; i++) {
  777                   final ModelMBeanNotificationInfo nInfo =
  778                       (ModelMBeanNotificationInfo)notifInfo[i];
  779                   retStr.append(" ** NAME: \t"+ nInfo.getName());
  780                   retStr.append("    DESCR: \t"+ nInfo.getDescription());
  781                   retStr.append("    DESCRIPTOR: " +
  782                                 nInfo.getDescriptor().toString());
  783               }
  784           } else {
  785               retStr.append(" ** No notifications **");
  786           }
  787   
  788           retStr.append(" ** ModelMBean: End of MBeanInfo ** ");
  789   
  790           return retStr.toString();
  791       }
  792   
  793       /**
  794        * Invokes a method on or through a RequiredModelMBean and returns
  795        * the result of the method execution.
  796        * <P>
  797        * If the given method to be invoked, together with the provided
  798        * signature, matches one of RequiredModelMbean
  799        * accessible methods, this one will be call. Otherwise the call to
  800        * the given method will be tried on the managed resource.
  801        * <P>
  802        * The last value returned by an operation may be cached in
  803        * the operation's descriptor which
  804        * is in the ModelMBeanOperationInfo's descriptor.
  805        * The valid value will be in the 'value' field if there is one.
  806        * If the 'currencyTimeLimit' field in the descriptor is:
  807        * <UL>
  808        * <LI><b>&lt;0</b> Then the value is not cached and is never valid.
  809        *      The operation method is invoked.
  810        *      The 'value' and 'lastUpdatedTimeStamp' fields are cleared.</LI>
  811        * <LI><b>=0</b> Then the value is always cached and always valid.
  812        *      The 'value' field is returned. If there is no 'value' field
  813        *      then the operation method is invoked for the attribute.
  814        *      The 'lastUpdatedTimeStamp' field and `value' fields are set to
  815        *      the operation's return value and the current time stamp.</LI>
  816        * <LI><b>&gt;0</b> Represents the number of seconds that the 'value'
  817        *      field is valid.
  818        *      The 'value' field is no longer valid when
  819        *      'lastUpdatedTimeStamp' + 'currencyTimeLimit' &gt; Now.
  820        *      <UL>
  821        *         <LI>When 'value' is valid, 'value' is returned.</LI>
  822        *         <LI>When 'value' is no longer valid then the operation
  823        *             method is invoked. The 'lastUpdatedTimeStamp' field
  824        *             and `value' fields are updated.</lI>
  825        *      </UL>
  826        * </LI>
  827        * </UL>
  828        *
  829        * <p><b>Note:</b> because of inconsistencies in previous versions of
  830        * this specification, it is recommended not to use negative or zero
  831        * values for <code>currencyTimeLimit</code>.  To indicate that a
  832        * cached value is never valid, omit the
  833        * <code>currencyTimeLimit</code> field.  To indicate that it is
  834        * always valid, use a very large number for this field.</p>
  835        *
  836        * @param opName The name of the method to be invoked. The
  837        *     name can be the fully qualified method name including the
  838        *     classname, or just the method name if the classname is
  839        *     defined in the 'class' field of the operation descriptor.
  840        * @param opArgs An array containing the parameters to be set
  841        *     when the operation is invoked
  842        * @param sig An array containing the signature of the
  843        *     operation. The class objects will be loaded using the same
  844        *     class loader as the one used for loading the MBean on which
  845        *     the operation was invoked.
  846        *
  847        * @return  The object returned by the method, which represents the
  848        *     result of invoking the method on the specified managed resource.
  849        *
  850        * @exception MBeanException  Wraps one of the following Exceptions:
  851        * <UL>
  852        * <LI> An Exception thrown by the managed object's invoked method.</LI>
  853        * <LI> {@link ServiceNotFoundException}: No ModelMBeanOperationInfo or
  854        *      no descriptor defined for the specified operation or the managed
  855        *      resource is null.</LI>
  856        * <LI> {@link InvalidTargetObjectTypeException}: The 'targetType'
  857        *      field value is not 'objectReference'.</LI>
  858        * </UL>
  859        * @exception ReflectionException  Wraps an {@link java.lang.Exception}
  860        *      thrown while trying to invoke the method.
  861        * @exception RuntimeOperationsException Wraps an
  862        *      {@link IllegalArgumentException} Method name is null.
  863        *
  864        **/
  865       /*
  866         The requirement to be able to invoke methods on the
  867         RequiredModelMBean class itself makes this method considerably
  868         more complicated than it might otherwise be.  Note that, unlike
  869         earlier versions, we do not allow you to invoke such methods if
  870         they are not explicitly mentioned in the ModelMBeanInfo.  Doing
  871         so was potentially a security problem, and certainly very
  872         surprising.
  873   
  874         We do not look for the method in the RequiredModelMBean class
  875         itself if:
  876         (a) there is a "targetObject" field in the Descriptor for the
  877         operation; or
  878         (b) there is a "class" field in the Descriptor for the operation
  879         and the named class is not RequiredModelMBean or one of its
  880         superinterfaces; or
  881         (c) the name of the operation is not the name of a method in
  882         RequiredModelMBean (this is just an optimization).
  883   
  884         In cases (a) and (b), if you have gone to the trouble of adding
  885         those fields specifically for this operation then presumably you
  886         do not want RequiredModelMBean's methods to be called.
  887   
  888         We have to pay attention to class loading issues.  If the
  889         "class" field is present, the named class has to be resolved
  890         relative to RequiredModelMBean's class loader to test the
  891         condition (b) above, and relative to the managed resource's
  892         class loader to ensure that the managed resource is in fact of
  893         the named class (or a subclass).  The class names in the sig
  894         array likewise have to be resolved, first against
  895         RequiredModelMBean's class loader, then against the managed
  896         resource's class loader.  There is no point in using any other
  897         loader because when we call Method.invoke we must call it on
  898         a Method that is implemented by the target object.
  899        */
  900       public Object invoke(String opName, Object[] opArgs, String[] sig)
  901               throws MBeanException, ReflectionException {
  902   
  903           final boolean tracing = MODELMBEAN_LOGGER.isLoggable(Level.FINER);
  904           final String mth = "invoke(String, Object[], String[])";
  905   
  906           if (tracing) {
  907               MODELMBEAN_LOGGER.logp(Level.FINER,
  908                       RequiredModelMBean.class.getName(), mth, "Entry");
  909           }
  910   
  911           if (opName == null) {
  912               final RuntimeException x =
  913                   new IllegalArgumentException("Method name must not be null");
  914               throw new RuntimeOperationsException(x,
  915                         "An exception occurred while trying to " +
  916                         "invoke a method on a RequiredModelMBean");
  917           }
  918   
  919           String opClassName = null;
  920           String opMethodName;
  921   
  922           // Parse for class name and method
  923           int opSplitter = opName.lastIndexOf(".");
  924           if (opSplitter > 0) {
  925               opClassName = opName.substring(0,opSplitter);
  926               opMethodName = opName.substring(opSplitter+1);
  927           } else
  928               opMethodName = opName;
  929   
  930           /* Ignore anything after a left paren.  We keep this for
  931              compatibility but it isn't specified.  */
  932           opSplitter = opMethodName.indexOf("(");
  933           if (opSplitter > 0)
  934               opMethodName = opMethodName.substring(0,opSplitter);
  935   
  936           if (tracing) {
  937               MODELMBEAN_LOGGER.logp(Level.FINER,
  938                       RequiredModelMBean.class.getName(),
  939                       mth, "Finding operation " + opName + " as " + opMethodName);
  940           }
  941   
  942           ModelMBeanOperationInfo opInfo =
  943               modelMBeanInfo.getOperation(opMethodName);
  944           if (opInfo == null) {
  945               final String msg =
  946                   "Operation " + opName + " not in ModelMBeanInfo";
  947               throw new MBeanException(new ServiceNotFoundException(msg), msg);
  948           }
  949   
  950           final Descriptor opDescr = opInfo.getDescriptor();
  951           if (opDescr == null) {
  952               final String msg = "Operation descriptor null";
  953               throw new MBeanException(new ServiceNotFoundException(msg), msg);
  954           }
  955   
  956           final Object cached = resolveForCacheValue(opDescr);
  957           if (cached != null) {
  958               if (tracing) {
  959                   MODELMBEAN_LOGGER.logp(Level.FINER,
  960                           RequiredModelMBean.class.getName(),
  961                           mth,
  962                           "Returning cached value");
  963               }
  964               return cached;
  965           }
  966   
  967           if (opClassName == null)
  968               opClassName = (String) opDescr.getFieldValue("class");
  969           // may still be null now
  970   
  971           opMethodName = (String) opDescr.getFieldValue("name");
  972           if (opMethodName == null) {
  973               final String msg =
  974                   "Method descriptor must include `name' field";
  975               throw new MBeanException(new ServiceNotFoundException(msg), msg);
  976           }
  977   
  978           final String targetTypeField = (String)
  979               opDescr.getFieldValue("targetType");
  980           if (targetTypeField != null
  981               && !targetTypeField.equalsIgnoreCase("objectReference")) {
  982               final String msg =
  983                   "Target type must be objectReference: " + targetTypeField;
  984               throw new MBeanException(new InvalidTargetObjectTypeException(msg),
  985                                        msg);
  986           }
  987   
  988           final Object targetObjectField = opDescr.getFieldValue("targetObject");
  989           if (tracing && targetObjectField != null)
  990                   MODELMBEAN_LOGGER.logp(Level.FINER,
  991                       RequiredModelMBean.class.getName(),
  992                           mth, "Found target object in descriptor");
  993   
  994           /* Now look for the method, either in RequiredModelMBean itself
  995              or in the target object.  Set "method" and "targetObject"
  996              appropriately.  */
  997           Method method;
  998           Object targetObject;
  999   
 1000           method = findRMMBMethod(opMethodName, targetObjectField,
 1001                                   opClassName, sig);
 1002   
 1003           if (method != null)
 1004               targetObject = this;
 1005           else {
 1006               if (tracing) {
 1007                   MODELMBEAN_LOGGER.logp(Level.FINER,
 1008                       RequiredModelMBean.class.getName(),
 1009                           mth, "looking for method in managedResource class");
 1010               }
 1011               if (targetObjectField != null)
 1012                   targetObject = targetObjectField;
 1013               else {
 1014                   targetObject = managedResource;
 1015                   if (targetObject == null) {
 1016                       final String msg =
 1017                           "managedResource for invoke " + opName +
 1018                           " is null";
 1019                       Exception snfe = new ServiceNotFoundException(msg);
 1020                       throw new MBeanException(snfe);
 1021                   }
 1022               }
 1023   
 1024               final Class<?> targetClass;
 1025   
 1026               if (opClassName != null) {
 1027                   try {
 1028                       final ClassLoader targetClassLoader =
 1029                           targetObject.getClass().getClassLoader();
 1030                       targetClass = Class.forName(opClassName, false,
 1031                                                   targetClassLoader);
 1032                   } catch (ClassNotFoundException e) {
 1033                       final String msg =
 1034                           "class for invoke " + opName + " not found";
 1035                       throw new ReflectionException(e, msg);
 1036                   }
 1037               } else
 1038                   targetClass = targetObject.getClass();
 1039   
 1040               method = resolveMethod(targetClass, opMethodName, sig);
 1041           }
 1042   
 1043           if (tracing) {
 1044               MODELMBEAN_LOGGER.logp(Level.FINER,
 1045                   RequiredModelMBean.class.getName(),
 1046                       mth, "found " + opMethodName + ", now invoking");
 1047           }
 1048   
 1049           final Object result =
 1050               invokeMethod(opName, method, targetObject, opArgs);
 1051   
 1052           if (tracing) {
 1053               MODELMBEAN_LOGGER.logp(Level.FINER,
 1054                   RequiredModelMBean.class.getName(),
 1055                       mth, "successfully invoked method");
 1056           }
 1057   
 1058           if (result != null)
 1059               cacheResult(opInfo, opDescr, result);
 1060   
 1061           return result;
 1062       }
 1063   
 1064       private static Method resolveMethod(Class<?> targetClass,
 1065                                           String opMethodName,
 1066                                           String[] sig)
 1067               throws ReflectionException {
 1068           final boolean tracing = MODELMBEAN_LOGGER.isLoggable(Level.FINER);
 1069   
 1070           if (tracing) {
 1071               MODELMBEAN_LOGGER.logp(Level.FINER,
 1072                   RequiredModelMBean.class.getName(),"resolveMethod",
 1073                     "resolving " + targetClass.getName() + "." + opMethodName);
 1074           }
 1075   
 1076           final Class<?>[] argClasses;
 1077   
 1078           if (sig == null)
 1079               argClasses = null;
 1080           else {
 1081               final ClassLoader targetClassLoader = targetClass.getClassLoader();
 1082               argClasses = new Class<?>[sig.length];
 1083               for (int i = 0; i < sig.length; i++) {
 1084                   if (tracing) {
 1085                       MODELMBEAN_LOGGER.logp(Level.FINER,
 1086                           RequiredModelMBean.class.getName(),"resolveMethod",
 1087                               "resolve type " + sig[i]);
 1088                   }
 1089                   argClasses[i] = (Class<?>) primitiveClassMap.get(sig[i]);
 1090                   if (argClasses[i] == null) {
 1091                       try {
 1092                           argClasses[i] =
 1093                               Class.forName(sig[i], false, targetClassLoader);
 1094                       } catch (ClassNotFoundException e) {
 1095                           if (tracing) {
 1096                               MODELMBEAN_LOGGER.logp(Level.FINER,
 1097                                       RequiredModelMBean.class.getName(),
 1098                                       "resolveMethod",
 1099                                       "class not found");
 1100                           }
 1101                           final String msg = "Parameter class not found";
 1102                           throw new ReflectionException(e, msg);
 1103                       }
 1104                   }
 1105               }
 1106           }
 1107   
 1108           try {
 1109               return targetClass.getMethod(opMethodName, argClasses);
 1110           } catch (NoSuchMethodException e) {
 1111               final String msg =
 1112                   "Target method not found: " + targetClass.getName() + "." +
 1113                   opMethodName;
 1114               throw new ReflectionException(e, msg);
 1115           }
 1116       }
 1117   
 1118       /* Map e.g. "int" to int.class.  Goodness knows how many time this
 1119          particular wheel has been reinvented.  */
 1120       private static final Class<?>[] primitiveClasses = {
 1121           int.class, long.class, boolean.class, double.class,
 1122           float.class, short.class, byte.class, char.class,
 1123       };
 1124       private static final Map<String,Class<?>> primitiveClassMap =
 1125           new HashMap<String,Class<?>>();
 1126       static {
 1127           for (int i = 0; i < primitiveClasses.length; i++) {
 1128               final Class<?> c = primitiveClasses[i];
 1129               primitiveClassMap.put(c.getName(), c);
 1130           }
 1131       }
 1132   
 1133       /* Find a method in RequiredModelMBean as determined by the given
 1134          parameters.  Return null if there is none, or if the parameters
 1135          exclude using it.  Called from invoke. */
 1136       private static Method findRMMBMethod(String opMethodName,
 1137                                            Object targetObjectField,
 1138                                            String opClassName,
 1139                                            String[] sig) {
 1140           final boolean tracing = MODELMBEAN_LOGGER.isLoggable(Level.FINER);
 1141   
 1142           if (tracing) {
 1143               MODELMBEAN_LOGGER.logp(Level.FINER,
 1144                   RequiredModelMBean.class.getName(),
 1145                       "invoke(String, Object[], String[])",
 1146                     "looking for method in RequiredModelMBean class");
 1147           }
 1148   
 1149           if (!isRMMBMethodName(opMethodName))
 1150               return null;
 1151           if (targetObjectField != null)
 1152               return null;
 1153           final Class<RequiredModelMBean> rmmbClass = RequiredModelMBean.class;
 1154           final Class<?> targetClass;
 1155           if (opClassName == null)
 1156               targetClass = rmmbClass;
 1157           else {
 1158               try {
 1159                   final ClassLoader targetClassLoader =
 1160                       rmmbClass.getClassLoader();
 1161                   targetClass = Class.forName(opClassName, false,
 1162                                               targetClassLoader);
 1163                   if (!rmmbClass.isAssignableFrom(targetClass))
 1164                       return null;
 1165               } catch (ClassNotFoundException e) {
 1166                   return null;
 1167               }
 1168           }
 1169           try {
 1170               return resolveMethod(targetClass, opMethodName, sig);
 1171           } catch (ReflectionException e) {
 1172               return null;
 1173           }
 1174       }
 1175   
 1176       /*
 1177        * Invoke the given method, and throw the somewhat unpredictable
 1178        * appropriate exception if the method itself gets an exception.
 1179        */
 1180       private Object invokeMethod(String opName, Method method,
 1181                                   Object targetObject, Object[] opArgs)
 1182               throws MBeanException, ReflectionException {
 1183           try {
 1184               ReflectUtil.checkPackageAccess(method.getDeclaringClass());
 1185               return MethodUtil.invoke(method, targetObject, opArgs);
 1186           } catch (RuntimeErrorException ree) {
 1187               throw new RuntimeOperationsException(ree,
 1188                         "RuntimeException occurred in RequiredModelMBean "+
 1189                         "while trying to invoke operation " + opName);
 1190           } catch (RuntimeException re) {
 1191               throw new RuntimeOperationsException(re,
 1192                         "RuntimeException occurred in RequiredModelMBean "+
 1193                         "while trying to invoke operation " + opName);
 1194           } catch (IllegalAccessException iae) {
 1195               throw new ReflectionException(iae,
 1196                         "IllegalAccessException occurred in " +
 1197                         "RequiredModelMBean while trying to " +
 1198                         "invoke operation " + opName);
 1199           } catch (InvocationTargetException ite) {
 1200               Throwable mmbTargEx = ite.getTargetException();
 1201               if (mmbTargEx instanceof RuntimeException) {
 1202                   throw new MBeanException ((RuntimeException)mmbTargEx,
 1203                         "RuntimeException thrown in RequiredModelMBean "+
 1204                         "while trying to invoke operation " + opName);
 1205               } else if (mmbTargEx instanceof Error) {
 1206                   throw new RuntimeErrorException((Error)mmbTargEx,
 1207                         "Error occurred in RequiredModelMBean while trying "+
 1208                         "to invoke operation " + opName);
 1209               } else if (mmbTargEx instanceof ReflectionException) {
 1210                   throw (ReflectionException) mmbTargEx;
 1211               } else {
 1212                   throw new MBeanException ((Exception)mmbTargEx,
 1213                         "Exception thrown in RequiredModelMBean "+
 1214                         "while trying to invoke operation " + opName);
 1215               }
 1216           } catch (Error err) {
 1217               throw new RuntimeErrorException(err,
 1218                     "Error occurred in RequiredModelMBean while trying "+
 1219                     "to invoke operation " + opName);
 1220           } catch (Exception e) {
 1221               throw new ReflectionException(e,
 1222                     "Exception occurred in RequiredModelMBean while " +
 1223                     "trying to invoke operation " + opName);
 1224           }
 1225       }
 1226   
 1227       /*
 1228        * Cache the result of an operation in the descriptor, if that is
 1229        * called for by the descriptor's configuration.  Note that we
 1230        * don't remember operation parameters when caching the result, so
 1231        * this is unlikely to be useful if there are any.
 1232        */
 1233       private void cacheResult(ModelMBeanOperationInfo opInfo,
 1234                                Descriptor opDescr, Object result)
 1235               throws MBeanException {
 1236   
 1237           Descriptor mmbDesc =
 1238               modelMBeanInfo.getMBeanDescriptor();
 1239   
 1240           Object objctl =
 1241               opDescr.getFieldValue("currencyTimeLimit");
 1242           String ctl;
 1243           if (objctl != null) {
 1244               ctl = objctl.toString();
 1245           } else {
 1246               ctl = null;
 1247           }
 1248           if ((ctl == null) && (mmbDesc != null)) {
 1249               objctl =
 1250                   mmbDesc.getFieldValue("currencyTimeLimit");
 1251               if (objctl != null) {
 1252                   ctl = objctl.toString();
 1253               } else {
 1254                   ctl = null;
 1255               }
 1256           }
 1257           if ((ctl != null) && !(ctl.equals("-1"))) {
 1258               opDescr.setField("value", result);
 1259               opDescr.setField("lastUpdatedTimeStamp",
 1260                       String.valueOf((new Date()).getTime()));
 1261   
 1262   
 1263               modelMBeanInfo.setDescriptor(opDescr,
 1264                                            "operation");
 1265               if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
 1266                   MODELMBEAN_LOGGER.logp(Level.FINER,
 1267                           RequiredModelMBean.class.getName(),
 1268                           "invoke(String,Object[],Object[])",
 1269                           "new descriptor is " + opDescr);
 1270               }
 1271           }
 1272       }
 1273   
 1274       /*
 1275        * Determine whether the given name is the name of a public method
 1276        * in this class.  This is only an optimization: it prevents us
 1277        * from trying to do argument type lookups and reflection on a
 1278        * method that will obviously fail because it has the wrong name.
 1279        *
 1280        * The first time this method is called we do the reflection, and
 1281        * every other time we reuse the remembered values.
 1282        *
 1283        * It's conceivable that the (possibly malicious) first caller
 1284        * doesn't have the required permissions to do reflection, in
 1285        * which case we don't touch anything so as not to interfere
 1286        * with a later permissionful caller.
 1287        */
 1288       private static Set<String> rmmbMethodNames;
 1289       private static synchronized boolean isRMMBMethodName(String name) {
 1290           if (rmmbMethodNames == null) {
 1291               try {
 1292                   Set<String> names = new HashSet<String>();
 1293                   Method[] methods = RequiredModelMBean.class.getMethods();
 1294                   for (int i = 0; i < methods.length; i++)
 1295                       names.add(methods[i].getName());
 1296                   rmmbMethodNames = names;
 1297               } catch (Exception e) {
 1298                   return true;
 1299                   // This is only an optimization so we'll go on to discover
 1300                   // whether the name really is an RMMB method.
 1301               }
 1302           }
 1303           return rmmbMethodNames.contains(name);
 1304       }
 1305   
 1306       /**
 1307        * Returns the value of a specific attribute defined for this
 1308        * ModelMBean.
 1309        * The last value returned by an attribute may be cached in the
 1310        * attribute's descriptor.
 1311        * The valid value will be in the 'value' field if there is one.
 1312        * If the 'currencyTimeLimit' field in the descriptor is:
 1313        * <UL>
 1314        * <LI>  <b>&lt;0</b> Then the value is not cached and is never valid.
 1315        *       The getter method is invoked for the attribute.
 1316        *       The 'value' and 'lastUpdatedTimeStamp' fields are cleared.</LI>
 1317        * <LI>  <b>=0</b> Then the value is always cached and always valid.
 1318        *       The 'value' field is returned. If there is no'value' field
 1319        *       then the getter method is invoked for the attribute.
 1320        *       The 'lastUpdatedTimeStamp' field and `value' fields are set
 1321        *       to the attribute's value and the current time stamp.</LI>
 1322        * <LI>  <b>&gt;0</b> Represents the number of seconds that the 'value'
 1323        *       field is valid.
 1324        *       The 'value' field is no longer valid when
 1325        *       'lastUpdatedTimeStamp' + 'currencyTimeLimit' &gt; Now.
 1326        *   <UL>
 1327        *        <LI>When 'value' is valid, 'value' is returned.</LI>
 1328        *        <LI>When 'value' is no longer valid then the getter
 1329        *            method is invoked for the attribute.
 1330        *            The 'lastUpdatedTimeStamp' field and `value' fields
 1331        *            are updated.</LI>
 1332        *   </UL></LI>
 1333        * </UL>
 1334        *
 1335        * <p><b>Note:</b> because of inconsistencies in previous versions of
 1336        * this specification, it is recommended not to use negative or zero
 1337        * values for <code>currencyTimeLimit</code>.  To indicate that a
 1338        * cached value is never valid, omit the
 1339        * <code>currencyTimeLimit</code> field.  To indicate that it is
 1340        * always valid, use a very large number for this field.</p>
 1341        *
 1342        * <p>If the 'getMethod' field contains the name of a valid
 1343        * operation descriptor, then the method described by the
 1344        * operation descriptor is executed.  The response from the
 1345        * method is returned as the value of the attribute.  If the
 1346        * operation fails or the returned value is not compatible with
 1347        * the declared type of the attribute, an exception will be thrown.</p>
 1348        *
 1349        * <p>If no 'getMethod' field is defined then the default value of the
 1350        * attribute is returned. If the returned value is not compatible with
 1351        * the declared type of the attribute, an exception will be thrown.</p>
 1352        *
 1353        * <p>The declared type of the attribute is the String returned by
 1354        * {@link ModelMBeanAttributeInfo#getType()}.  A value is compatible
 1355        * with this type if one of the following is true:
 1356        * <ul>
 1357        * <li>the value is null;</li>
 1358        * <li>the declared name is a primitive type name (such as "int")
 1359        *     and the value is an instance of the corresponding wrapper
 1360        *     type (such as java.lang.Integer);</li>
 1361        * <li>the name of the value's class is identical to the declared name;</li>
 1362        * <li>the declared name can be loaded by the value's class loader and
 1363        *     produces a class to which the value can be assigned.</li>
 1364        * </ul>
 1365        *
 1366        * <p>In this implementation, in every case where the getMethod needs to
 1367        * be called, because the method is invoked through the standard "invoke"
 1368        * method and thus needs operationInfo, an operation must be specified
 1369        * for that getMethod so that the invocation works correctly.</p>
 1370        *
 1371        * @param attrName A String specifying the name of the
 1372        * attribute to be retrieved. It must match the name of a
 1373        * ModelMBeanAttributeInfo.
 1374        *
 1375        * @return The value of the retrieved attribute from the
 1376        * descriptor 'value' field or from the invocation of the
 1377        * operation in the 'getMethod' field of the descriptor.
 1378        *
 1379        * @exception AttributeNotFoundException The specified attribute is
 1380        *    not accessible in the MBean.
 1381        *    The following cases may result in an AttributeNotFoundException:
 1382        *    <UL>
 1383        *      <LI> No ModelMBeanInfo was found for the Model MBean.</LI>
 1384        *      <LI> No ModelMBeanAttributeInfo was found for the specified
 1385        *           attribute name.</LI>
 1386        *      <LI> The ModelMBeanAttributeInfo isReadable method returns
 1387        *           'false'.</LI>
 1388        *    </UL>
 1389        * @exception MBeanException  Wraps one of the following Exceptions:
 1390        *    <UL>
 1391        *      <LI> {@link InvalidAttributeValueException}: A wrong value type
 1392        *           was received from the attribute's getter method or
 1393        *           no 'getMethod' field defined in the descriptor for
 1394        *           the attribute and no default value exists.</LI>
 1395        *      <LI> {@link ServiceNotFoundException}: No
 1396        *           ModelMBeanOperationInfo defined for the attribute's
 1397        *           getter method or no descriptor associated with the
 1398        *           ModelMBeanOperationInfo or the managed resource is
 1399        *           null.</LI>
 1400        *      <LI> {@link InvalidTargetObjectTypeException} The 'targetType'
 1401        *           field value is not 'objectReference'.</LI>
 1402        *      <LI> An Exception thrown by the managed object's getter.</LI>
 1403        *    </UL>
 1404        * @exception ReflectionException  Wraps an {@link java.lang.Exception}
 1405        *    thrown while trying to invoke the getter.
 1406        * @exception RuntimeOperationsException Wraps an
 1407        *    {@link IllegalArgumentException}: The attribute name in
 1408        *    parameter is null.
 1409        *
 1410        * @see #setAttribute(javax.management.Attribute)
 1411        **/
 1412       public Object getAttribute(String attrName)
 1413           throws AttributeNotFoundException, MBeanException,
 1414                  ReflectionException {
 1415           if (attrName == null)
 1416               throw new RuntimeOperationsException(new
 1417                   IllegalArgumentException("attributeName must not be null"),
 1418                   "Exception occurred trying to get attribute of a " +
 1419                   "RequiredModelMBean");
 1420           final String mth = "getAttribute(String)";
 1421           final boolean tracing = MODELMBEAN_LOGGER.isLoggable(Level.FINER);
 1422           if (tracing) {
 1423               MODELMBEAN_LOGGER.logp(Level.FINER,
 1424                       RequiredModelMBean.class.getName(),
 1425                   mth, "Entry with " + attrName);
 1426           }
 1427   
 1428           /* Check attributeDescriptor for getMethod */
 1429           Object response;
 1430   
 1431           try {
 1432               if (modelMBeanInfo == null)
 1433                   throw new AttributeNotFoundException(
 1434                         "getAttribute failed: ModelMBeanInfo not found for "+
 1435                         attrName);
 1436   
 1437               ModelMBeanAttributeInfo attrInfo = modelMBeanInfo.getAttribute(attrName);
 1438               Descriptor mmbDesc = modelMBeanInfo.getMBeanDescriptor();
 1439   
 1440               if (attrInfo == null)
 1441                   throw new AttributeNotFoundException("getAttribute failed:"+
 1442                         " ModelMBeanAttributeInfo not found for " + attrName);
 1443   
 1444               Descriptor attrDescr = attrInfo.getDescriptor();
 1445               if (attrDescr != null) {
 1446                   if (!attrInfo.isReadable())
 1447                       throw new AttributeNotFoundException(
 1448                             "getAttribute failed: " + attrName +
 1449                             " is not readable ");
 1450   
 1451                   response = resolveForCacheValue(attrDescr);
 1452   
 1453                   /* return current cached value */
 1454                   if (tracing) {
 1455                       MODELMBEAN_LOGGER.logp(Level.FINER,
 1456                               RequiredModelMBean.class.getName(), mth,
 1457                           "*** cached value is " + response);
 1458                   }
 1459   
 1460                   if (response == null) {
 1461                       /* no cached value, run getMethod */
 1462                       if (tracing) {
 1463                           MODELMBEAN_LOGGER.logp(Level.FINER,
 1464                                   RequiredModelMBean.class.getName(), mth,
 1465                               "**** cached value is null - getting getMethod");
 1466                       }
 1467                       String attrGetMethod =
 1468                           (String)(attrDescr.getFieldValue("getMethod"));
 1469   
 1470                       if (attrGetMethod != null) {
 1471                           /* run method from operations descriptor */
 1472                           if (tracing) {
 1473                               MODELMBEAN_LOGGER.logp(Level.FINER,
 1474                                       RequiredModelMBean.class.getName(),
 1475                                   mth, "invoking a getMethod for " +  attrName);
 1476                           }
 1477   
 1478                           Object getResponse =
 1479                               invoke(attrGetMethod, new Object[] {},
 1480                                      new String[] {});
 1481   
 1482                           if (getResponse != null) {
 1483                               // error/validity check return value here
 1484                               if (tracing) {
 1485                                   MODELMBEAN_LOGGER.logp(Level.FINER,
 1486                                           RequiredModelMBean.class.getName(),
 1487                                           mth, "got a non-null response " +
 1488                                           "from getMethod\n");
 1489                               }
 1490   
 1491                               response = getResponse;
 1492   
 1493                               // change cached value in attribute descriptor
 1494                               Object objctl =
 1495                                   attrDescr.getFieldValue("currencyTimeLimit");
 1496   
 1497                               String ctl;
 1498                               if (objctl != null) ctl = objctl.toString();
 1499                               else ctl = null;
 1500   
 1501                               if ((ctl == null) && (mmbDesc != null)) {
 1502                                   objctl = mmbDesc.
 1503                                       getFieldValue("currencyTimeLimit");
 1504                                   if (objctl != null) ctl = objctl.toString();
 1505                                   else ctl = null;
 1506                               }
 1507   
 1508                               if ((ctl != null) && !(ctl.equals("-1"))) {
 1509                                   if (tracing) {
 1510                                       MODELMBEAN_LOGGER.logp(Level.FINER,
 1511                                               RequiredModelMBean.class.getName(),
 1512                                               mth,
 1513                                               "setting cached value and " +
 1514                                               "lastUpdatedTime in descriptor");
 1515                                   }
 1516                                   attrDescr.setField("value", response);
 1517                                   final String stamp = String.valueOf(
 1518                                       (new Date()).getTime());
 1519                                   attrDescr.setField("lastUpdatedTimeStamp",
 1520                                                      stamp);
 1521                                   attrInfo.setDescriptor(attrDescr);
 1522                                   modelMBeanInfo.setDescriptor(attrDescr,
 1523                                                                "attribute");
 1524                                   if (tracing) {
 1525                                       MODELMBEAN_LOGGER.logp(Level.FINER,
 1526                                               RequiredModelMBean.class.getName(),
 1527                                           mth,"new descriptor is " +attrDescr);
 1528                                       MODELMBEAN_LOGGER.logp(Level.FINER,
 1529                                               RequiredModelMBean.class.getName(),
 1530                                           mth,"AttributeInfo descriptor is " +
 1531                                               attrInfo.getDescriptor());
 1532                                       final String attStr = modelMBeanInfo.
 1533                                           getDescriptor(attrName,"attribute").
 1534                                               toString();
 1535                                       MODELMBEAN_LOGGER.logp(Level.FINER,
 1536                                               RequiredModelMBean.class.getName(),
 1537                                               mth,
 1538                                               "modelMBeanInfo: AttributeInfo " +
 1539                                               "descriptor is " + attStr);
 1540                                   }
 1541                               }
 1542                           } else {
 1543                               // response was invalid or really returned null
 1544                               if (tracing) {
 1545                                   MODELMBEAN_LOGGER.logp(Level.FINER,
 1546                                           RequiredModelMBean.class.getName(), mth,
 1547                                       "got a null response from getMethod\n");
 1548                               }
 1549                               response = null;
 1550                           }
 1551                       } else {
 1552                           // not getMethod so return descriptor (default) value
 1553                           String qualifier="";
 1554                           response = attrDescr.getFieldValue("value");
 1555                           if (response == null) {
 1556                               qualifier="default ";
 1557                               response = attrDescr.getFieldValue("default");
 1558                           }
 1559                           if (tracing) {
 1560                               MODELMBEAN_LOGGER.logp(Level.FINER,
 1561                                       RequiredModelMBean.class.getName(), mth,
 1562                                   "could not find getMethod for " +attrName +
 1563                                   ", returning descriptor " +qualifier + "value");
 1564                           }
 1565                           // !! cast response to right class
 1566                       }
 1567                   }
 1568   
 1569                   // make sure response class matches type field
 1570                   String respType = attrInfo.getType();
 1571                   if (response != null) {
 1572                       String responseClass = response.getClass().getName();
 1573                       if (!respType.equals(responseClass)) {
 1574                           boolean wrongType = false;
 1575                           boolean primitiveType = false;
 1576                           boolean correspondingTypes = false;
 1577                           for (int i = 0; i < primitiveTypes.length; i++) {
 1578                               if (respType.equals(primitiveTypes[i])) {
 1579                                   primitiveType = true;
 1580                                   if (responseClass.equals(primitiveWrappers[i]))
 1581                                       correspondingTypes = true;
 1582                                   break;
 1583                               }
 1584                           }
 1585                           if (primitiveType) {
 1586                               // inequality may come from primitive/wrapper class
 1587                               if (!correspondingTypes)
 1588                                   wrongType = true;
 1589                           } else {
 1590                               // inequality may come from type subclassing
 1591                               boolean subtype;
 1592                               try {
 1593                                   ClassLoader cl =
 1594                                       response.getClass().getClassLoader();
 1595                                   Class<?> c = Class.forName(respType, true, cl);
 1596                                   subtype = c.isInstance(response);
 1597                               } catch (Exception e) {
 1598                                   subtype = false;
 1599   
 1600                                   if (tracing) {
 1601                                       MODELMBEAN_LOGGER.logp(Level.FINER,
 1602                                               RequiredModelMBean.class.getName(),
 1603                                           mth, "Exception: ",e);
 1604                                   }
 1605                               }
 1606                               if (!subtype)
 1607                                   wrongType = true;
 1608                           }
 1609                           if (wrongType) {
 1610                               if (tracing) {
 1611                                   MODELMBEAN_LOGGER.logp(Level.FINER,
 1612                                           RequiredModelMBean.class.getName(), mth,
 1613                                       "Wrong response type '" + respType + "'");
 1614                               }
 1615                               // throw exception, didn't get
 1616                               // back right attribute type
 1617                               throw new MBeanException(
 1618                                 new InvalidAttributeValueException(
 1619                                   "Wrong value type received for get attribute"),
 1620                                 "An exception occurred while trying to get an " +
 1621                                 "attribute value through a RequiredModelMBean");
 1622                           }
 1623                       }
 1624                   }
 1625               } else {
 1626                   if (tracing) {
 1627                       MODELMBEAN_LOGGER.logp(Level.FINER,
 1628                               RequiredModelMBean.class.getName(), mth,
 1629                               "getMethod failed " + attrName +
 1630                               " not in attributeDescriptor\n");
 1631                   }
 1632                   throw new MBeanException(new
 1633                       InvalidAttributeValueException(
 1634                       "Unable to resolve attribute value, " +
 1635                       "no getMethod defined in descriptor for attribute"),
 1636                       "An exception occurred while trying to get an "+
 1637                       "attribute value through a RequiredModelMBean");
 1638               }
 1639   
 1640           } catch (MBeanException mbe) {
 1641               throw mbe;
 1642           } catch (AttributeNotFoundException t) {
 1643               throw t;
 1644           } catch (Exception e) {
 1645               if (tracing) {
 1646                   MODELMBEAN_LOGGER.logp(Level.FINER,
 1647                           RequiredModelMBean.class.getName(), mth,
 1648                           "getMethod failed with " + e.getMessage() +
 1649                           " exception type " + (e.getClass()).toString());
 1650               }
 1651               throw new MBeanException(e,"An exception occurred while trying "+
 1652                         "to get an attribute value: " + e.getMessage());
 1653           }
 1654   
 1655           if (tracing) {
 1656               MODELMBEAN_LOGGER.logp(Level.FINER,
 1657                       RequiredModelMBean.class.getName(), mth, "Exit");
 1658           }
 1659   
 1660           return response;
 1661       }
 1662   
 1663       /**
 1664        * Returns the values of several attributes in the ModelMBean.
 1665        * Executes a getAttribute for each attribute name in the
 1666        * attrNames array passed in.
 1667        *
 1668        * @param attrNames A String array of names of the attributes
 1669        * to be retrieved.
 1670        *
 1671        * @return The array of the retrieved attributes.
 1672        *
 1673        * @exception RuntimeOperationsException Wraps an
 1674        * {@link IllegalArgumentException}: The object name in parameter is
 1675        * null or attributes in parameter is null.
 1676        *
 1677        * @see #setAttributes(javax.management.AttributeList)
 1678        */
 1679       public AttributeList getAttributes(String[] attrNames)      {
 1680           if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
 1681               MODELMBEAN_LOGGER.logp(Level.FINER,
 1682                       RequiredModelMBean.class.getName(),
 1683               "getAttributes(String[])","Entry");
 1684           }
 1685   
 1686           if (attrNames == null)
 1687               throw new RuntimeOperationsException(new
 1688                   IllegalArgumentException("attributeNames must not be null"),
 1689                   "Exception occurred trying to get attributes of a "+
 1690                   "RequiredModelMBean");
 1691   
 1692           AttributeList responseList = new AttributeList();
 1693           for (int i = 0; i < attrNames.length; i++) {
 1694               try {
 1695                   responseList.add(new Attribute(attrNames[i],
 1696                                        getAttribute(attrNames[i])));
 1697               } catch (Exception e) {
 1698                   // eat exceptions because interface doesn't have an
 1699                   // exception on it
 1700                   if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
 1701                       MODELMBEAN_LOGGER.logp(Level.FINER,
 1702                               RequiredModelMBean.class.getName(),
 1703                           "getAttributes(String[])",
 1704                               "Failed to get \"" + attrNames[i] + "\": ", e);
 1705                   }
 1706               }
 1707           }
 1708   
 1709           if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
 1710               MODELMBEAN_LOGGER.logp(Level.FINER,
 1711                   RequiredModelMBean.class.getName(),
 1712                       "getAttributes(String[])","Exit");
 1713           }
 1714   
 1715           return responseList;
 1716       }
 1717   
 1718       /**
 1719        * Sets the value of a specific attribute of a named ModelMBean.
 1720        *
 1721        * If the 'setMethod' field of the attribute's descriptor
 1722        * contains the name of a valid operation descriptor, then the
 1723        * method described by the operation descriptor is executed.
 1724        * In this implementation, the operation descriptor must be specified
 1725        * correctly and assigned to the modelMBeanInfo so that the 'setMethod'
 1726        * works correctly.
 1727        * The response from the method is set as the value of the attribute
 1728        * in the descriptor.
 1729        *
 1730        * <p>If currencyTimeLimit is &gt; 0, then the new value for the
 1731        * attribute is cached in the attribute descriptor's
 1732        * 'value' field and the 'lastUpdatedTimeStamp' field is set to
 1733        * the current time stamp.
 1734        *
 1735        * <p>If the persist field of the attribute's descriptor is not null
 1736        * then Persistence policy from the attribute descriptor is used to
 1737        * guide storing the attribute in a persistent store.
 1738        * <br>Store the MBean if 'persistPolicy' field is:
 1739        * <UL>
 1740        * <Li> != "never"</Li>
 1741        * <Li> = "always"</Li>
 1742        * <Li> = "onUpdate"</Li>
 1743        * <Li> = "onTimer" and now &gt; 'lastPersistTime' + 'persistPeriod'</Li>
 1744        * <Li> = "NoMoreOftenThan" and now &gt; 'lastPersistTime' +
 1745        *         'persistPeriod'</Li>
 1746        * </UL>
 1747        * Do not store the MBean if 'persistPolicy' field is:
 1748        * <UL>
 1749        * <Li> = "never"</Li>
 1750        * <Li> = "onTimer" && now &lt; 'lastPersistTime' + 'persistPeriod'</Li>
 1751        * <Li> = "onUnregister"</Li>
 1752        * <Li> = "NoMoreOftenThan" and now &lt; 'lastPersistTime' +
 1753        *        'persistPeriod'</Li>
 1754        * </UL>
 1755        *
 1756        * <p>The ModelMBeanInfo of the Model MBean is stored in a file.
 1757        *
 1758        * @param attribute The Attribute instance containing the name of
 1759        *        the attribute to be set and the value it is to be set to.
 1760        *
 1761        *
 1762        * @exception AttributeNotFoundException The specified attribute is
 1763        *   not accessible in the MBean.
 1764        *   <br>The following cases may result in an AttributeNotFoundException:
 1765        *   <UL>
 1766        *     <LI> No ModelMBeanAttributeInfo is found for the specified
 1767        *          attribute.</LI>
 1768        *     <LI> The ModelMBeanAttributeInfo's isWritable method returns
 1769        *          'false'.</LI>
 1770        *   </UL>
 1771        * @exception InvalidAttributeValueException No descriptor is defined
 1772        *   for the specified attribute.
 1773        * @exception MBeanException Wraps one of the following Exceptions:
 1774        *   <UL>
 1775        *     <LI> An Exception thrown by the managed object's setter.</LI>
 1776        *     <LI> A {@link ServiceNotFoundException} if a setMethod field is
 1777        *          defined in the descriptor for the attribute and the managed
 1778        *          resource is null; or if no setMethod field is defined and
 1779        *          caching is not enabled for the attribute.
 1780        *          Note that if there is no getMethod field either, then caching
 1781        *          is automatically enabled.</LI>
 1782        *     <LI> {@link InvalidTargetObjectTypeException} The 'targetType'
 1783        *          field value is not 'objectReference'.</LI>
 1784        *     <LI> An Exception thrown by the managed object's getter.</LI>
 1785        *   </UL>
 1786        * @exception ReflectionException  Wraps an {@link java.lang.Exception}
 1787        *   thrown while trying to invoke the setter.
 1788        * @exception RuntimeOperationsException Wraps an
 1789        *   {@link IllegalArgumentException}: The attribute in parameter is
 1790        *   null.
 1791        *
 1792        * @see #getAttribute(java.lang.String)
 1793        **/
 1794       public void setAttribute(Attribute attribute)
 1795           throws AttributeNotFoundException, InvalidAttributeValueException,
 1796                  MBeanException, ReflectionException {
 1797           final boolean tracing = MODELMBEAN_LOGGER.isLoggable(Level.FINER);
 1798           if (tracing) {
 1799               MODELMBEAN_LOGGER.logp(Level.FINER,
 1800                       RequiredModelMBean.class.getName(),
 1801                   "setAttribute()","Entry");
 1802           }
 1803   
 1804           if (attribute == null)
 1805               throw new RuntimeOperationsException(new
 1806                   IllegalArgumentException("attribute must not be null"),
 1807                   "Exception occurred trying to set an attribute of a "+
 1808                   "RequiredModelMBean");
 1809   
 1810           /* run setMethod if there is one */
 1811           /* return cached value if its current */
 1812           /* set cached value in descriptor and set date/time */
 1813           /* send attribute change Notification */
 1814           /* check persistence policy and persist if need be */
 1815           String attrName = attribute.getName();
 1816           Object attrValue = attribute.getValue();
 1817           boolean updateDescriptor = false;
 1818   
 1819           ModelMBeanAttributeInfo attrInfo =
 1820               modelMBeanInfo.getAttribute(attrName);
 1821   
 1822           if (attrInfo == null)
 1823               throw new AttributeNotFoundException("setAttribute failed: " +
 1824                                                  attrName + " is not found ");
 1825   
 1826           Descriptor mmbDesc = modelMBeanInfo.getMBeanDescriptor();
 1827           Descriptor attrDescr = attrInfo.getDescriptor();
 1828   
 1829           if (attrDescr != null) {
 1830               if (!attrInfo.isWritable())
 1831                   throw new AttributeNotFoundException("setAttribute failed: "
 1832                                             + attrName + " is not writable ");
 1833   
 1834               String attrSetMethod = (String)
 1835                   (attrDescr.getFieldValue("setMethod"));
 1836               String attrGetMethod = (String)
 1837                   (attrDescr.getFieldValue("getMethod"));
 1838   
 1839               String attrType = attrInfo.getType();
 1840               Object currValue = "Unknown";
 1841   
 1842               try {
 1843                   currValue = this.getAttribute(attrName);
 1844               } catch (Throwable t) {
 1845                   // OK: Default "Unknown" value used for unknown attribute
 1846               }
 1847   
 1848               Attribute oldAttr = new Attribute(attrName, currValue);
 1849   
 1850               /* run method from operations descriptor */
 1851               if (attrSetMethod == null) {
 1852                   if (attrValue != null) {
 1853                       try {
 1854                           final Class<?> clazz = loadClass(attrType);
 1855                           if (! clazz.isInstance(attrValue))  throw new
 1856                               InvalidAttributeValueException(clazz.getName() +
 1857                                                              " expected, "   +
 1858                                               attrValue.getClass().getName() +
 1859                                                              " received.");
 1860                       } catch (ClassNotFoundException x) {
 1861                           if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
 1862                               MODELMBEAN_LOGGER.logp(Level.FINER,
 1863                                       RequiredModelMBean.class.getName(),
 1864                                   "setAttribute(Attribute)","Class " +
 1865                                       attrType + " for attribute "
 1866                                   + attrName + " not found: ", x);
 1867                           }
 1868                       }
 1869                   }
 1870                   updateDescriptor = true;
 1871               } else {
 1872                   invoke(attrSetMethod,
 1873                          (new Object[] {attrValue}),
 1874                          (new String[] {attrType}) );
 1875               }
 1876   
 1877               /* change cached value */
 1878               Object objctl = attrDescr.getFieldValue("currencyTimeLimit");
 1879               String ctl;
 1880               if (objctl != null) ctl = objctl.toString();
 1881               else ctl = null;
 1882   
 1883               if ((ctl == null) && (mmbDesc != null)) {
 1884                   objctl = mmbDesc.getFieldValue("currencyTimeLimit");
 1885                   if (objctl != null) ctl = objctl.toString();
 1886                   else ctl = null;
 1887               }
 1888   
 1889               final boolean updateCache = ((ctl != null) && !(ctl.equals("-1")));
 1890   
 1891                if(attrSetMethod == null  && !updateCache && attrGetMethod != null)
 1892                   throw new MBeanException(new ServiceNotFoundException("No " +
 1893                           "setMethod field is defined in the descriptor for " +
 1894                           attrName + " attribute and caching is not enabled " +
 1895                           "for it"));
 1896   
 1897               if (updateCache || updateDescriptor) {
 1898                   if (tracing) {
 1899                       MODELMBEAN_LOGGER.logp(Level.FINER,
 1900                           RequiredModelMBean.class.getName(),
 1901                               "setAttribute(Attribute)",
 1902                               "setting cached value of " +
 1903                               attrName + " to " + attrValue);
 1904                   }
 1905   
 1906                   attrDescr.setField("value", attrValue);
 1907   
 1908                   if (updateCache) {
 1909                       final String currtime = String.valueOf(
 1910                           (new Date()).getTime());
 1911   
 1912                       attrDescr.setField("lastUpdatedTimeStamp", currtime);
 1913                   }
 1914   
 1915                   attrInfo.setDescriptor(attrDescr);
 1916   
 1917                   modelMBeanInfo.setDescriptor(attrDescr,"attribute");
 1918                   if (tracing) {
 1919                       final StringBuilder strb = new StringBuilder()
 1920                       .append("new descriptor is ").append(attrDescr)
 1921                       .append(". AttributeInfo descriptor is ")
 1922                       .append(attrInfo.getDescriptor())
 1923                       .append(". AttributeInfo descriptor is ")
 1924                       .append(modelMBeanInfo.getDescriptor(attrName,"attribute"));
 1925                       MODELMBEAN_LOGGER.logp(Level.FINER,
 1926                               RequiredModelMBean.class.getName(),
 1927                               "setAttribute(Attribute)",strb.toString());
 1928                   }
 1929   
 1930               }
 1931   
 1932               if (tracing) {
 1933                   MODELMBEAN_LOGGER.logp(Level.FINER,
 1934                           RequiredModelMBean.class.getName(),
 1935                   "setAttribute(Attribute)","sending sendAttributeNotification");
 1936               }
 1937               sendAttributeChangeNotification(oldAttr,attribute);
 1938   
 1939           } else { // if descriptor ... else no descriptor
 1940   
 1941               if (tracing) {
 1942                       MODELMBEAN_LOGGER.logp(Level.FINER,
 1943                               RequiredModelMBean.class.getName(),
 1944                           "setAttribute(Attribute)","setMethod failed "+attrName+
 1945                           " not in attributeDescriptor\n");
 1946               }
 1947   
 1948               throw new InvalidAttributeValueException(
 1949                         "Unable to resolve attribute value, "+
 1950                         "no defined in descriptor for attribute");
 1951           } // else no descriptor
 1952   
 1953           if (tracing) {
 1954               MODELMBEAN_LOGGER.logp(Level.FINER,
 1955                       RequiredModelMBean.class.getName(),
 1956                   "setAttribute(Attribute)", "Exit");
 1957           }
 1958   
 1959       }
 1960   
 1961       /**
 1962        * Sets the values of an array of attributes of this ModelMBean.
 1963        * Executes the setAttribute() method for each attribute in the list.
 1964        *
 1965        * @param attributes A list of attributes: The identification of the
 1966        * attributes to be set and  the values they are to be set to.
 1967        *
 1968        * @return  The array of attributes that were set, with their new
 1969        *    values in Attribute instances.
 1970        *
 1971        * @exception RuntimeOperationsException Wraps an
 1972        *   {@link IllegalArgumentException}: The object name in parameter
 1973        *   is null or attributes in parameter is null.
 1974        *
 1975        * @see #getAttributes
 1976        **/
 1977       public AttributeList setAttributes(AttributeList attributes) {
 1978   
 1979           if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
 1980               MODELMBEAN_LOGGER.logp(Level.FINER,
 1981                       RequiredModelMBean.class.getName(),
 1982                   "setAttribute(Attribute)", "Entry");
 1983           }
 1984   
 1985           if (attributes == null)
 1986               throw new RuntimeOperationsException(new
 1987                   IllegalArgumentException("attributes must not be null"),
 1988                   "Exception occurred trying to set attributes of a "+
 1989                   "RequiredModelMBean");
 1990   
 1991           final AttributeList responseList = new AttributeList();
 1992   
 1993           // Go through the list of attributes
 1994           for (Attribute attr : attributes.asList()) {
 1995               try {
 1996                   setAttribute(attr);
 1997                   responseList.add(attr);
 1998               } catch (Exception excep) {
 1999                   responseList.remove(attr);
 2000               }
 2001           }
 2002   
 2003           return responseList;
 2004       }
 2005   
 2006   
 2007   
 2008       private ModelMBeanInfo createDefaultModelMBeanInfo() {
 2009           return(new ModelMBeanInfoSupport((this.getClass().getName()),
 2010                      "Default ModelMBean", null, null, null, null));
 2011       }
 2012   
 2013       /*************************************/
 2014       /* NotificationBroadcaster Interface */
 2015       /*************************************/
 2016   
 2017   
 2018       private synchronized void writeToLog(String logFileName,
 2019                                            String logEntry) throws Exception {
 2020   
 2021           if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
 2022               MODELMBEAN_LOGGER.logp(Level.FINER,
 2023                       RequiredModelMBean.class.getName(),
 2024                   "writeToLog(String, String)",
 2025                   "Notification Logging to " + logFileName + ": " + logEntry);
 2026           }
 2027           if ((logFileName == null) || (logEntry == null)) {
 2028               if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
 2029                   MODELMBEAN_LOGGER.logp(Level.FINER,
 2030                           RequiredModelMBean.class.getName(),
 2031                       "writeToLog(String, String)",
 2032                       "Bad input parameters, will not log this entry.");
 2033               }
 2034               return;
 2035           }
 2036   
 2037           FileOutputStream fos = new FileOutputStream(logFileName, true);
 2038           try {
 2039               PrintStream logOut = new PrintStream(fos);
 2040               logOut.println(logEntry);
 2041               logOut.close();
 2042               if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
 2043                   MODELMBEAN_LOGGER.logp(Level.FINER,
 2044                           RequiredModelMBean.class.getName(),
 2045                       "writeToLog(String, String)","Successfully opened log " +
 2046                           logFileName);
 2047               }
 2048           } catch (Exception e) {
 2049               if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
 2050                   MODELMBEAN_LOGGER.logp(Level.FINER,
 2051                       RequiredModelMBean.class.getName(),
 2052                           "writeToLog(String, String)",
 2053                           "Exception " + e.toString() +
 2054                           " trying to write to the Notification log file " +
 2055                           logFileName);
 2056               }
 2057               throw e;
 2058           } finally {
 2059               fos.close();
 2060           }
 2061       }
 2062   
 2063   
 2064       /**
 2065        * Registers an object which implements the NotificationListener
 2066        * interface as a listener.  This
 2067        * object's 'handleNotification()' method will be invoked when any
 2068        * notification is issued through or by the ModelMBean.  This does
 2069        * not include attributeChangeNotifications.  They must be registered
 2070        * for independently.
 2071        *
 2072        * @param listener The listener object which will handles
 2073        *        notifications emitted by the registered MBean.
 2074        * @param filter The filter object. If null, no filtering will be
 2075        *        performed before handling notifications.
 2076        * @param handback The context to be sent to the listener with
 2077        *        the notification when a notification is emitted.
 2078        *
 2079        * @exception IllegalArgumentException The listener cannot be null.
 2080        *
 2081        * @see #removeNotificationListener
 2082        */
 2083       public void addNotificationListener(NotificationListener listener,
 2084                                           NotificationFilter filter,
 2085                                           Object handback)
 2086           throws java.lang.IllegalArgumentException {
 2087           final String mth = "addNotificationListener(" +
 2088                   "NotificationListener, NotificationFilter, Object)";
 2089           if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
 2090                   MODELMBEAN_LOGGER.logp(Level.FINER,
 2091                           RequiredModelMBean.class.getName(), mth, "Entry");
 2092           }
 2093   
 2094           if (listener == null)
 2095               throw new IllegalArgumentException(
 2096                     "notification listener must not be null");
 2097   
 2098           if (generalBroadcaster == null)
 2099               generalBroadcaster = new NotificationBroadcasterSupport();
 2100   
 2101           generalBroadcaster.addNotificationListener(listener, filter,
 2102                                                      handback);
 2103           if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
 2104                   MODELMBEAN_LOGGER.logp(Level.FINER,
 2105                           RequiredModelMBean.class.getName(), mth,
 2106                       "NotificationListener added");
 2107                   MODELMBEAN_LOGGER.logp(Level.FINER,
 2108                           RequiredModelMBean.class.getName(), mth, "Exit");
 2109           }
 2110       }
 2111   
 2112       /**
 2113        * Removes a listener for Notifications from the RequiredModelMBean.
 2114        *
 2115        * @param listener The listener name which was handling notifications
 2116        *    emitted by the registered MBean.
 2117        *    This method will remove all information related to this listener.
 2118        *
 2119        * @exception ListenerNotFoundException The listener is not registered
 2120        *    in the MBean or is null.
 2121        *
 2122        * @see #addNotificationListener
 2123        **/
 2124       public void removeNotificationListener(NotificationListener listener)
 2125           throws ListenerNotFoundException {
 2126           if (listener == null)
 2127               throw new ListenerNotFoundException(
 2128                         "Notification listener is null");
 2129   
 2130           final String mth="removeNotificationListener(NotificationListener)";
 2131           if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
 2132                   MODELMBEAN_LOGGER.logp(Level.FINER,
 2133                       RequiredModelMBean.class.getName(), mth, "Entry");
 2134           }
 2135   
 2136           if (generalBroadcaster == null)
 2137               throw new ListenerNotFoundException(
 2138                     "No notification listeners registered");
 2139   
 2140   
 2141           generalBroadcaster.removeNotificationListener(listener);
 2142           if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
 2143               MODELMBEAN_LOGGER.logp(Level.FINER,
 2144                       RequiredModelMBean.class.getName(), mth, "Exit");
 2145           }
 2146   
 2147       }
 2148   
 2149       public void removeNotificationListener(NotificationListener listener,
 2150                                              NotificationFilter filter,
 2151                                              Object handback)
 2152           throws ListenerNotFoundException {
 2153   
 2154           if (listener == null)
 2155               throw new ListenerNotFoundException(
 2156                         "Notification listener is null");
 2157   
 2158           final String mth = "removeNotificationListener(" +
 2159                   "NotificationListener, NotificationFilter, Object)";
 2160   
 2161           if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
 2162               MODELMBEAN_LOGGER.logp(Level.FINER,
 2163                       RequiredModelMBean.class.getName(), mth, "Entry");
 2164           }
 2165   
 2166           if (generalBroadcaster == null)
 2167               throw new ListenerNotFoundException(
 2168                     "No notification listeners registered");
 2169   
 2170   
 2171           generalBroadcaster.removeNotificationListener(listener,filter,
 2172                                                         handback);
 2173   
 2174           if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
 2175               MODELMBEAN_LOGGER.logp(Level.FINER,
 2176                       RequiredModelMBean.class.getName(), mth, "Exit");
 2177           }
 2178   
 2179       }
 2180   
 2181       public void sendNotification(Notification ntfyObj)
 2182           throws MBeanException, RuntimeOperationsException {
 2183           if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
 2184               MODELMBEAN_LOGGER.logp(Level.FINER,
 2185                       RequiredModelMBean.class.getName(),
 2186                   "sendNotification(Notification)", "Entry");
 2187           }
 2188   
 2189           if (ntfyObj == null)
 2190               throw new RuntimeOperationsException(new
 2191                   IllegalArgumentException("notification object must not be "+
 2192                                            "null"),
 2193                   "Exception occurred trying to send a notification from a "+
 2194                   "RequiredModelMBean");
 2195   
 2196   
 2197           // log notification if specified in descriptor
 2198           Descriptor ntfyDesc =
 2199               modelMBeanInfo.getDescriptor(ntfyObj.getType(),"notification");
 2200           Descriptor mmbDesc = modelMBeanInfo.getMBeanDescriptor();
 2201   
 2202           if (ntfyDesc != null) {
 2203               String logging = (String) ntfyDesc.getFieldValue("log");
 2204   
 2205               if (logging == null) {
 2206                   if (mmbDesc != null)
 2207                       logging = (String) mmbDesc.getFieldValue("log");
 2208               }
 2209   
 2210               if ((logging != null) &&
 2211                   (logging.equalsIgnoreCase("t") ||
 2212                    logging.equalsIgnoreCase("true"))) {
 2213   
 2214                   String logfile = (String) ntfyDesc.getFieldValue("logfile");
 2215                   if (logfile == null) {
 2216                       if (mmbDesc != null)
 2217                           logfile = (String)mmbDesc.getFieldValue("logfile");
 2218                   }
 2219                   if (logfile != null) {
 2220                       try {
 2221                           writeToLog(logfile,"LogMsg: " +
 2222                               ((new Date(ntfyObj.getTimeStamp())).toString())+
 2223                               " " + ntfyObj.getType() + " " +
 2224                               ntfyObj.getMessage() + " Severity = " +
 2225                               (String)ntfyDesc.getFieldValue("severity"));
 2226                       } catch (Exception e) {
 2227                           if (MODELMBEAN_LOGGER.isLoggable(Level.FINE)) {
 2228                               MODELMBEAN_LOGGER.logp(Level.FINE,
 2229                                       RequiredModelMBean.class.getName(),
 2230                                       "sendNotification(Notification)",
 2231                                       "Failed to log " +
 2232                                       ntfyObj.getType() + " notification: ", e);
 2233                           }
 2234                       }
 2235                   }
 2236               }
 2237           }
 2238           if (generalBroadcaster != null) {
 2239               generalBroadcaster.sendNotification(ntfyObj);
 2240           }
 2241   
 2242           if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
 2243               MODELMBEAN_LOGGER.logp(Level.FINER,
 2244                   RequiredModelMBean.class.getName(),
 2245                       "sendNotification(Notification)",
 2246                       "sendNotification sent provided notification object");
 2247               MODELMBEAN_LOGGER.logp(Level.FINER,
 2248                   RequiredModelMBean.class.getName(),
 2249                       "sendNotification(Notification)"," Exit");
 2250           }
 2251   
 2252       }
 2253   
 2254   
 2255       public void sendNotification(String ntfyText)
 2256           throws MBeanException, RuntimeOperationsException {
 2257           if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
 2258               MODELMBEAN_LOGGER.logp(Level.FINER,
 2259                       RequiredModelMBean.class.getName(),
 2260                   "sendNotification(String)","Entry");
 2261           }
 2262   
 2263           if (ntfyText == null)
 2264               throw new RuntimeOperationsException(new
 2265                   IllegalArgumentException("notification message must not "+
 2266                                            "be null"),
 2267                   "Exception occurred trying to send a text notification "+
 2268                   "from a ModelMBean");
 2269   
 2270           Notification myNtfyObj = new Notification("jmx.modelmbean.generic",
 2271                                                     this, 1, ntfyText);
 2272           sendNotification(myNtfyObj);
 2273           if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
 2274               MODELMBEAN_LOGGER.logp(Level.FINER,
 2275                       RequiredModelMBean.class.getName(),
 2276                   "sendNotification(String)","Notification sent");
 2277               MODELMBEAN_LOGGER.logp(Level.FINER,
 2278                       RequiredModelMBean.class.getName(),
 2279                   "sendNotification(String)","Exit");
 2280           }
 2281       }
 2282   
 2283       /**
 2284        * Returns `true' if the notification `notifName' is found
 2285        * in `info'. (bug 4744667)
 2286        **/
 2287       private static final
 2288           boolean hasNotification(final ModelMBeanInfo info,
 2289                                   final String notifName) {
 2290           try {
 2291               if (info == null) return false;
 2292               else return (info.getNotification(notifName)!=null);
 2293           } catch (MBeanException x) {
 2294               return false;
 2295           } catch (RuntimeOperationsException r) {
 2296               return false;
 2297           }
 2298       }
 2299   
 2300       /**
 2301        * Creates a default ModelMBeanNotificationInfo for GENERIC
 2302        * notification.  (bug 4744667)
 2303        **/
 2304       private static final ModelMBeanNotificationInfo makeGenericInfo() {
 2305           final Descriptor genericDescriptor = new DescriptorSupport( new
 2306               String[] {
 2307                   "name=GENERIC",
 2308                   "descriptorType=notification",
 2309                   "log=T",
 2310                   "severity=6",
 2311                   "displayName=jmx.modelmbean.generic"} );
 2312   
 2313           return new ModelMBeanNotificationInfo(new
 2314               String[] {"jmx.modelmbean.generic"},
 2315               "GENERIC",
 2316               "A text notification has been issued by the managed resource",
 2317               genericDescriptor);
 2318       }
 2319   
 2320       /**
 2321        * Creates a default ModelMBeanNotificationInfo for ATTRIBUTE_CHANGE
 2322        * notification.  (bug 4744667)
 2323        **/
 2324       private static final
 2325           ModelMBeanNotificationInfo makeAttributeChangeInfo() {
 2326           final Descriptor attributeDescriptor = new DescriptorSupport(new
 2327               String[] {
 2328                   "name=ATTRIBUTE_CHANGE",
 2329                   "descriptorType=notification",
 2330                   "log=T",
 2331                   "severity=6",
 2332                   "displayName=jmx.attribute.change"});
 2333   
 2334           return new ModelMBeanNotificationInfo(new
 2335               String[] {"jmx.attribute.change"},
 2336               "ATTRIBUTE_CHANGE",
 2337               "Signifies that an observed MBean attribute value has changed",
 2338               attributeDescriptor );
 2339       }
 2340   
 2341       /**
 2342        * Returns the array of Notifications always generated by the
 2343        * RequiredModelMBean.
 2344        * <P>
 2345        *
 2346        * RequiredModelMBean may always send also two additional notifications:
 2347        * <UL>
 2348        *   <LI> One with descriptor <code>"name=GENERIC,descriptorType=notification,log=T,severity=6,displayName=jmx.modelmbean.generic"</code></LI>
 2349        *   <LI> Second is a standard attribute change notification
 2350        *        with descriptor <code>"name=ATTRIBUTE_CHANGE,descriptorType=notification,log=T,severity=6,displayName=jmx.attribute.change"</code></LI>
 2351        * </UL>
 2352        * Thus these two notifications are always added to those specified
 2353        * by the application.
 2354        *
 2355        * @return MBeanNotificationInfo[]
 2356        *
 2357        **/
 2358       public MBeanNotificationInfo[] getNotificationInfo() {
 2359           if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
 2360               MODELMBEAN_LOGGER.logp(Level.FINER,
 2361                       RequiredModelMBean.class.getName(),
 2362                   "getNotificationInfo()","Entry");
 2363           }
 2364   
 2365           // Using hasNotification() is not optimal, but shouldn't really
 2366           // matter in this context...
 2367   
 2368           // hasGeneric==true if GENERIC notification is present.
 2369           // (bug 4744667)
 2370           final boolean hasGeneric = hasNotification(modelMBeanInfo,"GENERIC");
 2371   
 2372           // hasAttributeChange==true if ATTRIBUTE_CHANGE notification is
 2373           // present.
 2374           // (bug 4744667)
 2375           final boolean hasAttributeChange =
 2376              hasNotification(modelMBeanInfo,"ATTRIBUTE_CHANGE");
 2377   
 2378           // User supplied list of notification infos.
 2379           //
 2380           final ModelMBeanNotificationInfo[] currInfo =
 2381              (ModelMBeanNotificationInfo[])modelMBeanInfo.getNotifications();
 2382   
 2383           // Length of the returned list of notification infos:
 2384           //    length of user suplied list + possibly 1 for GENERIC, +
 2385           //    possibly 1 for ATTRIBUTE_CHANGE
 2386           //    (bug 4744667)
 2387           final int len = ((currInfo==null?0:currInfo.length) +
 2388                            (hasGeneric?0:1) + (hasAttributeChange?0:1));
 2389   
 2390           // Returned list of notification infos:
 2391           //
 2392           final ModelMBeanNotificationInfo[] respInfo =
 2393              new ModelMBeanNotificationInfo[len];
 2394   
 2395           // Preserve previous ordering (JMX 1.1)
 2396           //
 2397   
 2398           // Counter of "standard" notification inserted before user
 2399           // supplied notifications.
 2400           //
 2401           int inserted=0;
 2402           if (!hasGeneric)
 2403               // We need to add description for GENERIC notification
 2404               // (bug 4744667)
 2405               respInfo[inserted++] = makeGenericInfo();
 2406   
 2407   
 2408           if (!hasAttributeChange)
 2409               // We need to add description for ATTRIBUTE_CHANGE notification
 2410               // (bug 4744667)
 2411               respInfo[inserted++] = makeAttributeChangeInfo();
 2412   
 2413           // Now copy user supplied list in returned list.
 2414           //
 2415           final int count  = currInfo.length;
 2416           final int offset = inserted;
 2417           for (int j=0; j < count; j++) {
 2418               respInfo[offset+j] = currInfo[j];
 2419           }
 2420   
 2421           if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
 2422               MODELMBEAN_LOGGER.logp(Level.FINER,
 2423                       RequiredModelMBean.class.getName(),
 2424                   "getNotificationInfo()","Exit");
 2425           }
 2426   
 2427           return respInfo;
 2428       }
 2429   
 2430   
 2431       public void addAttributeChangeNotificationListener(NotificationListener
 2432                                                          inlistener,
 2433                                                          String
 2434                                                          inAttributeName,
 2435                                                          Object inhandback)
 2436           throws MBeanException, RuntimeOperationsException,
 2437                  IllegalArgumentException {
 2438           final String mth="addAttributeChangeNotificationListener(" +
 2439                   "NotificationListener, String, Object)";
 2440   
 2441           if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
 2442               MODELMBEAN_LOGGER.logp(Level.FINER,
 2443                       RequiredModelMBean.class.getName(),mth,"Entry");
 2444           }
 2445   
 2446           if (inlistener == null)
 2447               throw new IllegalArgumentException(
 2448                     "Listener to be registered must not be null");
 2449   
 2450   
 2451           if (attributeBroadcaster == null)
 2452               attributeBroadcaster = new NotificationBroadcasterSupport();
 2453   
 2454           AttributeChangeNotificationFilter currFilter =
 2455               new AttributeChangeNotificationFilter();
 2456   
 2457           MBeanAttributeInfo[] attrInfo = modelMBeanInfo.getAttributes();
 2458           boolean found = false;
 2459           if (inAttributeName == null) {
 2460               if ((attrInfo != null) && (attrInfo.length>0)) {
 2461                   for (int i=0; i<attrInfo.length; i++) {
 2462                       currFilter.enableAttribute(attrInfo[i].getName());
 2463                   }
 2464               }
 2465           } else {
 2466               if ((attrInfo != null) && (attrInfo.length>0)) {
 2467                   for (int i=0; i<attrInfo.length; i++) {
 2468                       if (inAttributeName.equals(attrInfo[i].getName())) {
 2469                           found = true;
 2470                           currFilter.enableAttribute(inAttributeName);
 2471                           break;
 2472                       }
 2473                   }
 2474               }
 2475               if (!found) {
 2476                   throw new RuntimeOperationsException(new
 2477                       IllegalArgumentException(
 2478                       "The attribute name does not exist"),
 2479                       "Exception occurred trying to add an "+
 2480                       "AttributeChangeNotification listener");
 2481               }
 2482           }
 2483   
 2484           if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
 2485               Vector<String> enabledAttrs = currFilter.getEnabledAttributes();
 2486               String s = (enabledAttrs.size() > 1) ?
 2487                           "[" + enabledAttrs.firstElement() + ", ...]" :
 2488                           enabledAttrs.toString();
 2489               MODELMBEAN_LOGGER.logp(Level.FINER,
 2490                       RequiredModelMBean.class.getName(), mth,
 2491                   "Set attribute change filter to " + s);
 2492           }
 2493   
 2494           attributeBroadcaster.addNotificationListener(inlistener,currFilter,
 2495                                                        inhandback);
 2496           if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
 2497               MODELMBEAN_LOGGER.logp(Level.FINER,
 2498                       RequiredModelMBean.class.getName(),mth,
 2499                       "Notification listener added for " + inAttributeName);
 2500               MODELMBEAN_LOGGER.logp(Level.FINER,
 2501                       RequiredModelMBean.class.getName(),mth,"Exit");
 2502           }
 2503       }
 2504   
 2505       public void removeAttributeChangeNotificationListener(
 2506               NotificationListener inlistener, String inAttributeName)
 2507           throws MBeanException, RuntimeOperationsException,
 2508                  ListenerNotFoundException {
 2509           if (inlistener == null) throw new
 2510               ListenerNotFoundException("Notification listener is null");
 2511   
 2512           final String mth = "removeAttributeChangeNotificationListener(" +
 2513                   "NotificationListener, String)";
 2514   
 2515           if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
 2516               MODELMBEAN_LOGGER.logp(Level.FINER,
 2517                       RequiredModelMBean.class.getName(),mth,"Entry");
 2518           }
 2519   
 2520   
 2521           if (attributeBroadcaster == null)
 2522               throw new ListenerNotFoundException(
 2523                     "No attribute change notification listeners registered");
 2524   
 2525   
 2526           MBeanAttributeInfo[] attrInfo = modelMBeanInfo.getAttributes();
 2527           boolean found = false;
 2528           if ((attrInfo != null) && (attrInfo.length>0)) {
 2529               for (int i=0; i<attrInfo.length; i++) {
 2530                   if (attrInfo[i].getName().equals(inAttributeName)) {
 2531                       found = true;
 2532                       break;
 2533                   }
 2534               }
 2535           }
 2536   
 2537           if ((!found) && (inAttributeName != null)) {
 2538               throw new RuntimeOperationsException(new
 2539                   IllegalArgumentException("Invalid attribute name"),
 2540                   "Exception occurred trying to remove "+
 2541                   "attribute change notification listener");
 2542           }
 2543   
 2544           /* note: */
 2545           /* this may be a problem if the same listener is registered for
 2546              multiple attributes with multiple filters and/or handback
 2547              objects.  It may remove all of them */
 2548   
 2549           attributeBroadcaster.removeNotificationListener(inlistener);
 2550   
 2551           if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
 2552               MODELMBEAN_LOGGER.logp(Level.FINER,
 2553                       RequiredModelMBean.class.getName(),mth,"Exit");
 2554           }
 2555       }
 2556   
 2557       public void sendAttributeChangeNotification(AttributeChangeNotification
 2558                                                   ntfyObj)
 2559           throws MBeanException, RuntimeOperationsException {
 2560           final String mth = "sendAttributeChangeNotification(" +
 2561                   "AttributeChangeNotification)";
 2562   
 2563           if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
 2564               MODELMBEAN_LOGGER.logp(Level.FINER,
 2565                       RequiredModelMBean.class.getName(),mth,"Entry");
 2566           }
 2567   
 2568           if (ntfyObj == null)
 2569               throw new RuntimeOperationsException(new
 2570                   IllegalArgumentException(
 2571                   "attribute change notification object must not be null"),
 2572                   "Exception occurred trying to send "+
 2573                   "attribute change notification of a ModelMBean");
 2574   
 2575           Object oldv = ntfyObj.getOldValue();
 2576           Object newv =  ntfyObj.getNewValue();
 2577   
 2578           if (oldv == null) oldv = "null";
 2579           if (newv == null) newv = "null";
 2580   
 2581           if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
 2582               MODELMBEAN_LOGGER.logp(Level.FINER,
 2583                       RequiredModelMBean.class.getName(),mth,
 2584                   "Sending AttributeChangeNotification with " +
 2585                   ntfyObj.getAttributeName() + ntfyObj.getAttributeType() +
 2586                   ntfyObj.getNewValue() + ntfyObj.getOldValue());
 2587           }
 2588   
 2589           // log notification if specified in descriptor
 2590           Descriptor ntfyDesc =
 2591               modelMBeanInfo.getDescriptor(ntfyObj.getType(),"notification");
 2592           Descriptor mmbDesc = modelMBeanInfo.getMBeanDescriptor();
 2593   
 2594           String logging, logfile;
 2595   
 2596           if (ntfyDesc != null) {
 2597               logging =(String)  ntfyDesc.getFieldValue("log");
 2598               if (logging == null) {
 2599                   if (mmbDesc != null)
 2600                       logging = (String) mmbDesc.getFieldValue("log");
 2601               }
 2602               if ((logging != null) &&
 2603                   ( logging.equalsIgnoreCase("t") ||
 2604                     logging.equalsIgnoreCase("true"))) {
 2605                   logfile = (String) ntfyDesc.getFieldValue("logfile");
 2606                   if (logfile == null) {
 2607                       if (mmbDesc != null)
 2608                           logfile = (String)mmbDesc.getFieldValue("logfile");
 2609                   }
 2610   
 2611                   if (logfile != null) {
 2612                       try {
 2613                           writeToLog(logfile,"LogMsg: " +
 2614                              ((new Date(ntfyObj.getTimeStamp())).toString())+
 2615                              " " + ntfyObj.getType() + " " +
 2616                              ntfyObj.getMessage() +
 2617                              " Name = " + ntfyObj.getAttributeName() +
 2618                              " Old value = " + oldv +
 2619                              " New value = " + newv);
 2620                       } catch (Exception e) {
 2621                           if (MODELMBEAN_LOGGER.isLoggable(Level.FINE)) {
 2622                               MODELMBEAN_LOGGER.logp(Level.FINE,
 2623                                       RequiredModelMBean.class.getName(),mth,
 2624                                   "Failed to log " + ntfyObj.getType() +
 2625                                       " notification: ", e);
 2626                           }
 2627                       }
 2628                   }
 2629               }
 2630           } else if (mmbDesc != null) {
 2631               logging = (String) mmbDesc.getFieldValue("log");
 2632               if ((logging != null) &&
 2633                   ( logging.equalsIgnoreCase("t") ||
 2634                     logging.equalsIgnoreCase("true") )) {
 2635                   logfile = (String) mmbDesc.getFieldValue("logfile");
 2636   
 2637                   if (logfile != null) {
 2638                       try {
 2639                           writeToLog(logfile,"LogMsg: " +
 2640                              ((new Date(ntfyObj.getTimeStamp())).toString())+
 2641                              " " + ntfyObj.getType() + " " +
 2642                              ntfyObj.getMessage() +
 2643                              " Name = " + ntfyObj.getAttributeName() +
 2644                              " Old value = " + oldv +
 2645                              " New value = " + newv);
 2646                       } catch (Exception e) {
 2647                           if (MODELMBEAN_LOGGER.isLoggable(Level.FINE)) {
 2648                               MODELMBEAN_LOGGER.logp(Level.FINE,
 2649                                       RequiredModelMBean.class.getName(),mth,
 2650                                   "Failed to log " + ntfyObj.getType() +
 2651                                       " notification: ", e);
 2652                           }
 2653                       }
 2654                   }
 2655               }
 2656           }
 2657           if (attributeBroadcaster != null) {
 2658               attributeBroadcaster.sendNotification(ntfyObj);
 2659           }
 2660   
 2661           // XXX Revisit: This is a quickfix: it would be better to have a
 2662           //     single broadcaster. However, it is not so simple because
 2663           //     removeAttributeChangeNotificationListener() should
 2664           //     remove only listeners whose filter is an instanceof
 2665           //     AttributeChangeNotificationFilter.
 2666           //
 2667           if (generalBroadcaster != null) {
 2668               generalBroadcaster.sendNotification(ntfyObj);
 2669           }
 2670   
 2671           if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
 2672               MODELMBEAN_LOGGER.logp(Level.FINER,
 2673                       RequiredModelMBean.class.getName(),mth,
 2674                   "sent notification");
 2675               MODELMBEAN_LOGGER.logp(Level.FINER,
 2676                       RequiredModelMBean.class.getName(),mth,
 2677                   "Exit");
 2678           }
 2679       }
 2680   
 2681       public void sendAttributeChangeNotification(Attribute inOldVal,
 2682                                                   Attribute inNewVal)
 2683           throws MBeanException, RuntimeOperationsException {
 2684           final String mth =
 2685               "sendAttributeChangeNotification(Attribute, Attribute)";
 2686           if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
 2687               MODELMBEAN_LOGGER.logp(Level.FINER,
 2688                       RequiredModelMBean.class.getName(),mth,
 2689                   "Entry");
 2690           }
 2691   
 2692           // do we really want to do this?
 2693           if ((inOldVal == null) || (inNewVal == null))
 2694               throw new RuntimeOperationsException(new
 2695                  IllegalArgumentException("Attribute object must not be null"),
 2696                  "Exception occurred trying to send " +
 2697                  "attribute change notification of a ModelMBean");
 2698   
 2699   
 2700           if (!(inOldVal.getName().equals(inNewVal.getName())))
 2701               throw new RuntimeOperationsException(new
 2702                   IllegalArgumentException("Attribute names are not the same"),
 2703                   "Exception occurred trying to send " +
 2704                   "attribute change notification of a ModelMBean");
 2705   
 2706   
 2707           Object newVal = inNewVal.getValue();
 2708           Object oldVal = inOldVal.getValue();
 2709           String className = "unknown";
 2710           if (newVal != null)
 2711               className = newVal.getClass().getName();
 2712           if (oldVal != null)
 2713               className = oldVal.getClass().getName();
 2714   
 2715           AttributeChangeNotification myNtfyObj = new
 2716               AttributeChangeNotification(this,
 2717                                           1,
 2718                                           ((new Date()).getTime()),
 2719                                           "AttributeChangeDetected",
 2720                                           inOldVal.getName(),
 2721                                           className,
 2722                                           inOldVal.getValue(),
 2723                                           inNewVal.getValue());
 2724   
 2725           sendAttributeChangeNotification(myNtfyObj);
 2726   
 2727           if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
 2728               MODELMBEAN_LOGGER.logp(Level.FINER,
 2729                       RequiredModelMBean.class.getName(),mth,
 2730                   "Exit");
 2731           }
 2732   
 2733       }
 2734   
 2735       /**
 2736        * Return the Class Loader Repository used to perform class loading.
 2737        * Subclasses may wish to redefine this method in order to return
 2738        * the appropriate {@link javax.management.loading.ClassLoaderRepository}
 2739        * that should be used in this object.
 2740        *
 2741        * @return the Class Loader Repository.
 2742        *
 2743        */
 2744       protected ClassLoaderRepository getClassLoaderRepository() {
 2745           return MBeanServerFactory.getClassLoaderRepository(server);
 2746       }
 2747   
 2748       private Class<?> loadClass(String className)
 2749           throws ClassNotFoundException {
 2750           try {
 2751               return Class.forName(className);
 2752           } catch (ClassNotFoundException e) {
 2753               final ClassLoaderRepository clr =
 2754                   getClassLoaderRepository();
 2755               if (clr == null) throw new ClassNotFoundException(className);
 2756               return clr.loadClass(className);
 2757           }
 2758       }
 2759   
 2760   
 2761       /*************************************/
 2762       /* MBeanRegistration Interface       */
 2763       /*************************************/
 2764   
 2765       /**
 2766        * Allows the MBean to perform any operations it needs before
 2767        * being registered in the MBean server.  If the name of the MBean
 2768        * is not specified, the MBean can provide a name for its
 2769        * registration.  If any exception is raised, the MBean will not be
 2770        * registered in the MBean server.
 2771        * <P>
 2772        * In order to ensure proper run-time semantics of RequireModelMBean,
 2773        * Any subclass of RequiredModelMBean overloading or overriding this
 2774        * method should call <code>super.preRegister(server, name)</code>
 2775        * in its own <code>preRegister</code> implementation.
 2776        *
 2777        * @param server The MBean server in which the MBean will be registered.
 2778        *
 2779        * @param name The object name of the MBean.  This name is null if
 2780        * the name parameter to one of the <code>createMBean</code> or
 2781        * <code>registerMBean</code> methods in the {@link MBeanServer}
 2782        * interface is null.  In that case, this method must return a
 2783        * non-null ObjectName for the new MBean.
 2784        *
 2785        * @return The name under which the MBean is to be registered.
 2786        * This value must not be null.  If the <code>name</code>
 2787        * parameter is not null, it will usually but not necessarily be
 2788        * the returned value.
 2789        *
 2790        * @exception java.lang.Exception This exception will be caught by
 2791        * the MBean server and re-thrown as an
 2792        * {@link javax.management.MBeanRegistrationException
 2793        * MBeanRegistrationException}.
 2794        */
 2795       public ObjectName preRegister(MBeanServer server,
 2796                                     ObjectName name)
 2797           throws java.lang.Exception  {
 2798           // Since ModelMbeanInfo cannot be null (otherwise exception
 2799           // thrown at creation)
 2800           // no exception thrown on ModelMBeanInfo not set.
 2801           if (name == null) throw new NullPointerException(
 2802                        "name of RequiredModelMBean to registered is null");
 2803           this.server = server;
 2804           return name;
 2805       }
 2806   
 2807       /**
 2808        * Allows the MBean to perform any operations needed after having been
 2809        * registered in the MBean server or after the registration has failed.
 2810        * <P>
 2811        * In order to ensure proper run-time semantics of RequireModelMBean,
 2812        * Any subclass of RequiredModelMBean overloading or overriding this
 2813        * method should call <code>super.postRegister(registrationDone)</code>
 2814        * in its own <code>postRegister</code> implementation.
 2815        *
 2816        * @param registrationDone Indicates whether or not the MBean has
 2817        * been successfully registered in the MBean server. The value
 2818        * false means that the registration phase has failed.
 2819        */
 2820       public void postRegister(Boolean registrationDone) {
 2821           registered = registrationDone.booleanValue();
 2822       }
 2823   
 2824       /**
 2825        * Allows the MBean to perform any operations it needs before
 2826        * being unregistered by the MBean server.
 2827        * <P>
 2828        * In order to ensure proper run-time semantics of RequireModelMBean,
 2829        * Any subclass of RequiredModelMBean overloading or overriding this
 2830        * method should call <code>super.preDeregister()</code> in its own
 2831        * <code>preDeregister</code> implementation.
 2832        *
 2833        * @exception java.lang.Exception This exception will be caught by
 2834        * the MBean server and re-thrown as an
 2835        * {@link javax.management.MBeanRegistrationException
 2836        * MBeanRegistrationException}.
 2837        */
 2838       public void preDeregister() throws java.lang.Exception {
 2839       }
 2840   
 2841       /**
 2842        * Allows the MBean to perform any operations needed after having been
 2843        * unregistered in the MBean server.
 2844        * <P>
 2845        * In order to ensure proper run-time semantics of RequireModelMBean,
 2846        * Any subclass of RequiredModelMBean overloading or overriding this
 2847        * method should call <code>super.postDeregister()</code> in its own
 2848        * <code>postDeregister</code> implementation.
 2849        */
 2850       public void postDeregister() {
 2851           registered = false;
 2852           this.server=null;
 2853       }
 2854   
 2855       private static final String[] primitiveTypes;
 2856       private static final String[] primitiveWrappers;
 2857       static {
 2858           primitiveTypes = new String[] {
 2859               Boolean.TYPE.getName(),
 2860               Byte.TYPE.getName(),
 2861               Character.TYPE.getName(),
 2862               Short.TYPE.getName(),
 2863               Integer.TYPE.getName(),
 2864               Long.TYPE.getName(),
 2865               Float.TYPE.getName(),
 2866               Double.TYPE.getName(),
 2867               Void.TYPE.getName()
 2868           };
 2869           primitiveWrappers = new String[] {
 2870               Boolean.class.getName(),
 2871               Byte.class.getName(),
 2872               Character.class.getName(),
 2873               Short.class.getName(),
 2874               Integer.class.getName(),
 2875               Long.class.getName(),
 2876               Float.class.getName(),
 2877               Double.class.getName(),
 2878               Void.class.getName()
 2879           };
 2880       }
 2881   }

Home » openjdk-7 » javax » management » modelmbean » [javadoc | source]