Save This Page
Home » openjdk-7 » javax » management » modelmbean » [javadoc | source]
    1   /*
    2    * Portions Copyright 2000-2007 Sun Microsystems, Inc.  All Rights Reserved.
    3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    4    *
    5    * This code is free software; you can redistribute it and/or modify it
    6    * under the terms of the GNU General Public License version 2 only, as
    7    * published by the Free Software Foundation.  Sun designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Sun in the LICENSE file that accompanied this code.
   10    *
   11    * This code is distributed in the hope that it will be useful, but WITHOUT
   12    * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   13    * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   14    * version 2 for more details (a copy is included in the LICENSE file that
   15    * accompanied this code).
   16    *
   17    * You should have received a copy of the GNU General Public License version
   18    * 2 along with this work; if not, write to the Free Software Foundation,
   19    * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   20    *
   21    * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
   22    * CA 95054 USA or visit www.sun.com if you need additional information or
   23    * have any questions.
   24    */
   25   /*
   26    * @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       /* records the registering in MBeanServer */
  137       private boolean registered = false;
  138       private transient MBeanServer server = null;
  139   
  140       /*************************************/
  141       /* constructors                      */
  142       /*************************************/
  143   
  144       /**
  145        * Constructs an <CODE>RequiredModelMBean</CODE> with an empty
  146        * ModelMBeanInfo.
  147        * <P>
  148        * The RequiredModelMBean's MBeanInfo and Descriptors
  149        * can be customized using the {@link #setModelMBeanInfo} method.
  150        * After the RequiredModelMBean's MBeanInfo and Descriptors are
  151        * customized, the RequiredModelMBean can be registered with
  152        * the MBeanServer.
  153        *
  154        * @exception MBeanException Wraps a distributed communication Exception.
  155        *
  156        * @exception RuntimeOperationsException Wraps a {@link
  157        * RuntimeException} during the construction of the object.
  158        **/
  159       public RequiredModelMBean()
  160           throws MBeanException, RuntimeOperationsException {
  161           if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
  162               MODELMBEAN_LOGGER.logp(Level.FINER,
  163                       RequiredModelMBean.class.getName(),
  164                       "RequiredModelMBean()", "Entry");
  165           }
  166           modelMBeanInfo = createDefaultModelMBeanInfo();
  167           if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
  168               MODELMBEAN_LOGGER.logp(Level.FINER,
  169                       RequiredModelMBean.class.getName(),
  170                       "RequiredModelMBean()", "Exit");
  171           }
  172       }
  173   
  174       /**
  175        * Constructs a RequiredModelMBean object using ModelMBeanInfo passed in.
  176        * As long as the RequiredModelMBean is not registered
  177        * with the MBeanServer yet, the RequiredModelMBean's MBeanInfo and
  178        * Descriptors can be customized using the {@link #setModelMBeanInfo}
  179        * method.
  180        * After the RequiredModelMBean's MBeanInfo and Descriptors are
  181        * customized, the RequiredModelMBean can be registered with the
  182        * MBeanServer.
  183        *
  184        * @param mbi The ModelMBeanInfo object to be used by the
  185        *            RequiredModelMBean. The given ModelMBeanInfo is cloned
  186        *            and modified as specified by {@link #setModelMBeanInfo}
  187        *
  188        * @exception MBeanException Wraps a distributed communication Exception.
  189        * @exception RuntimeOperationsException Wraps an
  190        *    {link java.lang.IllegalArgumentException}:
  191        *          The MBeanInfo passed in parameter is null.
  192        *
  193        **/
  194       public RequiredModelMBean(ModelMBeanInfo mbi)
  195           throws MBeanException, RuntimeOperationsException {
  196   
  197           if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
  198               MODELMBEAN_LOGGER.logp(Level.FINER,
  199                       RequiredModelMBean.class.getName(),
  200                       "RequiredModelMBean(MBeanInfo)", "Entry");
  201           }
  202           setModelMBeanInfo(mbi);
  203   
  204           if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
  205               MODELMBEAN_LOGGER.logp(Level.FINER,
  206                       RequiredModelMBean.class.getName(),
  207                       "RequiredModelMBean(MBeanInfo)", "Exit");
  208           }
  209       }
  210   
  211   
  212       /*************************************/
  213       /* initializers                      */
  214       /*************************************/
  215   
  216       /**
  217        * Initializes a ModelMBean object using ModelMBeanInfo passed in.
  218        * This method makes it possible to set a customized ModelMBeanInfo on
  219        * the ModelMBean as long as it is not registered with the MBeanServer.
  220        * <br>
  221        * Once the ModelMBean's ModelMBeanInfo (with Descriptors) are
  222        * customized and set on the ModelMBean, the  ModelMBean be
  223        * registered with the MBeanServer.
  224        * <P>
  225        * If the ModelMBean is currently registered, this method throws
  226        * a {@link javax.management.RuntimeOperationsException} wrapping an
  227        * {@link IllegalStateException}
  228        * <P>
  229        * If the given <var>inModelMBeanInfo</var> does not contain any
  230        * {@link ModelMBeanNotificationInfo} for the <code>GENERIC</code>
  231        * or <code>ATTRIBUTE_CHANGE</code> notifications, then the
  232        * RequiredModelMBean will supply its own default
  233        * {@link ModelMBeanNotificationInfo ModelMBeanNotificationInfo}s for
  234        * those missing notifications.
  235        *
  236        * @param mbi The ModelMBeanInfo object to be used
  237        *        by the ModelMBean.
  238        *
  239        * @exception MBeanException Wraps a distributed communication
  240        *        Exception.
  241        * @exception RuntimeOperationsException
  242        * <ul><li>Wraps an {@link IllegalArgumentException} if
  243        *         the MBeanInfo passed in parameter is null.</li>
  244        *     <li>Wraps an {@link IllegalStateException} if the ModelMBean
  245        *         is currently registered in the MBeanServer.</li>
  246        * </ul>
  247        *
  248        **/
  249       public void setModelMBeanInfo(ModelMBeanInfo mbi)
  250           throws MBeanException, RuntimeOperationsException {
  251   
  252           if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
  253               MODELMBEAN_LOGGER.logp(Level.FINER,
  254                       RequiredModelMBean.class.getName(),
  255                   "setModelMBeanInfo(ModelMBeanInfo)","Entry");
  256           }
  257   
  258           if (mbi == null) {
  259               if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
  260                   MODELMBEAN_LOGGER.logp(Level.FINER,
  261                           RequiredModelMBean.class.getName(),
  262                       "setModelMBeanInfo(ModelMBeanInfo)",
  263                       "ModelMBeanInfo is null: Raising exception.");
  264               }
  265               final RuntimeException x = new
  266                   IllegalArgumentException("ModelMBeanInfo must not be null");
  267               final String exceptionText =
  268                   "Exception occurred trying to initialize the " +
  269                   "ModelMBeanInfo of the RequiredModelMBean";
  270               throw new RuntimeOperationsException(x,exceptionText);
  271           }
  272   
  273           if (registered) {
  274               if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
  275                   MODELMBEAN_LOGGER.logp(Level.FINER,
  276                           RequiredModelMBean.class.getName(),
  277                       "setModelMBeanInfo(ModelMBeanInfo)",
  278                       "RequiredMBean is registered: Raising exception.");
  279               }
  280               final String exceptionText =
  281                   "Exception occurred trying to set the " +
  282                   "ModelMBeanInfo of the RequiredModelMBean";
  283               final RuntimeException x = new IllegalStateException(
  284                "cannot call setModelMBeanInfo while ModelMBean is registered");
  285               throw new RuntimeOperationsException(x,exceptionText);
  286           }
  287   
  288           if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
  289               MODELMBEAN_LOGGER.logp(Level.FINER,
  290                       RequiredModelMBean.class.getName(),
  291                   "setModelMBeanInfo(ModelMBeanInfo)",
  292                   "Setting ModelMBeanInfo to " + printModelMBeanInfo(mbi));
  293               MODELMBEAN_LOGGER.logp(Level.FINER,
  294                       RequiredModelMBean.class.getName(),
  295                   "setModelMBeanInfo(ModelMBeanInfo)",
  296                   "ModelMBeanInfo notifications has " +
  297                   (mbi.getNotifications()).length + " elements");
  298           }
  299   
  300           modelMBeanInfo = (ModelMBeanInfo)mbi.clone();
  301   
  302           if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
  303               MODELMBEAN_LOGGER.logp(Level.FINER,
  304                       RequiredModelMBean.class.getName(),
  305                   "setModelMBeanInfo(ModelMBeanInfo)","set mbeanInfo to: "+
  306                    printModelMBeanInfo(modelMBeanInfo));
  307               MODELMBEAN_LOGGER.logp(Level.FINER,
  308                       RequiredModelMBean.class.getName(),
  309                   "setModelMBeanInfo(ModelMBeanInfo)","Exit");
  310           }
  311       }
  312   
  313   
  314       /**
  315        * Sets the instance handle of the object against which to
  316        * execute all methods in this ModelMBean management interface
  317        * (MBeanInfo and Descriptors).
  318        *
  319        * @param mr Object that is the managed resource
  320        * @param mr_type The type of reference for the managed resource.
  321        *     <br>Can be: "ObjectReference", "Handle", "IOR", "EJBHandle",
  322        *         or "RMIReference".
  323        *     <br>In this implementation only "ObjectReference" is supported.
  324        *
  325        * @exception MBeanException The initializer of the object has
  326        *            thrown an exception.
  327        * @exception InstanceNotFoundException The managed resource
  328        *            object could not be found
  329        * @exception InvalidTargetObjectTypeException The managed
  330        *            resource type should be "ObjectReference".
  331        * @exception RuntimeOperationsException Wraps a {@link
  332        *            RuntimeException} when setting the resource.
  333        **/
  334       public void setManagedResource(Object mr, String mr_type)
  335           throws MBeanException, RuntimeOperationsException,
  336                  InstanceNotFoundException, InvalidTargetObjectTypeException {
  337           if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
  338               MODELMBEAN_LOGGER.logp(Level.FINER,
  339                       RequiredModelMBean.class.getName(),
  340                   "setManagedResource(Object,String)","Entry");
  341           }
  342   
  343           // check that the mr_type is supported by this JMXAgent
  344           // only "objectReference" is supported
  345           if ((mr_type == null) ||
  346               (! mr_type.equalsIgnoreCase("objectReference"))) {
  347               if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
  348                   MODELMBEAN_LOGGER.logp(Level.FINER,
  349                           RequiredModelMBean.class.getName(),
  350                       "setManagedResource(Object,String)",
  351                       "Managed Resouce Type is not supported: " + mr_type);
  352               }
  353               throw new InvalidTargetObjectTypeException(mr_type);
  354           }
  355   
  356           if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
  357               MODELMBEAN_LOGGER.logp(Level.FINER,
  358                       RequiredModelMBean.class.getName(),
  359                   "setManagedResource(Object,String)",
  360                   "Managed Resouce is valid");
  361           }
  362           managedResource = mr;
  363   
  364           if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
  365               MODELMBEAN_LOGGER.logp(Level.FINER,
  366                       RequiredModelMBean.class.getName(),
  367                   "setManagedResource(Object, String)", "Exit");
  368           }
  369       }
  370   
  371       /**
  372        * <p>Instantiates this MBean instance with the data found for
  373        * the MBean in the persistent store.  The data loaded could include
  374        * attribute and operation values.</p>
  375        *
  376        * <p>This method should be called during construction or
  377        * initialization of this instance, and before the MBean is
  378        * registered with the MBeanServer.</p>
  379        *
  380        * <p>If the implementation of this class does not support
  381        * persistence, an {@link MBeanException} wrapping a {@link
  382        * ServiceNotFoundException} is thrown.</p>
  383        *
  384        * @exception MBeanException Wraps another exception, or
  385        * persistence is not supported
  386        * @exception RuntimeOperationsException Wraps exceptions from the
  387        * persistence mechanism
  388        * @exception InstanceNotFoundException Could not find or load
  389        * this MBean from persistent storage
  390        */
  391       public void load()
  392           throws MBeanException, RuntimeOperationsException,
  393                  InstanceNotFoundException {
  394           final ServiceNotFoundException x = new ServiceNotFoundException(
  395                                   "Persistence not supported for this MBean");
  396           throw new MBeanException(x, x.getMessage());
  397       }
  398   
  399           /**
  400        * <p>Captures the current state of this MBean instance and writes
  401        * it out to the persistent store.  The state stored could include
  402        * attribute and operation values.</p>
  403        *
  404        * <p>If the implementation of this class does not support
  405        * persistence, an {@link MBeanException} wrapping a {@link
  406        * ServiceNotFoundException} is thrown.</p>
  407        *
  408        * <p>Persistence policy from the MBean and attribute descriptor
  409        * is used to guide execution of this method. The MBean should be
  410        * stored if 'persistPolicy' field is:</p>
  411        *
  412        * <PRE>  != "never"
  413        *   = "always"
  414        *   = "onTimer" and now > 'lastPersistTime' + 'persistPeriod'
  415        *   = "NoMoreOftenThan" and now > 'lastPersistTime' + 'persistPeriod'
  416        *   = "onUnregister"
  417        * </PRE>
  418        *
  419        * <p>Do not store the MBean if 'persistPolicy' field is:</p>
  420        * <PRE>
  421        *    = "never"
  422        *    = "onUpdate"
  423        *    = "onTimer" && now < 'lastPersistTime' + 'persistPeriod'
  424        * </PRE>
  425        *
  426        * @exception MBeanException Wraps another exception, or
  427        * persistence is not supported
  428        * @exception RuntimeOperationsException Wraps exceptions from the
  429        * persistence mechanism
  430        * @exception InstanceNotFoundException Could not find/access the
  431        * persistent store
  432        */
  433       public void store()
  434           throws MBeanException, RuntimeOperationsException,
  435                  InstanceNotFoundException {
  436           final ServiceNotFoundException x = new ServiceNotFoundException(
  437                                   "Persistence not supported for this MBean");
  438           throw new MBeanException(x, x.getMessage());
  439       }
  440   
  441       /*************************************/
  442       /* DynamicMBean Interface            */
  443       /*************************************/
  444   
  445       /**
  446        * The resolveForCacheValue method checks the descriptor passed in to
  447        * see if there is a valid cached value in the descriptor.
  448        * The valid value will be in the 'value' field if there is one.
  449        * If the 'currencyTimeLimit' field in the descriptor is:
  450        * <ul>
  451        *   <li><b>&lt;0</b> Then the value is not cached and is never valid.
  452        *         Null is returned. The 'value' and 'lastUpdatedTimeStamp'
  453        *         fields are cleared.</li>
  454        *   <li><b>=0</b> Then the value is always cached and always valid.
  455        *         The 'value' field is returned.
  456        *         The 'lastUpdatedTimeStamp' field is not checked.</li>
  457        *   <li><b>&gt;0</b> Represents the number of seconds that the
  458        *         'value' field is valid.
  459        *         The 'value' field is no longer valid when
  460        *         'lastUpdatedTimeStamp' + 'currencyTimeLimit' &gt; Now.</li>
  461        * </ul>
  462        * <li>When 'value' is valid, 'valid' is returned.</li>
  463        * <li>When 'value' is no longer valid then null is returned and
  464        *     'value' and 'lastUpdatedTimeStamp' fields are cleared.</li>
  465        *
  466        **/
  467       private Object resolveForCacheValue(Descriptor descr)
  468           throws MBeanException, RuntimeOperationsException {
  469   
  470           final boolean tracing = MODELMBEAN_LOGGER.isLoggable(Level.FINER);
  471           final String mth = "resolveForCacheValue(Descriptor)";
  472           if (tracing) {
  473               MODELMBEAN_LOGGER.logp(Level.FINER,
  474                       RequiredModelMBean.class.getName(),mth,"Entry");
  475           }
  476   
  477           Object response = null;
  478           boolean resetValue = false, returnCachedValue = true;
  479           long currencyPeriod = 0;
  480   
  481           if (descr == null) {
  482               if (tracing) {
  483                   MODELMBEAN_LOGGER.logp(Level.FINER,
  484                           RequiredModelMBean.class.getName(),mth,
  485                       "Input Descriptor is null");
  486               }
  487               return response;
  488           }
  489   
  490           if (tracing) {
  491               MODELMBEAN_LOGGER.logp(Level.FINER,
  492                       RequiredModelMBean.class.getName(),
  493                       mth, "descriptor is " + descr);
  494           }
  495   
  496           final Descriptor mmbDescr = modelMBeanInfo.getMBeanDescriptor();
  497           if (mmbDescr == null) {
  498               if (tracing) {
  499                   MODELMBEAN_LOGGER.logp(Level.FINER,
  500                       RequiredModelMBean.class.getName(),
  501                           mth,"MBean Descriptor is null");
  502               }
  503               //return response;
  504           }
  505   
  506           Object objExpTime = descr.getFieldValue("currencyTimeLimit");
  507   
  508           String expTime;
  509           if (objExpTime != null) {
  510               expTime = objExpTime.toString();
  511           } else {
  512               expTime = null;
  513           }
  514   
  515           if ((expTime == null) && (mmbDescr != null)) {
  516               objExpTime = mmbDescr.getFieldValue("currencyTimeLimit");
  517               if (objExpTime != null) {
  518                   expTime = objExpTime.toString();
  519               } else {
  520                   expTime = null;
  521               }
  522           }
  523   
  524           if (expTime != null) {
  525               if (tracing) {
  526                   MODELMBEAN_LOGGER.logp(Level.FINER,
  527                       RequiredModelMBean.class.getName(),
  528                           mth,"currencyTimeLimit: " + expTime);
  529               }
  530   
  531               // convert seconds to milliseconds for time comparison
  532               currencyPeriod = ((new Long(expTime)).longValue()) * 1000;
  533               if (currencyPeriod < 0) {
  534                   /* if currencyTimeLimit is -1 then value is never cached */
  535                   returnCachedValue = false;
  536                   resetValue = true;
  537                   if (tracing) {
  538                       MODELMBEAN_LOGGER.logp(Level.FINER,
  539                               RequiredModelMBean.class.getName(),mth,
  540                           currencyPeriod + ": never Cached");
  541                   }
  542               } else if (currencyPeriod == 0) {
  543                   /* if currencyTimeLimit is 0 then value is always cached */
  544                   returnCachedValue = true;
  545                   resetValue = false;
  546                   if (tracing) {
  547                       MODELMBEAN_LOGGER.logp(Level.FINER,
  548                               RequiredModelMBean.class.getName(),mth,
  549                           "always valid Cache");
  550                   }
  551               } else {
  552                   Object objtStamp =
  553                       descr.getFieldValue("lastUpdatedTimeStamp");
  554   
  555                   String tStamp;
  556                   if (objtStamp != null) tStamp = objtStamp.toString();
  557                   else tStamp = null;
  558   
  559                   if (tracing) {
  560                       MODELMBEAN_LOGGER.logp(Level.FINER,
  561                               RequiredModelMBean.class.getName(),mth,
  562                           "lastUpdatedTimeStamp: " + tStamp);
  563                   }
  564   
  565                   if (tStamp == null)
  566                       tStamp = "0";
  567   
  568                   long lastTime = (new Long(tStamp)).longValue();
  569   
  570                   if (tracing) {
  571                       MODELMBEAN_LOGGER.logp(Level.FINER,
  572                               RequiredModelMBean.class.getName(),mth,
  573                           "currencyPeriod:" + currencyPeriod +
  574                           " lastUpdatedTimeStamp:" + lastTime);
  575                   }
  576   
  577                   long now = (new Date()).getTime();
  578   
  579                   if (now < (lastTime + currencyPeriod)) {
  580                       returnCachedValue = true;
  581                       resetValue = false;
  582                       if (tracing) {
  583                           MODELMBEAN_LOGGER.logp(Level.FINER,
  584                                   RequiredModelMBean.class.getName(),mth,
  585                               " timed valid Cache for " + now + " < " +
  586                               (lastTime + currencyPeriod));
  587                       }
  588                   } else { /* value is expired */
  589                       returnCachedValue = false;
  590                       resetValue = true;
  591                       if (tracing) {
  592                           MODELMBEAN_LOGGER.logp(Level.FINER,
  593                                   RequiredModelMBean.class.getName(),mth,
  594                               "timed expired cache for " + now + " > " +
  595                               (lastTime + currencyPeriod));
  596                       }
  597                   }
  598               }
  599               if (tracing) {
  600                   MODELMBEAN_LOGGER.logp(Level.FINER,
  601                           RequiredModelMBean.class.getName(),mth,
  602                       "returnCachedValue:" + returnCachedValue +
  603                       " resetValue: " + resetValue);
  604               }
  605   
  606               if (returnCachedValue == true) {
  607                   Object currValue = descr.getFieldValue("value");
  608                   if (currValue != null) {
  609                       /* error/validity check return value here */
  610                       response = currValue;
  611                       /* need to cast string cached value to type */
  612                       if (tracing) {
  613                           MODELMBEAN_LOGGER.logp(Level.FINER,
  614                                   RequiredModelMBean.class.getName(),mth,
  615                               "valid Cache value: " + currValue);
  616                       }
  617   
  618                   } else {
  619                       response = null;
  620                       if (tracing) {
  621                           MODELMBEAN_LOGGER.logp(Level.FINER,
  622                               RequiredModelMBean.class.getName(),
  623                                   mth,"no Cached value");
  624                       }
  625                   }
  626               }
  627   
  628               if (resetValue == true) {
  629                   /* value is not current, so remove it */
  630                   descr.removeField("lastUpdatedTimeStamp");
  631                   descr.removeField("value");
  632                   response = null;
  633                   modelMBeanInfo.setDescriptor(descr,null);
  634                   if (tracing) {
  635                       MODELMBEAN_LOGGER.logp(Level.FINER,
  636                           RequiredModelMBean.class.getName(),
  637                               mth,"reset cached value to null");
  638                   }
  639               }
  640           }
  641   
  642           if (tracing) {
  643               MODELMBEAN_LOGGER.logp(Level.FINER,
  644                       RequiredModelMBean.class.getName(),mth,"Exit");
  645           }
  646   
  647           return response;
  648       }
  649   
  650       /**
  651        * Returns the attributes, operations, constructors and notifications
  652        * that this RequiredModelMBean exposes for management.
  653        *
  654        * @return  An instance of ModelMBeanInfo allowing retrieval all
  655        *          attributes, operations, and Notifications of this MBean.
  656        *
  657        **/
  658       public MBeanInfo getMBeanInfo() {
  659   
  660           if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
  661               MODELMBEAN_LOGGER.logp(Level.FINER,
  662                       RequiredModelMBean.class.getName(),
  663                       "getMBeanInfo()","Entry");
  664           }
  665   
  666           if (modelMBeanInfo == null) {
  667               if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
  668                   MODELMBEAN_LOGGER.logp(Level.FINER,
  669                           RequiredModelMBean.class.getName(),
  670                       "getMBeanInfo()","modelMBeanInfo is null");
  671               }
  672               modelMBeanInfo = createDefaultModelMBeanInfo();
  673               //return new ModelMBeanInfo(" ", "", null, null, null, null);
  674           }
  675   
  676           if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
  677               MODELMBEAN_LOGGER.logp(Level.FINER,
  678                       RequiredModelMBean.class.getName(),
  679                   "getMBeanInfo()","ModelMBeanInfo is " +
  680                     modelMBeanInfo.getClassName() + " for " +
  681                     modelMBeanInfo.getDescription());
  682               MODELMBEAN_LOGGER.logp(Level.FINER,
  683                       RequiredModelMBean.class.getName(),
  684                   "getMBeanInfo()",printModelMBeanInfo(modelMBeanInfo));
  685           }
  686   
  687           return((MBeanInfo) modelMBeanInfo.clone());
  688       }
  689   
  690       private String printModelMBeanInfo(ModelMBeanInfo info) {
  691           final StringBuilder retStr = new StringBuilder();
  692           if (info == null) {
  693               if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
  694                   MODELMBEAN_LOGGER.logp(Level.FINER,
  695                           RequiredModelMBean.class.getName(),
  696                           "printModelMBeanInfo(ModelMBeanInfo)",
  697                           "ModelMBeanInfo to print is null, " +
  698                           "printing local ModelMBeanInfo");
  699               }
  700               info = modelMBeanInfo;
  701           }
  702   
  703           retStr.append("\nMBeanInfo for ModelMBean is:");
  704           retStr.append("\nCLASSNAME: \t"+ info.getClassName());
  705           retStr.append("\nDESCRIPTION: \t"+ info.getDescription());
  706   
  707   
  708           try {
  709               retStr.append("\nMBEAN DESCRIPTOR: \t"+
  710                             info.getMBeanDescriptor());
  711           } catch (Exception e) {
  712               retStr.append("\nMBEAN DESCRIPTOR: \t" + " is invalid");
  713           }
  714   
  715           retStr.append("\nATTRIBUTES");
  716   
  717           final MBeanAttributeInfo[] attrInfo = info.getAttributes();
  718           if ((attrInfo != null) && (attrInfo.length>0)) {
  719               for (int i=0; i<attrInfo.length; i++) {
  720                   final ModelMBeanAttributeInfo attInfo =
  721                       (ModelMBeanAttributeInfo)attrInfo[i];
  722                   retStr.append(" ** NAME: \t"+ attInfo.getName());
  723                   retStr.append("    DESCR: \t"+ attInfo.getDescription());
  724                   retStr.append("    TYPE: \t"+ attInfo.getType() +
  725                                 "    READ: \t"+ attInfo.isReadable() +
  726                                 "    WRITE: \t"+ attInfo.isWritable());
  727                   retStr.append("    DESCRIPTOR: " +
  728                                 attInfo.getDescriptor().toString());
  729               }
  730           } else {
  731               retStr.append(" ** No attributes **");
  732           }
  733   
  734           retStr.append("\nCONSTRUCTORS");
  735           final MBeanConstructorInfo[] constrInfo = info.getConstructors();
  736           if ((constrInfo != null) && (constrInfo.length > 0 )) {
  737               for (int i=0; i<constrInfo.length; i++) {
  738                   final ModelMBeanConstructorInfo ctorInfo =
  739                       (ModelMBeanConstructorInfo)constrInfo[i];
  740                   retStr.append(" ** NAME: \t"+ ctorInfo.getName());
  741                   retStr.append("    DESCR: \t"+
  742                                 ctorInfo.getDescription());
  743                   retStr.append("    PARAM: \t"+
  744                                 ctorInfo.getSignature().length +
  745                                 " parameter(s)");
  746                   retStr.append("    DESCRIPTOR: " +
  747                                 ctorInfo.getDescriptor().toString());
  748               }
  749           } else {
  750               retStr.append(" ** No Constructors **");
  751           }
  752   
  753           retStr.append("\nOPERATIONS");
  754           final MBeanOperationInfo[] opsInfo = info.getOperations();
  755           if ((opsInfo != null) && (opsInfo.length>0)) {
  756               for (int i=0; i<opsInfo.length; i++) {
  757                   final ModelMBeanOperationInfo operInfo =
  758                       (ModelMBeanOperationInfo)opsInfo[i];
  759                   retStr.append(" ** NAME: \t"+ operInfo.getName());
  760                   retStr.append("    DESCR: \t"+ operInfo.getDescription());
  761                   retStr.append("    PARAM: \t"+
  762                                 operInfo.getSignature().length +
  763                                 " parameter(s)");
  764                   retStr.append("    DESCRIPTOR: " +
  765                                 operInfo.getDescriptor().toString());
  766               }
  767           } else {
  768               retStr.append(" ** No operations ** ");
  769           }
  770   
  771           retStr.append("\nNOTIFICATIONS");
  772   
  773           MBeanNotificationInfo[] notifInfo = info.getNotifications();
  774           if ((notifInfo != null) && (notifInfo.length>0)) {
  775               for (int i=0; i<notifInfo.length; i++) {
  776                   final ModelMBeanNotificationInfo nInfo =
  777                       (ModelMBeanNotificationInfo)notifInfo[i];
  778                   retStr.append(" ** NAME: \t"+ nInfo.getName());
  779                   retStr.append("    DESCR: \t"+ nInfo.getDescription());
  780                   retStr.append("    DESCRIPTOR: " +
  781                                 nInfo.getDescriptor().toString());
  782               }
  783           } else {
  784               retStr.append(" ** No notifications **");
  785           }
  786   
  787           retStr.append(" ** ModelMBean: End of MBeanInfo ** ");
  788   
  789           return retStr.toString();
  790       }
  791   
  792       /**
  793        * Invokes a method on or through a RequiredModelMBean and returns
  794        * the result of the method execution.
  795        * <P>
  796        * If the given method to be invoked, together with the provided
  797        * signature, matches one of RequiredModelMbean
  798        * accessible methods, this one will be call. Otherwise the call to
  799        * the given method will be tried on the managed resource.
  800        * <P>
  801        * The last value returned by an operation may be cached in
  802        * the operation's descriptor which
  803        * is in the ModelMBeanOperationInfo's descriptor.
  804        * The valid value will be in the 'value' field if there is one.
  805        * If the 'currencyTimeLimit' field in the descriptor is:
  806        * <UL>
  807        * <LI><b>&lt;0</b> Then the value is not cached and is never valid.
  808        *      The operation method is invoked.
  809        *      The 'value' and 'lastUpdatedTimeStamp' fields are cleared.</LI>
  810        * <LI><b>=0</b> Then the value is always cached and always valid.
  811        *      The 'value' field is returned. If there is no 'value' field
  812        *      then the operation method is invoked for the attribute.
  813        *      The 'lastUpdatedTimeStamp' field and `value' fields are set to
  814        *      the operation's return value and the current time stamp.</LI>
  815        * <LI><b>&gt;0</b> Represents the number of seconds that the 'value'
  816        *      field is valid.
  817        *      The 'value' field is no longer valid when
  818        *      'lastUpdatedTimeStamp' + 'currencyTimeLimit' &gt; Now.
  819        *      <UL>
  820        *         <LI>When 'value' is valid, 'value' is returned.</LI>
  821        *         <LI>When 'value' is no longer valid then the operation
  822        *             method is invoked. The 'lastUpdatedTimeStamp' field
  823        *             and `value' fields are updated.</lI>
  824        *      </UL>
  825        * </LI>
  826        * </UL>
  827        *
  828        * <p><b>Note:</b> because of inconsistencies in previous versions of
  829        * this specification, it is recommended not to use negative or zero
  830        * values for <code>currencyTimeLimit</code>.  To indicate that a
  831        * cached value is never valid, omit the
  832        * <code>currencyTimeLimit</code> field.  To indicate that it is
  833        * always valid, use a very large number for this field.</p>
  834        *
  835        * @param opName The name of the method to be invoked. The
  836        *     name can be the fully qualified method name including the
  837        *     classname, or just the method name if the classname is
  838        *     defined in the 'class' field of the operation descriptor.
  839        * @param opArgs An array containing the parameters to be set
  840        *     when the operation is invoked
  841        * @param sig An array containing the signature of the
  842        *     operation. The class objects will be loaded using the same
  843        *     class loader as the one used for loading the MBean on which
  844        *     the operation was invoked.
  845        *
  846        * @return  The object returned by the method, which represents the
  847        *     result of invoking the method on the specified managed resource.
  848        *
  849        * @exception MBeanException  Wraps one of the following Exceptions:
  850        * <UL>
  851        * <LI> An Exception thrown by the managed object's invoked method.</LI>
  852        * <LI> {@link ServiceNotFoundException}: No ModelMBeanOperationInfo or
  853        *      no descriptor defined for the specified operation or the managed
  854        *      resource is null.</LI>
  855        * <LI> {@link InvalidTargetObjectTypeException}: The 'targetType'
  856        *      field value is not 'objectReference'.</LI>
  857        * </UL>
  858        * @exception ReflectionException  Wraps an {@link java.lang.Exception}
  859        *      thrown while trying to invoke the method.
  860        * @exception RuntimeOperationsException Wraps an
  861        *      {@link IllegalArgumentException} Method name is null.
  862        *
  863        **/
  864       /*
  865         The requirement to be able to invoke methods on the
  866         RequiredModelMBean class itself makes this method considerably
  867         more complicated than it might otherwise be.  Note that, unlike
  868         earlier versions, we do not allow you to invoke such methods if
  869         they are not explicitly mentioned in the ModelMBeanInfo.  Doing
  870         so was potentially a security problem, and certainly very
  871         surprising.
  872   
  873         We do not look for the method in the RequiredModelMBean class
  874         itself if:
  875         (a) there is a "targetObject" field in the Descriptor for the
  876         operation; or
  877         (b) there is a "class" field in the Descriptor for the operation
  878         and the named class is not RequiredModelMBean or one of its
  879         superinterfaces; or
  880         (c) the name of the operation is not the name of a method in
  881         RequiredModelMBean (this is just an optimization).
  882   
  883         In cases (a) and (b), if you have gone to the trouble of adding
  884         those fields specifically for this operation then presumably you
  885         do not want RequiredModelMBean's methods to be called.
  886   
  887         We have to pay attention to class loading issues.  If the
  888         "class" field is present, the named class has to be resolved
  889         relative to RequiredModelMBean's class loader to test the
  890         condition (b) above, and relative to the managed resource's
  891         class loader to ensure that the managed resource is in fact of
  892         the named class (or a subclass).  The class names in the sig
  893         array likewise have to be resolved, first against
  894         RequiredModelMBean's class loader, then against the managed
  895         resource's class loader.  There is no point in using any other
  896         loader because when we call Method.invoke we must call it on
  897         a Method that is implemented by the target object.
  898        */
  899       public Object invoke(String opName, Object[] opArgs, String[] sig)
  900               throws MBeanException, ReflectionException {
  901   
  902           final boolean tracing = MODELMBEAN_LOGGER.isLoggable(Level.FINER);
  903           final String mth = "invoke(String, Object[], String[])";
  904   
  905           if (tracing) {
  906               MODELMBEAN_LOGGER.logp(Level.FINER,
  907                       RequiredModelMBean.class.getName(), mth, "Entry");
  908           }
  909   
  910           if (opName == null) {
  911               final RuntimeException x =
  912                   new IllegalArgumentException("Method name must not be null");
  913               throw new RuntimeOperationsException(x,
  914                         "An exception occurred while trying to " +
  915                         "invoke a method on a RequiredModelMBean");
  916           }
  917   
  918           String opClassName = null;
  919           String opMethodName;
  920   
  921           // Parse for class name and method
  922           int opSplitter = opName.lastIndexOf(".");
  923           if (opSplitter > 0) {
  924               opClassName = opName.substring(0,opSplitter);
  925               opMethodName = opName.substring(opSplitter+1);
  926           } else
  927               opMethodName = opName;
  928   
  929           /* Ignore anything after a left paren.  We keep this for
  930              compatibility but it isn't specified.  */
  931           opSplitter = opMethodName.indexOf("(");
  932           if (opSplitter > 0)
  933               opMethodName = opMethodName.substring(0,opSplitter);
  934   
  935           if (tracing) {
  936               MODELMBEAN_LOGGER.logp(Level.FINER,
  937                       RequiredModelMBean.class.getName(),
  938                       mth, "Finding operation " + opName + " as " + opMethodName);
  939           }
  940   
  941           ModelMBeanOperationInfo opInfo =
  942               modelMBeanInfo.getOperation(opMethodName);
  943           if (opInfo == null) {
  944               final String msg =
  945                   "Operation " + opName + " not in ModelMBeanInfo";
  946               throw new MBeanException(new ServiceNotFoundException(msg), msg);
  947           }
  948   
  949           final Descriptor opDescr = opInfo.getDescriptor();
  950           if (opDescr == null) {
  951               final String msg = "Operation descriptor null";
  952               throw new MBeanException(new ServiceNotFoundException(msg), msg);
  953           }
  954   
  955           final Object cached = resolveForCacheValue(opDescr);
  956           if (cached != null) {
  957               if (tracing) {
  958                   MODELMBEAN_LOGGER.logp(Level.FINER,
  959                           RequiredModelMBean.class.getName(),
  960                           mth,
  961                           "Returning cached value");
  962               }
  963               return cached;
  964           }
  965   
  966           if (opClassName == null)
  967               opClassName = (String) opDescr.getFieldValue("class");
  968           // may still be null now
  969   
  970           opMethodName = (String) opDescr.getFieldValue("name");
  971           if (opMethodName == null) {
  972               final String msg =
  973                   "Method descriptor must include `name' field";
  974               throw new MBeanException(new ServiceNotFoundException(msg), msg);
  975           }
  976   
  977           final String targetTypeField = (String)
  978               opDescr.getFieldValue("targetType");
  979           if (targetTypeField != null
  980               && !targetTypeField.equalsIgnoreCase("objectReference")) {
  981               final String msg =
  982                   "Target type must be objectReference: " + targetTypeField;
  983               throw new MBeanException(new InvalidTargetObjectTypeException(msg),
  984                                        msg);
  985           }
  986   
  987           final Object targetObjectField = opDescr.getFieldValue("targetObject");
  988           if (tracing && targetObjectField != null)
  989                   MODELMBEAN_LOGGER.logp(Level.FINER,
  990                       RequiredModelMBean.class.getName(),
  991                           mth, "Found target object in descriptor");
  992   
  993           /* Now look for the method, either in RequiredModelMBean itself
  994              or in the target object.  Set "method" and "targetObject"
  995              appropriately.  */
  996           Method method;
  997           Object targetObject;
  998   
  999           method = findRMMBMethod(opMethodName, targetObjectField,
 1000                                   opClassName, sig);
 1001   
 1002           if (method != null)
 1003               targetObject = this;
 1004           else {
 1005               if (tracing) {
 1006                   MODELMBEAN_LOGGER.logp(Level.FINER,
 1007                       RequiredModelMBean.class.getName(),
 1008                           mth, "looking for method in managedResource class");
 1009               }
 1010               if (targetObjectField != null)
 1011                   targetObject = targetObjectField;
 1012               else {
 1013                   targetObject = managedResource;
 1014                   if (targetObject == null) {
 1015                       final String msg =
 1016                           "managedResource for invoke " + opName +
 1017                           " is null";
 1018                       Exception snfe = new ServiceNotFoundException(msg);
 1019                       throw new MBeanException(snfe);
 1020                   }
 1021               }
 1022   
 1023               final Class targetClass;
 1024   
 1025               if (opClassName != null) {
 1026                   try {
 1027                       final ClassLoader targetClassLoader =
 1028                           targetObject.getClass().getClassLoader();
 1029                       targetClass = Class.forName(opClassName, false,
 1030                                                   targetClassLoader);
 1031                   } catch (ClassNotFoundException e) {
 1032                       final String msg =
 1033                           "class for invoke " + opName + " not found";
 1034                       throw new ReflectionException(e, msg);
 1035                   }
 1036               } else
 1037                   targetClass = targetObject.getClass();
 1038   
 1039               method = resolveMethod(targetClass, opMethodName, sig);
 1040           }
 1041   
 1042           if (tracing) {
 1043               MODELMBEAN_LOGGER.logp(Level.FINER,
 1044                   RequiredModelMBean.class.getName(),
 1045                       mth, "found " + opMethodName + ", now invoking");
 1046           }
 1047   
 1048           final Object result =
 1049               invokeMethod(opName, method, targetObject, opArgs);
 1050   
 1051           if (tracing) {
 1052               MODELMBEAN_LOGGER.logp(Level.FINER,
 1053                   RequiredModelMBean.class.getName(),
 1054                       mth, "successfully invoked method");
 1055           }
 1056   
 1057           if (result != null)
 1058               cacheResult(opInfo, opDescr, result);
 1059   
 1060           return result;
 1061       }
 1062   
 1063       private static Method resolveMethod(Class<?> targetClass,
 1064                                           String opMethodName,
 1065                                           String[] sig)
 1066               throws ReflectionException {
 1067           final boolean tracing = MODELMBEAN_LOGGER.isLoggable(Level.FINER);
 1068   
 1069           if (tracing) {
 1070               MODELMBEAN_LOGGER.logp(Level.FINER,
 1071                   RequiredModelMBean.class.getName(),"resolveMethod",
 1072                     "resolving " + targetClass + "." + opMethodName);
 1073           }
 1074   
 1075           final Class[] argClasses;
 1076   
 1077           if (sig == null)
 1078               argClasses = null;
 1079           else {
 1080               final ClassLoader targetClassLoader = targetClass.getClassLoader();
 1081               argClasses = new Class[sig.length];
 1082               for (int i = 0; i < sig.length; i++) {
 1083                   if (tracing) {
 1084                       MODELMBEAN_LOGGER.logp(Level.FINER,
 1085                           RequiredModelMBean.class.getName(),"resolveMethod",
 1086                               "resolve type " + sig[i]);
 1087                   }
 1088                   argClasses[i] = (Class) primitiveClassMap.get(sig[i]);
 1089                   if (argClasses[i] == null) {
 1090                       try {
 1091                           argClasses[i] =
 1092                               Class.forName(sig[i], false, targetClassLoader);
 1093                       } catch (ClassNotFoundException e) {
 1094                           if (tracing) {
 1095                               MODELMBEAN_LOGGER.logp(Level.FINER,
 1096                                       RequiredModelMBean.class.getName(),
 1097                                       "resolveMethod",
 1098                                       "class not found");
 1099                           }
 1100                           final String msg = "Parameter class not found";
 1101                           throw new ReflectionException(e, msg);
 1102                       }
 1103                   }
 1104               }
 1105           }
 1106   
 1107           try {
 1108               return targetClass.getMethod(opMethodName, argClasses);
 1109           } catch (NoSuchMethodException e) {
 1110               final String msg =
 1111                   "Target method not found: " + targetClass.getName() + "." +
 1112                   opMethodName;
 1113               throw new ReflectionException(e, msg);
 1114           }
 1115       }
 1116   
 1117       /* Map e.g. "int" to int.class.  Goodness knows how many time this
 1118          particular wheel has been reinvented.  */
 1119       private static final Class[] primitiveClasses = {
 1120           int.class, long.class, boolean.class, double.class,
 1121           float.class, short.class, byte.class, char.class,
 1122       };
 1123       private static final Map<String,Class<?>> primitiveClassMap =
 1124           new HashMap<String,Class<?>>();
 1125       static {
 1126           for (int i = 0; i < primitiveClasses.length; i++) {
 1127               final Class c = primitiveClasses[i];
 1128               primitiveClassMap.put(c.getName(), c);
 1129           }
 1130       }
 1131   
 1132       /* Find a method in RequiredModelMBean as determined by the given
 1133          parameters.  Return null if there is none, or if the parameters
 1134          exclude using it.  Called from invoke. */
 1135       private static Method findRMMBMethod(String opMethodName,
 1136                                            Object targetObjectField,
 1137                                            String opClassName,
 1138                                            String[] sig) {
 1139           final boolean tracing = MODELMBEAN_LOGGER.isLoggable(Level.FINER);
 1140   
 1141           if (tracing) {
 1142               MODELMBEAN_LOGGER.logp(Level.FINER,
 1143                   RequiredModelMBean.class.getName(),
 1144                       "invoke(String, Object[], String[])",
 1145                     "looking for method in RequiredModelMBean class");
 1146           }
 1147   
 1148           if (!isRMMBMethodName(opMethodName))
 1149               return null;
 1150           if (targetObjectField != null)
 1151               return null;
 1152           final Class<RequiredModelMBean> rmmbClass = RequiredModelMBean.class;
 1153           final Class<?> targetClass;
 1154           if (opClassName == null)
 1155               targetClass = rmmbClass;
 1156           else {
 1157               try {
 1158                   final ClassLoader targetClassLoader =
 1159                       rmmbClass.getClassLoader();
 1160                   targetClass = Class.forName(opClassName, false,
 1161                                               targetClassLoader);
 1162                   if (!rmmbClass.isAssignableFrom(targetClass))
 1163                       return null;
 1164               } catch (ClassNotFoundException e) {
 1165                   return null;
 1166               }
 1167           }
 1168           try {
 1169               return resolveMethod(targetClass, opMethodName, sig);
 1170           } catch (ReflectionException e) {
 1171               return null;
 1172           }
 1173       }
 1174   
 1175       /*
 1176        * Invoke the given method, and throw the somewhat unpredictable
 1177        * appropriate exception if the method itself gets an exception.
 1178        */
 1179       private Object invokeMethod(String opName, Method method,
 1180                                   Object targetObject, Object[] opArgs)
 1181               throws MBeanException, ReflectionException {
 1182           try {
 1183               ReflectUtil.checkPackageAccess(method.getDeclaringClass());
 1184               return MethodUtil.invoke(method, targetObject, opArgs);
 1185           } catch (RuntimeErrorException ree) {
 1186               throw new RuntimeOperationsException(ree,
 1187                         "RuntimeException occurred in RequiredModelMBean "+
 1188                         "while trying to invoke operation " + opName);
 1189           } catch (RuntimeException re) {
 1190               throw new RuntimeOperationsException(re,
 1191                         "RuntimeException occurred in RequiredModelMBean "+
 1192                         "while trying to invoke operation " + opName);
 1193           } catch (IllegalAccessException iae) {
 1194               throw new ReflectionException(iae,
 1195                         "IllegalAccessException occurred in " +
 1196                         "RequiredModelMBean while trying to " +
 1197                         "invoke operation " + opName);
 1198           } catch (InvocationTargetException ite) {
 1199               Throwable mmbTargEx = ite.getTargetException();
 1200               if (mmbTargEx instanceof RuntimeException) {
 1201                   throw new MBeanException ((RuntimeException)mmbTargEx,
 1202                         "RuntimeException thrown in RequiredModelMBean "+
 1203                         "while trying to invoke operation " + opName);
 1204               } else if (mmbTargEx instanceof Error) {
 1205                   throw new RuntimeErrorException((Error)mmbTargEx,
 1206                         "Error occurred in RequiredModelMBean while trying "+
 1207                         "to invoke operation " + opName);
 1208               } else if (mmbTargEx instanceof ReflectionException) {
 1209                   throw (ReflectionException) mmbTargEx;
 1210               } else {
 1211                   throw new MBeanException ((Exception)mmbTargEx,
 1212                         "Exception thrown in RequiredModelMBean "+
 1213                         "while trying to invoke operation " + opName);
 1214               }
 1215           } catch (Error err) {
 1216               throw new RuntimeErrorException(err,
 1217                     "Error occurred in RequiredModelMBean while trying "+
 1218                     "to invoke operation " + opName);
 1219           } catch (Exception e) {
 1220               throw new ReflectionException(e,
 1221                     "Exception occurred in RequiredModelMBean while " +
 1222                     "trying to invoke operation " + opName);
 1223           }
 1224       }
 1225   
 1226       /*
 1227        * Cache the result of an operation in the descriptor, if that is
 1228        * called for by the descriptor's configuration.  Note that we
 1229        * don't remember operation parameters when caching the result, so
 1230        * this is unlikely to be useful if there are any.
 1231        */
 1232       private void cacheResult(ModelMBeanOperationInfo opInfo,
 1233                                Descriptor opDescr, Object result)
 1234               throws MBeanException {
 1235   
 1236           Descriptor mmbDesc =
 1237               modelMBeanInfo.getMBeanDescriptor();
 1238   
 1239           Object objctl =
 1240               opDescr.getFieldValue("currencyTimeLimit");
 1241           String ctl;
 1242           if (objctl != null) {
 1243               ctl = objctl.toString();
 1244           } else {
 1245               ctl = null;
 1246           }
 1247           if ((ctl == null) && (mmbDesc != null)) {
 1248               objctl =
 1249                   mmbDesc.getFieldValue("currencyTimeLimit");
 1250               if (objctl != null) {
 1251                   ctl = objctl.toString();
 1252               } else {
 1253                   ctl = null;
 1254               }
 1255           }
 1256           if ((ctl != null) && !(ctl.equals("-1"))) {
 1257               opDescr.setField("value", result);
 1258               opDescr.setField("lastUpdatedTimeStamp",
 1259                       String.valueOf((new Date()).getTime()));
 1260   
 1261   
 1262               modelMBeanInfo.setDescriptor(opDescr,
 1263                                            "operation");
 1264               if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
 1265                   MODELMBEAN_LOGGER.logp(Level.FINER,
 1266                           RequiredModelMBean.class.getName(),
 1267                           "invoke(String,Object[],Object[])",
 1268                           "new descriptor is " + opDescr);
 1269               }
 1270           }
 1271       }
 1272   
 1273       /*
 1274        * Determine whether the given name is the name of a public method
 1275        * in this class.  This is only an optimization: it prevents us
 1276        * from trying to do argument type lookups and reflection on a
 1277        * method that will obviously fail because it has the wrong name.
 1278        *
 1279        * The first time this method is called we do the reflection, and
 1280        * every other time we reuse the remembered values.
 1281        *
 1282        * It's conceivable that the (possibly malicious) first caller
 1283        * doesn't have the required permissions to do reflection, in
 1284        * which case we don't touch anything so as not to interfere
 1285        * with a later permissionful caller.
 1286        */
 1287       private static Set<String> rmmbMethodNames;
 1288       private static synchronized boolean isRMMBMethodName(String name) {
 1289           if (rmmbMethodNames == null) {
 1290               try {
 1291                   Set<String> names = new HashSet<String>();
 1292                   Method[] methods = RequiredModelMBean.class.getMethods();
 1293                   for (int i = 0; i < methods.length; i++)
 1294                       names.add(methods[i].getName());
 1295                   rmmbMethodNames = names;
 1296               } catch (Exception e) {
 1297                   return true;
 1298                   // This is only an optimization so we'll go on to discover
 1299                   // whether the name really is an RMMB method.
 1300               }
 1301           }
 1302           return rmmbMethodNames.contains(name);
 1303       }
 1304   
 1305       /**
 1306        * Returns the value of a specific attribute defined for this
 1307        * ModelMBean.
 1308        * The last value returned by an attribute may be cached in the
 1309        * attribute's descriptor.
 1310        * The valid value will be in the 'value' field if there is one.
 1311        * If the 'currencyTimeLimit' field in the descriptor is:
 1312        * <UL>
 1313        * <LI>  <b>&lt;0</b> Then the value is not cached and is never valid.
 1314        *       The getter method is invoked for the attribute.
 1315        *       The 'value' and 'lastUpdatedTimeStamp' fields are cleared.</LI>
 1316        * <LI>  <b>=0</b> Then the value is always cached and always valid.
 1317        *       The 'value' field is returned. If there is no'value' field
 1318        *       then the getter method is invoked for the attribute.
 1319        *       The 'lastUpdatedTimeStamp' field and `value' fields are set
 1320        *       to the attribute's value and the current time stamp.</LI>
 1321        * <LI>  <b>&gt;0</b> Represents the number of seconds that the 'value'
 1322        *       field is valid.
 1323        *       The 'value' field is no longer valid when
 1324        *       'lastUpdatedTimeStamp' + 'currencyTimeLimit' &gt; Now.
 1325        *   <UL>
 1326        *        <LI>When 'value' is valid, 'value' is returned.</LI>
 1327        *        <LI>When 'value' is no longer valid then the getter
 1328        *            method is invoked for the attribute.
 1329        *            The 'lastUpdatedTimeStamp' field and `value' fields
 1330        *            are updated.</LI>
 1331        *   </UL></LI>
 1332        * </UL>
 1333        *
 1334        * <p><b>Note:</b> because of inconsistencies in previous versions of
 1335        * this specification, it is recommended not to use negative or zero
 1336        * values for <code>currencyTimeLimit</code>.  To indicate that a
 1337        * cached value is never valid, omit the
 1338        * <code>currencyTimeLimit</code> field.  To indicate that it is
 1339        * always valid, use a very large number for this field.</p>
 1340        *
 1341        * <p>If the 'getMethod' field contains the name of a valid
 1342        * operation descriptor, then the method described by the
 1343        * operation descriptor is executed.  The response from the
 1344        * method is returned as the value of the attribute.  If the
 1345        * operation fails or the returned value is not compatible with
 1346        * the declared type of the attribute, an exception will be thrown.</p>
 1347        *
 1348        * <p>If no 'getMethod' field is defined then the default value of the
 1349        * attribute is returned. If the returned value is not compatible with
 1350        * the declared type of the attribute, an exception will be thrown.</p>
 1351        *
 1352        * <p>The declared type of the attribute is the String returned by
 1353        * {@link ModelMBeanAttributeInfo#getType()}.  A value is compatible
 1354        * with this type if one of the following is true:
 1355        * <ul>
 1356        * <li>the value is null;</li>
 1357        * <li>the declared name is a primitive type name (such as "int")
 1358        *     and the value is an instance of the corresponding wrapper
 1359        *     type (such as java.lang.Integer);</li>
 1360        * <li>the name of the value's class is identical to the declared name;</li>
 1361        * <li>the declared name can be loaded by the value's class loader and
 1362        *     produces a class to which the value can be assigned.</li>
 1363        * </ul>
 1364        *
 1365        * <p>In this implementation, in every case where the getMethod needs to
 1366        * be called, because the method is invoked through the standard "invoke"
 1367        * method and thus needs operationInfo, an operation must be specified
 1368        * for that getMethod so that the invocation works correctly.</p>
 1369        *
 1370        * @param attrName A String specifying the name of the
 1371        * attribute to be retrieved. It must match the name of a
 1372        * ModelMBeanAttributeInfo.
 1373        *
 1374        * @return The value of the retrieved attribute from the
 1375        * descriptor 'value' field or from the invocation of the
 1376        * operation in the 'getMethod' field of the descriptor.
 1377        *
 1378        * @exception AttributeNotFoundException The specified attribute is
 1379        *    not accessible in the MBean.
 1380        *    The following cases may result in an AttributeNotFoundException:
 1381        *    <UL>
 1382        *      <LI> No ModelMBeanInfo was found for the Model MBean.</LI>
 1383        *      <LI> No ModelMBeanAttributeInfo was found for the specified
 1384        *           attribute name.</LI>
 1385        *      <LI> The ModelMBeanAttributeInfo isReadable method returns
 1386        *           'false'.</LI>
 1387        *    </UL>
 1388        * @exception MBeanException  Wraps one of the following Exceptions:
 1389        *    <UL>
 1390        *      <LI> {@link InvalidAttributeValueException}: A wrong value type
 1391        *           was received from the attribute's getter method or
 1392        *           no 'getMethod' field defined in the descriptor for
 1393        *           the attribute and no default value exists.</LI>
 1394        *      <LI> {@link ServiceNotFoundException}: No
 1395        *           ModelMBeanOperationInfo defined for the attribute's
 1396        *           getter method or no descriptor associated with the
 1397        *           ModelMBeanOperationInfo or the managed resource is
 1398        *           null.</LI>
 1399        *      <LI> {@link InvalidTargetObjectTypeException} The 'targetType'
 1400        *           field value is not 'objectReference'.</LI>
 1401        *      <LI> An Exception thrown by the managed object's getter.</LI>
 1402        *    </UL>
 1403        * @exception ReflectionException  Wraps an {@link java.lang.Exception}
 1404        *    thrown while trying to invoke the getter.
 1405        * @exception RuntimeOperationsException Wraps an
 1406        *    {@link IllegalArgumentException}: The attribute name in
 1407        *    parameter is null.
 1408        *
 1409        * @see #setAttribute(javax.management.Attribute)
 1410        **/
 1411       public Object getAttribute(String attrName)
 1412           throws AttributeNotFoundException, MBeanException,
 1413                  ReflectionException {
 1414           if (attrName == null)
 1415               throw new RuntimeOperationsException(new
 1416                   IllegalArgumentException("attributeName must not be null"),
 1417                   "Exception occurred trying to get attribute of a " +
 1418                   "RequiredModelMBean");
 1419           final String mth = "getAttribute(String)";
 1420           final boolean tracing = MODELMBEAN_LOGGER.isLoggable(Level.FINER);
 1421           if (tracing) {
 1422               MODELMBEAN_LOGGER.logp(Level.FINER,
 1423                       RequiredModelMBean.class.getName(),
 1424                   mth, "Entry with " + attrName);
 1425           }
 1426   
 1427           /* Check attributeDescriptor for getMethod */
 1428           Object response;
 1429   
 1430           try {
 1431               if (modelMBeanInfo == null)
 1432                   throw new AttributeNotFoundException(
 1433                         "getAttribute failed: ModelMBeanInfo not found for "+
 1434                         attrName);
 1435   
 1436               ModelMBeanAttributeInfo attrInfo = modelMBeanInfo.getAttribute(attrName);
 1437               Descriptor mmbDesc = modelMBeanInfo.getMBeanDescriptor();
 1438   
 1439               if (attrInfo == null)
 1440                   throw new AttributeNotFoundException("getAttribute failed:"+
 1441                         " ModelMBeanAttributeInfo not found for " + attrName);
 1442   
 1443               Descriptor attrDescr = attrInfo.getDescriptor();
 1444               if (attrDescr != null) {
 1445                   if (!attrInfo.isReadable())
 1446                       throw new AttributeNotFoundException(
 1447                             "getAttribute failed: " + attrName +
 1448                             " is not readable ");
 1449   
 1450                   response = resolveForCacheValue(attrDescr);
 1451   
 1452                   /* return current cached value */
 1453                   if (tracing) {
 1454                       MODELMBEAN_LOGGER.logp(Level.FINER,
 1455                               RequiredModelMBean.class.getName(), mth,
 1456                           "*** cached value is " + response);
 1457                   }
 1458   
 1459                   if (response == null) {
 1460                       /* no cached value, run getMethod */
 1461                       if (tracing) {
 1462                           MODELMBEAN_LOGGER.logp(Level.FINER,
 1463                                   RequiredModelMBean.class.getName(), mth,
 1464                               "**** cached value is null - getting getMethod");
 1465                       }
 1466                       String attrGetMethod =
 1467                           (String)(attrDescr.getFieldValue("getMethod"));
 1468   
 1469                       if (attrGetMethod != null) {
 1470                           /* run method from operations descriptor */
 1471                           if (tracing) {
 1472                               MODELMBEAN_LOGGER.logp(Level.FINER,
 1473                                       RequiredModelMBean.class.getName(),
 1474                                   mth, "invoking a getMethod for " +  attrName);
 1475                           }
 1476   
 1477                           Object getResponse =
 1478                               invoke(attrGetMethod, new Object[] {},
 1479                                      new String[] {});
 1480   
 1481                           if (getResponse != null) {
 1482                               // error/validity check return value here
 1483                               if (tracing) {
 1484                                   MODELMBEAN_LOGGER.logp(Level.FINER,
 1485                                           RequiredModelMBean.class.getName(),
 1486                                           mth, "got a non-null response " +
 1487                                           "from getMethod\n");
 1488                               }
 1489   
 1490                               response = getResponse;
 1491   
 1492                               // change cached value in attribute descriptor
 1493                               Object objctl =
 1494                                   attrDescr.getFieldValue("currencyTimeLimit");
 1495   
 1496                               String ctl;
 1497                               if (objctl != null) ctl = objctl.toString();
 1498                               else ctl = null;
 1499   
 1500                               if ((ctl == null) && (mmbDesc != null)) {
 1501                                   objctl = mmbDesc.
 1502                                       getFieldValue("currencyTimeLimit");
 1503                                   if (objctl != null) ctl = objctl.toString();
 1504                                   else ctl = null;
 1505                               }
 1506   
 1507                               if ((ctl != null) && !(ctl.equals("-1"))) {
 1508                                   if (tracing) {
 1509                                       MODELMBEAN_LOGGER.logp(Level.FINER,
 1510                                               RequiredModelMBean.class.getName(),
 1511                                               mth,
 1512                                               "setting cached value and " +
 1513                                               "lastUpdatedTime in descriptor");
 1514                                   }
 1515                                   attrDescr.setField("value", response);
 1516                                   final String stamp = String.valueOf(
 1517                                       (new Date()).getTime());
 1518                                   attrDescr.setField("lastUpdatedTimeStamp",
 1519                                                      stamp);
 1520                                   attrInfo.setDescriptor(attrDescr);
 1521                                   modelMBeanInfo.setDescriptor(attrDescr,
 1522                                                                "attribute");
 1523                                   if (tracing) {
 1524                                       MODELMBEAN_LOGGER.logp(Level.FINER,
 1525                                               RequiredModelMBean.class.getName(),
 1526                                           mth,"new descriptor is " +attrDescr);
 1527                                       MODELMBEAN_LOGGER.logp(Level.FINER,
 1528                                               RequiredModelMBean.class.getName(),
 1529                                           mth,"AttributeInfo descriptor is " +
 1530                                               attrInfo.getDescriptor());
 1531                                       final String attStr = modelMBeanInfo.
 1532                                           getDescriptor(attrName,"attribute").
 1533                                               toString();
 1534                                       MODELMBEAN_LOGGER.logp(Level.FINER,
 1535                                               RequiredModelMBean.class.getName(),
 1536                                               mth,
 1537                                               "modelMBeanInfo: AttributeInfo " +
 1538                                               "descriptor is " + attStr);
 1539                                   }
 1540                               }
 1541                           } else {
 1542                               // response was invalid or really returned null
 1543                               if (tracing) {
 1544                                   MODELMBEAN_LOGGER.logp(Level.FINER,
 1545                                           RequiredModelMBean.class.getName(), mth,
 1546                                       "got a null response from getMethod\n");
 1547                               }
 1548                               response = null;
 1549                           }
 1550                       } else {
 1551                           // not getMethod so return descriptor (default) value
 1552                           String qualifier="";
 1553                           response = attrDescr.getFieldValue("value");
 1554                           if (response == null) {
 1555                               qualifier="default ";
 1556                               response = attrDescr.getFieldValue("default");
 1557                           }
 1558                           if (tracing) {
 1559                               MODELMBEAN_LOGGER.logp(Level.FINER,
 1560                                       RequiredModelMBean.class.getName(), mth,
 1561                                   "could not find getMethod for " +attrName +
 1562                                   ", returning descriptor " +qualifier + "value");
 1563                           }
 1564                           // !! cast response to right class
 1565                       }
 1566                   }
 1567   
 1568                   // make sure response class matches type field
 1569                   String respType = attrInfo.getType();
 1570                   if (response != null) {
 1571                       String responseClass = response.getClass().getName();
 1572                       if (!respType.equals(responseClass)) {
 1573                           boolean wrongType = false;
 1574                           boolean primitiveType = false;
 1575                           boolean correspondingTypes = false;
 1576                           for (int i = 0; i < primitiveTypes.length; i++) {
 1577                               if (respType.equals(primitiveTypes[i])) {
 1578                                   primitiveType = true;
 1579                                   if (responseClass.equals(primitiveWrappers[i]))
 1580                                       correspondingTypes = true;
 1581                                   break;
 1582                               }
 1583                           }
 1584                           if (primitiveType) {
 1585                               // inequality may come from primitive/wrapper class
 1586                               if (!correspondingTypes)
 1587                                   wrongType = true;
 1588                           } else {
 1589                               // inequality may come from type subclassing
 1590                               boolean subtype;
 1591                               try {
 1592                                   ClassLoader cl =
 1593                                       response.getClass().getClassLoader();
 1594                                   Class c = Class.forName(respType, true, cl);
 1595                                   subtype = c.isInstance(response);
 1596                               } catch (Exception e) {
 1597                                   subtype = false;
 1598   
 1599                                   if (tracing) {
 1600                                       MODELMBEAN_LOGGER.logp(Level.FINER,
 1601                                               RequiredModelMBean.class.getName(),
 1602                                           mth, "Exception: ",e);
 1603                                   }
 1604                               }
 1605                               if (!subtype)
 1606                                   wrongType = true;
 1607                           }
 1608                           if (wrongType) {
 1609                               if (tracing) {
 1610                                   MODELMBEAN_LOGGER.logp(Level.FINER,
 1611                                           RequiredModelMBean.class.getName(), mth,
 1612                                       "Wrong response type '" + respType + "'");
 1613                               }
 1614                               // throw exception, didn't get
 1615                               // back right attribute type
 1616                               throw new MBeanException(
 1617                                 new InvalidAttributeValueException(
 1618                                   "Wrong value type received for get attribute"),
 1619                                 "An exception occurred while trying to get an " +
 1620                                 "attribute value through a RequiredModelMBean");
 1621                           }
 1622                       }
 1623                   }
 1624               } else {
 1625                   if (tracing) {
 1626                       MODELMBEAN_LOGGER.logp(Level.FINER,
 1627                               RequiredModelMBean.class.getName(), mth,
 1628                               "getMethod failed " + attrName +
 1629                               " not in attributeDescriptor\n");
 1630                   }
 1631                   throw new MBeanException(new
 1632                       InvalidAttributeValueException(
 1633                       "Unable to resolve attribute value, " +
 1634                       "no getMethod defined in descriptor for attribute"),
 1635                       "An exception occurred while trying to get an "+
 1636                       "attribute value through a RequiredModelMBean");
 1637               }
 1638   
 1639           } catch (MBeanException mbe) {
 1640               throw mbe;
 1641           } catch (AttributeNotFoundException t) {
 1642               throw t;
 1643           } catch (Exception e) {
 1644               if (tracing) {
 1645                   MODELMBEAN_LOGGER.logp(Level.FINER,
 1646                           RequiredModelMBean.class.getName(), mth,
 1647                           "getMethod failed with " + e.getMessage() +
 1648                           " exception type " + (e.getClass()).toString());
 1649               }
 1650               throw new MBeanException(e,"An exception occurred while trying "+
 1651                         "to get an attribute value: " + e.getMessage());
 1652           }
 1653   
 1654           if (tracing) {
 1655               MODELMBEAN_LOGGER.logp(Level.FINER,
 1656                       RequiredModelMBean.class.getName(), mth, "Exit");
 1657           }
 1658   
 1659           return response;
 1660       }
 1661   
 1662       /**
 1663        * Returns the values of several attributes in the ModelMBean.
 1664        * Executes a getAttribute for each attribute name in the
 1665        * attrNames array passed in.
 1666        *
 1667        * @param attrNames A String array of names of the attributes
 1668        * to be retrieved.
 1669        *
 1670        * @return The array of the retrieved attributes.
 1671        *
 1672        * @exception RuntimeOperationsException Wraps an
 1673        * {@link IllegalArgumentException}: The object name in parameter is
 1674        * null or attributes in parameter is null.
 1675        *
 1676        * @see #setAttributes(javax.management.AttributeList)
 1677        */
 1678       public AttributeList getAttributes(String[] attrNames)      {
 1679           if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
 1680               MODELMBEAN_LOGGER.logp(Level.FINER,
 1681                       RequiredModelMBean.class.getName(),
 1682               "getAttributes(String[])","Entry");
 1683           }
 1684   
 1685           if (attrNames == null)
 1686               throw new RuntimeOperationsException(new
 1687                   IllegalArgumentException("attributeNames must not be null"),
 1688                   "Exception occurred trying to get attributes of a "+
 1689                   "RequiredModelMBean");
 1690   
 1691           AttributeList responseList = new AttributeList();
 1692           for (int i = 0; i < attrNames.length; i++) {
 1693               try {
 1694                   responseList.add(new Attribute(attrNames[i],
 1695                                        getAttribute(attrNames[i])));
 1696               } catch (Exception e) {
 1697                   // eat exceptions because interface doesn't have an
 1698                   // exception on it
 1699                   if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
 1700                       MODELMBEAN_LOGGER.logp(Level.FINER,
 1701                               RequiredModelMBean.class.getName(),
 1702                           "getAttributes(String[])",
 1703                               "Failed to get \"" + attrNames[i] + "\": ", e);
 1704                   }
 1705               }
 1706           }
 1707   
 1708           if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
 1709               MODELMBEAN_LOGGER.logp(Level.FINER,
 1710                   RequiredModelMBean.class.getName(),
 1711                       "getAttributes(String[])","Exit");
 1712           }
 1713   
 1714           return responseList;
 1715       }
 1716   
 1717       /**
 1718        * Sets the value of a specific attribute of a named ModelMBean.
 1719        *
 1720        * If the 'setMethod' field of the attribute's descriptor
 1721        * contains the name of a valid operation descriptor, then the
 1722        * method described by the operation descriptor is executed.
 1723        * In this implementation, the operation descriptor must be specified
 1724        * correctly and assigned to the modelMBeanInfo so that the 'setMethod'
 1725        * works correctly.
 1726        * The response from the method is set as the value of the attribute
 1727        * in the descriptor.
 1728        *
 1729        * <p>If currencyTimeLimit is &gt; 0, then the new value for the
 1730        * attribute is cached in the attribute descriptor's
 1731        * 'value' field and the 'lastUpdatedTimeStamp' field is set to
 1732        * the current time stamp.
 1733        *
 1734        * <p>If the persist field of the attribute's descriptor is not null
 1735        * then Persistence policy from the attribute descriptor is used to
 1736        * guide storing the attribute in a persistent store.
 1737        * <br>Store the MBean if 'persistPolicy' field is:
 1738        * <UL>
 1739        * <Li> != "never"</Li>
 1740        * <Li> = "always"</Li>
 1741        * <Li> = "onUpdate"</Li>
 1742        * <Li> = "onTimer" and now &gt; 'lastPersistTime' + 'persistPeriod'</Li>
 1743        * <Li> = "NoMoreOftenThan" and now &gt; 'lastPersistTime' +
 1744        *         'persistPeriod'</Li>
 1745        * </UL>
 1746        * Do not store the MBean if 'persistPolicy' field is:
 1747        * <UL>
 1748        * <Li> = "never"</Li>
 1749        * <Li> = "onTimer" && now &lt; 'lastPersistTime' + 'persistPeriod'</Li>
 1750        * <Li> = "onUnregister"</Li>
 1751        * <Li> = "NoMoreOftenThan" and now &lt; 'lastPersistTime' +
 1752        *        'persistPeriod'</Li>
 1753        * </UL>
 1754        *
 1755        * <p>The ModelMBeanInfo of the Model MBean is stored in a file.
 1756        *
 1757        * @param attribute The Attribute instance containing the name of
 1758        *        the attribute to be set and the value it is to be set to.
 1759        *
 1760        *
 1761        * @exception AttributeNotFoundException The specified attribute is
 1762        *   not accessible in the MBean.
 1763        *   <br>The following cases may result in an AttributeNotFoundException:
 1764        *   <UL>
 1765        *     <LI> No ModelMBeanAttributeInfo is found for the specified
 1766        *          attribute.</LI>
 1767        *     <LI> The ModelMBeanAttributeInfo's isWritable method returns
 1768        *          'false'.</LI>
 1769        *   </UL>
 1770        * @exception InvalidAttributeValueException No descriptor is defined
 1771        *   for the specified attribute.
 1772        * @exception MBeanException Wraps one of the following Exceptions:
 1773        *   <UL>
 1774        *     <LI> An Exception thrown by the managed object's setter.</LI>
 1775        *     <LI> A {@link ServiceNotFoundException} if a setMethod field is
 1776        *          defined in the descriptor for the attribute and the managed
 1777        *          resource is null; or if no setMethod field is defined and
 1778        *          caching is not enabled for the attribute.
 1779        *          Note that if there is no getMethod field either, then caching
 1780        *          is automatically enabled.</LI>
 1781        *     <LI> {@link InvalidTargetObjectTypeException} The 'targetType'
 1782        *          field value is not 'objectReference'.</LI>
 1783        *     <LI> An Exception thrown by the managed object's getter.</LI>
 1784        *   </UL>
 1785        * @exception ReflectionException  Wraps an {@link java.lang.Exception}
 1786        *   thrown while trying to invoke the setter.
 1787        * @exception RuntimeOperationsException Wraps an
 1788        *   {@link IllegalArgumentException}: The attribute in parameter is
 1789        *   null.
 1790        *
 1791        * @see #getAttribute(java.lang.String)
 1792        **/
 1793       public void setAttribute(Attribute attribute)
 1794           throws AttributeNotFoundException, InvalidAttributeValueException,
 1795                  MBeanException, ReflectionException {
 1796           final boolean tracing = MODELMBEAN_LOGGER.isLoggable(Level.FINER);
 1797           if (tracing) {
 1798               MODELMBEAN_LOGGER.logp(Level.FINER,
 1799                       RequiredModelMBean.class.getName(),
 1800                   "setAttribute()","Entry");
 1801           }
 1802   
 1803           if (attribute == null)
 1804               throw new RuntimeOperationsException(new
 1805                   IllegalArgumentException("attribute must not be null"),
 1806                   "Exception occurred trying to set an attribute of a "+
 1807                   "RequiredModelMBean");
 1808   
 1809           /* run setMethod if there is one */
 1810           /* return cached value if its current */
 1811           /* set cached value in descriptor and set date/time */
 1812           /* send attribute change Notification */
 1813           /* check persistence policy and persist if need be */
 1814           String attrName = attribute.getName();
 1815           Object attrValue = attribute.getValue();
 1816           boolean updateDescriptor = false;
 1817   
 1818           ModelMBeanAttributeInfo attrInfo =
 1819               modelMBeanInfo.getAttribute(attrName);
 1820   
 1821           if (attrInfo == null)
 1822               throw new AttributeNotFoundException("setAttribute failed: " +
 1823                                                  attrName + " is not found ");
 1824   
 1825           Descriptor mmbDesc = modelMBeanInfo.getMBeanDescriptor();
 1826           Descriptor attrDescr = attrInfo.getDescriptor();
 1827   
 1828           if (attrDescr != null) {
 1829               if (!attrInfo.isWritable())
 1830                   throw new AttributeNotFoundException("setAttribute failed: "
 1831                                             + attrName + " is not writable ");
 1832   
 1833               String attrSetMethod = (String)
 1834                   (attrDescr.getFieldValue("setMethod"));
 1835               String attrGetMethod = (String)
 1836                   (attrDescr.getFieldValue("getMethod"));
 1837   
 1838               String attrType = attrInfo.getType();
 1839               Object currValue = "Unknown";
 1840   
 1841               try {
 1842                   currValue = this.getAttribute(attrName);
 1843               } catch (Throwable t) {
 1844                   // OK: Default "Unknown" value used for unknown attribute
 1845               }
 1846   
 1847               Attribute oldAttr = new Attribute(attrName, currValue);
 1848   
 1849               /* run method from operations descriptor */
 1850               if (attrSetMethod == null) {
 1851                   if (attrValue != null) {
 1852                       try {
 1853                           final Class  clazz    = loadClass(attrType);
 1854                           if (! clazz.isInstance(attrValue))  throw new
 1855                               InvalidAttributeValueException(clazz.getName() +
 1856                                                              " expected, "   +
 1857                                               attrValue.getClass().getName() +
 1858                                                              " received.");
 1859                       } catch (ClassNotFoundException x) {
 1860                           if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
 1861                               MODELMBEAN_LOGGER.logp(Level.FINER,
 1862                                       RequiredModelMBean.class.getName(),
 1863                                   "setAttribute(Attribute)","Class " +
 1864                                       attrType + " for attribute "
 1865                                   + attrName + " not found: ", x);
 1866                           }
 1867                       }
 1868                   }
 1869                   updateDescriptor = true;
 1870               } else {
 1871                   invoke(attrSetMethod,
 1872                          (new Object[] {attrValue}),
 1873                          (new String[] {attrType}) );
 1874               }
 1875   
 1876               /* change cached value */
 1877               Object objctl = attrDescr.getFieldValue("currencyTimeLimit");
 1878               String ctl;
 1879               if (objctl != null) ctl = objctl.toString();
 1880               else ctl = null;
 1881   
 1882               if ((ctl == null) && (mmbDesc != null)) {
 1883                   objctl = mmbDesc.getFieldValue("currencyTimeLimit");
 1884                   if (objctl != null) ctl = objctl.toString();
 1885                   else ctl = null;
 1886               }
 1887   
 1888               final boolean updateCache = ((ctl != null) && !(ctl.equals("-1")));
 1889   
 1890                if(attrSetMethod == null  && !updateCache && attrGetMethod != null)
 1891                   throw new MBeanException(new ServiceNotFoundException("No " +
 1892                           "setMethod field is defined in the descriptor for " +
 1893                           attrName + " attribute and caching is not enabled " +
 1894                           "for it"));
 1895   
 1896               if (updateCache || updateDescriptor) {
 1897                   if (tracing) {
 1898                       MODELMBEAN_LOGGER.logp(Level.FINER,
 1899                           RequiredModelMBean.class.getName(),
 1900                               "setAttribute(Attribute)",
 1901                               "setting cached value of " +
 1902                               attrName + " to " + attrValue);
 1903                   }
 1904   
 1905                   attrDescr.setField("value", attrValue);
 1906   
 1907                   if (updateCache) {
 1908                       final String currtime = String.valueOf(
 1909                           (new Date()).getTime());
 1910   
 1911                       attrDescr.setField("lastUpdatedTimeStamp", currtime);
 1912                   }
 1913   
 1914                   attrInfo.setDescriptor(attrDescr);
 1915   
 1916                   modelMBeanInfo.setDescriptor(attrDescr,"attribute");
 1917                   if (tracing) {
 1918                       final StringBuilder strb = new StringBuilder()
 1919                       .append("new descriptor is ").append(attrDescr)
 1920                       .append(". AttributeInfo descriptor is ")
 1921                       .append(attrInfo.getDescriptor())
 1922                       .append(". AttributeInfo descriptor is ")
 1923                       .append(modelMBeanInfo.getDescriptor(attrName,"attribute"));
 1924                       MODELMBEAN_LOGGER.logp(Level.FINER,
 1925                               RequiredModelMBean.class.getName(),
 1926                               "setAttribute(Attribute)",strb.toString());
 1927                   }
 1928   
 1929               }
 1930   
 1931               if (tracing) {
 1932                   MODELMBEAN_LOGGER.logp(Level.FINER,
 1933                           RequiredModelMBean.class.getName(),
 1934                   "setAttribute(Attribute)","sending sendAttributeNotification");
 1935               }
 1936               sendAttributeChangeNotification(oldAttr,attribute);
 1937   
 1938           } else { // if descriptor ... else no descriptor
 1939   
 1940               if (tracing) {
 1941                       MODELMBEAN_LOGGER.logp(Level.FINER,
 1942                               RequiredModelMBean.class.getName(),
 1943                           "setAttribute(Attribute)","setMethod failed "+attrName+
 1944                           " not in attributeDescriptor\n");
 1945               }
 1946   
 1947               throw new InvalidAttributeValueException(
 1948                         "Unable to resolve attribute value, "+
 1949                         "no defined in descriptor for attribute");
 1950           } // else no descriptor
 1951   
 1952           if (tracing) {
 1953               MODELMBEAN_LOGGER.logp(Level.FINER,
 1954                       RequiredModelMBean.class.getName(),
 1955                   "setAttribute(Attribute)", "Exit");
 1956           }
 1957   
 1958       }
 1959   
 1960       /**
 1961        * Sets the values of an array of attributes of this ModelMBean.
 1962        * Executes the setAttribute() method for each attribute in the list.
 1963        *
 1964        * @param attributes A list of attributes: The identification of the
 1965        * attributes to be set and  the values they are to be set to.
 1966        *
 1967        * @return  The array of attributes that were set, with their new
 1968        *    values in Attribute instances.
 1969        *
 1970        * @exception RuntimeOperationsException Wraps an
 1971        *   {@link IllegalArgumentException}: The object name in parameter
 1972        *   is null or attributes in parameter is null.
 1973        *
 1974        * @see #getAttributes
 1975        **/
 1976       public AttributeList setAttributes(AttributeList attributes) {
 1977   
 1978           if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) {
 1979               MODELMBEAN_LOGGER.logp(Level.FINER,
 1980                       RequiredModelMBean.class.getName(),
 1981                   "setAttribute(Attribute)", "Entry");
 1982           }
 1983   
 1984           if (attributes == null)
 1985               throw new RuntimeOperationsException(new
 1986                   IllegalArgumentException("attributes must not be null"),
 1987                   "Exception occurred trying to set attributes of a "+
 1988                   "RequiredModelMBean");
 1989   
 1990           final AttributeList responseList = new AttributeList();
 1991   
 1992           // Go through the list of attributes
 1993           for (Iterator i = attributes.iterator(); i.hasNext();) {
 1994               final Attribute attr = (Attribute) i.next();
 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 l