| /* |
| * Copyright (c) 2000, 2008, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. Oracle designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Oracle in the LICENSE file that accompanied this code. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| /* |
| * @author IBM Corp. |
| * |
| * Copyright IBM Corp. 1999-2000. All rights reserved. |
| */ |
| |
| |
| package javax.management.modelmbean; |
| |
| /* java imports */ |
| |
| import static com.sun.jmx.defaults.JmxProperties.MODELMBEAN_LOGGER; |
| import java.io.FileOutputStream; |
| import java.io.PrintStream; |
| import java.lang.reflect.InvocationTargetException; |
| |
| import java.lang.reflect.Method; |
| |
| import java.util.Date; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.logging.Level; |
| import java.util.Map; |
| import java.util.Set; |
| |
| import java.util.Vector; |
| import javax.management.Attribute; |
| import javax.management.AttributeChangeNotification; |
| import javax.management.AttributeChangeNotificationFilter; |
| import javax.management.AttributeList; |
| import javax.management.AttributeNotFoundException; |
| import javax.management.Descriptor; |
| import javax.management.InstanceNotFoundException; |
| import javax.management.InvalidAttributeValueException; |
| import javax.management.ListenerNotFoundException; |
| import javax.management.MBeanAttributeInfo; |
| import javax.management.MBeanConstructorInfo; |
| import javax.management.MBeanException; |
| import javax.management.MBeanInfo; |
| import javax.management.MBeanNotificationInfo; |
| import javax.management.MBeanOperationInfo; |
| import javax.management.MBeanRegistration; |
| import javax.management.MBeanServer; |
| import javax.management.MBeanServerFactory; |
| import javax.management.Notification; |
| import javax.management.NotificationBroadcasterSupport; |
| import javax.management.NotificationEmitter; |
| import javax.management.NotificationFilter; |
| import javax.management.NotificationListener; |
| import javax.management.ObjectName; |
| import javax.management.ReflectionException; |
| import javax.management.RuntimeErrorException; |
| import javax.management.RuntimeOperationsException; |
| import javax.management.ServiceNotFoundException; |
| import javax.management.loading.ClassLoaderRepository; |
| |
| import sun.reflect.misc.MethodUtil; |
| import sun.reflect.misc.ReflectUtil; |
| |
| /** |
| * This class is the implementation of a ModelMBean. An appropriate |
| * implementation of a ModelMBean must be shipped with every JMX Agent |
| * and the class must be named RequiredModelMBean. |
| * <P> |
| * Java resources wishing to be manageable instantiate the |
| * RequiredModelMBean using the MBeanServer's createMBean method. |
| * The resource then sets the MBeanInfo and Descriptors for the |
| * RequiredModelMBean instance. The attributes and operations exposed |
| * via the ModelMBeanInfo for the ModelMBean are accessible |
| * from MBeans, connectors/adaptors like other MBeans. Through the |
| * Descriptors, values and methods in the managed application can be |
| * defined and mapped to attributes and operations of the ModelMBean. |
| * This mapping can be defined in an XML formatted file or dynamically and |
| * programmatically at runtime. |
| * <P> |
| * Every RequiredModelMBean which is instantiated in the MBeanServer |
| * becomes manageable:<br> |
| * its attributes and operations become remotely accessible through the |
| * connectors/adaptors connected to that MBeanServer. |
| * <P> |
| * A Java object cannot be registered in the MBeanServer unless it is a |
| * JMX compliant MBean. By instantiating a RequiredModelMBean, resources |
| * are guaranteed that the MBean is valid. |
| * |
| * MBeanException and RuntimeOperationsException must be thrown on every |
| * public method. This allows for wrapping exceptions from distributed |
| * communications (RMI, EJB, etc.) |
| * |
| * @since 1.5 |
| */ |
| |
| public class RequiredModelMBean |
| implements ModelMBean, MBeanRegistration, NotificationEmitter { |
| |
| /*************************************/ |
| /* attributes */ |
| /*************************************/ |
| ModelMBeanInfo modelMBeanInfo; |
| |
| /* Notification broadcaster for any notification to be sent |
| * from the application through the RequiredModelMBean. */ |
| private NotificationBroadcasterSupport generalBroadcaster = null; |
| |
| /* Notification broadcaster for attribute change notifications */ |
| private NotificationBroadcasterSupport attributeBroadcaster = null; |
| |
| /* handle, name, or reference for instance on which the actual invoke |
| * and operations will be executed */ |
| private Object managedResource = null; |
| |
| |
| /* records the registering in MBeanServer */ |
| private boolean registered = false; |
| private transient MBeanServer server = null; |
| |
| /*************************************/ |
| /* constructors */ |
| /*************************************/ |
| |
| /** |
| * Constructs an <CODE>RequiredModelMBean</CODE> with an empty |
| * ModelMBeanInfo. |
| * <P> |
| * The RequiredModelMBean's MBeanInfo and Descriptors |
| * can be customized using the {@link #setModelMBeanInfo} method. |
| * After the RequiredModelMBean's MBeanInfo and Descriptors are |
| * customized, the RequiredModelMBean can be registered with |
| * the MBeanServer. |
| * |
| * @exception MBeanException Wraps a distributed communication Exception. |
| * |
| * @exception RuntimeOperationsException Wraps a {@link |
| * RuntimeException} during the construction of the object. |
| **/ |
| public RequiredModelMBean() |
| throws MBeanException, RuntimeOperationsException { |
| if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(), |
| "RequiredModelMBean()", "Entry"); |
| } |
| modelMBeanInfo = createDefaultModelMBeanInfo(); |
| if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(), |
| "RequiredModelMBean()", "Exit"); |
| } |
| } |
| |
| /** |
| * Constructs a RequiredModelMBean object using ModelMBeanInfo passed in. |
| * As long as the RequiredModelMBean is not registered |
| * with the MBeanServer yet, the RequiredModelMBean's MBeanInfo and |
| * Descriptors can be customized using the {@link #setModelMBeanInfo} |
| * method. |
| * After the RequiredModelMBean's MBeanInfo and Descriptors are |
| * customized, the RequiredModelMBean can be registered with the |
| * MBeanServer. |
| * |
| * @param mbi The ModelMBeanInfo object to be used by the |
| * RequiredModelMBean. The given ModelMBeanInfo is cloned |
| * and modified as specified by {@link #setModelMBeanInfo} |
| * |
| * @exception MBeanException Wraps a distributed communication Exception. |
| * @exception RuntimeOperationsException Wraps an |
| * {link java.lang.IllegalArgumentException}: |
| * The MBeanInfo passed in parameter is null. |
| * |
| **/ |
| public RequiredModelMBean(ModelMBeanInfo mbi) |
| throws MBeanException, RuntimeOperationsException { |
| |
| if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(), |
| "RequiredModelMBean(MBeanInfo)", "Entry"); |
| } |
| setModelMBeanInfo(mbi); |
| |
| if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(), |
| "RequiredModelMBean(MBeanInfo)", "Exit"); |
| } |
| } |
| |
| |
| /*************************************/ |
| /* initializers */ |
| /*************************************/ |
| |
| /** |
| * Initializes a ModelMBean object using ModelMBeanInfo passed in. |
| * This method makes it possible to set a customized ModelMBeanInfo on |
| * the ModelMBean as long as it is not registered with the MBeanServer. |
| * <br> |
| * Once the ModelMBean's ModelMBeanInfo (with Descriptors) are |
| * customized and set on the ModelMBean, the ModelMBean be |
| * registered with the MBeanServer. |
| * <P> |
| * If the ModelMBean is currently registered, this method throws |
| * a {@link javax.management.RuntimeOperationsException} wrapping an |
| * {@link IllegalStateException} |
| * <P> |
| * If the given <var>inModelMBeanInfo</var> does not contain any |
| * {@link ModelMBeanNotificationInfo} for the <code>GENERIC</code> |
| * or <code>ATTRIBUTE_CHANGE</code> notifications, then the |
| * RequiredModelMBean will supply its own default |
| * {@link ModelMBeanNotificationInfo ModelMBeanNotificationInfo}s for |
| * those missing notifications. |
| * |
| * @param mbi The ModelMBeanInfo object to be used |
| * by the ModelMBean. |
| * |
| * @exception MBeanException Wraps a distributed communication |
| * Exception. |
| * @exception RuntimeOperationsException |
| * <ul><li>Wraps an {@link IllegalArgumentException} if |
| * the MBeanInfo passed in parameter is null.</li> |
| * <li>Wraps an {@link IllegalStateException} if the ModelMBean |
| * is currently registered in the MBeanServer.</li> |
| * </ul> |
| * |
| **/ |
| public void setModelMBeanInfo(ModelMBeanInfo mbi) |
| throws MBeanException, RuntimeOperationsException { |
| |
| if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(), |
| "setModelMBeanInfo(ModelMBeanInfo)","Entry"); |
| } |
| |
| if (mbi == null) { |
| if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(), |
| "setModelMBeanInfo(ModelMBeanInfo)", |
| "ModelMBeanInfo is null: Raising exception."); |
| } |
| final RuntimeException x = new |
| IllegalArgumentException("ModelMBeanInfo must not be null"); |
| final String exceptionText = |
| "Exception occurred trying to initialize the " + |
| "ModelMBeanInfo of the RequiredModelMBean"; |
| throw new RuntimeOperationsException(x,exceptionText); |
| } |
| |
| if (registered) { |
| if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(), |
| "setModelMBeanInfo(ModelMBeanInfo)", |
| "RequiredMBean is registered: Raising exception."); |
| } |
| final String exceptionText = |
| "Exception occurred trying to set the " + |
| "ModelMBeanInfo of the RequiredModelMBean"; |
| final RuntimeException x = new IllegalStateException( |
| "cannot call setModelMBeanInfo while ModelMBean is registered"); |
| throw new RuntimeOperationsException(x,exceptionText); |
| } |
| |
| if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(), |
| "setModelMBeanInfo(ModelMBeanInfo)", |
| "Setting ModelMBeanInfo to " + printModelMBeanInfo(mbi)); |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(), |
| "setModelMBeanInfo(ModelMBeanInfo)", |
| "ModelMBeanInfo notifications has " + |
| (mbi.getNotifications()).length + " elements"); |
| } |
| |
| modelMBeanInfo = (ModelMBeanInfo)mbi.clone(); |
| |
| if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(), |
| "setModelMBeanInfo(ModelMBeanInfo)","set mbeanInfo to: "+ |
| printModelMBeanInfo(modelMBeanInfo)); |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(), |
| "setModelMBeanInfo(ModelMBeanInfo)","Exit"); |
| } |
| } |
| |
| |
| /** |
| * Sets the instance handle of the object against which to |
| * execute all methods in this ModelMBean management interface |
| * (MBeanInfo and Descriptors). |
| * |
| * @param mr Object that is the managed resource |
| * @param mr_type The type of reference for the managed resource. |
| * <br>Can be: "ObjectReference", "Handle", "IOR", "EJBHandle", |
| * or "RMIReference". |
| * <br>In this implementation only "ObjectReference" is supported. |
| * |
| * @exception MBeanException The initializer of the object has |
| * thrown an exception. |
| * @exception InstanceNotFoundException The managed resource |
| * object could not be found |
| * @exception InvalidTargetObjectTypeException The managed |
| * resource type should be "ObjectReference". |
| * @exception RuntimeOperationsException Wraps a {@link |
| * RuntimeException} when setting the resource. |
| **/ |
| public void setManagedResource(Object mr, String mr_type) |
| throws MBeanException, RuntimeOperationsException, |
| InstanceNotFoundException, InvalidTargetObjectTypeException { |
| if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(), |
| "setManagedResource(Object,String)","Entry"); |
| } |
| |
| // check that the mr_type is supported by this JMXAgent |
| // only "objectReference" is supported |
| if ((mr_type == null) || |
| (! mr_type.equalsIgnoreCase("objectReference"))) { |
| if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(), |
| "setManagedResource(Object,String)", |
| "Managed Resouce Type is not supported: " + mr_type); |
| } |
| throw new InvalidTargetObjectTypeException(mr_type); |
| } |
| |
| if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(), |
| "setManagedResource(Object,String)", |
| "Managed Resouce is valid"); |
| } |
| managedResource = mr; |
| |
| if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(), |
| "setManagedResource(Object, String)", "Exit"); |
| } |
| } |
| |
| /** |
| * <p>Instantiates this MBean instance with the data found for |
| * the MBean in the persistent store. The data loaded could include |
| * attribute and operation values.</p> |
| * |
| * <p>This method should be called during construction or |
| * initialization of this instance, and before the MBean is |
| * registered with the MBeanServer.</p> |
| * |
| * <p>If the implementation of this class does not support |
| * persistence, an {@link MBeanException} wrapping a {@link |
| * ServiceNotFoundException} is thrown.</p> |
| * |
| * @exception MBeanException Wraps another exception, or |
| * persistence is not supported |
| * @exception RuntimeOperationsException Wraps exceptions from the |
| * persistence mechanism |
| * @exception InstanceNotFoundException Could not find or load |
| * this MBean from persistent storage |
| */ |
| public void load() |
| throws MBeanException, RuntimeOperationsException, |
| InstanceNotFoundException { |
| final ServiceNotFoundException x = new ServiceNotFoundException( |
| "Persistence not supported for this MBean"); |
| throw new MBeanException(x, x.getMessage()); |
| } |
| |
| /** |
| * <p>Captures the current state of this MBean instance and writes |
| * it out to the persistent store. The state stored could include |
| * attribute and operation values.</p> |
| * |
| * <p>If the implementation of this class does not support |
| * persistence, an {@link MBeanException} wrapping a {@link |
| * ServiceNotFoundException} is thrown.</p> |
| * |
| * <p>Persistence policy from the MBean and attribute descriptor |
| * is used to guide execution of this method. The MBean should be |
| * stored if 'persistPolicy' field is:</p> |
| * |
| * <PRE> != "never" |
| * = "always" |
| * = "onTimer" and now > 'lastPersistTime' + 'persistPeriod' |
| * = "NoMoreOftenThan" and now > 'lastPersistTime' + 'persistPeriod' |
| * = "onUnregister" |
| * </PRE> |
| * |
| * <p>Do not store the MBean if 'persistPolicy' field is:</p> |
| * <PRE> |
| * = "never" |
| * = "onUpdate" |
| * = "onTimer" && now < 'lastPersistTime' + 'persistPeriod' |
| * </PRE> |
| * |
| * @exception MBeanException Wraps another exception, or |
| * persistence is not supported |
| * @exception RuntimeOperationsException Wraps exceptions from the |
| * persistence mechanism |
| * @exception InstanceNotFoundException Could not find/access the |
| * persistent store |
| */ |
| public void store() |
| throws MBeanException, RuntimeOperationsException, |
| InstanceNotFoundException { |
| final ServiceNotFoundException x = new ServiceNotFoundException( |
| "Persistence not supported for this MBean"); |
| throw new MBeanException(x, x.getMessage()); |
| } |
| |
| /*************************************/ |
| /* DynamicMBean Interface */ |
| /*************************************/ |
| |
| /** |
| * The resolveForCacheValue method checks the descriptor passed in to |
| * see if there is a valid cached value in the descriptor. |
| * The valid value will be in the 'value' field if there is one. |
| * If the 'currencyTimeLimit' field in the descriptor is: |
| * <ul> |
| * <li><b><0</b> Then the value is not cached and is never valid. |
| * Null is returned. The 'value' and 'lastUpdatedTimeStamp' |
| * fields are cleared.</li> |
| * <li><b>=0</b> Then the value is always cached and always valid. |
| * The 'value' field is returned. |
| * The 'lastUpdatedTimeStamp' field is not checked.</li> |
| * <li><b>>0</b> Represents the number of seconds that the |
| * 'value' field is valid. |
| * The 'value' field is no longer valid when |
| * 'lastUpdatedTimeStamp' + 'currencyTimeLimit' > Now.</li> |
| * </ul> |
| * <li>When 'value' is valid, 'valid' is returned.</li> |
| * <li>When 'value' is no longer valid then null is returned and |
| * 'value' and 'lastUpdatedTimeStamp' fields are cleared.</li> |
| * |
| **/ |
| private Object resolveForCacheValue(Descriptor descr) |
| throws MBeanException, RuntimeOperationsException { |
| |
| final boolean tracing = MODELMBEAN_LOGGER.isLoggable(Level.FINER); |
| final String mth = "resolveForCacheValue(Descriptor)"; |
| if (tracing) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(),mth,"Entry"); |
| } |
| |
| Object response = null; |
| boolean resetValue = false, returnCachedValue = true; |
| long currencyPeriod = 0; |
| |
| if (descr == null) { |
| if (tracing) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(),mth, |
| "Input Descriptor is null"); |
| } |
| return response; |
| } |
| |
| if (tracing) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(), |
| mth, "descriptor is " + descr); |
| } |
| |
| final Descriptor mmbDescr = modelMBeanInfo.getMBeanDescriptor(); |
| if (mmbDescr == null) { |
| if (tracing) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(), |
| mth,"MBean Descriptor is null"); |
| } |
| //return response; |
| } |
| |
| Object objExpTime = descr.getFieldValue("currencyTimeLimit"); |
| |
| String expTime; |
| if (objExpTime != null) { |
| expTime = objExpTime.toString(); |
| } else { |
| expTime = null; |
| } |
| |
| if ((expTime == null) && (mmbDescr != null)) { |
| objExpTime = mmbDescr.getFieldValue("currencyTimeLimit"); |
| if (objExpTime != null) { |
| expTime = objExpTime.toString(); |
| } else { |
| expTime = null; |
| } |
| } |
| |
| if (expTime != null) { |
| if (tracing) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(), |
| mth,"currencyTimeLimit: " + expTime); |
| } |
| |
| // convert seconds to milliseconds for time comparison |
| currencyPeriod = ((new Long(expTime)).longValue()) * 1000; |
| if (currencyPeriod < 0) { |
| /* if currencyTimeLimit is -1 then value is never cached */ |
| returnCachedValue = false; |
| resetValue = true; |
| if (tracing) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(),mth, |
| currencyPeriod + ": never Cached"); |
| } |
| } else if (currencyPeriod == 0) { |
| /* if currencyTimeLimit is 0 then value is always cached */ |
| returnCachedValue = true; |
| resetValue = false; |
| if (tracing) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(),mth, |
| "always valid Cache"); |
| } |
| } else { |
| Object objtStamp = |
| descr.getFieldValue("lastUpdatedTimeStamp"); |
| |
| String tStamp; |
| if (objtStamp != null) tStamp = objtStamp.toString(); |
| else tStamp = null; |
| |
| if (tracing) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(),mth, |
| "lastUpdatedTimeStamp: " + tStamp); |
| } |
| |
| if (tStamp == null) |
| tStamp = "0"; |
| |
| long lastTime = (new Long(tStamp)).longValue(); |
| |
| if (tracing) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(),mth, |
| "currencyPeriod:" + currencyPeriod + |
| " lastUpdatedTimeStamp:" + lastTime); |
| } |
| |
| long now = (new Date()).getTime(); |
| |
| if (now < (lastTime + currencyPeriod)) { |
| returnCachedValue = true; |
| resetValue = false; |
| if (tracing) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(),mth, |
| " timed valid Cache for " + now + " < " + |
| (lastTime + currencyPeriod)); |
| } |
| } else { /* value is expired */ |
| returnCachedValue = false; |
| resetValue = true; |
| if (tracing) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(),mth, |
| "timed expired cache for " + now + " > " + |
| (lastTime + currencyPeriod)); |
| } |
| } |
| } |
| if (tracing) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(),mth, |
| "returnCachedValue:" + returnCachedValue + |
| " resetValue: " + resetValue); |
| } |
| |
| if (returnCachedValue == true) { |
| Object currValue = descr.getFieldValue("value"); |
| if (currValue != null) { |
| /* error/validity check return value here */ |
| response = currValue; |
| /* need to cast string cached value to type */ |
| if (tracing) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(),mth, |
| "valid Cache value: " + currValue); |
| } |
| |
| } else { |
| response = null; |
| if (tracing) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(), |
| mth,"no Cached value"); |
| } |
| } |
| } |
| |
| if (resetValue == true) { |
| /* value is not current, so remove it */ |
| descr.removeField("lastUpdatedTimeStamp"); |
| descr.removeField("value"); |
| response = null; |
| modelMBeanInfo.setDescriptor(descr,null); |
| if (tracing) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(), |
| mth,"reset cached value to null"); |
| } |
| } |
| } |
| |
| if (tracing) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(),mth,"Exit"); |
| } |
| |
| return response; |
| } |
| |
| /** |
| * Returns the attributes, operations, constructors and notifications |
| * that this RequiredModelMBean exposes for management. |
| * |
| * @return An instance of ModelMBeanInfo allowing retrieval all |
| * attributes, operations, and Notifications of this MBean. |
| * |
| **/ |
| public MBeanInfo getMBeanInfo() { |
| |
| if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(), |
| "getMBeanInfo()","Entry"); |
| } |
| |
| if (modelMBeanInfo == null) { |
| if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(), |
| "getMBeanInfo()","modelMBeanInfo is null"); |
| } |
| modelMBeanInfo = createDefaultModelMBeanInfo(); |
| //return new ModelMBeanInfo(" ", "", null, null, null, null); |
| } |
| |
| if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(), |
| "getMBeanInfo()","ModelMBeanInfo is " + |
| modelMBeanInfo.getClassName() + " for " + |
| modelMBeanInfo.getDescription()); |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(), |
| "getMBeanInfo()",printModelMBeanInfo(modelMBeanInfo)); |
| } |
| |
| return((MBeanInfo) modelMBeanInfo.clone()); |
| } |
| |
| private String printModelMBeanInfo(ModelMBeanInfo info) { |
| final StringBuilder retStr = new StringBuilder(); |
| if (info == null) { |
| if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(), |
| "printModelMBeanInfo(ModelMBeanInfo)", |
| "ModelMBeanInfo to print is null, " + |
| "printing local ModelMBeanInfo"); |
| } |
| info = modelMBeanInfo; |
| } |
| |
| retStr.append("\nMBeanInfo for ModelMBean is:"); |
| retStr.append("\nCLASSNAME: \t"+ info.getClassName()); |
| retStr.append("\nDESCRIPTION: \t"+ info.getDescription()); |
| |
| |
| try { |
| retStr.append("\nMBEAN DESCRIPTOR: \t"+ |
| info.getMBeanDescriptor()); |
| } catch (Exception e) { |
| retStr.append("\nMBEAN DESCRIPTOR: \t" + " is invalid"); |
| } |
| |
| retStr.append("\nATTRIBUTES"); |
| |
| final MBeanAttributeInfo[] attrInfo = info.getAttributes(); |
| if ((attrInfo != null) && (attrInfo.length>0)) { |
| for (int i=0; i<attrInfo.length; i++) { |
| final ModelMBeanAttributeInfo attInfo = |
| (ModelMBeanAttributeInfo)attrInfo[i]; |
| retStr.append(" ** NAME: \t"+ attInfo.getName()); |
| retStr.append(" DESCR: \t"+ attInfo.getDescription()); |
| retStr.append(" TYPE: \t"+ attInfo.getType() + |
| " READ: \t"+ attInfo.isReadable() + |
| " WRITE: \t"+ attInfo.isWritable()); |
| retStr.append(" DESCRIPTOR: " + |
| attInfo.getDescriptor().toString()); |
| } |
| } else { |
| retStr.append(" ** No attributes **"); |
| } |
| |
| retStr.append("\nCONSTRUCTORS"); |
| final MBeanConstructorInfo[] constrInfo = info.getConstructors(); |
| if ((constrInfo != null) && (constrInfo.length > 0 )) { |
| for (int i=0; i<constrInfo.length; i++) { |
| final ModelMBeanConstructorInfo ctorInfo = |
| (ModelMBeanConstructorInfo)constrInfo[i]; |
| retStr.append(" ** NAME: \t"+ ctorInfo.getName()); |
| retStr.append(" DESCR: \t"+ |
| ctorInfo.getDescription()); |
| retStr.append(" PARAM: \t"+ |
| ctorInfo.getSignature().length + |
| " parameter(s)"); |
| retStr.append(" DESCRIPTOR: " + |
| ctorInfo.getDescriptor().toString()); |
| } |
| } else { |
| retStr.append(" ** No Constructors **"); |
| } |
| |
| retStr.append("\nOPERATIONS"); |
| final MBeanOperationInfo[] opsInfo = info.getOperations(); |
| if ((opsInfo != null) && (opsInfo.length>0)) { |
| for (int i=0; i<opsInfo.length; i++) { |
| final ModelMBeanOperationInfo operInfo = |
| (ModelMBeanOperationInfo)opsInfo[i]; |
| retStr.append(" ** NAME: \t"+ operInfo.getName()); |
| retStr.append(" DESCR: \t"+ operInfo.getDescription()); |
| retStr.append(" PARAM: \t"+ |
| operInfo.getSignature().length + |
| " parameter(s)"); |
| retStr.append(" DESCRIPTOR: " + |
| operInfo.getDescriptor().toString()); |
| } |
| } else { |
| retStr.append(" ** No operations ** "); |
| } |
| |
| retStr.append("\nNOTIFICATIONS"); |
| |
| MBeanNotificationInfo[] notifInfo = info.getNotifications(); |
| if ((notifInfo != null) && (notifInfo.length>0)) { |
| for (int i=0; i<notifInfo.length; i++) { |
| final ModelMBeanNotificationInfo nInfo = |
| (ModelMBeanNotificationInfo)notifInfo[i]; |
| retStr.append(" ** NAME: \t"+ nInfo.getName()); |
| retStr.append(" DESCR: \t"+ nInfo.getDescription()); |
| retStr.append(" DESCRIPTOR: " + |
| nInfo.getDescriptor().toString()); |
| } |
| } else { |
| retStr.append(" ** No notifications **"); |
| } |
| |
| retStr.append(" ** ModelMBean: End of MBeanInfo ** "); |
| |
| return retStr.toString(); |
| } |
| |
| /** |
| * Invokes a method on or through a RequiredModelMBean and returns |
| * the result of the method execution. |
| * <P> |
| * If the given method to be invoked, together with the provided |
| * signature, matches one of RequiredModelMbean |
| * accessible methods, this one will be call. Otherwise the call to |
| * the given method will be tried on the managed resource. |
| * <P> |
| * The last value returned by an operation may be cached in |
| * the operation's descriptor which |
| * is in the ModelMBeanOperationInfo's descriptor. |
| * The valid value will be in the 'value' field if there is one. |
| * If the 'currencyTimeLimit' field in the descriptor is: |
| * <UL> |
| * <LI><b><0</b> Then the value is not cached and is never valid. |
| * The operation method is invoked. |
| * The 'value' and 'lastUpdatedTimeStamp' fields are cleared.</LI> |
| * <LI><b>=0</b> Then the value is always cached and always valid. |
| * The 'value' field is returned. If there is no 'value' field |
| * then the operation method is invoked for the attribute. |
| * The 'lastUpdatedTimeStamp' field and `value' fields are set to |
| * the operation's return value and the current time stamp.</LI> |
| * <LI><b>>0</b> Represents the number of seconds that the 'value' |
| * field is valid. |
| * The 'value' field is no longer valid when |
| * 'lastUpdatedTimeStamp' + 'currencyTimeLimit' > Now. |
| * <UL> |
| * <LI>When 'value' is valid, 'value' is returned.</LI> |
| * <LI>When 'value' is no longer valid then the operation |
| * method is invoked. The 'lastUpdatedTimeStamp' field |
| * and `value' fields are updated.</lI> |
| * </UL> |
| * </LI> |
| * </UL> |
| * |
| * <p><b>Note:</b> because of inconsistencies in previous versions of |
| * this specification, it is recommended not to use negative or zero |
| * values for <code>currencyTimeLimit</code>. To indicate that a |
| * cached value is never valid, omit the |
| * <code>currencyTimeLimit</code> field. To indicate that it is |
| * always valid, use a very large number for this field.</p> |
| * |
| * @param opName The name of the method to be invoked. The |
| * name can be the fully qualified method name including the |
| * classname, or just the method name if the classname is |
| * defined in the 'class' field of the operation descriptor. |
| * @param opArgs An array containing the parameters to be set |
| * when the operation is invoked |
| * @param sig An array containing the signature of the |
| * operation. The class objects will be loaded using the same |
| * class loader as the one used for loading the MBean on which |
| * the operation was invoked. |
| * |
| * @return The object returned by the method, which represents the |
| * result of invoking the method on the specified managed resource. |
| * |
| * @exception MBeanException Wraps one of the following Exceptions: |
| * <UL> |
| * <LI> An Exception thrown by the managed object's invoked method.</LI> |
| * <LI> {@link ServiceNotFoundException}: No ModelMBeanOperationInfo or |
| * no descriptor defined for the specified operation or the managed |
| * resource is null.</LI> |
| * <LI> {@link InvalidTargetObjectTypeException}: The 'targetType' |
| * field value is not 'objectReference'.</LI> |
| * </UL> |
| * @exception ReflectionException Wraps an {@link java.lang.Exception} |
| * thrown while trying to invoke the method. |
| * @exception RuntimeOperationsException Wraps an |
| * {@link IllegalArgumentException} Method name is null. |
| * |
| **/ |
| /* |
| The requirement to be able to invoke methods on the |
| RequiredModelMBean class itself makes this method considerably |
| more complicated than it might otherwise be. Note that, unlike |
| earlier versions, we do not allow you to invoke such methods if |
| they are not explicitly mentioned in the ModelMBeanInfo. Doing |
| so was potentially a security problem, and certainly very |
| surprising. |
| |
| We do not look for the method in the RequiredModelMBean class |
| itself if: |
| (a) there is a "targetObject" field in the Descriptor for the |
| operation; or |
| (b) there is a "class" field in the Descriptor for the operation |
| and the named class is not RequiredModelMBean or one of its |
| superinterfaces; or |
| (c) the name of the operation is not the name of a method in |
| RequiredModelMBean (this is just an optimization). |
| |
| In cases (a) and (b), if you have gone to the trouble of adding |
| those fields specifically for this operation then presumably you |
| do not want RequiredModelMBean's methods to be called. |
| |
| We have to pay attention to class loading issues. If the |
| "class" field is present, the named class has to be resolved |
| relative to RequiredModelMBean's class loader to test the |
| condition (b) above, and relative to the managed resource's |
| class loader to ensure that the managed resource is in fact of |
| the named class (or a subclass). The class names in the sig |
| array likewise have to be resolved, first against |
| RequiredModelMBean's class loader, then against the managed |
| resource's class loader. There is no point in using any other |
| loader because when we call Method.invoke we must call it on |
| a Method that is implemented by the target object. |
| */ |
| public Object invoke(String opName, Object[] opArgs, String[] sig) |
| throws MBeanException, ReflectionException { |
| |
| final boolean tracing = MODELMBEAN_LOGGER.isLoggable(Level.FINER); |
| final String mth = "invoke(String, Object[], String[])"; |
| |
| if (tracing) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(), mth, "Entry"); |
| } |
| |
| if (opName == null) { |
| final RuntimeException x = |
| new IllegalArgumentException("Method name must not be null"); |
| throw new RuntimeOperationsException(x, |
| "An exception occurred while trying to " + |
| "invoke a method on a RequiredModelMBean"); |
| } |
| |
| String opClassName = null; |
| String opMethodName; |
| |
| // Parse for class name and method |
| int opSplitter = opName.lastIndexOf("."); |
| if (opSplitter > 0) { |
| opClassName = opName.substring(0,opSplitter); |
| opMethodName = opName.substring(opSplitter+1); |
| } else |
| opMethodName = opName; |
| |
| /* Ignore anything after a left paren. We keep this for |
| compatibility but it isn't specified. */ |
| opSplitter = opMethodName.indexOf("("); |
| if (opSplitter > 0) |
| opMethodName = opMethodName.substring(0,opSplitter); |
| |
| if (tracing) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(), |
| mth, "Finding operation " + opName + " as " + opMethodName); |
| } |
| |
| ModelMBeanOperationInfo opInfo = |
| modelMBeanInfo.getOperation(opMethodName); |
| if (opInfo == null) { |
| final String msg = |
| "Operation " + opName + " not in ModelMBeanInfo"; |
| throw new MBeanException(new ServiceNotFoundException(msg), msg); |
| } |
| |
| final Descriptor opDescr = opInfo.getDescriptor(); |
| if (opDescr == null) { |
| final String msg = "Operation descriptor null"; |
| throw new MBeanException(new ServiceNotFoundException(msg), msg); |
| } |
| |
| final Object cached = resolveForCacheValue(opDescr); |
| if (cached != null) { |
| if (tracing) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(), |
| mth, |
| "Returning cached value"); |
| } |
| return cached; |
| } |
| |
| if (opClassName == null) |
| opClassName = (String) opDescr.getFieldValue("class"); |
| // may still be null now |
| |
| opMethodName = (String) opDescr.getFieldValue("name"); |
| if (opMethodName == null) { |
| final String msg = |
| "Method descriptor must include `name' field"; |
| throw new MBeanException(new ServiceNotFoundException(msg), msg); |
| } |
| |
| final String targetTypeField = (String) |
| opDescr.getFieldValue("targetType"); |
| if (targetTypeField != null |
| && !targetTypeField.equalsIgnoreCase("objectReference")) { |
| final String msg = |
| "Target type must be objectReference: " + targetTypeField; |
| throw new MBeanException(new InvalidTargetObjectTypeException(msg), |
| msg); |
| } |
| |
| final Object targetObjectField = opDescr.getFieldValue("targetObject"); |
| if (tracing && targetObjectField != null) |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(), |
| mth, "Found target object in descriptor"); |
| |
| /* Now look for the method, either in RequiredModelMBean itself |
| or in the target object. Set "method" and "targetObject" |
| appropriately. */ |
| Method method; |
| Object targetObject; |
| |
| method = findRMMBMethod(opMethodName, targetObjectField, |
| opClassName, sig); |
| |
| if (method != null) |
| targetObject = this; |
| else { |
| if (tracing) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(), |
| mth, "looking for method in managedResource class"); |
| } |
| if (targetObjectField != null) |
| targetObject = targetObjectField; |
| else { |
| targetObject = managedResource; |
| if (targetObject == null) { |
| final String msg = |
| "managedResource for invoke " + opName + |
| " is null"; |
| Exception snfe = new ServiceNotFoundException(msg); |
| throw new MBeanException(snfe); |
| } |
| } |
| |
| final Class<?> targetClass; |
| |
| if (opClassName != null) { |
| try { |
| final ClassLoader targetClassLoader = |
| targetObject.getClass().getClassLoader(); |
| targetClass = Class.forName(opClassName, false, |
| targetClassLoader); |
| } catch (ClassNotFoundException e) { |
| final String msg = |
| "class for invoke " + opName + " not found"; |
| throw new ReflectionException(e, msg); |
| } |
| } else |
| targetClass = targetObject.getClass(); |
| |
| method = resolveMethod(targetClass, opMethodName, sig); |
| } |
| |
| if (tracing) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(), |
| mth, "found " + opMethodName + ", now invoking"); |
| } |
| |
| final Object result = |
| invokeMethod(opName, method, targetObject, opArgs); |
| |
| if (tracing) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(), |
| mth, "successfully invoked method"); |
| } |
| |
| if (result != null) |
| cacheResult(opInfo, opDescr, result); |
| |
| return result; |
| } |
| |
| private static Method resolveMethod(Class<?> targetClass, |
| String opMethodName, |
| String[] sig) |
| throws ReflectionException { |
| final boolean tracing = MODELMBEAN_LOGGER.isLoggable(Level.FINER); |
| |
| if (tracing) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(),"resolveMethod", |
| "resolving " + targetClass.getName() + "." + opMethodName); |
| } |
| |
| final Class<?>[] argClasses; |
| |
| if (sig == null) |
| argClasses = null; |
| else { |
| final ClassLoader targetClassLoader = targetClass.getClassLoader(); |
| argClasses = new Class<?>[sig.length]; |
| for (int i = 0; i < sig.length; i++) { |
| if (tracing) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(),"resolveMethod", |
| "resolve type " + sig[i]); |
| } |
| argClasses[i] = (Class<?>) primitiveClassMap.get(sig[i]); |
| if (argClasses[i] == null) { |
| try { |
| argClasses[i] = |
| Class.forName(sig[i], false, targetClassLoader); |
| } catch (ClassNotFoundException e) { |
| if (tracing) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(), |
| "resolveMethod", |
| "class not found"); |
| } |
| final String msg = "Parameter class not found"; |
| throw new ReflectionException(e, msg); |
| } |
| } |
| } |
| } |
| |
| try { |
| return targetClass.getMethod(opMethodName, argClasses); |
| } catch (NoSuchMethodException e) { |
| final String msg = |
| "Target method not found: " + targetClass.getName() + "." + |
| opMethodName; |
| throw new ReflectionException(e, msg); |
| } |
| } |
| |
| /* Map e.g. "int" to int.class. Goodness knows how many time this |
| particular wheel has been reinvented. */ |
| private static final Class<?>[] primitiveClasses = { |
| int.class, long.class, boolean.class, double.class, |
| float.class, short.class, byte.class, char.class, |
| }; |
| private static final Map<String,Class<?>> primitiveClassMap = |
| new HashMap<String,Class<?>>(); |
| static { |
| for (int i = 0; i < primitiveClasses.length; i++) { |
| final Class<?> c = primitiveClasses[i]; |
| primitiveClassMap.put(c.getName(), c); |
| } |
| } |
| |
| /* Find a method in RequiredModelMBean as determined by the given |
| parameters. Return null if there is none, or if the parameters |
| exclude using it. Called from invoke. */ |
| private static Method findRMMBMethod(String opMethodName, |
| Object targetObjectField, |
| String opClassName, |
| String[] sig) { |
| final boolean tracing = MODELMBEAN_LOGGER.isLoggable(Level.FINER); |
| |
| if (tracing) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(), |
| "invoke(String, Object[], String[])", |
| "looking for method in RequiredModelMBean class"); |
| } |
| |
| if (!isRMMBMethodName(opMethodName)) |
| return null; |
| if (targetObjectField != null) |
| return null; |
| final Class<RequiredModelMBean> rmmbClass = RequiredModelMBean.class; |
| final Class<?> targetClass; |
| if (opClassName == null) |
| targetClass = rmmbClass; |
| else { |
| try { |
| final ClassLoader targetClassLoader = |
| rmmbClass.getClassLoader(); |
| targetClass = Class.forName(opClassName, false, |
| targetClassLoader); |
| if (!rmmbClass.isAssignableFrom(targetClass)) |
| return null; |
| } catch (ClassNotFoundException e) { |
| return null; |
| } |
| } |
| try { |
| return resolveMethod(targetClass, opMethodName, sig); |
| } catch (ReflectionException e) { |
| return null; |
| } |
| } |
| |
| /* |
| * Invoke the given method, and throw the somewhat unpredictable |
| * appropriate exception if the method itself gets an exception. |
| */ |
| private Object invokeMethod(String opName, Method method, |
| Object targetObject, Object[] opArgs) |
| throws MBeanException, ReflectionException { |
| try { |
| ReflectUtil.checkPackageAccess(method.getDeclaringClass()); |
| return MethodUtil.invoke(method, targetObject, opArgs); |
| } catch (RuntimeErrorException ree) { |
| throw new RuntimeOperationsException(ree, |
| "RuntimeException occurred in RequiredModelMBean "+ |
| "while trying to invoke operation " + opName); |
| } catch (RuntimeException re) { |
| throw new RuntimeOperationsException(re, |
| "RuntimeException occurred in RequiredModelMBean "+ |
| "while trying to invoke operation " + opName); |
| } catch (IllegalAccessException iae) { |
| throw new ReflectionException(iae, |
| "IllegalAccessException occurred in " + |
| "RequiredModelMBean while trying to " + |
| "invoke operation " + opName); |
| } catch (InvocationTargetException ite) { |
| Throwable mmbTargEx = ite.getTargetException(); |
| if (mmbTargEx instanceof RuntimeException) { |
| throw new MBeanException ((RuntimeException)mmbTargEx, |
| "RuntimeException thrown in RequiredModelMBean "+ |
| "while trying to invoke operation " + opName); |
| } else if (mmbTargEx instanceof Error) { |
| throw new RuntimeErrorException((Error)mmbTargEx, |
| "Error occurred in RequiredModelMBean while trying "+ |
| "to invoke operation " + opName); |
| } else if (mmbTargEx instanceof ReflectionException) { |
| throw (ReflectionException) mmbTargEx; |
| } else { |
| throw new MBeanException ((Exception)mmbTargEx, |
| "Exception thrown in RequiredModelMBean "+ |
| "while trying to invoke operation " + opName); |
| } |
| } catch (Error err) { |
| throw new RuntimeErrorException(err, |
| "Error occurred in RequiredModelMBean while trying "+ |
| "to invoke operation " + opName); |
| } catch (Exception e) { |
| throw new ReflectionException(e, |
| "Exception occurred in RequiredModelMBean while " + |
| "trying to invoke operation " + opName); |
| } |
| } |
| |
| /* |
| * Cache the result of an operation in the descriptor, if that is |
| * called for by the descriptor's configuration. Note that we |
| * don't remember operation parameters when caching the result, so |
| * this is unlikely to be useful if there are any. |
| */ |
| private void cacheResult(ModelMBeanOperationInfo opInfo, |
| Descriptor opDescr, Object result) |
| throws MBeanException { |
| |
| Descriptor mmbDesc = |
| modelMBeanInfo.getMBeanDescriptor(); |
| |
| Object objctl = |
| opDescr.getFieldValue("currencyTimeLimit"); |
| String ctl; |
| if (objctl != null) { |
| ctl = objctl.toString(); |
| } else { |
| ctl = null; |
| } |
| if ((ctl == null) && (mmbDesc != null)) { |
| objctl = |
| mmbDesc.getFieldValue("currencyTimeLimit"); |
| if (objctl != null) { |
| ctl = objctl.toString(); |
| } else { |
| ctl = null; |
| } |
| } |
| if ((ctl != null) && !(ctl.equals("-1"))) { |
| opDescr.setField("value", result); |
| opDescr.setField("lastUpdatedTimeStamp", |
| String.valueOf((new Date()).getTime())); |
| |
| |
| modelMBeanInfo.setDescriptor(opDescr, |
| "operation"); |
| if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(), |
| "invoke(String,Object[],Object[])", |
| "new descriptor is " + opDescr); |
| } |
| } |
| } |
| |
| /* |
| * Determine whether the given name is the name of a public method |
| * in this class. This is only an optimization: it prevents us |
| * from trying to do argument type lookups and reflection on a |
| * method that will obviously fail because it has the wrong name. |
| * |
| * The first time this method is called we do the reflection, and |
| * every other time we reuse the remembered values. |
| * |
| * It's conceivable that the (possibly malicious) first caller |
| * doesn't have the required permissions to do reflection, in |
| * which case we don't touch anything so as not to interfere |
| * with a later permissionful caller. |
| */ |
| private static Set<String> rmmbMethodNames; |
| private static synchronized boolean isRMMBMethodName(String name) { |
| if (rmmbMethodNames == null) { |
| try { |
| Set<String> names = new HashSet<String>(); |
| Method[] methods = RequiredModelMBean.class.getMethods(); |
| for (int i = 0; i < methods.length; i++) |
| names.add(methods[i].getName()); |
| rmmbMethodNames = names; |
| } catch (Exception e) { |
| return true; |
| // This is only an optimization so we'll go on to discover |
| // whether the name really is an RMMB method. |
| } |
| } |
| return rmmbMethodNames.contains(name); |
| } |
| |
| /** |
| * Returns the value of a specific attribute defined for this |
| * ModelMBean. |
| * The last value returned by an attribute may be cached in the |
| * attribute's descriptor. |
| * The valid value will be in the 'value' field if there is one. |
| * If the 'currencyTimeLimit' field in the descriptor is: |
| * <UL> |
| * <LI> <b><0</b> Then the value is not cached and is never valid. |
| * The getter method is invoked for the attribute. |
| * The 'value' and 'lastUpdatedTimeStamp' fields are cleared.</LI> |
| * <LI> <b>=0</b> Then the value is always cached and always valid. |
| * The 'value' field is returned. If there is no'value' field |
| * then the getter method is invoked for the attribute. |
| * The 'lastUpdatedTimeStamp' field and `value' fields are set |
| * to the attribute's value and the current time stamp.</LI> |
| * <LI> <b>>0</b> Represents the number of seconds that the 'value' |
| * field is valid. |
| * The 'value' field is no longer valid when |
| * 'lastUpdatedTimeStamp' + 'currencyTimeLimit' > Now. |
| * <UL> |
| * <LI>When 'value' is valid, 'value' is returned.</LI> |
| * <LI>When 'value' is no longer valid then the getter |
| * method is invoked for the attribute. |
| * The 'lastUpdatedTimeStamp' field and `value' fields |
| * are updated.</LI> |
| * </UL></LI> |
| * </UL> |
| * |
| * <p><b>Note:</b> because of inconsistencies in previous versions of |
| * this specification, it is recommended not to use negative or zero |
| * values for <code>currencyTimeLimit</code>. To indicate that a |
| * cached value is never valid, omit the |
| * <code>currencyTimeLimit</code> field. To indicate that it is |
| * always valid, use a very large number for this field.</p> |
| * |
| * <p>If the 'getMethod' field contains the name of a valid |
| * operation descriptor, then the method described by the |
| * operation descriptor is executed. The response from the |
| * method is returned as the value of the attribute. If the |
| * operation fails or the returned value is not compatible with |
| * the declared type of the attribute, an exception will be thrown.</p> |
| * |
| * <p>If no 'getMethod' field is defined then the default value of the |
| * attribute is returned. If the returned value is not compatible with |
| * the declared type of the attribute, an exception will be thrown.</p> |
| * |
| * <p>The declared type of the attribute is the String returned by |
| * {@link ModelMBeanAttributeInfo#getType()}. A value is compatible |
| * with this type if one of the following is true: |
| * <ul> |
| * <li>the value is null;</li> |
| * <li>the declared name is a primitive type name (such as "int") |
| * and the value is an instance of the corresponding wrapper |
| * type (such as java.lang.Integer);</li> |
| * <li>the name of the value's class is identical to the declared name;</li> |
| * <li>the declared name can be loaded by the value's class loader and |
| * produces a class to which the value can be assigned.</li> |
| * </ul> |
| * |
| * <p>In this implementation, in every case where the getMethod needs to |
| * be called, because the method is invoked through the standard "invoke" |
| * method and thus needs operationInfo, an operation must be specified |
| * for that getMethod so that the invocation works correctly.</p> |
| * |
| * @param attrName A String specifying the name of the |
| * attribute to be retrieved. It must match the name of a |
| * ModelMBeanAttributeInfo. |
| * |
| * @return The value of the retrieved attribute from the |
| * descriptor 'value' field or from the invocation of the |
| * operation in the 'getMethod' field of the descriptor. |
| * |
| * @exception AttributeNotFoundException The specified attribute is |
| * not accessible in the MBean. |
| * The following cases may result in an AttributeNotFoundException: |
| * <UL> |
| * <LI> No ModelMBeanInfo was found for the Model MBean.</LI> |
| * <LI> No ModelMBeanAttributeInfo was found for the specified |
| * attribute name.</LI> |
| * <LI> The ModelMBeanAttributeInfo isReadable method returns |
| * 'false'.</LI> |
| * </UL> |
| * @exception MBeanException Wraps one of the following Exceptions: |
| * <UL> |
| * <LI> {@link InvalidAttributeValueException}: A wrong value type |
| * was received from the attribute's getter method or |
| * no 'getMethod' field defined in the descriptor for |
| * the attribute and no default value exists.</LI> |
| * <LI> {@link ServiceNotFoundException}: No |
| * ModelMBeanOperationInfo defined for the attribute's |
| * getter method or no descriptor associated with the |
| * ModelMBeanOperationInfo or the managed resource is |
| * null.</LI> |
| * <LI> {@link InvalidTargetObjectTypeException} The 'targetType' |
| * field value is not 'objectReference'.</LI> |
| * <LI> An Exception thrown by the managed object's getter.</LI> |
| * </UL> |
| * @exception ReflectionException Wraps an {@link java.lang.Exception} |
| * thrown while trying to invoke the getter. |
| * @exception RuntimeOperationsException Wraps an |
| * {@link IllegalArgumentException}: The attribute name in |
| * parameter is null. |
| * |
| * @see #setAttribute(javax.management.Attribute) |
| **/ |
| public Object getAttribute(String attrName) |
| throws AttributeNotFoundException, MBeanException, |
| ReflectionException { |
| if (attrName == null) |
| throw new RuntimeOperationsException(new |
| IllegalArgumentException("attributeName must not be null"), |
| "Exception occurred trying to get attribute of a " + |
| "RequiredModelMBean"); |
| final String mth = "getAttribute(String)"; |
| final boolean tracing = MODELMBEAN_LOGGER.isLoggable(Level.FINER); |
| if (tracing) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(), |
| mth, "Entry with " + attrName); |
| } |
| |
| /* Check attributeDescriptor for getMethod */ |
| Object response; |
| |
| try { |
| if (modelMBeanInfo == null) |
| throw new AttributeNotFoundException( |
| "getAttribute failed: ModelMBeanInfo not found for "+ |
| attrName); |
| |
| ModelMBeanAttributeInfo attrInfo = modelMBeanInfo.getAttribute(attrName); |
| Descriptor mmbDesc = modelMBeanInfo.getMBeanDescriptor(); |
| |
| if (attrInfo == null) |
| throw new AttributeNotFoundException("getAttribute failed:"+ |
| " ModelMBeanAttributeInfo not found for " + attrName); |
| |
| Descriptor attrDescr = attrInfo.getDescriptor(); |
| if (attrDescr != null) { |
| if (!attrInfo.isReadable()) |
| throw new AttributeNotFoundException( |
| "getAttribute failed: " + attrName + |
| " is not readable "); |
| |
| response = resolveForCacheValue(attrDescr); |
| |
| /* return current cached value */ |
| if (tracing) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(), mth, |
| "*** cached value is " + response); |
| } |
| |
| if (response == null) { |
| /* no cached value, run getMethod */ |
| if (tracing) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(), mth, |
| "**** cached value is null - getting getMethod"); |
| } |
| String attrGetMethod = |
| (String)(attrDescr.getFieldValue("getMethod")); |
| |
| if (attrGetMethod != null) { |
| /* run method from operations descriptor */ |
| if (tracing) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(), |
| mth, "invoking a getMethod for " + attrName); |
| } |
| |
| Object getResponse = |
| invoke(attrGetMethod, new Object[] {}, |
| new String[] {}); |
| |
| if (getResponse != null) { |
| // error/validity check return value here |
| if (tracing) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(), |
| mth, "got a non-null response " + |
| "from getMethod\n"); |
| } |
| |
| response = getResponse; |
| |
| // change cached value in attribute descriptor |
| Object objctl = |
| attrDescr.getFieldValue("currencyTimeLimit"); |
| |
| String ctl; |
| if (objctl != null) ctl = objctl.toString(); |
| else ctl = null; |
| |
| if ((ctl == null) && (mmbDesc != null)) { |
| objctl = mmbDesc. |
| getFieldValue("currencyTimeLimit"); |
| if (objctl != null) ctl = objctl.toString(); |
| else ctl = null; |
| } |
| |
| if ((ctl != null) && !(ctl.equals("-1"))) { |
| if (tracing) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(), |
| mth, |
| "setting cached value and " + |
| "lastUpdatedTime in descriptor"); |
| } |
| attrDescr.setField("value", response); |
| final String stamp = String.valueOf( |
| (new Date()).getTime()); |
| attrDescr.setField("lastUpdatedTimeStamp", |
| stamp); |
| attrInfo.setDescriptor(attrDescr); |
| modelMBeanInfo.setDescriptor(attrDescr, |
| "attribute"); |
| if (tracing) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(), |
| mth,"new descriptor is " +attrDescr); |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(), |
| mth,"AttributeInfo descriptor is " + |
| attrInfo.getDescriptor()); |
| final String attStr = modelMBeanInfo. |
| getDescriptor(attrName,"attribute"). |
| toString(); |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(), |
| mth, |
| "modelMBeanInfo: AttributeInfo " + |
| "descriptor is " + attStr); |
| } |
| } |
| } else { |
| // response was invalid or really returned null |
| if (tracing) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(), mth, |
| "got a null response from getMethod\n"); |
| } |
| response = null; |
| } |
| } else { |
| // not getMethod so return descriptor (default) value |
| String qualifier=""; |
| response = attrDescr.getFieldValue("value"); |
| if (response == null) { |
| qualifier="default "; |
| response = attrDescr.getFieldValue("default"); |
| } |
| if (tracing) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(), mth, |
| "could not find getMethod for " +attrName + |
| ", returning descriptor " +qualifier + "value"); |
| } |
| // !! cast response to right class |
| } |
| } |
| |
| // make sure response class matches type field |
| String respType = attrInfo.getType(); |
| if (response != null) { |
| String responseClass = response.getClass().getName(); |
| if (!respType.equals(responseClass)) { |
| boolean wrongType = false; |
| boolean primitiveType = false; |
| boolean correspondingTypes = false; |
| for (int i = 0; i < primitiveTypes.length; i++) { |
| if (respType.equals(primitiveTypes[i])) { |
| primitiveType = true; |
| if (responseClass.equals(primitiveWrappers[i])) |
| correspondingTypes = true; |
| break; |
| } |
| } |
| if (primitiveType) { |
| // inequality may come from primitive/wrapper class |
| if (!correspondingTypes) |
| wrongType = true; |
| } else { |
| // inequality may come from type subclassing |
| boolean subtype; |
| try { |
| ClassLoader cl = |
| response.getClass().getClassLoader(); |
| Class<?> c = Class.forName(respType, true, cl); |
| subtype = c.isInstance(response); |
| } catch (Exception e) { |
| subtype = false; |
| |
| if (tracing) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(), |
| mth, "Exception: ",e); |
| } |
| } |
| if (!subtype) |
| wrongType = true; |
| } |
| if (wrongType) { |
| if (tracing) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(), mth, |
| "Wrong response type '" + respType + "'"); |
| } |
| // throw exception, didn't get |
| // back right attribute type |
| throw new MBeanException( |
| new InvalidAttributeValueException( |
| "Wrong value type received for get attribute"), |
| "An exception occurred while trying to get an " + |
| "attribute value through a RequiredModelMBean"); |
| } |
| } |
| } |
| } else { |
| if (tracing) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(), mth, |
| "getMethod failed " + attrName + |
| " not in attributeDescriptor\n"); |
| } |
| throw new MBeanException(new |
| InvalidAttributeValueException( |
| "Unable to resolve attribute value, " + |
| "no getMethod defined in descriptor for attribute"), |
| "An exception occurred while trying to get an "+ |
| "attribute value through a RequiredModelMBean"); |
| } |
| |
| } catch (MBeanException mbe) { |
| throw mbe; |
| } catch (AttributeNotFoundException t) { |
| throw t; |
| } catch (Exception e) { |
| if (tracing) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(), mth, |
| "getMethod failed with " + e.getMessage() + |
| " exception type " + (e.getClass()).toString()); |
| } |
| throw new MBeanException(e,"An exception occurred while trying "+ |
| "to get an attribute value: " + e.getMessage()); |
| } |
| |
| if (tracing) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(), mth, "Exit"); |
| } |
| |
| return response; |
| } |
| |
| /** |
| * Returns the values of several attributes in the ModelMBean. |
| * Executes a getAttribute for each attribute name in the |
| * attrNames array passed in. |
| * |
| * @param attrNames A String array of names of the attributes |
| * to be retrieved. |
| * |
| * @return The array of the retrieved attributes. |
| * |
| * @exception RuntimeOperationsException Wraps an |
| * {@link IllegalArgumentException}: The object name in parameter is |
| * null or attributes in parameter is null. |
| * |
| * @see #setAttributes(javax.management.AttributeList) |
| */ |
| public AttributeList getAttributes(String[] attrNames) { |
| if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(), |
| "getAttributes(String[])","Entry"); |
| } |
| |
| if (attrNames == null) |
| throw new RuntimeOperationsException(new |
| IllegalArgumentException("attributeNames must not be null"), |
| "Exception occurred trying to get attributes of a "+ |
| "RequiredModelMBean"); |
| |
| AttributeList responseList = new AttributeList(); |
| for (int i = 0; i < attrNames.length; i++) { |
| try { |
| responseList.add(new Attribute(attrNames[i], |
| getAttribute(attrNames[i]))); |
| } catch (Exception e) { |
| // eat exceptions because interface doesn't have an |
| // exception on it |
| if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(), |
| "getAttributes(String[])", |
| "Failed to get \"" + attrNames[i] + "\": ", e); |
| } |
| } |
| } |
| |
| if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(), |
| "getAttributes(String[])","Exit"); |
| } |
| |
| return responseList; |
| } |
| |
| /** |
| * Sets the value of a specific attribute of a named ModelMBean. |
| * |
| * If the 'setMethod' field of the attribute's descriptor |
| * contains the name of a valid operation descriptor, then the |
| * method described by the operation descriptor is executed. |
| * In this implementation, the operation descriptor must be specified |
| * correctly and assigned to the modelMBeanInfo so that the 'setMethod' |
| * works correctly. |
| * The response from the method is set as the value of the attribute |
| * in the descriptor. |
| * |
| * <p>If currencyTimeLimit is > 0, then the new value for the |
| * attribute is cached in the attribute descriptor's |
| * 'value' field and the 'lastUpdatedTimeStamp' field is set to |
| * the current time stamp. |
| * |
| * <p>If the persist field of the attribute's descriptor is not null |
| * then Persistence policy from the attribute descriptor is used to |
| * guide storing the attribute in a persistent store. |
| * <br>Store the MBean if 'persistPolicy' field is: |
| * <UL> |
| * <Li> != "never"</Li> |
| * <Li> = "always"</Li> |
| * <Li> = "onUpdate"</Li> |
| * <Li> = "onTimer" and now > 'lastPersistTime' + 'persistPeriod'</Li> |
| * <Li> = "NoMoreOftenThan" and now > 'lastPersistTime' + |
| * 'persistPeriod'</Li> |
| * </UL> |
| * Do not store the MBean if 'persistPolicy' field is: |
| * <UL> |
| * <Li> = "never"</Li> |
| * <Li> = "onTimer" && now < 'lastPersistTime' + 'persistPeriod'</Li> |
| * <Li> = "onUnregister"</Li> |
| * <Li> = "NoMoreOftenThan" and now < 'lastPersistTime' + |
| * 'persistPeriod'</Li> |
| * </UL> |
| * |
| * <p>The ModelMBeanInfo of the Model MBean is stored in a file. |
| * |
| * @param attribute The Attribute instance containing the name of |
| * the attribute to be set and the value it is to be set to. |
| * |
| * |
| * @exception AttributeNotFoundException The specified attribute is |
| * not accessible in the MBean. |
| * <br>The following cases may result in an AttributeNotFoundException: |
| * <UL> |
| * <LI> No ModelMBeanAttributeInfo is found for the specified |
| * attribute.</LI> |
| * <LI> The ModelMBeanAttributeInfo's isWritable method returns |
| * 'false'.</LI> |
| * </UL> |
| * @exception InvalidAttributeValueException No descriptor is defined |
| * for the specified attribute. |
| * @exception MBeanException Wraps one of the following Exceptions: |
| * <UL> |
| * <LI> An Exception thrown by the managed object's setter.</LI> |
| * <LI> A {@link ServiceNotFoundException} if a setMethod field is |
| * defined in the descriptor for the attribute and the managed |
| * resource is null; or if no setMethod field is defined and |
| * caching is not enabled for the attribute. |
| * Note that if there is no getMethod field either, then caching |
| * is automatically enabled.</LI> |
| * <LI> {@link InvalidTargetObjectTypeException} The 'targetType' |
| * field value is not 'objectReference'.</LI> |
| * <LI> An Exception thrown by the managed object's getter.</LI> |
| * </UL> |
| * @exception ReflectionException Wraps an {@link java.lang.Exception} |
| * thrown while trying to invoke the setter. |
| * @exception RuntimeOperationsException Wraps an |
| * {@link IllegalArgumentException}: The attribute in parameter is |
| * null. |
| * |
| * @see #getAttribute(java.lang.String) |
| **/ |
| public void setAttribute(Attribute attribute) |
| throws AttributeNotFoundException, InvalidAttributeValueException, |
| MBeanException, ReflectionException { |
| final boolean tracing = MODELMBEAN_LOGGER.isLoggable(Level.FINER); |
| if (tracing) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(), |
| "setAttribute()","Entry"); |
| } |
| |
| if (attribute == null) |
| throw new RuntimeOperationsException(new |
| IllegalArgumentException("attribute must not be null"), |
| "Exception occurred trying to set an attribute of a "+ |
| "RequiredModelMBean"); |
| |
| /* run setMethod if there is one */ |
| /* return cached value if its current */ |
| /* set cached value in descriptor and set date/time */ |
| /* send attribute change Notification */ |
| /* check persistence policy and persist if need be */ |
| String attrName = attribute.getName(); |
| Object attrValue = attribute.getValue(); |
| boolean updateDescriptor = false; |
| |
| ModelMBeanAttributeInfo attrInfo = |
| modelMBeanInfo.getAttribute(attrName); |
| |
| if (attrInfo == null) |
| throw new AttributeNotFoundException("setAttribute failed: " + |
| attrName + " is not found "); |
| |
| Descriptor mmbDesc = modelMBeanInfo.getMBeanDescriptor(); |
| Descriptor attrDescr = attrInfo.getDescriptor(); |
| |
| if (attrDescr != null) { |
| if (!attrInfo.isWritable()) |
| throw new AttributeNotFoundException("setAttribute failed: " |
| + attrName + " is not writable "); |
| |
| String attrSetMethod = (String) |
| (attrDescr.getFieldValue("setMethod")); |
| String attrGetMethod = (String) |
| (attrDescr.getFieldValue("getMethod")); |
| |
| String attrType = attrInfo.getType(); |
| Object currValue = "Unknown"; |
| |
| try { |
| currValue = this.getAttribute(attrName); |
| } catch (Throwable t) { |
| // OK: Default "Unknown" value used for unknown attribute |
| } |
| |
| Attribute oldAttr = new Attribute(attrName, currValue); |
| |
| /* run method from operations descriptor */ |
| if (attrSetMethod == null) { |
| if (attrValue != null) { |
| try { |
| final Class<?> clazz = loadClass(attrType); |
| if (! clazz.isInstance(attrValue)) throw new |
| InvalidAttributeValueException(clazz.getName() + |
| " expected, " + |
| attrValue.getClass().getName() + |
| " received."); |
| } catch (ClassNotFoundException x) { |
| if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(), |
| "setAttribute(Attribute)","Class " + |
| attrType + " for attribute " |
| + attrName + " not found: ", x); |
| } |
| } |
| } |
| updateDescriptor = true; |
| } else { |
| invoke(attrSetMethod, |
| (new Object[] {attrValue}), |
| (new String[] {attrType}) ); |
| } |
| |
| /* change cached value */ |
| Object objctl = attrDescr.getFieldValue("currencyTimeLimit"); |
| String ctl; |
| if (objctl != null) ctl = objctl.toString(); |
| else ctl = null; |
| |
| if ((ctl == null) && (mmbDesc != null)) { |
| objctl = mmbDesc.getFieldValue("currencyTimeLimit"); |
| if (objctl != null) ctl = objctl.toString(); |
| else ctl = null; |
| } |
| |
| final boolean updateCache = ((ctl != null) && !(ctl.equals("-1"))); |
| |
| if(attrSetMethod == null && !updateCache && attrGetMethod != null) |
| throw new MBeanException(new ServiceNotFoundException("No " + |
| "setMethod field is defined in the descriptor for " + |
| attrName + " attribute and caching is not enabled " + |
| "for it")); |
| |
| if (updateCache || updateDescriptor) { |
| if (tracing) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(), |
| "setAttribute(Attribute)", |
| "setting cached value of " + |
| attrName + " to " + attrValue); |
| } |
| |
| attrDescr.setField("value", attrValue); |
| |
| if (updateCache) { |
| final String currtime = String.valueOf( |
| (new Date()).getTime()); |
| |
| attrDescr.setField("lastUpdatedTimeStamp", currtime); |
| } |
| |
| attrInfo.setDescriptor(attrDescr); |
| |
| modelMBeanInfo.setDescriptor(attrDescr,"attribute"); |
| if (tracing) { |
| final StringBuilder strb = new StringBuilder() |
| .append("new descriptor is ").append(attrDescr) |
| .append(". AttributeInfo descriptor is ") |
| .append(attrInfo.getDescriptor()) |
| .append(". AttributeInfo descriptor is ") |
| .append(modelMBeanInfo.getDescriptor(attrName,"attribute")); |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(), |
| "setAttribute(Attribute)",strb.toString()); |
| } |
| |
| } |
| |
| if (tracing) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(), |
| "setAttribute(Attribute)","sending sendAttributeNotification"); |
| } |
| sendAttributeChangeNotification(oldAttr,attribute); |
| |
| } else { // if descriptor ... else no descriptor |
| |
| if (tracing) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(), |
| "setAttribute(Attribute)","setMethod failed "+attrName+ |
| " not in attributeDescriptor\n"); |
| } |
| |
| throw new InvalidAttributeValueException( |
| "Unable to resolve attribute value, "+ |
| "no defined in descriptor for attribute"); |
| } // else no descriptor |
| |
| if (tracing) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(), |
| "setAttribute(Attribute)", "Exit"); |
| } |
| |
| } |
| |
| /** |
| * Sets the values of an array of attributes of this ModelMBean. |
| * Executes the setAttribute() method for each attribute in the list. |
| * |
| * @param attributes A list of attributes: The identification of the |
| * attributes to be set and the values they are to be set to. |
| * |
| * @return The array of attributes that were set, with their new |
| * values in Attribute instances. |
| * |
| * @exception RuntimeOperationsException Wraps an |
| * {@link IllegalArgumentException}: The object name in parameter |
| * is null or attributes in parameter is null. |
| * |
| * @see #getAttributes |
| **/ |
| public AttributeList setAttributes(AttributeList attributes) { |
| |
| if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(), |
| "setAttribute(Attribute)", "Entry"); |
| } |
| |
| if (attributes == null) |
| throw new RuntimeOperationsException(new |
| IllegalArgumentException("attributes must not be null"), |
| "Exception occurred trying to set attributes of a "+ |
| "RequiredModelMBean"); |
| |
| final AttributeList responseList = new AttributeList(); |
| |
| // Go through the list of attributes |
| for (Attribute attr : attributes.asList()) { |
| try { |
| setAttribute(attr); |
| responseList.add(attr); |
| } catch (Exception excep) { |
| responseList.remove(attr); |
| } |
| } |
| |
| return responseList; |
| } |
| |
| |
| |
| private ModelMBeanInfo createDefaultModelMBeanInfo() { |
| return(new ModelMBeanInfoSupport((this.getClass().getName()), |
| "Default ModelMBean", null, null, null, null)); |
| } |
| |
| /*************************************/ |
| /* NotificationBroadcaster Interface */ |
| /*************************************/ |
| |
| |
| private synchronized void writeToLog(String logFileName, |
| String logEntry) throws Exception { |
| |
| if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(), |
| "writeToLog(String, String)", |
| "Notification Logging to " + logFileName + ": " + logEntry); |
| } |
| if ((logFileName == null) || (logEntry == null)) { |
| if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(), |
| "writeToLog(String, String)", |
| "Bad input parameters, will not log this entry."); |
| } |
| return; |
| } |
| |
| FileOutputStream fos = new FileOutputStream(logFileName, true); |
| try { |
| PrintStream logOut = new PrintStream(fos); |
| logOut.println(logEntry); |
| logOut.close(); |
| if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(), |
| "writeToLog(String, String)","Successfully opened log " + |
| logFileName); |
| } |
| } catch (Exception e) { |
| if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(), |
| "writeToLog(String, String)", |
| "Exception " + e.toString() + |
| " trying to write to the Notification log file " + |
| logFileName); |
| } |
| throw e; |
| } finally { |
| fos.close(); |
| } |
| } |
| |
| |
| /** |
| * Registers an object which implements the NotificationListener |
| * interface as a listener. This |
| * object's 'handleNotification()' method will be invoked when any |
| * notification is issued through or by the ModelMBean. This does |
| * not include attributeChangeNotifications. They must be registered |
| * for independently. |
| * |
| * @param listener The listener object which will handles |
| * notifications emitted by the registered MBean. |
| * @param filter The filter object. If null, no filtering will be |
| * performed before handling notifications. |
| * @param handback The context to be sent to the listener with |
| * the notification when a notification is emitted. |
| * |
| * @exception IllegalArgumentException The listener cannot be null. |
| * |
| * @see #removeNotificationListener |
| */ |
| public void addNotificationListener(NotificationListener listener, |
| NotificationFilter filter, |
| Object handback) |
| throws java.lang.IllegalArgumentException { |
| final String mth = "addNotificationListener(" + |
| "NotificationListener, NotificationFilter, Object)"; |
| if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(), mth, "Entry"); |
| } |
| |
| if (listener == null) |
| throw new IllegalArgumentException( |
| "notification listener must not be null"); |
| |
| if (generalBroadcaster == null) |
| generalBroadcaster = new NotificationBroadcasterSupport(); |
| |
| generalBroadcaster.addNotificationListener(listener, filter, |
| handback); |
| if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(), mth, |
| "NotificationListener added"); |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(), mth, "Exit"); |
| } |
| } |
| |
| /** |
| * Removes a listener for Notifications from the RequiredModelMBean. |
| * |
| * @param listener The listener name which was handling notifications |
| * emitted by the registered MBean. |
| * This method will remove all information related to this listener. |
| * |
| * @exception ListenerNotFoundException The listener is not registered |
| * in the MBean or is null. |
| * |
| * @see #addNotificationListener |
| **/ |
| public void removeNotificationListener(NotificationListener listener) |
| throws ListenerNotFoundException { |
| if (listener == null) |
| throw new ListenerNotFoundException( |
| "Notification listener is null"); |
| |
| final String mth="removeNotificationListener(NotificationListener)"; |
| if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(), mth, "Entry"); |
| } |
| |
| if (generalBroadcaster == null) |
| throw new ListenerNotFoundException( |
| "No notification listeners registered"); |
| |
| |
| generalBroadcaster.removeNotificationListener(listener); |
| if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(), mth, "Exit"); |
| } |
| |
| } |
| |
| public void removeNotificationListener(NotificationListener listener, |
| NotificationFilter filter, |
| Object handback) |
| throws ListenerNotFoundException { |
| |
| if (listener == null) |
| throw new ListenerNotFoundException( |
| "Notification listener is null"); |
| |
| final String mth = "removeNotificationListener(" + |
| "NotificationListener, NotificationFilter, Object)"; |
| |
| if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(), mth, "Entry"); |
| } |
| |
| if (generalBroadcaster == null) |
| throw new ListenerNotFoundException( |
| "No notification listeners registered"); |
| |
| |
| generalBroadcaster.removeNotificationListener(listener,filter, |
| handback); |
| |
| if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(), mth, "Exit"); |
| } |
| |
| } |
| |
| public void sendNotification(Notification ntfyObj) |
| throws MBeanException, RuntimeOperationsException { |
| if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(), |
| "sendNotification(Notification)", "Entry"); |
| } |
| |
| if (ntfyObj == null) |
| throw new RuntimeOperationsException(new |
| IllegalArgumentException("notification object must not be "+ |
| "null"), |
| "Exception occurred trying to send a notification from a "+ |
| "RequiredModelMBean"); |
| |
| |
| // log notification if specified in descriptor |
| Descriptor ntfyDesc = |
| modelMBeanInfo.getDescriptor(ntfyObj.getType(),"notification"); |
| Descriptor mmbDesc = modelMBeanInfo.getMBeanDescriptor(); |
| |
| if (ntfyDesc != null) { |
| String logging = (String) ntfyDesc.getFieldValue("log"); |
| |
| if (logging == null) { |
| if (mmbDesc != null) |
| logging = (String) mmbDesc.getFieldValue("log"); |
| } |
| |
| if ((logging != null) && |
| (logging.equalsIgnoreCase("t") || |
| logging.equalsIgnoreCase("true"))) { |
| |
| String logfile = (String) ntfyDesc.getFieldValue("logfile"); |
| if (logfile == null) { |
| if (mmbDesc != null) |
| logfile = (String)mmbDesc.getFieldValue("logfile"); |
| } |
| if (logfile != null) { |
| try { |
| writeToLog(logfile,"LogMsg: " + |
| ((new Date(ntfyObj.getTimeStamp())).toString())+ |
| " " + ntfyObj.getType() + " " + |
| ntfyObj.getMessage() + " Severity = " + |
| (String)ntfyDesc.getFieldValue("severity")); |
| } catch (Exception e) { |
| if (MODELMBEAN_LOGGER.isLoggable(Level.FINE)) { |
| MODELMBEAN_LOGGER.logp(Level.FINE, |
| RequiredModelMBean.class.getName(), |
| "sendNotification(Notification)", |
| "Failed to log " + |
| ntfyObj.getType() + " notification: ", e); |
| } |
| } |
| } |
| } |
| } |
| if (generalBroadcaster != null) { |
| generalBroadcaster.sendNotification(ntfyObj); |
| } |
| |
| if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(), |
| "sendNotification(Notification)", |
| "sendNotification sent provided notification object"); |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(), |
| "sendNotification(Notification)"," Exit"); |
| } |
| |
| } |
| |
| |
| public void sendNotification(String ntfyText) |
| throws MBeanException, RuntimeOperationsException { |
| if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(), |
| "sendNotification(String)","Entry"); |
| } |
| |
| if (ntfyText == null) |
| throw new RuntimeOperationsException(new |
| IllegalArgumentException("notification message must not "+ |
| "be null"), |
| "Exception occurred trying to send a text notification "+ |
| "from a ModelMBean"); |
| |
| Notification myNtfyObj = new Notification("jmx.modelmbean.generic", |
| this, 1, ntfyText); |
| sendNotification(myNtfyObj); |
| if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(), |
| "sendNotification(String)","Notification sent"); |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(), |
| "sendNotification(String)","Exit"); |
| } |
| } |
| |
| /** |
| * Returns `true' if the notification `notifName' is found |
| * in `info'. (bug 4744667) |
| **/ |
| private static final |
| boolean hasNotification(final ModelMBeanInfo info, |
| final String notifName) { |
| try { |
| if (info == null) return false; |
| else return (info.getNotification(notifName)!=null); |
| } catch (MBeanException x) { |
| return false; |
| } catch (RuntimeOperationsException r) { |
| return false; |
| } |
| } |
| |
| /** |
| * Creates a default ModelMBeanNotificationInfo for GENERIC |
| * notification. (bug 4744667) |
| **/ |
| private static final ModelMBeanNotificationInfo makeGenericInfo() { |
| final Descriptor genericDescriptor = new DescriptorSupport( new |
| String[] { |
| "name=GENERIC", |
| "descriptorType=notification", |
| "log=T", |
| "severity=6", |
| "displayName=jmx.modelmbean.generic"} ); |
| |
| return new ModelMBeanNotificationInfo(new |
| String[] {"jmx.modelmbean.generic"}, |
| "GENERIC", |
| "A text notification has been issued by the managed resource", |
| genericDescriptor); |
| } |
| |
| /** |
| * Creates a default ModelMBeanNotificationInfo for ATTRIBUTE_CHANGE |
| * notification. (bug 4744667) |
| **/ |
| private static final |
| ModelMBeanNotificationInfo makeAttributeChangeInfo() { |
| final Descriptor attributeDescriptor = new DescriptorSupport(new |
| String[] { |
| "name=ATTRIBUTE_CHANGE", |
| "descriptorType=notification", |
| "log=T", |
| "severity=6", |
| "displayName=jmx.attribute.change"}); |
| |
| return new ModelMBeanNotificationInfo(new |
| String[] {"jmx.attribute.change"}, |
| "ATTRIBUTE_CHANGE", |
| "Signifies that an observed MBean attribute value has changed", |
| attributeDescriptor ); |
| } |
| |
| /** |
| * Returns the array of Notifications always generated by the |
| * RequiredModelMBean. |
| * <P> |
| * |
| * RequiredModelMBean may always send also two additional notifications: |
| * <UL> |
| * <LI> One with descriptor <code>"name=GENERIC,descriptorType=notification,log=T,severity=6,displayName=jmx.modelmbean.generic"</code></LI> |
| * <LI> Second is a standard attribute change notification |
| * with descriptor <code>"name=ATTRIBUTE_CHANGE,descriptorType=notification,log=T,severity=6,displayName=jmx.attribute.change"</code></LI> |
| * </UL> |
| * Thus these two notifications are always added to those specified |
| * by the application. |
| * |
| * @return MBeanNotificationInfo[] |
| * |
| **/ |
| public MBeanNotificationInfo[] getNotificationInfo() { |
| if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(), |
| "getNotificationInfo()","Entry"); |
| } |
| |
| // Using hasNotification() is not optimal, but shouldn't really |
| // matter in this context... |
| |
| // hasGeneric==true if GENERIC notification is present. |
| // (bug 4744667) |
| final boolean hasGeneric = hasNotification(modelMBeanInfo,"GENERIC"); |
| |
| // hasAttributeChange==true if ATTRIBUTE_CHANGE notification is |
| // present. |
| // (bug 4744667) |
| final boolean hasAttributeChange = |
| hasNotification(modelMBeanInfo,"ATTRIBUTE_CHANGE"); |
| |
| // User supplied list of notification infos. |
| // |
| final ModelMBeanNotificationInfo[] currInfo = |
| (ModelMBeanNotificationInfo[])modelMBeanInfo.getNotifications(); |
| |
| // Length of the returned list of notification infos: |
| // length of user suplied list + possibly 1 for GENERIC, + |
| // possibly 1 for ATTRIBUTE_CHANGE |
| // (bug 4744667) |
| final int len = ((currInfo==null?0:currInfo.length) + |
| (hasGeneric?0:1) + (hasAttributeChange?0:1)); |
| |
| // Returned list of notification infos: |
| // |
| final ModelMBeanNotificationInfo[] respInfo = |
| new ModelMBeanNotificationInfo[len]; |
| |
| // Preserve previous ordering (JMX 1.1) |
| // |
| |
| // Counter of "standard" notification inserted before user |
| // supplied notifications. |
| // |
| int inserted=0; |
| if (!hasGeneric) |
| // We need to add description for GENERIC notification |
| // (bug 4744667) |
| respInfo[inserted++] = makeGenericInfo(); |
| |
| |
| if (!hasAttributeChange) |
| // We need to add description for ATTRIBUTE_CHANGE notification |
| // (bug 4744667) |
| respInfo[inserted++] = makeAttributeChangeInfo(); |
| |
| // Now copy user supplied list in returned list. |
| // |
| final int count = currInfo.length; |
| final int offset = inserted; |
| for (int j=0; j < count; j++) { |
| respInfo[offset+j] = currInfo[j]; |
| } |
| |
| if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(), |
| "getNotificationInfo()","Exit"); |
| } |
| |
| return respInfo; |
| } |
| |
| |
| public void addAttributeChangeNotificationListener(NotificationListener |
| inlistener, |
| String |
| inAttributeName, |
| Object inhandback) |
| throws MBeanException, RuntimeOperationsException, |
| IllegalArgumentException { |
| final String mth="addAttributeChangeNotificationListener(" + |
| "NotificationListener, String, Object)"; |
| |
| if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(),mth,"Entry"); |
| } |
| |
| if (inlistener == null) |
| throw new IllegalArgumentException( |
| "Listener to be registered must not be null"); |
| |
| |
| if (attributeBroadcaster == null) |
| attributeBroadcaster = new NotificationBroadcasterSupport(); |
| |
| AttributeChangeNotificationFilter currFilter = |
| new AttributeChangeNotificationFilter(); |
| |
| MBeanAttributeInfo[] attrInfo = modelMBeanInfo.getAttributes(); |
| boolean found = false; |
| if (inAttributeName == null) { |
| if ((attrInfo != null) && (attrInfo.length>0)) { |
| for (int i=0; i<attrInfo.length; i++) { |
| currFilter.enableAttribute(attrInfo[i].getName()); |
| } |
| } |
| } else { |
| if ((attrInfo != null) && (attrInfo.length>0)) { |
| for (int i=0; i<attrInfo.length; i++) { |
| if (inAttributeName.equals(attrInfo[i].getName())) { |
| found = true; |
| currFilter.enableAttribute(inAttributeName); |
| break; |
| } |
| } |
| } |
| if (!found) { |
| throw new RuntimeOperationsException(new |
| IllegalArgumentException( |
| "The attribute name does not exist"), |
| "Exception occurred trying to add an "+ |
| "AttributeChangeNotification listener"); |
| } |
| } |
| |
| if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { |
| Vector<String> enabledAttrs = currFilter.getEnabledAttributes(); |
| String s = (enabledAttrs.size() > 1) ? |
| "[" + enabledAttrs.firstElement() + ", ...]" : |
| enabledAttrs.toString(); |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(), mth, |
| "Set attribute change filter to " + s); |
| } |
| |
| attributeBroadcaster.addNotificationListener(inlistener,currFilter, |
| inhandback); |
| if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(),mth, |
| "Notification listener added for " + inAttributeName); |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(),mth,"Exit"); |
| } |
| } |
| |
| public void removeAttributeChangeNotificationListener( |
| NotificationListener inlistener, String inAttributeName) |
| throws MBeanException, RuntimeOperationsException, |
| ListenerNotFoundException { |
| if (inlistener == null) throw new |
| ListenerNotFoundException("Notification listener is null"); |
| |
| final String mth = "removeAttributeChangeNotificationListener(" + |
| "NotificationListener, String)"; |
| |
| if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(),mth,"Entry"); |
| } |
| |
| |
| if (attributeBroadcaster == null) |
| throw new ListenerNotFoundException( |
| "No attribute change notification listeners registered"); |
| |
| |
| MBeanAttributeInfo[] attrInfo = modelMBeanInfo.getAttributes(); |
| boolean found = false; |
| if ((attrInfo != null) && (attrInfo.length>0)) { |
| for (int i=0; i<attrInfo.length; i++) { |
| if (attrInfo[i].getName().equals(inAttributeName)) { |
| found = true; |
| break; |
| } |
| } |
| } |
| |
| if ((!found) && (inAttributeName != null)) { |
| throw new RuntimeOperationsException(new |
| IllegalArgumentException("Invalid attribute name"), |
| "Exception occurred trying to remove "+ |
| "attribute change notification listener"); |
| } |
| |
| /* note: */ |
| /* this may be a problem if the same listener is registered for |
| multiple attributes with multiple filters and/or handback |
| objects. It may remove all of them */ |
| |
| attributeBroadcaster.removeNotificationListener(inlistener); |
| |
| if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(),mth,"Exit"); |
| } |
| } |
| |
| public void sendAttributeChangeNotification(AttributeChangeNotification |
| ntfyObj) |
| throws MBeanException, RuntimeOperationsException { |
| final String mth = "sendAttributeChangeNotification(" + |
| "AttributeChangeNotification)"; |
| |
| if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(),mth,"Entry"); |
| } |
| |
| if (ntfyObj == null) |
| throw new RuntimeOperationsException(new |
| IllegalArgumentException( |
| "attribute change notification object must not be null"), |
| "Exception occurred trying to send "+ |
| "attribute change notification of a ModelMBean"); |
| |
| Object oldv = ntfyObj.getOldValue(); |
| Object newv = ntfyObj.getNewValue(); |
| |
| if (oldv == null) oldv = "null"; |
| if (newv == null) newv = "null"; |
| |
| if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(),mth, |
| "Sending AttributeChangeNotification with " + |
| ntfyObj.getAttributeName() + ntfyObj.getAttributeType() + |
| ntfyObj.getNewValue() + ntfyObj.getOldValue()); |
| } |
| |
| // log notification if specified in descriptor |
| Descriptor ntfyDesc = |
| modelMBeanInfo.getDescriptor(ntfyObj.getType(),"notification"); |
| Descriptor mmbDesc = modelMBeanInfo.getMBeanDescriptor(); |
| |
| String logging, logfile; |
| |
| if (ntfyDesc != null) { |
| logging =(String) ntfyDesc.getFieldValue("log"); |
| if (logging == null) { |
| if (mmbDesc != null) |
| logging = (String) mmbDesc.getFieldValue("log"); |
| } |
| if ((logging != null) && |
| ( logging.equalsIgnoreCase("t") || |
| logging.equalsIgnoreCase("true"))) { |
| logfile = (String) ntfyDesc.getFieldValue("logfile"); |
| if (logfile == null) { |
| if (mmbDesc != null) |
| logfile = (String)mmbDesc.getFieldValue("logfile"); |
| } |
| |
| if (logfile != null) { |
| try { |
| writeToLog(logfile,"LogMsg: " + |
| ((new Date(ntfyObj.getTimeStamp())).toString())+ |
| " " + ntfyObj.getType() + " " + |
| ntfyObj.getMessage() + |
| " Name = " + ntfyObj.getAttributeName() + |
| " Old value = " + oldv + |
| " New value = " + newv); |
| } catch (Exception e) { |
| if (MODELMBEAN_LOGGER.isLoggable(Level.FINE)) { |
| MODELMBEAN_LOGGER.logp(Level.FINE, |
| RequiredModelMBean.class.getName(),mth, |
| "Failed to log " + ntfyObj.getType() + |
| " notification: ", e); |
| } |
| } |
| } |
| } |
| } else if (mmbDesc != null) { |
| logging = (String) mmbDesc.getFieldValue("log"); |
| if ((logging != null) && |
| ( logging.equalsIgnoreCase("t") || |
| logging.equalsIgnoreCase("true") )) { |
| logfile = (String) mmbDesc.getFieldValue("logfile"); |
| |
| if (logfile != null) { |
| try { |
| writeToLog(logfile,"LogMsg: " + |
| ((new Date(ntfyObj.getTimeStamp())).toString())+ |
| " " + ntfyObj.getType() + " " + |
| ntfyObj.getMessage() + |
| " Name = " + ntfyObj.getAttributeName() + |
| " Old value = " + oldv + |
| " New value = " + newv); |
| } catch (Exception e) { |
| if (MODELMBEAN_LOGGER.isLoggable(Level.FINE)) { |
| MODELMBEAN_LOGGER.logp(Level.FINE, |
| RequiredModelMBean.class.getName(),mth, |
| "Failed to log " + ntfyObj.getType() + |
| " notification: ", e); |
| } |
| } |
| } |
| } |
| } |
| if (attributeBroadcaster != null) { |
| attributeBroadcaster.sendNotification(ntfyObj); |
| } |
| |
| // XXX Revisit: This is a quickfix: it would be better to have a |
| // single broadcaster. However, it is not so simple because |
| // removeAttributeChangeNotificationListener() should |
| // remove only listeners whose filter is an instanceof |
| // AttributeChangeNotificationFilter. |
| // |
| if (generalBroadcaster != null) { |
| generalBroadcaster.sendNotification(ntfyObj); |
| } |
| |
| if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(),mth, |
| "sent notification"); |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(),mth, |
| "Exit"); |
| } |
| } |
| |
| public void sendAttributeChangeNotification(Attribute inOldVal, |
| Attribute inNewVal) |
| throws MBeanException, RuntimeOperationsException { |
| final String mth = |
| "sendAttributeChangeNotification(Attribute, Attribute)"; |
| if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(),mth, |
| "Entry"); |
| } |
| |
| // do we really want to do this? |
| if ((inOldVal == null) || (inNewVal == null)) |
| throw new RuntimeOperationsException(new |
| IllegalArgumentException("Attribute object must not be null"), |
| "Exception occurred trying to send " + |
| "attribute change notification of a ModelMBean"); |
| |
| |
| if (!(inOldVal.getName().equals(inNewVal.getName()))) |
| throw new RuntimeOperationsException(new |
| IllegalArgumentException("Attribute names are not the same"), |
| "Exception occurred trying to send " + |
| "attribute change notification of a ModelMBean"); |
| |
| |
| Object newVal = inNewVal.getValue(); |
| Object oldVal = inOldVal.getValue(); |
| String className = "unknown"; |
| if (newVal != null) |
| className = newVal.getClass().getName(); |
| if (oldVal != null) |
| className = oldVal.getClass().getName(); |
| |
| AttributeChangeNotification myNtfyObj = new |
| AttributeChangeNotification(this, |
| 1, |
| ((new Date()).getTime()), |
| "AttributeChangeDetected", |
| inOldVal.getName(), |
| className, |
| inOldVal.getValue(), |
| inNewVal.getValue()); |
| |
| sendAttributeChangeNotification(myNtfyObj); |
| |
| if (MODELMBEAN_LOGGER.isLoggable(Level.FINER)) { |
| MODELMBEAN_LOGGER.logp(Level.FINER, |
| RequiredModelMBean.class.getName(),mth, |
| "Exit"); |
| } |
| |
| } |
| |
| /** |
| * Return the Class Loader Repository used to perform class loading. |
| * Subclasses may wish to redefine this method in order to return |
| * the appropriate {@link javax.management.loading.ClassLoaderRepository} |
| * that should be used in this object. |
| * |
| * @return the Class Loader Repository. |
| * |
| */ |
| protected ClassLoaderRepository getClassLoaderRepository() { |
| return MBeanServerFactory.getClassLoaderRepository(server); |
| } |
| |
| private Class<?> loadClass(String className) |
| throws ClassNotFoundException { |
| try { |
| return Class.forName(className); |
| } catch (ClassNotFoundException e) { |
| final ClassLoaderRepository clr = |
| getClassLoaderRepository(); |
| if (clr == null) throw new ClassNotFoundException(className); |
| return clr.loadClass(className); |
| } |
| } |
| |
| |
| /*************************************/ |
| /* MBeanRegistration Interface */ |
| /*************************************/ |
| |
| /** |
| * Allows the MBean to perform any operations it needs before |
| * being registered in the MBean server. If the name of the MBean |
| * is not specified, the MBean can provide a name for its |
| * registration. If any exception is raised, the MBean will not be |
| * registered in the MBean server. |
| * <P> |
| * In order to ensure proper run-time semantics of RequireModelMBean, |
| * Any subclass of RequiredModelMBean overloading or overriding this |
| * method should call <code>super.preRegister(server, name)</code> |
| * in its own <code>preRegister</code> implementation. |
| * |
| * @param server The MBean server in which the MBean will be registered. |
| * |
| * @param name The object name of the MBean. This name is null if |
| * the name parameter to one of the <code>createMBean</code> or |
| * <code>registerMBean</code> methods in the {@link MBeanServer} |
| * interface is null. In that case, this method must return a |
| * non-null ObjectName for the new MBean. |
| * |
| * @return The name under which the MBean is to be registered. |
| * This value must not be null. If the <code>name</code> |
| * parameter is not null, it will usually but not necessarily be |
| * the returned value. |
| * |
| * @exception java.lang.Exception This exception will be caught by |
| * the MBean server and re-thrown as an |
| * {@link javax.management.MBeanRegistrationException |
| * MBeanRegistrationException}. |
| */ |
| public ObjectName preRegister(MBeanServer server, |
| ObjectName name) |
| throws java.lang.Exception { |
| // Since ModelMbeanInfo cannot be null (otherwise exception |
| // thrown at creation) |
| // no exception thrown on ModelMBeanInfo not set. |
| if (name == null) throw new NullPointerException( |
| "name of RequiredModelMBean to registered is null"); |
| this.server = server; |
| return name; |
| } |
| |
| /** |
| * Allows the MBean to perform any operations needed after having been |
| * registered in the MBean server or after the registration has failed. |
| * <P> |
| * In order to ensure proper run-time semantics of RequireModelMBean, |
| * Any subclass of RequiredModelMBean overloading or overriding this |
| * method should call <code>super.postRegister(registrationDone)</code> |
| * in its own <code>postRegister</code> implementation. |
| * |
| * @param registrationDone Indicates whether or not the MBean has |
| * been successfully registered in the MBean server. The value |
| * false means that the registration phase has failed. |
| */ |
| public void postRegister(Boolean registrationDone) { |
| registered = registrationDone.booleanValue(); |
| } |
| |
| /** |
| * Allows the MBean to perform any operations it needs before |
| * being unregistered by the MBean server. |
| * <P> |
| * In order to ensure proper run-time semantics of RequireModelMBean, |
| * Any subclass of RequiredModelMBean overloading or overriding this |
| * method should call <code>super.preDeregister()</code> in its own |
| * <code>preDeregister</code> implementation. |
| * |
| * @exception java.lang.Exception This exception will be caught by |
| * the MBean server and re-thrown as an |
| * {@link javax.management.MBeanRegistrationException |
| * MBeanRegistrationException}. |
| */ |
| public void preDeregister() throws java.lang.Exception { |
| } |
| |
| /** |
| * Allows the MBean to perform any operations needed after having been |
| * unregistered in the MBean server. |
| * <P> |
| * In order to ensure proper run-time semantics of RequireModelMBean, |
| * Any subclass of RequiredModelMBean overloading or overriding this |
| * method should call <code>super.postDeregister()</code> in its own |
| * <code>postDeregister</code> implementation. |
| */ |
| public void postDeregister() { |
| registered = false; |
| this.server=null; |
| } |
| |
| private static final String[] primitiveTypes; |
| private static final String[] primitiveWrappers; |
| static { |
| primitiveTypes = new String[] { |
| Boolean.TYPE.getName(), |
| Byte.TYPE.getName(), |
| Character.TYPE.getName(), |
| Short.TYPE.getName(), |
| Integer.TYPE.getName(), |
| Long.TYPE.getName(), |
| Float.TYPE.getName(), |
| Double.TYPE.getName(), |
| Void.TYPE.getName() |
| }; |
| primitiveWrappers = new String[] { |
| Boolean.class.getName(), |
| Byte.class.getName(), |
| Character.class.getName(), |
| Short.class.getName(), |
| Integer.class.getName(), |
| Long.class.getName(), |
| Float.class.getName(), |
| Double.class.getName(), |
| Void.class.getName() |
| }; |
| } |
| } |