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.tomcat.util.modeler;
0019:
0020: import java.lang.reflect.InvocationTargetException;
0021: import java.lang.reflect.Method;
0022: import java.util.Iterator;
0023:
0024: import javax.management.Attribute;
0025: import javax.management.AttributeChangeNotification;
0026: import javax.management.AttributeList;
0027: import javax.management.AttributeNotFoundException;
0028: import javax.management.DynamicMBean;
0029: import javax.management.InstanceNotFoundException;
0030: import javax.management.InvalidAttributeValueException;
0031: import javax.management.ListenerNotFoundException;
0032: import javax.management.MBeanException;
0033: import javax.management.MBeanInfo;
0034: import javax.management.MBeanNotificationInfo;
0035: import javax.management.MBeanRegistration;
0036: import javax.management.MBeanServer;
0037: import javax.management.Notification;
0038: import javax.management.NotificationFilter;
0039: import javax.management.NotificationListener;
0040: import javax.management.ObjectName;
0041: import javax.management.ReflectionException;
0042: import javax.management.RuntimeErrorException;
0043: import javax.management.RuntimeOperationsException;
0044: import javax.management.modelmbean.InvalidTargetObjectTypeException;
0045: import javax.management.modelmbean.ModelMBeanNotificationBroadcaster;
0046:
0047: import org.apache.juli.logging.Log;
0048: import org.apache.juli.logging.LogFactory;
0049:
0050: /*
0051: * Changes from commons.modeler:
0052: *
0053: * - use DynamicMBean
0054: * - remove methods not used in tomcat and redundant/not very generic
0055: * - must be created from the ManagedBean - I don't think there were any direct
0056: * uses, but now it is required.
0057: * - some of the gratuituous flexibility removed - instead this is more predictive and
0058: * strict with the use cases.
0059: * - all Method and metadata is stored in ManagedBean. BaseModelBMean and ManagedBean act
0060: * like Object and Class.
0061: * - setModelMBean is no longer called on resources ( not used in tomcat )
0062: * - no caching of Methods for now - operations and setters are not called repeatedly in most
0063: * management use cases. Getters should't be called very frequently either - and even if they
0064: * are, the overhead of getting the method should be small compared with other JMX costs ( RMI, etc ).
0065: * We can add getter cache if needed.
0066: * - removed unused constructor, fields
0067: *
0068: * TODO:
0069: * - clean up catalina.mbeans, stop using weird inheritance
0070: */
0071:
0072: /**
0073: * <p>Basic implementation of the <code>DynamicMBean</code> interface, which
0074: * supports the minimal requirements of the interface contract.</p>
0075: *
0076: * <p>This can be used directly to wrap an existing java bean, or inside
0077: * an mlet or anywhere an MBean would be used.
0078: *
0079: * Limitations:
0080: * <ul>
0081: * <li>Only managed resources of type <code>objectReference</code> are
0082: * supportd.</li>
0083: * <li>Caching of attribute values and operation results is not supported.
0084: * All calls to <code>invoke()</code> are immediately executed.</li>
0085: * <li>Persistence of MBean attributes and operations is not supported.</li>
0086: * <li>All classes referenced as attribute types, operation parameters, or
0087: * operation return values must be one of the following:
0088: * <ul>
0089: * <li>One of the Java primitive types (boolean, byte, char, double,
0090: * float, integer, long, short). Corresponding value will be wrapped
0091: * in the appropriate wrapper class automatically.</li>
0092: * <li>Operations that return no value should declare a return type of
0093: * <code>void</code>.</li>
0094: * </ul>
0095: * <li>Attribute caching is not supported</li>
0096: * </ul>
0097: *
0098: * @author Craig R. McClanahan
0099: * @author Costin Manolache
0100: */
0101: public class BaseModelMBean implements DynamicMBean, MBeanRegistration,
0102: ModelMBeanNotificationBroadcaster {
0103: private static Log log = LogFactory.getLog(BaseModelMBean.class);
0104:
0105: // ----------------------------------------------------------- Constructors
0106:
0107: /**
0108: * Construct a <code>ModelMBean</code> with default
0109: * <code>ModelMBeanInfo</code> information.
0110: *
0111: * @exception MBeanException if the initializer of an object
0112: * throws an exception
0113: * @exception RuntimeOperationsException if an IllegalArgumentException
0114: * occurs
0115: */
0116: protected BaseModelMBean() throws MBeanException,
0117: RuntimeOperationsException {
0118: super ();
0119: }
0120:
0121: // ----------------------------------------------------- Instance Variables
0122:
0123: protected ObjectName oname = null;
0124:
0125: /**
0126: * Notification broadcaster for attribute changes.
0127: */
0128: protected BaseNotificationBroadcaster attributeBroadcaster = null;
0129:
0130: /**
0131: * Notification broadcaster for general notifications.
0132: */
0133: protected BaseNotificationBroadcaster generalBroadcaster = null;
0134:
0135: /** Metadata for the mbean instance.
0136: */
0137: protected ManagedBean managedBean = null;
0138:
0139: /**
0140: * The managed resource this MBean is associated with (if any).
0141: */
0142: protected Object resource = null;
0143:
0144: // --------------------------------------------------- DynamicMBean Methods
0145: // TODO: move to ManagedBean
0146: static final Object[] NO_ARGS_PARAM = new Object[0];
0147: static final Class[] NO_ARGS_PARAM_SIG = new Class[0];
0148:
0149: protected String resourceType = null;
0150:
0151: // key: operation val: invoke method
0152: //private Hashtable invokeAttMap=new Hashtable();
0153:
0154: /**
0155: * Obtain and return the value of a specific attribute of this MBean.
0156: *
0157: * @param name Name of the requested attribute
0158: *
0159: * @exception AttributeNotFoundException if this attribute is not
0160: * supported by this MBean
0161: * @exception MBeanException if the initializer of an object
0162: * throws an exception
0163: * @exception ReflectionException if a Java reflection exception
0164: * occurs when invoking the getter
0165: */
0166: public Object getAttribute(String name)
0167: throws AttributeNotFoundException, MBeanException,
0168: ReflectionException {
0169: // Validate the input parameters
0170: if (name == null)
0171: throw new RuntimeOperationsException(
0172: new IllegalArgumentException(
0173: "Attribute name is null"),
0174: "Attribute name is null");
0175:
0176: if ((resource instanceof DynamicMBean)
0177: && !(resource instanceof BaseModelMBean)) {
0178: return ((DynamicMBean) resource).getAttribute(name);
0179: }
0180:
0181: Method m = managedBean.getGetter(name, this , resource);
0182: Object result = null;
0183: try {
0184: Class declaring = m.getDeclaringClass();
0185: // workaround for catalina weird mbeans - the declaring class is BaseModelMBean.
0186: // but this is the catalina class.
0187: if (declaring.isAssignableFrom(this .getClass())) {
0188: result = m.invoke(this , NO_ARGS_PARAM);
0189: } else {
0190: result = m.invoke(resource, NO_ARGS_PARAM);
0191: }
0192: } catch (InvocationTargetException e) {
0193: Throwable t = e.getTargetException();
0194: if (t == null)
0195: t = e;
0196: if (t instanceof RuntimeException)
0197: throw new RuntimeOperationsException(
0198: (RuntimeException) t,
0199: "Exception invoking method " + name);
0200: else if (t instanceof Error)
0201: throw new RuntimeErrorException((Error) t,
0202: "Error invoking method " + name);
0203: else
0204: throw new MBeanException(e,
0205: "Exception invoking method " + name);
0206: } catch (Exception e) {
0207: throw new MBeanException(e, "Exception invoking method "
0208: + name);
0209: }
0210:
0211: // Return the results of this method invocation
0212: // FIXME - should we validate the return type?
0213: return (result);
0214: }
0215:
0216: /**
0217: * Obtain and return the values of several attributes of this MBean.
0218: *
0219: * @param names Names of the requested attributes
0220: */
0221: public AttributeList getAttributes(String names[]) {
0222:
0223: // Validate the input parameters
0224: if (names == null)
0225: throw new RuntimeOperationsException(
0226: new IllegalArgumentException(
0227: "Attribute names list is null"),
0228: "Attribute names list is null");
0229:
0230: // Prepare our response, eating all exceptions
0231: AttributeList response = new AttributeList();
0232: for (int i = 0; i < names.length; i++) {
0233: try {
0234: response.add(new Attribute(names[i],
0235: getAttribute(names[i])));
0236: } catch (Exception e) {
0237: ; // Not having a particular attribute in the response
0238: ; // is the indication of a getter problem
0239: }
0240: }
0241: return (response);
0242:
0243: }
0244:
0245: public void setManagedBean(ManagedBean managedBean) {
0246: this .managedBean = managedBean;
0247: }
0248:
0249: /**
0250: * Return the <code>MBeanInfo</code> object for this MBean.
0251: */
0252: public MBeanInfo getMBeanInfo() {
0253: return managedBean.getMBeanInfo();
0254: }
0255:
0256: /**
0257: * Invoke a particular method on this MBean, and return any returned
0258: * value.
0259: *
0260: * <p><strong>IMPLEMENTATION NOTE</strong> - This implementation will
0261: * attempt to invoke this method on the MBean itself, or (if not
0262: * available) on the managed resource object associated with this
0263: * MBean.</p>
0264: *
0265: * @param name Name of the operation to be invoked
0266: * @param params Array containing the method parameters of this operation
0267: * @param signature Array containing the class names representing
0268: * the signature of this operation
0269: *
0270: * @exception MBeanException if the initializer of an object
0271: * throws an exception
0272: * @exception ReflectioNException if a Java reflection exception
0273: * occurs when invoking a method
0274: */
0275: public Object invoke(String name, Object params[],
0276: String signature[]) throws MBeanException,
0277: ReflectionException {
0278: if ((resource instanceof DynamicMBean)
0279: && !(resource instanceof BaseModelMBean)) {
0280: return ((DynamicMBean) resource).invoke(name, params,
0281: signature);
0282: }
0283:
0284: // Validate the input parameters
0285: if (name == null)
0286: throw new RuntimeOperationsException(
0287: new IllegalArgumentException("Method name is null"),
0288: "Method name is null");
0289:
0290: if (log.isDebugEnabled())
0291: log.debug("Invoke " + name);
0292: MethodKey mkey = new MethodKey(name, signature);
0293: Method method = managedBean.getInvoke(name, params, signature,
0294: this , resource);
0295:
0296: // Invoke the selected method on the appropriate object
0297: Object result = null;
0298: try {
0299: if (method.getDeclaringClass().isAssignableFrom(
0300: this .getClass())) {
0301: result = method.invoke(this , params);
0302: } else {
0303: result = method.invoke(resource, params);
0304: }
0305: } catch (InvocationTargetException e) {
0306: Throwable t = e.getTargetException();
0307: log.error("Exception invoking method " + name, t);
0308: if (t == null)
0309: t = e;
0310: if (t instanceof RuntimeException)
0311: throw new RuntimeOperationsException(
0312: (RuntimeException) t,
0313: "Exception invoking method " + name);
0314: else if (t instanceof Error)
0315: throw new RuntimeErrorException((Error) t,
0316: "Error invoking method " + name);
0317: else
0318: throw new MBeanException((Exception) t,
0319: "Exception invoking method " + name);
0320: } catch (Exception e) {
0321: log.error("Exception invoking method " + name, 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: static Class getAttributeClass(String signature)
0333: throws ReflectionException {
0334: if (signature.equals(Boolean.TYPE.getName()))
0335: return Boolean.TYPE;
0336: else if (signature.equals(Byte.TYPE.getName()))
0337: return Byte.TYPE;
0338: else if (signature.equals(Character.TYPE.getName()))
0339: return Character.TYPE;
0340: else if (signature.equals(Double.TYPE.getName()))
0341: return Double.TYPE;
0342: else if (signature.equals(Float.TYPE.getName()))
0343: return Float.TYPE;
0344: else if (signature.equals(Integer.TYPE.getName()))
0345: return Integer.TYPE;
0346: else if (signature.equals(Long.TYPE.getName()))
0347: return Long.TYPE;
0348: else if (signature.equals(Short.TYPE.getName()))
0349: return Short.TYPE;
0350: else {
0351: try {
0352: ClassLoader cl = Thread.currentThread()
0353: .getContextClassLoader();
0354: if (cl != null)
0355: return cl.loadClass(signature);
0356: } catch (ClassNotFoundException e) {
0357: }
0358: try {
0359: return Class.forName(signature);
0360: } catch (ClassNotFoundException e) {
0361: throw new ReflectionException(e,
0362: "Cannot find Class for " + signature);
0363: }
0364: }
0365: }
0366:
0367: /**
0368: * Set the value of a specific attribute of this MBean.
0369: *
0370: * @param attribute The identification of the attribute to be set
0371: * and the new value
0372: *
0373: * @exception AttributeNotFoundException if this attribute is not
0374: * supported by this MBean
0375: * @exception MBeanException if the initializer of an object
0376: * throws an exception
0377: * @exception ReflectionException if a Java reflection exception
0378: * occurs when invoking the getter
0379: */
0380: public void setAttribute(Attribute attribute)
0381: throws AttributeNotFoundException, MBeanException,
0382: ReflectionException {
0383: if (log.isDebugEnabled())
0384: log.debug("Setting attribute " + this + " " + attribute);
0385:
0386: if ((resource instanceof DynamicMBean)
0387: && !(resource instanceof BaseModelMBean)) {
0388: try {
0389: ((DynamicMBean) resource).setAttribute(attribute);
0390: } catch (InvalidAttributeValueException e) {
0391: throw new MBeanException(e);
0392: }
0393: return;
0394: }
0395:
0396: // Validate the input parameters
0397: if (attribute == null)
0398: throw new RuntimeOperationsException(
0399: new IllegalArgumentException("Attribute is null"),
0400: "Attribute is null");
0401:
0402: String name = attribute.getName();
0403: Object value = attribute.getValue();
0404:
0405: if (name == null)
0406: throw new RuntimeOperationsException(
0407: new IllegalArgumentException(
0408: "Attribute name is null"),
0409: "Attribute name is null");
0410:
0411: Object oldValue = null;
0412: //if( getAttMap.get(name) != null )
0413: // oldValue=getAttribute( name );
0414:
0415: Method m = managedBean.getSetter(name, this , resource);
0416:
0417: try {
0418: if (m.getDeclaringClass().isAssignableFrom(this .getClass())) {
0419: m.invoke(this , new Object[] { value });
0420: } else {
0421: m.invoke(resource, new Object[] { value });
0422: }
0423: } catch (InvocationTargetException e) {
0424: Throwable t = e.getTargetException();
0425: if (t == null)
0426: t = e;
0427: if (t instanceof RuntimeException)
0428: throw new RuntimeOperationsException(
0429: (RuntimeException) t,
0430: "Exception invoking method " + name);
0431: else if (t instanceof Error)
0432: throw new RuntimeErrorException((Error) t,
0433: "Error invoking method " + name);
0434: else
0435: throw new MBeanException(e,
0436: "Exception invoking method " + name);
0437: } catch (Exception e) {
0438: log.error("Exception invoking method " + name, e);
0439: throw new MBeanException(e, "Exception invoking method "
0440: + name);
0441: }
0442: try {
0443: sendAttributeChangeNotification(new Attribute(name,
0444: oldValue), attribute);
0445: } catch (Exception ex) {
0446: log.error("Error sending notification " + name, ex);
0447: }
0448: //attributes.put( name, value );
0449: // if( source != null ) {
0450: // // this mbean is asscoiated with a source - maybe we want to persist
0451: // source.updateField(oname, name, value);
0452: // }
0453: }
0454:
0455: public String toString() {
0456: if (resource == null)
0457: return "BaseModelMbean[" + resourceType + "]";
0458: return resource.toString();
0459: }
0460:
0461: /**
0462: * Set the values of several attributes of this MBean.
0463: *
0464: * @param attributes THe names and values to be set
0465: *
0466: * @return The list of attributes that were set and their new values
0467: */
0468: public AttributeList setAttributes(AttributeList attributes) {
0469: AttributeList response = new AttributeList();
0470:
0471: // Validate the input parameters
0472: if (attributes == null)
0473: return response;
0474:
0475: // Prepare and return our response, eating all exceptions
0476: String names[] = new String[attributes.size()];
0477: int n = 0;
0478: Iterator items = attributes.iterator();
0479: while (items.hasNext()) {
0480: Attribute item = (Attribute) items.next();
0481: names[n++] = item.getName();
0482: try {
0483: setAttribute(item);
0484: } catch (Exception e) {
0485: ; // Ignore all exceptions
0486: }
0487: }
0488:
0489: return (getAttributes(names));
0490:
0491: }
0492:
0493: // ----------------------------------------------------- ModelMBean Methods
0494:
0495: /**
0496: * Get the instance handle of the object against which we execute
0497: * all methods in this ModelMBean management interface.
0498: *
0499: * @exception InstanceNotFoundException if the managed resource object
0500: * cannot be found
0501: * @exception MBeanException if the initializer of the object throws
0502: * an exception
0503: * @exception RuntimeOperationsException if the managed resource or the
0504: * resource type is <code>null</code> or invalid
0505: */
0506: public Object getManagedResource()
0507: throws InstanceNotFoundException,
0508: InvalidTargetObjectTypeException, MBeanException,
0509: RuntimeOperationsException {
0510:
0511: if (resource == null)
0512: throw new RuntimeOperationsException(
0513: new IllegalArgumentException(
0514: "Managed resource is null"),
0515: "Managed resource is null");
0516:
0517: return resource;
0518:
0519: }
0520:
0521: /**
0522: * Set the instance handle of the object against which we will execute
0523: * all methods in this ModelMBean management interface.
0524: *
0525: * <strike>This method will detect and call "setModelMbean" method. A resource
0526: * can implement this method to get a reference to the model mbean.
0527: * The reference can be used to send notification and access the
0528: * registry.
0529: * </strike> The caller can provide the mbean instance or the object name to
0530: * the resource, if needed.
0531: *
0532: * @param resource The resource object to be managed
0533: * @param type The type of reference for the managed resource
0534: * ("ObjectReference", "Handle", "IOR", "EJBHandle", or
0535: * "RMIReference")
0536: *
0537: * @exception InstanceNotFoundException if the managed resource object
0538: * cannot be found
0539: * @exception InvalidTargetObjectTypeException if this ModelMBean is
0540: * asked to handle a reference type it cannot deal with
0541: * @exception MBeanException if the initializer of the object throws
0542: * an exception
0543: * @exception RuntimeOperationsException if the managed resource or the
0544: * resource type is <code>null</code> or invalid
0545: */
0546: public void setManagedResource(Object resource, String type)
0547: throws InstanceNotFoundException, MBeanException,
0548: RuntimeOperationsException {
0549: if (resource == null)
0550: throw new RuntimeOperationsException(
0551: new IllegalArgumentException(
0552: "Managed resource is null"),
0553: "Managed resource is null");
0554:
0555: // if (!"objectreference".equalsIgnoreCase(type))
0556: // throw new InvalidTargetObjectTypeException(type);
0557:
0558: this .resource = resource;
0559: this .resourceType = resource.getClass().getName();
0560:
0561: // // Make the resource aware of the model mbean.
0562: // try {
0563: // Method m=resource.getClass().getMethod("setModelMBean",
0564: // new Class[] {ModelMBean.class});
0565: // if( m!= null ) {
0566: // m.invoke(resource, new Object[] {this});
0567: // }
0568: // } catch( NoSuchMethodException t ) {
0569: // // ignore
0570: // } catch( Throwable t ) {
0571: // log.error( "Can't set model mbean ", t );
0572: // }
0573: }
0574:
0575: // ------------------------------ ModelMBeanNotificationBroadcaster Methods
0576:
0577: /**
0578: * Add an attribute change notification event listener to this MBean.
0579: *
0580: * @param listener Listener that will receive event notifications
0581: * @param name Name of the attribute of interest, or <code>null</code>
0582: * to indicate interest in all attributes
0583: * @param handback Handback object to be sent along with event
0584: * notifications
0585: *
0586: * @exception IllegalArgumentException if the listener parameter is null
0587: */
0588: public void addAttributeChangeNotificationListener(
0589: NotificationListener listener, String name, Object handback)
0590: throws IllegalArgumentException {
0591:
0592: if (listener == null)
0593: throw new IllegalArgumentException("Listener is null");
0594: if (attributeBroadcaster == null)
0595: attributeBroadcaster = new BaseNotificationBroadcaster();
0596:
0597: if (log.isDebugEnabled())
0598: log.debug("addAttributeNotificationListener " + listener);
0599:
0600: BaseAttributeFilter filter = new BaseAttributeFilter(name);
0601: attributeBroadcaster.addNotificationListener(listener, filter,
0602: handback);
0603:
0604: }
0605:
0606: /**
0607: * Remove an attribute change notification event listener from
0608: * this MBean.
0609: *
0610: * @param listener The listener to be removed
0611: * @param name The attribute name for which no more events are required
0612: *
0613: *
0614: * @exception ListenerNotFoundException if this listener is not
0615: * registered in the MBean
0616: */
0617: public void removeAttributeChangeNotificationListener(
0618: NotificationListener listener, String name)
0619: throws ListenerNotFoundException {
0620:
0621: if (listener == null)
0622: throw new IllegalArgumentException("Listener is null");
0623: if (attributeBroadcaster == null)
0624: attributeBroadcaster = new BaseNotificationBroadcaster();
0625:
0626: // FIXME - currently this removes *all* notifications for this listener
0627: attributeBroadcaster.removeNotificationListener(listener);
0628:
0629: }
0630:
0631: /**
0632: * Remove an attribute change notification event listener from
0633: * this MBean.
0634: *
0635: * @param listener The listener to be removed
0636: * @param attributeName The attribute name for which no more events are required
0637: * @param handback Handback object to be sent along with event
0638: * notifications
0639: *
0640: *
0641: * @exception ListenerNotFoundException if this listener is not
0642: * registered in the MBean
0643: */
0644: public void removeAttributeChangeNotificationListener(
0645: NotificationListener listener, String attributeName,
0646: Object handback) throws ListenerNotFoundException {
0647:
0648: removeAttributeChangeNotificationListener(listener,
0649: attributeName);
0650:
0651: }
0652:
0653: /**
0654: * Send an <code>AttributeChangeNotification</code> to all registered
0655: * listeners.
0656: *
0657: * @param notification The <code>AttributeChangeNotification</code>
0658: * that will be passed
0659: *
0660: * @exception MBeanException if an object initializer throws an
0661: * exception
0662: * @exception RuntimeOperationsException wraps IllegalArgumentException
0663: * when the specified notification is <code>null</code> or invalid
0664: */
0665: public void sendAttributeChangeNotification(
0666: AttributeChangeNotification notification)
0667: throws MBeanException, RuntimeOperationsException {
0668:
0669: if (notification == null)
0670: throw new RuntimeOperationsException(
0671: new IllegalArgumentException("Notification is null"),
0672: "Notification is null");
0673: if (attributeBroadcaster == null)
0674: return; // This means there are no registered listeners
0675: if (log.isDebugEnabled())
0676: log.debug("AttributeChangeNotification " + notification);
0677: attributeBroadcaster.sendNotification(notification);
0678:
0679: }
0680:
0681: /**
0682: * Send an <code>AttributeChangeNotification</code> to all registered
0683: * listeners.
0684: *
0685: * @param oldValue The original value of the <code>Attribute</code>
0686: * @param newValue The new value of the <code>Attribute</code>
0687: *
0688: * @exception MBeanException if an object initializer throws an
0689: * exception
0690: * @exception RuntimeOperationsException wraps IllegalArgumentException
0691: * when the specified notification is <code>null</code> or invalid
0692: */
0693: public void sendAttributeChangeNotification(Attribute oldValue,
0694: Attribute newValue) throws MBeanException,
0695: RuntimeOperationsException {
0696:
0697: // Calculate the class name for the change notification
0698: String type = null;
0699: if (newValue.getValue() != null)
0700: type = newValue.getValue().getClass().getName();
0701: else if (oldValue.getValue() != null)
0702: type = oldValue.getValue().getClass().getName();
0703: else
0704: return; // Old and new are both null == no change
0705:
0706: AttributeChangeNotification notification = new AttributeChangeNotification(
0707: this , 1, System.currentTimeMillis(),
0708: "Attribute value has changed", oldValue.getName(),
0709: type, oldValue.getValue(), newValue.getValue());
0710: sendAttributeChangeNotification(notification);
0711:
0712: }
0713:
0714: /**
0715: * Send a <code>Notification</code> to all registered listeners as a
0716: * <code>jmx.modelmbean.general</code> notification.
0717: *
0718: * @param notification The <code>Notification</code> that will be passed
0719: *
0720: * @exception MBeanException if an object initializer throws an
0721: * exception
0722: * @exception RuntimeOperationsException wraps IllegalArgumentException
0723: * when the specified notification is <code>null</code> or invalid
0724: */
0725: public void sendNotification(Notification notification)
0726: throws MBeanException, RuntimeOperationsException {
0727:
0728: if (notification == null)
0729: throw new RuntimeOperationsException(
0730: new IllegalArgumentException("Notification is null"),
0731: "Notification is null");
0732: if (generalBroadcaster == null)
0733: return; // This means there are no registered listeners
0734: generalBroadcaster.sendNotification(notification);
0735:
0736: }
0737:
0738: /**
0739: * Send a <code>Notification</code> which contains the specified string
0740: * as a <code>jmx.modelmbean.generic</code> notification.
0741: *
0742: * @param message The message string to be passed
0743: *
0744: * @exception MBeanException if an object initializer throws an
0745: * exception
0746: * @exception RuntimeOperationsException wraps IllegalArgumentException
0747: * when the specified notification is <code>null</code> or invalid
0748: */
0749: public void sendNotification(String message) throws MBeanException,
0750: RuntimeOperationsException {
0751:
0752: if (message == null)
0753: throw new RuntimeOperationsException(
0754: new IllegalArgumentException("Message is null"),
0755: "Message is null");
0756: Notification notification = new Notification(
0757: "jmx.modelmbean.generic", this , 1, message);
0758: sendNotification(notification);
0759:
0760: }
0761:
0762: // ---------------------------------------- NotificationBroadcaster Methods
0763:
0764: /**
0765: * Add a notification event listener to this MBean.
0766: *
0767: * @param listener Listener that will receive event notifications
0768: * @param filter Filter object used to filter event notifications
0769: * actually delivered, or <code>null</code> for no filtering
0770: * @param handback Handback object to be sent along with event
0771: * notifications
0772: *
0773: * @exception IllegalArgumentException if the listener parameter is null
0774: */
0775: public void addNotificationListener(NotificationListener listener,
0776: NotificationFilter filter, Object handback)
0777: throws IllegalArgumentException {
0778:
0779: if (listener == null)
0780: throw new IllegalArgumentException("Listener is null");
0781:
0782: if (log.isDebugEnabled())
0783: log.debug("addNotificationListener " + listener);
0784:
0785: if (generalBroadcaster == null)
0786: generalBroadcaster = new BaseNotificationBroadcaster();
0787: generalBroadcaster.addNotificationListener(listener, filter,
0788: handback);
0789:
0790: // We'll send the attribute change notifications to all listeners ( who care )
0791: // The normal filtering can be used.
0792: // The problem is that there is no other way to add attribute change listeners
0793: // to a model mbean ( AFAIK ). I suppose the spec should be fixed.
0794: if (attributeBroadcaster == null)
0795: attributeBroadcaster = new BaseNotificationBroadcaster();
0796:
0797: if (log.isDebugEnabled())
0798: log.debug("addAttributeNotificationListener " + listener);
0799:
0800: attributeBroadcaster.addNotificationListener(listener, filter,
0801: handback);
0802: }
0803:
0804: /**
0805: * Return an <code>MBeanNotificationInfo</code> object describing the
0806: * notifications sent by this MBean.
0807: */
0808: public MBeanNotificationInfo[] getNotificationInfo() {
0809:
0810: // Acquire the set of application notifications
0811: MBeanNotificationInfo current[] = getMBeanInfo()
0812: .getNotifications();
0813: if (current == null)
0814: current = new MBeanNotificationInfo[0];
0815: MBeanNotificationInfo response[] = new MBeanNotificationInfo[current.length + 2];
0816: // Descriptor descriptor = null;
0817:
0818: // Fill in entry for general notifications
0819: // descriptor = new DescriptorSupport
0820: // (new String[] { "name=GENERIC",
0821: // "descriptorType=notification",
0822: // "log=T",
0823: // "severity=5",
0824: // "displayName=jmx.modelmbean.generic" });
0825: response[0] = new MBeanNotificationInfo(
0826: new String[] { "jmx.modelmbean.generic" }, "GENERIC",
0827: "Text message notification from the managed resource");
0828: //descriptor);
0829:
0830: // Fill in entry for attribute change notifications
0831: // descriptor = new DescriptorSupport
0832: // (new String[] { "name=ATTRIBUTE_CHANGE",
0833: // "descriptorType=notification",
0834: // "log=T",
0835: // "severity=5",
0836: // "displayName=jmx.attribute.change" });
0837: response[1] = new MBeanNotificationInfo(
0838: new String[] { "jmx.attribute.change" },
0839: "ATTRIBUTE_CHANGE",
0840: "Observed MBean attribute value has changed");
0841: //descriptor);
0842:
0843: // Copy remaining notifications as reported by the application
0844: System.arraycopy(current, 0, response, 2, current.length);
0845: return (response);
0846:
0847: }
0848:
0849: /**
0850: * Remove a notification event listener from this MBean.
0851: *
0852: * @param listener The listener to be removed (any and all registrations
0853: * for this listener will be eliminated)
0854: *
0855: * @exception ListenerNotFoundException if this listener is not
0856: * registered in the MBean
0857: */
0858: public void removeNotificationListener(NotificationListener listener)
0859: throws ListenerNotFoundException {
0860:
0861: if (listener == null)
0862: throw new IllegalArgumentException("Listener is null");
0863: if (generalBroadcaster == null)
0864: generalBroadcaster = new BaseNotificationBroadcaster();
0865: generalBroadcaster.removeNotificationListener(listener);
0866:
0867: }
0868:
0869: /**
0870: * Remove a notification event listener from this MBean.
0871: *
0872: * @param listener The listener to be removed (any and all registrations
0873: * for this listener will be eliminated)
0874: * @param handback Handback object to be sent along with event
0875: * notifications
0876: *
0877: * @exception ListenerNotFoundException if this listener is not
0878: * registered in the MBean
0879: */
0880: public void removeNotificationListener(
0881: NotificationListener listener, Object handback)
0882: throws ListenerNotFoundException {
0883:
0884: removeNotificationListener(listener);
0885:
0886: }
0887:
0888: /**
0889: * Remove a notification event listener from this MBean.
0890: *
0891: * @param listener The listener to be removed (any and all registrations
0892: * for this listener will be eliminated)
0893: * @param filter Filter object used to filter event notifications
0894: * actually delivered, or <code>null</code> for no filtering
0895: * @param handback Handback object to be sent along with event
0896: * notifications
0897: *
0898: * @exception ListenerNotFoundException if this listener is not
0899: * registered in the MBean
0900: */
0901: public void removeNotificationListener(
0902: NotificationListener listener, NotificationFilter filter,
0903: Object handback) throws ListenerNotFoundException {
0904:
0905: removeNotificationListener(listener);
0906:
0907: }
0908:
0909: // ------------------------------------------------ PersistentMBean Methods
0910:
0911: /**
0912: * Instantiates this MBean instance from data found in the persistent
0913: * store. The data loaded could include attribute and operation values.
0914: * This method should be called during construction or initialization
0915: * of the instance, and before the MBean is registered with the
0916: * <code>MBeanServer</code>.
0917: *
0918: * <p><strong>IMPLEMENTATION NOTE</strong> - This implementation does
0919: * not support persistence.</p>
0920: *
0921: * @exception InstanceNotFoundException if the managed resource object
0922: * cannot be found
0923: * @exception MBeanException if the initializer of the object throws
0924: * an exception
0925: * @exception RuntimeOperationsException if an exception is reported
0926: * by the persistence mechanism
0927: */
0928: // public void load() throws InstanceNotFoundException,
0929: // MBeanException, RuntimeOperationsException {
0930: // // XXX If a context was set, use it to load the data
0931: // throw new MBeanException
0932: // (new IllegalStateException("Persistence is not supported"),
0933: // "Persistence is not supported");
0934: //
0935: // }
0936:
0937: /**
0938: * Capture the current state of this MBean instance and write it out
0939: * to the persistent store. The state stored could include attribute
0940: * and operation values. If one of these methods of persistence is not
0941: * supported, a "service not found" exception will be thrown.
0942: *
0943: * <p><strong>IMPLEMENTATION NOTE</strong> - This implementation does
0944: * not support persistence.</p>
0945: *
0946: * @exception InstanceNotFoundException if the managed resource object
0947: * cannot be found
0948: * @exception MBeanException if the initializer of the object throws
0949: * an exception, or persistence is not supported
0950: * @exception RuntimeOperationsException if an exception is reported
0951: * by the persistence mechanism
0952: */
0953: // public void store() throws InstanceNotFoundException,
0954: // MBeanException, RuntimeOperationsException {
0955: //
0956: // // XXX if a context was set, use it to store the data
0957: // throw new MBeanException
0958: // (new IllegalStateException("Persistence is not supported"),
0959: // "Persistence is not supported");
0960: //
0961: // }
0962: // -------------------- BaseModelMBean methods --------------------
0963: /** Set the type of the mbean. This is used as a key to locate
0964: * the description in the Registry.
0965: *
0966: * @param type the type of classname of the modeled object
0967: */
0968: // void setModeledType( String type ) {
0969: // initModelInfo(type);
0970: // createResource();
0971: // }
0972: /** Set the type of the mbean. This is used as a key to locate
0973: * the description in the Registry.
0974: *
0975: * @param type the type of classname of the modeled object
0976: */
0977: // void initModelInfo( String type ) {
0978: // try {
0979: // if( log.isDebugEnabled())
0980: // log.debug("setModeledType " + type);
0981: //
0982: // log.debug( "Set model Info " + type);
0983: // if(type==null) {
0984: // return;
0985: // }
0986: // resourceType=type;
0987: // //Thread.currentThread().setContextClassLoader(BaseModelMBean.class.getClassLoader());
0988: // Class c=null;
0989: // try {
0990: // c=Class.forName( type);
0991: // } catch( Throwable t ) {
0992: // log.debug( "Error creating class " + t);
0993: // }
0994: //
0995: // // The class c doesn't need to exist
0996: // ManagedBean descriptor=getRegistry().findManagedBean(c, type);
0997: // if( descriptor==null )
0998: // return;
0999: // this.setModelMBeanInfo(descriptor.createMBeanInfo());
1000: // } catch( Throwable ex) {
1001: // log.error( "TCL: " + Thread.currentThread().getContextClassLoader(),
1002: // ex);
1003: // }
1004: // }
1005: /** Set the type of the mbean. This is used as a key to locate
1006: * the description in the Registry.
1007: */
1008: // protected void createResource() {
1009: // try {
1010: // //Thread.currentThread().setContextClassLoader(BaseModelMBean.class.getClassLoader());
1011: // Class c=null;
1012: // try {
1013: // c=Class.forName( resourceType );
1014: // resource = c.newInstance();
1015: // } catch( Throwable t ) {
1016: // log.error( "Error creating class " + t);
1017: // }
1018: // } catch( Throwable ex) {
1019: // log.error( "TCL: " + Thread.currentThread().getContextClassLoader(),
1020: // ex);
1021: // }
1022: // }
1023:
1024: public String getModelerType() {
1025: return resourceType;
1026: }
1027:
1028: public String getClassName() {
1029: return getModelerType();
1030: }
1031:
1032: public ObjectName getJmxName() {
1033: return oname;
1034: }
1035:
1036: public String getObjectName() {
1037: if (oname != null) {
1038: return oname.toString();
1039: } else {
1040: return null;
1041: }
1042: }
1043:
1044: // public void setRegistry(Registry registry) {
1045: // this.registry = registry;
1046: // }
1047: //
1048: // public Registry getRegistry() {
1049: // // XXX Need a better solution - to avoid the static
1050: // if( registry == null )
1051: // registry=Registry.getRegistry();
1052: //
1053: // return registry;
1054: // }
1055:
1056: // ------------------------------------------------------ Protected Methods
1057:
1058: /**
1059: * Create and return a default <code>ModelMBeanInfo</code> object.
1060: */
1061: // protected ModelMBeanInfo createDefaultModelMBeanInfo() {
1062: //
1063: // return (new ModelMBeanInfoSupport(this.getClass().getName(),
1064: // "Default ModelMBean",
1065: // null, null, null, null));
1066: //
1067: // }
1068: /**
1069: * Is the specified <code>ModelMBeanInfo</code> instance valid?
1070: *
1071: * <p><strong>IMPLEMENTATION NOTE</strong> - This implementation
1072: * does not check anything, but this method can be overridden
1073: * as required.</p>
1074: *
1075: * @param info The <code>ModelMBeanInfo object to check
1076: */
1077: // protected boolean isModelMBeanInfoValid(ModelMBeanInfo info) {
1078: // return (true);
1079: // }
1080: // -------------------- Registration --------------------
1081: // XXX We can add some method patterns here- like setName() and
1082: // setDomain() for code that doesn't implement the Registration
1083: public ObjectName preRegister(MBeanServer server, ObjectName name)
1084: throws Exception {
1085: if (log.isDebugEnabled())
1086: log.debug("preRegister " + resource + " " + name);
1087: oname = name;
1088: if (resource instanceof MBeanRegistration) {
1089: oname = ((MBeanRegistration) resource).preRegister(server,
1090: name);
1091: }
1092: return oname;
1093: }
1094:
1095: public void postRegister(Boolean registrationDone) {
1096: if (resource instanceof MBeanRegistration) {
1097: ((MBeanRegistration) resource)
1098: .postRegister(registrationDone);
1099: }
1100: }
1101:
1102: public void preDeregister() throws Exception {
1103: if (resource instanceof MBeanRegistration) {
1104: ((MBeanRegistration) resource).preDeregister();
1105: }
1106: }
1107:
1108: public void postDeregister() {
1109: if (resource instanceof MBeanRegistration) {
1110: ((MBeanRegistration) resource).postDeregister();
1111: }
1112: }
1113:
1114: static class MethodKey {
1115: private String name;
1116: private String[] signature;
1117:
1118: MethodKey(String name, String[] signature) {
1119: this .name = name;
1120: if (signature == null) {
1121: signature = new String[0];
1122: }
1123: this .signature = signature;
1124: }
1125:
1126: public boolean equals(Object other) {
1127: if (!(other instanceof MethodKey)) {
1128: return false;
1129: }
1130: MethodKey omk = (MethodKey) other;
1131: if (!name.equals(omk.name)) {
1132: return false;
1133: }
1134: if (signature.length != omk.signature.length) {
1135: return false;
1136: }
1137: for (int i = 0; i < signature.length; i++) {
1138: if (!signature[i].equals(omk.signature[i])) {
1139: return false;
1140: }
1141: }
1142: return true;
1143: }
1144:
1145: public int hashCode() {
1146: return name.hashCode();
1147: }
1148: }
1149: }
|