0001: /*
0002: * Licensed to the Apache Software Foundation (ASF) under one or more
0003: * contributor license agreements. See the NOTICE file distributed with
0004: * this work for additional information regarding copyright ownership.
0005: * The ASF licenses this file to You under the Apache License, Version 2.0
0006: * (the "License"); you may not use this file except in compliance with
0007: * the License. You may obtain a copy of the License at
0008: *
0009: * http://www.apache.org/licenses/LICENSE-2.0
0010: *
0011: * Unless required by applicable law or agreed to in writing, software
0012: * distributed under the License is distributed on an "AS IS" BASIS,
0013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0014: * See the License for the specific language governing permissions and
0015: * limitations under the License.
0016: */
0017:
0018: package org.apache.commons.modeler;
0019:
0020: import java.lang.reflect.InvocationTargetException;
0021: import java.lang.reflect.Method;
0022: import java.util.HashMap;
0023: import java.util.Hashtable;
0024: import java.util.Iterator;
0025:
0026: import javax.management.Attribute;
0027: import javax.management.AttributeChangeNotification;
0028: import javax.management.AttributeList;
0029: import javax.management.AttributeNotFoundException;
0030: import javax.management.Descriptor;
0031: import javax.management.DynamicMBean;
0032: import javax.management.InstanceNotFoundException;
0033: import javax.management.InvalidAttributeValueException;
0034: import javax.management.ListenerNotFoundException;
0035: import javax.management.MBeanException;
0036: import javax.management.MBeanInfo;
0037: import javax.management.MBeanNotificationInfo;
0038: import javax.management.MBeanRegistration;
0039: import javax.management.MBeanServer;
0040: import javax.management.Notification;
0041: import javax.management.NotificationFilter;
0042: import javax.management.NotificationListener;
0043: import javax.management.ObjectName;
0044: import javax.management.ReflectionException;
0045: import javax.management.RuntimeErrorException;
0046: import javax.management.RuntimeOperationsException;
0047: import javax.management.ServiceNotFoundException;
0048: import javax.management.modelmbean.DescriptorSupport;
0049: import javax.management.modelmbean.InvalidTargetObjectTypeException;
0050: import javax.management.modelmbean.ModelMBean;
0051: import javax.management.modelmbean.ModelMBeanAttributeInfo;
0052: import javax.management.modelmbean.ModelMBeanInfo;
0053: import javax.management.modelmbean.ModelMBeanInfoSupport;
0054: import javax.management.modelmbean.ModelMBeanNotificationInfo;
0055: import javax.management.modelmbean.ModelMBeanOperationInfo;
0056:
0057: import org.apache.commons.logging.Log;
0058: import org.apache.commons.logging.LogFactory;
0059: import org.apache.commons.modeler.modules.ModelerSource;
0060:
0061: // TODO: enable ant-like substitutions ? ( or at least discuss it )
0062:
0063: /**
0064: * <p>Basic implementation of the <code>ModelMBean</code> interface, which
0065: * supports the minimal requirements of the interface contract.</p>
0066: *
0067: * <p>This can be used directly to wrap an existing java bean, or inside
0068: * an mlet or anywhere an MBean would be used. The String parameter
0069: * passed to the constructor will be used to construct an instance of the
0070: * real object that we wrap.
0071: *
0072: * Limitations:
0073: * <ul>
0074: * <li>Only managed resources of type <code>objectReference</code> are
0075: * supportd.</li>
0076: * <li>Caching of attribute values and operation results is not supported.
0077: * All calls to <code>invoke()</code> are immediately executed.</li>
0078: * <li>Logging (under control of descriptors) is not supported.</li>
0079: * <li>Persistence of MBean attributes and operations is not supported.</li>
0080: * <li>All classes referenced as attribute types, operation parameters, or
0081: * operation return values must be one of the following:
0082: * <ul>
0083: * <li>One of the Java primitive types (boolean, byte, char, double,
0084: * float, integer, long, short). Corresponding value will be wrapped
0085: * in the appropriate wrapper class automatically.</li>
0086: * <li>Operations that return no value should declare a return type of
0087: * <code>void</code>.</li>
0088: * </ul>
0089: * <li>Attribute caching is not supported</li>
0090: * </ul>
0091: *
0092: * @author Craig R. McClanahan
0093: * @author Costin Manolache
0094: * @version $Revision: 480402 $ $Date: 2006-11-29 04:43:23 +0000 (Wed, 29 Nov 2006) $
0095: */
0096:
0097: public class BaseModelMBean implements ModelMBean, MBeanRegistration {
0098: private static Log log = LogFactory.getLog(BaseModelMBean.class);
0099:
0100: // ----------------------------------------------------------- Constructors
0101:
0102: /**
0103: * Construct a <code>ModelMBean</code> with default
0104: * <code>ModelMBeanInfo</code> information.
0105: *
0106: * @exception MBeanException if the initializer of an object
0107: * throws an exception
0108: * @exception RuntimeOperationsException if an IllegalArgumentException
0109: * occurs
0110: */
0111: public BaseModelMBean() throws MBeanException,
0112: RuntimeOperationsException {
0113:
0114: super ();
0115: if (log.isDebugEnabled())
0116: log.debug("default constructor");
0117: setModelMBeanInfo(createDefaultModelMBeanInfo());
0118: }
0119:
0120: /**
0121: * Construct a <code>ModelMBean</code> associated with the specified
0122: * <code>ModelMBeanInfo</code> information.
0123: *
0124: * @param info ModelMBeanInfo for this MBean
0125: *
0126: * @exception MBeanException if the initializer of an object
0127: * throws an exception
0128: * @exception RuntimeOperationsException if an IllegalArgumentException
0129: * occurs
0130: */
0131: public BaseModelMBean(ModelMBeanInfo info) throws MBeanException,
0132: RuntimeOperationsException {
0133: // XXX should be deprecated - just call setInfo
0134: super ();
0135: setModelMBeanInfo(info);
0136: if (log.isDebugEnabled())
0137: log.debug("ModelMBeanInfo constructor");
0138: }
0139:
0140: /** Construct a ModelMBean of a specified type.
0141: * The type can be a class name or the key used in one of the descriptors.
0142: *
0143: * If no descriptor is available, we'll first try to locate one in
0144: * the same package with the class, then use introspection.
0145: *
0146: * The mbean resource will be created.
0147: *
0148: * @param type Class name or the type key used in the descriptor.
0149: * @throws MBeanException
0150: * @throws RuntimeOperationsException
0151: */
0152: public BaseModelMBean(String type) throws MBeanException,
0153: RuntimeOperationsException {
0154: try {
0155: // This constructor is used from <mlet>, it should create
0156: // the resource
0157: setModeledType(type);
0158: } catch (Throwable ex) {
0159: log.error("Error creating mbean ", ex);
0160: }
0161: }
0162:
0163: public BaseModelMBean(String type, ModelerSource source)
0164: throws MBeanException, RuntimeOperationsException {
0165: try {
0166: setModeledType(type);
0167: } catch (Throwable ex) {
0168: log.error("Error creating mbean ", ex);
0169: }
0170: this .source = source;
0171: }
0172:
0173: // ----------------------------------------------------- Instance Variables
0174:
0175: /**
0176: * Notification broadcaster for attribute changes.
0177: */
0178: protected BaseNotificationBroadcaster attributeBroadcaster = null;
0179:
0180: /** Registry we are associated with
0181: */
0182: protected Registry registry = null;
0183:
0184: /**
0185: * Notification broadcaster for general notifications.
0186: */
0187: protected BaseNotificationBroadcaster generalBroadcaster = null;
0188:
0189: protected ObjectName oname = null;
0190:
0191: /**
0192: * The <code>ModelMBeanInfo</code> object that controls our activity.
0193: */
0194: protected ModelMBeanInfo info = null;
0195:
0196: /**
0197: * The managed resource this MBean is associated with (if any).
0198: */
0199: protected Object resource = null;
0200: protected String resourceType = null;
0201:
0202: /** Source object used to read this mbean. Can be used to
0203: * persist the mbean
0204: */
0205: protected ModelerSource source = null;
0206:
0207: /** Attribute values. XXX That can be stored in the value Field
0208: */
0209: protected HashMap attributes = new HashMap();
0210:
0211: // --------------------------------------------------- DynamicMBean Methods
0212: static final Object[] NO_ARGS_PARAM = new Object[0];
0213: static final Class[] NO_ARGS_PARAM_SIG = new Class[0];
0214: // key: attribute val: getter method
0215: private Hashtable getAttMap = new Hashtable();
0216:
0217: // key: attribute val: setter method
0218: private Hashtable setAttMap = new Hashtable();
0219:
0220: // key: operation val: invoke method
0221: private Hashtable invokeAttMap = new Hashtable();
0222:
0223: /**
0224: * Obtain and return the value of a specific attribute of this MBean.
0225: *
0226: * @param name Name of the requested attribute
0227: *
0228: * @exception AttributeNotFoundException if this attribute is not
0229: * supported by this MBean
0230: * @exception MBeanException if the initializer of an object
0231: * throws an exception
0232: * @exception ReflectionException if a Java reflection exception
0233: * occurs when invoking the getter
0234: */
0235: public Object getAttribute(String name)
0236: throws AttributeNotFoundException, MBeanException,
0237: ReflectionException {
0238: // Validate the input parameters
0239: if (name == null)
0240: throw new RuntimeOperationsException(
0241: new IllegalArgumentException(
0242: "Attribute name is null"),
0243: "Attribute name is null");
0244:
0245: if ((resource instanceof DynamicMBean)
0246: && !(resource instanceof BaseModelMBean)) {
0247: return ((DynamicMBean) resource).getAttribute(name);
0248: }
0249:
0250: // Extract the method from cache
0251: Method m = (Method) getAttMap.get(name);
0252:
0253: if (m == null) {
0254: // Look up the actual operation to be used
0255: ModelMBeanAttributeInfo attrInfo = info.getAttribute(name);
0256: if (attrInfo == null)
0257: throw new AttributeNotFoundException(
0258: " Cannot find attribute " + name);
0259: Descriptor attrDesc = attrInfo.getDescriptor();
0260: if (attrDesc == null)
0261: throw new AttributeNotFoundException(
0262: "Cannot find attribute " + name + " descriptor");
0263: String getMethod = (String) attrDesc
0264: .getFieldValue("getMethod");
0265:
0266: if (getMethod == null)
0267: throw new AttributeNotFoundException(
0268: "Cannot find attribute " + name
0269: + " get method name");
0270:
0271: Object object = null;
0272: NoSuchMethodException exception = null;
0273: try {
0274: object = this ;
0275: m = object.getClass().getMethod(getMethod,
0276: NO_ARGS_PARAM_SIG);
0277: } catch (NoSuchMethodException e) {
0278: exception = e;
0279: ;
0280: }
0281: if (m == null && resource != null) {
0282: try {
0283: object = resource;
0284: m = object.getClass().getMethod(getMethod,
0285: NO_ARGS_PARAM_SIG);
0286: exception = null;
0287: } catch (NoSuchMethodException e) {
0288: exception = e;
0289: }
0290: }
0291: if (exception != null)
0292: throw new ReflectionException(exception,
0293: "Cannot find getter method " + getMethod);
0294: getAttMap.put(name, m);
0295: }
0296:
0297: Object result = null;
0298: try {
0299: Class declaring = m.getDeclaringClass();
0300: // workaround for catalina weird mbeans - the declaring class is BaseModelMBean.
0301: // but this is the catalina class.
0302: if (declaring.isAssignableFrom(this .getClass())) {
0303: result = m.invoke(this , NO_ARGS_PARAM);
0304: } else {
0305: result = m.invoke(resource, NO_ARGS_PARAM);
0306: }
0307: } catch (InvocationTargetException e) {
0308: Throwable t = e.getTargetException();
0309: if (t == null)
0310: t = e;
0311: if (t instanceof RuntimeException)
0312: throw new RuntimeOperationsException(
0313: (RuntimeException) t,
0314: "Exception invoking method " + name);
0315: else if (t instanceof Error)
0316: throw new RuntimeErrorException((Error) t,
0317: "Error invoking method " + name);
0318: else
0319: throw new MBeanException(e,
0320: "Exception invoking method " + name);
0321: } catch (Exception e) {
0322: throw new MBeanException(e, "Exception invoking method "
0323: + name);
0324: }
0325:
0326: // Return the results of this method invocation
0327: // FIXME - should we validate the return type?
0328: return (result);
0329: }
0330:
0331: /**
0332: * Obtain and return the values of several attributes of this MBean.
0333: *
0334: * @param names Names of the requested attributes
0335: */
0336: public AttributeList getAttributes(String names[]) {
0337:
0338: // Validate the input parameters
0339: if (names == null)
0340: throw new RuntimeOperationsException(
0341: new IllegalArgumentException(
0342: "Attribute names list is null"),
0343: "Attribute names list is null");
0344:
0345: // Prepare our response, eating all exceptions
0346: AttributeList response = new AttributeList();
0347: for (int i = 0; i < names.length; i++) {
0348: try {
0349: response.add(new Attribute(names[i],
0350: getAttribute(names[i])));
0351: } catch (Exception e) {
0352: ; // Not having a particular attribute in the response
0353: ; // is the indication of a getter problem
0354: }
0355: }
0356: return (response);
0357:
0358: }
0359:
0360: /**
0361: * Return the <code>MBeanInfo</code> object for this MBean.
0362: */
0363: public MBeanInfo getMBeanInfo() {
0364: // XXX Why do we have to clone ?
0365: if (info == null)
0366: return null;
0367: return ((MBeanInfo) info.clone());
0368: }
0369:
0370: /**
0371: * Invoke a particular method on this MBean, and return any returned
0372: * value.
0373: *
0374: * <p><strong>IMPLEMENTATION NOTE</strong> - This implementation will
0375: * attempt to invoke this method on the MBean itself, or (if not
0376: * available) on the managed resource object associated with this
0377: * MBean.</p>
0378: *
0379: * @param name Name of the operation to be invoked
0380: * @param params Array containing the method parameters of this operation
0381: * @param signature Array containing the class names representing
0382: * the signature of this operation
0383: *
0384: * @exception MBeanException if the initializer of an object
0385: * throws an exception
0386: * @exception ReflectioNException if a Java reflection exception
0387: * occurs when invoking a method
0388: */
0389: public Object invoke(String name, Object params[],
0390: String signature[]) throws MBeanException,
0391: ReflectionException {
0392: if ((resource instanceof DynamicMBean)
0393: && !(resource instanceof BaseModelMBean)) {
0394: return ((DynamicMBean) resource).invoke(name, params,
0395: signature);
0396: }
0397:
0398: // Validate the input parameters
0399: if (name == null)
0400: throw new RuntimeOperationsException(
0401: new IllegalArgumentException("Method name is null"),
0402: "Method name is null");
0403:
0404: if (log.isDebugEnabled())
0405: log.debug("Invoke " + name);
0406: MethodKey mkey = new MethodKey(name, signature);
0407: Method method = (Method) invokeAttMap.get(mkey);
0408: if (method == null) {
0409: if (params == null)
0410: params = new Object[0];
0411: if (signature == null)
0412: signature = new String[0];
0413: if (params.length != signature.length)
0414: throw new RuntimeOperationsException(
0415: new IllegalArgumentException(
0416: "Inconsistent arguments and signature"),
0417: "Inconsistent arguments and signature");
0418:
0419: // Acquire the ModelMBeanOperationInfo information for
0420: // the requested operation
0421: ModelMBeanOperationInfo opInfo = info.getOperation(name);
0422: if (opInfo == null)
0423: throw new MBeanException(new ServiceNotFoundException(
0424: "Cannot find operation " + name),
0425: "Cannot find operation " + name);
0426:
0427: // Prepare the signature required by Java reflection APIs
0428: // FIXME - should we use the signature from opInfo?
0429: Class types[] = new Class[signature.length];
0430: for (int i = 0; i < signature.length; i++) {
0431: types[i] = getAttributeClass(signature[i]);
0432: }
0433:
0434: // Locate the method to be invoked, either in this MBean itself
0435: // or in the corresponding managed resource
0436: // FIXME - Accessible methods in superinterfaces?
0437: Object object = null;
0438: Exception exception = null;
0439: try {
0440: object = this ;
0441: method = object.getClass().getMethod(name, types);
0442: } catch (NoSuchMethodException e) {
0443: exception = e;
0444: ;
0445: }
0446: try {
0447: if ((method == null) && (resource != null)) {
0448: object = resource;
0449: method = object.getClass().getMethod(name, types);
0450: }
0451: } catch (NoSuchMethodException e) {
0452: exception = e;
0453: }
0454: if (method == null) {
0455: throw new ReflectionException(exception,
0456: "Cannot find method " + name
0457: + " with this signature");
0458: }
0459: invokeAttMap.put(mkey, method);
0460: }
0461:
0462: // Invoke the selected method on the appropriate object
0463: Object result = null;
0464: try {
0465: if (method.getDeclaringClass().isAssignableFrom(
0466: this .getClass())) {
0467: result = method.invoke(this , params);
0468: } else {
0469: result = method.invoke(resource, params);
0470: }
0471: } catch (InvocationTargetException e) {
0472: Throwable t = e.getTargetException();
0473: log.error("Exception invoking method " + name, t);
0474: if (t == null)
0475: t = e;
0476: if (t instanceof RuntimeException)
0477: throw new RuntimeOperationsException(
0478: (RuntimeException) t,
0479: "Exception invoking method " + name);
0480: else if (t instanceof Error)
0481: throw new RuntimeErrorException((Error) t,
0482: "Error invoking method " + name);
0483: else
0484: throw new MBeanException((Exception) t,
0485: "Exception invoking method " + name);
0486: } catch (Exception e) {
0487: log.error("Exception invoking method " + name, e);
0488: throw new MBeanException(e, "Exception invoking method "
0489: + name);
0490: }
0491:
0492: // Return the results of this method invocation
0493: // FIXME - should we validate the return type?
0494: return (result);
0495:
0496: }
0497:
0498: private Class getAttributeClass(String signature)
0499: throws ReflectionException {
0500: if (signature.equals(Boolean.TYPE.getName()))
0501: return Boolean.TYPE;
0502: else if (signature.equals(Byte.TYPE.getName()))
0503: return Byte.TYPE;
0504: else if (signature.equals(Character.TYPE.getName()))
0505: return Character.TYPE;
0506: else if (signature.equals(Double.TYPE.getName()))
0507: return Double.TYPE;
0508: else if (signature.equals(Float.TYPE.getName()))
0509: return Float.TYPE;
0510: else if (signature.equals(Integer.TYPE.getName()))
0511: return Integer.TYPE;
0512: else if (signature.equals(Long.TYPE.getName()))
0513: return Long.TYPE;
0514: else if (signature.equals(Short.TYPE.getName()))
0515: return Short.TYPE;
0516: else {
0517: try {
0518: ClassLoader cl = Thread.currentThread()
0519: .getContextClassLoader();
0520: if (cl != null)
0521: return cl.loadClass(signature);
0522: } catch (ClassNotFoundException e) {
0523: }
0524: try {
0525: return Class.forName(signature);
0526: } catch (ClassNotFoundException e) {
0527: throw new ReflectionException(e,
0528: "Cannot find Class for " + signature);
0529: }
0530: }
0531: }
0532:
0533: /**
0534: * Set the value of a specific attribute of this MBean.
0535: *
0536: * @param attribute The identification of the attribute to be set
0537: * and the new value
0538: *
0539: * @exception AttributeNotFoundException if this attribute is not
0540: * supported by this MBean
0541: * @exception MBeanException if the initializer of an object
0542: * throws an exception
0543: * @exception ReflectionException if a Java reflection exception
0544: * occurs when invoking the getter
0545: */
0546: public void setAttribute(Attribute attribute)
0547: throws AttributeNotFoundException, MBeanException,
0548: ReflectionException {
0549: if (log.isDebugEnabled())
0550: log.debug("Setting attribute " + this + " " + attribute);
0551:
0552: if ((resource instanceof DynamicMBean)
0553: && !(resource instanceof BaseModelMBean)) {
0554: try {
0555: ((DynamicMBean) resource).setAttribute(attribute);
0556: } catch (InvalidAttributeValueException e) {
0557: throw new MBeanException(e);
0558: }
0559: return;
0560: }
0561:
0562: // Validate the input parameters
0563: if (attribute == null)
0564: throw new RuntimeOperationsException(
0565: new IllegalArgumentException("Attribute is null"),
0566: "Attribute is null");
0567:
0568: String name = attribute.getName();
0569: Object value = attribute.getValue();
0570:
0571: if (name == null)
0572: throw new RuntimeOperationsException(
0573: new IllegalArgumentException(
0574: "Attribute name is null"),
0575: "Attribute name is null");
0576:
0577: ModelMBeanAttributeInfo attrInfo = info.getAttribute(name);
0578: if (attrInfo == null)
0579: throw new AttributeNotFoundException(
0580: "Cannot find attribute " + name);
0581:
0582: Descriptor attrDesc = attrInfo.getDescriptor();
0583: if (attrDesc == null)
0584: throw new AttributeNotFoundException(
0585: "Cannot find attribute " + name + " descriptor");
0586:
0587: Object oldValue = null;
0588: if (getAttMap.get(name) != null)
0589: oldValue = getAttribute(name);
0590:
0591: // Extract the method from cache
0592: Method m = (Method) setAttMap.get(name);
0593:
0594: if (m == null) {
0595: // Look up the actual operation to be used
0596: String setMethod = (String) attrDesc
0597: .getFieldValue("setMethod");
0598: if (setMethod == null)
0599: throw new AttributeNotFoundException(
0600: "Cannot find attribute " + name
0601: + " set method name");
0602:
0603: String argType = attrInfo.getType();
0604:
0605: Class signature[] = new Class[] { getAttributeClass(argType) };
0606:
0607: Object object = null;
0608: NoSuchMethodException exception = null;
0609: try {
0610: object = this ;
0611: m = object.getClass().getMethod(setMethod, signature);
0612: } catch (NoSuchMethodException e) {
0613: exception = e;
0614: ;
0615: }
0616: if (m == null && resource != null) {
0617: try {
0618: object = resource;
0619: m = object.getClass().getMethod(setMethod,
0620: signature);
0621: exception = null;
0622: } catch (NoSuchMethodException e) {
0623: if (log.isDebugEnabled())
0624: log.debug("Method not found in resource "
0625: + resource);
0626: exception = e;
0627: }
0628: }
0629: if (exception != null)
0630: throw new ReflectionException(exception,
0631: "Cannot find setter method " + setMethod + " "
0632: + resource);
0633: setAttMap.put(name, m);
0634: }
0635:
0636: Object result = null;
0637: try {
0638: if (m.getDeclaringClass().isAssignableFrom(this .getClass())) {
0639: result = m.invoke(this , new Object[] { value });
0640: } else {
0641: result = m.invoke(resource, new Object[] { value });
0642: }
0643: } catch (InvocationTargetException e) {
0644: Throwable t = e.getTargetException();
0645: if (t == null)
0646: t = e;
0647: if (t instanceof RuntimeException)
0648: throw new RuntimeOperationsException(
0649: (RuntimeException) t,
0650: "Exception invoking method " + name);
0651: else if (t instanceof Error)
0652: throw new RuntimeErrorException((Error) t,
0653: "Error invoking method " + name);
0654: else
0655: throw new MBeanException(e,
0656: "Exception invoking method " + name);
0657: } catch (Exception e) {
0658: log.error("Exception invoking method " + name, e);
0659: throw new MBeanException(e, "Exception invoking method "
0660: + name);
0661: }
0662: try {
0663: sendAttributeChangeNotification(new Attribute(name,
0664: oldValue), attribute);
0665: } catch (Exception ex) {
0666: log.error("Error sending notification " + name, ex);
0667: }
0668: attributes.put(name, value);
0669: if (source != null) {
0670: // this mbean is asscoiated with a source - maybe we want to persist
0671: source.updateField(oname, name, value);
0672: }
0673: }
0674:
0675: public String toString() {
0676: if (resource == null)
0677: return "BaseModelMbean[" + resourceType + "]";
0678: return resource.toString();
0679: }
0680:
0681: /**
0682: * Set the values of several attributes of this MBean.
0683: *
0684: * @param attributes THe names and values to be set
0685: *
0686: * @return The list of attributes that were set and their new values
0687: */
0688: public AttributeList setAttributes(AttributeList attributes) {
0689:
0690: // Validate the input parameters
0691: if (attributes == null)
0692: throw new RuntimeOperationsException(
0693: new IllegalArgumentException(
0694: "Attributes list is null"),
0695: "Attributes list is null");
0696:
0697: // Prepare and return our response, eating all exceptions
0698: AttributeList response = new AttributeList();
0699: String names[] = new String[attributes.size()];
0700: int n = 0;
0701: Iterator items = attributes.iterator();
0702: while (items.hasNext()) {
0703: Attribute item = (Attribute) items.next();
0704: names[n++] = item.getName();
0705: try {
0706: setAttribute(item);
0707: } catch (Exception e) {
0708: ; // Ignore all exceptions
0709: }
0710: }
0711:
0712: return (getAttributes(names));
0713:
0714: }
0715:
0716: // ----------------------------------------------------- ModelMBean Methods
0717:
0718: /**
0719: * Get the instance handle of the object against which we execute
0720: * all methods in this ModelMBean management interface.
0721: *
0722: * @exception InstanceNotFoundException if the managed resource object
0723: * cannot be found
0724: * @exception MBeanException if the initializer of the object throws
0725: * an exception
0726: * @exception RuntimeOperationsException if the managed resource or the
0727: * resource type is <code>null</code> or invalid
0728: */
0729: public Object getManagedResource()
0730: throws InstanceNotFoundException,
0731: InvalidTargetObjectTypeException, MBeanException,
0732: RuntimeOperationsException {
0733:
0734: if (resource == null)
0735: throw new RuntimeOperationsException(
0736: new IllegalArgumentException(
0737: "Managed resource is null"),
0738: "Managed resource is null");
0739:
0740: return resource;
0741:
0742: }
0743:
0744: /**
0745: * Set the instance handle of the object against which we will execute
0746: * all methods in this ModelMBean management interface.
0747: *
0748: * This method will detect and call "setModelMbean" method. A resource
0749: * can implement this method to get a reference to the model mbean.
0750: * The reference can be used to send notification and access the
0751: * registry.
0752: *
0753: * @param resource The resource object to be managed
0754: * @param type The type of reference for the managed resource
0755: * ("ObjectReference", "Handle", "IOR", "EJBHandle", or
0756: * "RMIReference")
0757: *
0758: * @exception InstanceNotFoundException if the managed resource object
0759: * cannot be found
0760: * @exception InvalidTargetObjectTypeException if this ModelMBean is
0761: * asked to handle a reference type it cannot deal with
0762: * @exception MBeanException if the initializer of the object throws
0763: * an exception
0764: * @exception RuntimeOperationsException if the managed resource or the
0765: * resource type is <code>null</code> or invalid
0766: */
0767: public void setManagedResource(Object resource, String type)
0768: throws InstanceNotFoundException,
0769: InvalidTargetObjectTypeException, MBeanException,
0770: RuntimeOperationsException {
0771: if (resource == null)
0772: throw new RuntimeOperationsException(
0773: new IllegalArgumentException(
0774: "Managed resource is null"),
0775: "Managed resource is null");
0776:
0777: if (!"objectreference".equalsIgnoreCase(type))
0778: throw new InvalidTargetObjectTypeException(type);
0779:
0780: this .resource = resource;
0781: this .resourceType = resource.getClass().getName();
0782:
0783: // Make the resource aware of the model mbean.
0784: try {
0785: Method m = resource.getClass().getMethod("setModelMBean",
0786: new Class[] { ModelMBean.class });
0787: if (m != null) {
0788: m.invoke(resource, new Object[] { this });
0789: }
0790: } catch (NoSuchMethodException t) {
0791: // ignore
0792: } catch (Throwable t) {
0793: log.error("Can't set model mbean ", t);
0794: }
0795: }
0796:
0797: /**
0798: * Initialize the <code>ModelMBeanInfo</code> associated with this
0799: * <code>ModelMBean</code>. After the information and associated
0800: * descriptors have been customized, the <code>ModelMBean</code> should
0801: * be registered with the associated <code>MBeanServer</code>.
0802: *
0803: * Currently the model can be set after registration. This behavior is
0804: * deprecated and won't be supported in future versions.
0805: *
0806: * @param info The ModelMBeanInfo object to be used by this ModelMBean
0807: *
0808: * @exception MBeanException If an exception occurs recording this
0809: * ModelMBeanInfo information
0810: * @exception RuntimeOperations if the specified parameter is
0811: * <code>null</code> or invalid
0812: */
0813: public void setModelMBeanInfo(ModelMBeanInfo info)
0814: throws MBeanException, RuntimeOperationsException {
0815:
0816: if (info == null)
0817: throw new RuntimeOperationsException(
0818: new IllegalArgumentException(
0819: "ModelMBeanInfo is null"),
0820: "ModelMBeanInfo is null");
0821:
0822: if (!isModelMBeanInfoValid(info))
0823: throw new RuntimeOperationsException(
0824: new IllegalArgumentException(
0825: "ModelMBeanInfo is invalid"),
0826: "ModelMBeanInfo is invalid");
0827:
0828: this .info = (ModelMBeanInfo) info.clone();
0829:
0830: }
0831:
0832: // ------------------------------ ModelMBeanNotificationBroadcaster Methods
0833:
0834: /**
0835: * Add an attribute change notification event listener to this MBean.
0836: *
0837: * @param listener Listener that will receive event notifications
0838: * @param name Name of the attribute of interest, or <code>null</code>
0839: * to indicate interest in all attributes
0840: * @param handback Handback object to be sent along with event
0841: * notifications
0842: *
0843: * @exception IllegalArgumentException if the listener parameter is null
0844: */
0845: public void addAttributeChangeNotificationListener(
0846: NotificationListener listener, String name, Object handback)
0847: throws IllegalArgumentException {
0848:
0849: if (listener == null)
0850: throw new IllegalArgumentException("Listener is null");
0851: if (attributeBroadcaster == null)
0852: attributeBroadcaster = new BaseNotificationBroadcaster();
0853:
0854: if (log.isDebugEnabled())
0855: log.debug("addAttributeNotificationListener " + listener);
0856:
0857: BaseAttributeFilter filter = new BaseAttributeFilter(name);
0858: attributeBroadcaster.addNotificationListener(listener, filter,
0859: handback);
0860:
0861: }
0862:
0863: /**
0864: * Remove an attribute change notification event listener from
0865: * this MBean.
0866: *
0867: * @param listener The listener to be removed
0868: * @param name The attribute name for which no more events are required
0869: *
0870: *
0871: * @exception ListenerNotFoundException if this listener is not
0872: * registered in the MBean
0873: */
0874: public void removeAttributeChangeNotificationListener(
0875: NotificationListener listener, String name)
0876: throws ListenerNotFoundException {
0877:
0878: if (listener == null)
0879: throw new IllegalArgumentException("Listener is null");
0880: if (attributeBroadcaster == null)
0881: attributeBroadcaster = new BaseNotificationBroadcaster();
0882:
0883: // FIXME - currently this removes *all* notifications for this listener
0884: attributeBroadcaster.removeNotificationListener(listener);
0885:
0886: }
0887:
0888: /**
0889: * Remove an attribute change notification event listener from
0890: * this MBean.
0891: *
0892: * @param listener The listener to be removed
0893: * @param attributeName The attribute name for which no more events are required
0894: * @param handback Handback object to be sent along with event
0895: * notifications
0896: *
0897: *
0898: * @exception ListenerNotFoundException if this listener is not
0899: * registered in the MBean
0900: */
0901: public void removeAttributeChangeNotificationListener(
0902: NotificationListener listener, String attributeName,
0903: Object handback) throws ListenerNotFoundException {
0904:
0905: removeAttributeChangeNotificationListener(listener,
0906: attributeName);
0907:
0908: }
0909:
0910: /**
0911: * Send an <code>AttributeChangeNotification</code> to all registered
0912: * listeners.
0913: *
0914: * @param notification The <code>AttributeChangeNotification</code>
0915: * that will be passed
0916: *
0917: * @exception MBeanException if an object initializer throws an
0918: * exception
0919: * @exception RuntimeOperationsException wraps IllegalArgumentException
0920: * when the specified notification is <code>null</code> or invalid
0921: */
0922: public void sendAttributeChangeNotification(
0923: AttributeChangeNotification notification)
0924: throws MBeanException, RuntimeOperationsException {
0925:
0926: if (notification == null)
0927: throw new RuntimeOperationsException(
0928: new IllegalArgumentException("Notification is null"),
0929: "Notification is null");
0930: if (attributeBroadcaster == null)
0931: return; // This means there are no registered listeners
0932: if (log.isDebugEnabled())
0933: log.debug("AttributeChangeNotification " + notification);
0934: attributeBroadcaster.sendNotification(notification);
0935:
0936: }
0937:
0938: /**
0939: * Send an <code>AttributeChangeNotification</code> to all registered
0940: * listeners.
0941: *
0942: * @param oldValue The original value of the <code>Attribute</code>
0943: * @param newValue The new value of the <code>Attribute</code>
0944: *
0945: * @exception MBeanException if an object initializer throws an
0946: * exception
0947: * @exception RuntimeOperationsException wraps IllegalArgumentException
0948: * when the specified notification is <code>null</code> or invalid
0949: */
0950: public void sendAttributeChangeNotification(Attribute oldValue,
0951: Attribute newValue) throws MBeanException,
0952: RuntimeOperationsException {
0953:
0954: // Calculate the class name for the change notification
0955: String type = null;
0956: if (newValue.getValue() != null)
0957: type = newValue.getValue().getClass().getName();
0958: else if (oldValue.getValue() != null)
0959: type = oldValue.getValue().getClass().getName();
0960: else
0961: return; // Old and new are both null == no change
0962:
0963: AttributeChangeNotification notification = new AttributeChangeNotification(
0964: this , 1, System.currentTimeMillis(),
0965: "Attribute value has changed", oldValue.getName(),
0966: type, oldValue.getValue(), newValue.getValue());
0967: sendAttributeChangeNotification(notification);
0968:
0969: }
0970:
0971: /**
0972: * Send a <code>Notification</code> to all registered listeners as a
0973: * <code>jmx.modelmbean.general</code> notification.
0974: *
0975: * @param notification The <code>Notification</code> that will be passed
0976: *
0977: * @exception MBeanException if an object initializer throws an
0978: * exception
0979: * @exception RuntimeOperationsException wraps IllegalArgumentException
0980: * when the specified notification is <code>null</code> or invalid
0981: */
0982: public void sendNotification(Notification notification)
0983: throws MBeanException, RuntimeOperationsException {
0984:
0985: if (notification == null)
0986: throw new RuntimeOperationsException(
0987: new IllegalArgumentException("Notification is null"),
0988: "Notification is null");
0989: if (generalBroadcaster == null)
0990: return; // This means there are no registered listeners
0991: generalBroadcaster.sendNotification(notification);
0992:
0993: }
0994:
0995: /**
0996: * Send a <code>Notification</code> which contains the specified string
0997: * as a <code>jmx.modelmbean.generic</code> notification.
0998: *
0999: * @param message The message string to be passed
1000: *
1001: * @exception MBeanException if an object initializer throws an
1002: * exception
1003: * @exception RuntimeOperationsException wraps IllegalArgumentException
1004: * when the specified notification is <code>null</code> or invalid
1005: */
1006: public void sendNotification(String message) throws MBeanException,
1007: RuntimeOperationsException {
1008:
1009: if (message == null)
1010: throw new RuntimeOperationsException(
1011: new IllegalArgumentException("Message is null"),
1012: "Message is null");
1013: Notification notification = new Notification(
1014: "jmx.modelmbean.generic", this , 1, message);
1015: sendNotification(notification);
1016:
1017: }
1018:
1019: // ---------------------------------------- NotificationBroadcaster Methods
1020:
1021: /**
1022: * Add a notification event listener to this MBean.
1023: *
1024: * @param listener Listener that will receive event notifications
1025: * @param filter Filter object used to filter event notifications
1026: * actually delivered, or <code>null</code> for no filtering
1027: * @param handback Handback object to be sent along with event
1028: * notifications
1029: *
1030: * @exception IllegalArgumentException if the listener parameter is null
1031: */
1032: public void addNotificationListener(NotificationListener listener,
1033: NotificationFilter filter, Object handback)
1034: throws IllegalArgumentException {
1035:
1036: if (listener == null)
1037: throw new IllegalArgumentException("Listener is null");
1038:
1039: if (log.isDebugEnabled())
1040: log.debug("addNotificationListener " + listener);
1041:
1042: if (generalBroadcaster == null)
1043: generalBroadcaster = new BaseNotificationBroadcaster();
1044: generalBroadcaster.addNotificationListener(listener, filter,
1045: handback);
1046:
1047: // We'll send the attribute change notifications to all listeners ( who care )
1048: // The normal filtering can be used.
1049: // The problem is that there is no other way to add attribute change listeners
1050: // to a model mbean ( AFAIK ). I suppose the spec should be fixed.
1051: if (attributeBroadcaster == null)
1052: attributeBroadcaster = new BaseNotificationBroadcaster();
1053:
1054: if (log.isDebugEnabled())
1055: log.debug("addAttributeNotificationListener " + listener);
1056:
1057: attributeBroadcaster.addNotificationListener(listener, filter,
1058: handback);
1059: }
1060:
1061: /**
1062: * Return an <code>MBeanNotificationInfo</code> object describing the
1063: * notifications sent by this MBean.
1064: */
1065: public MBeanNotificationInfo[] getNotificationInfo() {
1066:
1067: // Acquire the set of application notifications
1068: MBeanNotificationInfo current[] = info.getNotifications();
1069: if (current == null)
1070: current = new MBeanNotificationInfo[0];
1071: MBeanNotificationInfo response[] = new MBeanNotificationInfo[current.length + 2];
1072: Descriptor descriptor = null;
1073:
1074: // Fill in entry for general notifications
1075: descriptor = new DescriptorSupport(new String[] {
1076: "name=GENERIC", "descriptorType=notification", "log=T",
1077: "severity=5", "displayName=jmx.modelmbean.generic" });
1078: response[0] = new ModelMBeanNotificationInfo(
1079: new String[] { "jmx.modelmbean.generic" }, "GENERIC",
1080: "Text message notification from the managed resource",
1081: descriptor);
1082:
1083: // Fill in entry for attribute change notifications
1084: descriptor = new DescriptorSupport(new String[] {
1085: "name=ATTRIBUTE_CHANGE", "descriptorType=notification",
1086: "log=T", "severity=5",
1087: "displayName=jmx.attribute.change" });
1088: response[1] = new ModelMBeanNotificationInfo(
1089: new String[] { "jmx.attribute.change" },
1090: "ATTRIBUTE_CHANGE",
1091: "Observed MBean attribute value has changed",
1092: descriptor);
1093:
1094: // Copy remaining notifications as reported by the application
1095: System.arraycopy(current, 0, response, 2, current.length);
1096: return (response);
1097:
1098: }
1099:
1100: /**
1101: * Remove a notification event listener from this MBean.
1102: *
1103: * @param listener The listener to be removed (any and all registrations
1104: * for this listener will be eliminated)
1105: *
1106: * @exception ListenerNotFoundException if this listener is not
1107: * registered in the MBean
1108: */
1109: public void removeNotificationListener(NotificationListener listener)
1110: throws ListenerNotFoundException {
1111:
1112: if (listener == null)
1113: throw new IllegalArgumentException("Listener is null");
1114: if (generalBroadcaster == null)
1115: generalBroadcaster = new BaseNotificationBroadcaster();
1116: generalBroadcaster.removeNotificationListener(listener);
1117:
1118: }
1119:
1120: /**
1121: * Remove a notification event listener from this MBean.
1122: *
1123: * @param listener The listener to be removed (any and all registrations
1124: * for this listener will be eliminated)
1125: * @param handback Handback object to be sent along with event
1126: * notifications
1127: *
1128: * @exception ListenerNotFoundException if this listener is not
1129: * registered in the MBean
1130: */
1131: public void removeNotificationListener(
1132: NotificationListener listener, Object handback)
1133: throws ListenerNotFoundException {
1134:
1135: removeNotificationListener(listener);
1136:
1137: }
1138:
1139: /**
1140: * Remove a notification event listener from this MBean.
1141: *
1142: * @param listener The listener to be removed (any and all registrations
1143: * for this listener will be eliminated)
1144: * @param filter Filter object used to filter event notifications
1145: * actually delivered, or <code>null</code> for no filtering
1146: * @param handback Handback object to be sent along with event
1147: * notifications
1148: *
1149: * @exception ListenerNotFoundException if this listener is not
1150: * registered in the MBean
1151: */
1152: public void removeNotificationListener(
1153: NotificationListener listener, NotificationFilter filter,
1154: Object handback) throws ListenerNotFoundException {
1155:
1156: removeNotificationListener(listener);
1157:
1158: }
1159:
1160: // ------------------------------------------------ PersistentMBean Methods
1161:
1162: /**
1163: * Instantiates this MBean instance from data found in the persistent
1164: * store. The data loaded could include attribute and operation values.
1165: * This method should be called during construction or initialization
1166: * of the instance, and before the MBean is registered with the
1167: * <code>MBeanServer</code>.
1168: *
1169: * <p><strong>IMPLEMENTATION NOTE</strong> - This implementation does
1170: * not support persistence.</p>
1171: *
1172: * @exception InstanceNotFoundException if the managed resource object
1173: * cannot be found
1174: * @exception MBeanException if the initializer of the object throws
1175: * an exception
1176: * @exception RuntimeOperationsException if an exception is reported
1177: * by the persistence mechanism
1178: */
1179: public void load() throws InstanceNotFoundException,
1180: MBeanException, RuntimeOperationsException {
1181: // XXX If a context was set, use it to load the data
1182: throw new MBeanException(new IllegalStateException(
1183: "Persistence is not supported"),
1184: "Persistence is not supported");
1185:
1186: }
1187:
1188: /**
1189: * Capture the current state of this MBean instance and write it out
1190: * to the persistent store. The state stored could include attribute
1191: * and operation values. If one of these methods of persistence is not
1192: * supported, a "service not found" exception will be thrown.
1193: *
1194: * <p><strong>IMPLEMENTATION NOTE</strong> - This implementation does
1195: * not support persistence.</p>
1196: *
1197: * @exception InstanceNotFoundException if the managed resource object
1198: * cannot be found
1199: * @exception MBeanException if the initializer of the object throws
1200: * an exception, or persistence is not supported
1201: * @exception RuntimeOperationsException if an exception is reported
1202: * by the persistence mechanism
1203: */
1204: public void store() throws InstanceNotFoundException,
1205: MBeanException, RuntimeOperationsException {
1206:
1207: // XXX if a context was set, use it to store the data
1208: throw new MBeanException(new IllegalStateException(
1209: "Persistence is not supported"),
1210: "Persistence is not supported");
1211:
1212: }
1213:
1214: // -------------------- BaseModelMBean methods --------------------
1215:
1216: /** Set the type of the mbean. This is used as a key to locate
1217: * the description in the Registry.
1218: *
1219: * @param type the type of classname of the modeled object
1220: */
1221: public void setModeledType(String type) {
1222: initModelInfo(type);
1223: createResource();
1224: }
1225:
1226: /** Set the type of the mbean. This is used as a key to locate
1227: * the description in the Registry.
1228: *
1229: * @param type the type of classname of the modeled object
1230: */
1231: protected void initModelInfo(String type) {
1232: try {
1233: if (log.isDebugEnabled())
1234: log.debug("setModeledType " + type);
1235:
1236: log.debug("Set model Info " + type);
1237: if (type == null) {
1238: return;
1239: }
1240: resourceType = type;
1241: //Thread.currentThread().setContextClassLoader(BaseModelMBean.class.getClassLoader());
1242: Class c = null;
1243: try {
1244: c = Class.forName(type);
1245: } catch (Throwable t) {
1246: log.debug("Error creating class " + t);
1247: }
1248:
1249: // The class c doesn't need to exist
1250: ManagedBean descriptor = getRegistry().findManagedBean(c,
1251: type);
1252: if (descriptor == null)
1253: return;
1254: this .setModelMBeanInfo(descriptor.createMBeanInfo());
1255: } catch (Throwable ex) {
1256: log.error("TCL: "
1257: + Thread.currentThread().getContextClassLoader(),
1258: ex);
1259: }
1260: }
1261:
1262: /** Set the type of the mbean. This is used as a key to locate
1263: * the description in the Registry.
1264: */
1265: protected void createResource() {
1266: try {
1267: //Thread.currentThread().setContextClassLoader(BaseModelMBean.class.getClassLoader());
1268: Class c = null;
1269: try {
1270: c = Class.forName(resourceType);
1271: resource = c.newInstance();
1272: } catch (Throwable t) {
1273: log.error("Error creating class " + t);
1274: }
1275: } catch (Throwable ex) {
1276: log.error("TCL: "
1277: + Thread.currentThread().getContextClassLoader(),
1278: ex);
1279: }
1280: }
1281:
1282: public String getModelerType() {
1283: return resourceType;
1284: }
1285:
1286: public String getClassName() {
1287: return getModelerType();
1288: }
1289:
1290: public ObjectName getJmxName() {
1291: return oname;
1292: }
1293:
1294: public String getObjectName() {
1295: if (oname != null) {
1296: return oname.toString();
1297: } else {
1298: return null;
1299: }
1300: }
1301:
1302: public void setRegistry(Registry registry) {
1303: this .registry = registry;
1304: }
1305:
1306: public Registry getRegistry() {
1307: // XXX Need a better solution - to avoid the static
1308: if (registry == null)
1309: registry = Registry.getRegistry();
1310:
1311: return registry;
1312: }
1313:
1314: // ------------------------------------------------------ Protected Methods
1315:
1316: /**
1317: * Create and return a default <code>ModelMBeanInfo</code> object.
1318: */
1319: protected ModelMBeanInfo createDefaultModelMBeanInfo() {
1320:
1321: return (new ModelMBeanInfoSupport(this .getClass().getName(),
1322: "Default ModelMBean", null, null, null, null));
1323:
1324: }
1325:
1326: /**
1327: * Is the specified <code>ModelMBeanInfo</code> instance valid?
1328: *
1329: * <p><strong>IMPLEMENTATION NOTE</strong> - This implementation
1330: * does not check anything, but this method can be overridden
1331: * as required.</p>
1332: *
1333: * @param info The <code>ModelMBeanInfo object to check
1334: */
1335: protected boolean isModelMBeanInfoValid(ModelMBeanInfo info) {
1336: return (true);
1337: }
1338:
1339: // -------------------- Registration --------------------
1340: // XXX We can add some method patterns here- like setName() and
1341: // setDomain() for code that doesn't implement the Registration
1342:
1343: public ObjectName preRegister(MBeanServer server, ObjectName name)
1344: throws Exception {
1345: if (log.isDebugEnabled())
1346: log.debug("preRegister " + resource + " " + name);
1347: oname = name;
1348: if (resource instanceof MBeanRegistration) {
1349: oname = ((MBeanRegistration) resource).preRegister(server,
1350: name);
1351: }
1352: return oname;
1353: }
1354:
1355: public void postRegister(Boolean registrationDone) {
1356: if (resource instanceof MBeanRegistration) {
1357: ((MBeanRegistration) resource)
1358: .postRegister(registrationDone);
1359: }
1360: }
1361:
1362: public void preDeregister() throws Exception {
1363: if (resource instanceof MBeanRegistration) {
1364: ((MBeanRegistration) resource).preDeregister();
1365: }
1366: }
1367:
1368: public void postDeregister() {
1369: if (resource instanceof MBeanRegistration) {
1370: ((MBeanRegistration) resource).postDeregister();
1371: }
1372: }
1373:
1374: static class MethodKey {
1375: private String name;
1376: private String[] signature;
1377:
1378: MethodKey(String name, String[] signature) {
1379: this .name = name;
1380: if (signature == null) {
1381: signature = new String[0];
1382: }
1383: this .signature = signature;
1384: }
1385:
1386: public boolean equals(Object other) {
1387: if (!(other instanceof MethodKey)) {
1388: return false;
1389: }
1390: MethodKey omk = (MethodKey) other;
1391: if (!name.equals(omk.name)) {
1392: return false;
1393: }
1394: if (signature.length != omk.signature.length) {
1395: return false;
1396: }
1397: for (int i = 0; i < signature.length; i++) {
1398: if (!signature[i].equals(omk.signature[i])) {
1399: return false;
1400: }
1401: }
1402: return true;
1403: }
1404:
1405: public int hashCode() {
1406: return name.hashCode();
1407: }
1408: }
1409: }
|