0001: /*
0002: * Copyright (C) The MX4J Contributors.
0003: * All rights reserved.
0004: *
0005: * This software is distributed under the terms of the MX4J License version 1.0.
0006: * See the terms of the MX4J License in the documentation provided with this software.
0007: */
0008:
0009: package javax.management.modelmbean;
0010:
0011: import java.lang.reflect.InvocationTargetException;
0012: import java.lang.reflect.Method;
0013: import java.util.Date;
0014: import java.util.Iterator;
0015: import javax.management.Attribute;
0016: import javax.management.AttributeChangeNotification;
0017: import javax.management.AttributeChangeNotificationFilter;
0018: import javax.management.AttributeList;
0019: import javax.management.AttributeNotFoundException;
0020: import javax.management.Descriptor;
0021: import javax.management.InstanceNotFoundException;
0022: import javax.management.InvalidAttributeValueException;
0023: import javax.management.ListenerNotFoundException;
0024: import javax.management.MBeanAttributeInfo;
0025: import javax.management.MBeanException;
0026: import javax.management.MBeanInfo;
0027: import javax.management.MBeanNotificationInfo;
0028: import javax.management.MBeanRegistration;
0029: import javax.management.MBeanServer;
0030: import javax.management.MalformedObjectNameException;
0031: import javax.management.Notification;
0032: import javax.management.NotificationBroadcasterSupport;
0033: import javax.management.NotificationEmitter;
0034: import javax.management.NotificationFilter;
0035: import javax.management.NotificationListener;
0036: import javax.management.ObjectName;
0037: import javax.management.ReflectionException;
0038: import javax.management.RuntimeErrorException;
0039: import javax.management.RuntimeOperationsException;
0040: import javax.management.ServiceNotFoundException;
0041: import javax.management.loading.ClassLoaderRepository;
0042:
0043: import mx4j.ImplementationException;
0044: import mx4j.log.FileLogger;
0045: import mx4j.log.Log;
0046: import mx4j.log.Logger;
0047: import mx4j.log.MBeanLogger;
0048: import mx4j.persist.FilePersister;
0049: import mx4j.persist.MBeanPersister;
0050: import mx4j.persist.PersisterMBean;
0051: import mx4j.util.Utils;
0052:
0053: /**
0054: * @version $Revision: 1.22 $
0055: */
0056: public class RequiredModelMBean implements ModelMBean,
0057: MBeanRegistration, NotificationEmitter {
0058: private static final String OBJECT_RESOURCE_TYPE = "ObjectReference";
0059: private static final ModelMBeanInfoSupport DEFAULT_INFO;
0060: private static final ModelMBeanNotificationInfo GENERIC_INFO;
0061: private static final ModelMBeanNotificationInfo ATTR_CHANGE_INFO;
0062: static {
0063: String[] fields = new String[] { "name=GENERIC",
0064: "descriptorType=notification", "log=T", "severity=6",
0065: "displayName=jmx.modelmbean.generic" };
0066: GENERIC_INFO = new ModelMBeanNotificationInfo(
0067: new String[] { "jmx.modelmbean.generic" }, "GENERIC",
0068: "", new DescriptorSupport(fields));
0069: fields = new String[] { "name=ATTRIBUTE_CHANGE",
0070: "descriptorType=notification", "log=T", "severity=6",
0071: "displayName=jmx.attribute.change" };
0072: ATTR_CHANGE_INFO = new ModelMBeanNotificationInfo(
0073: new String[] { "jmx.attribute.change" },
0074: "ATTRIBUTE_CHANGE", "", new DescriptorSupport(fields));
0075: DEFAULT_INFO = new ModelMBeanInfoSupport(
0076: RequiredModelMBean.class.getName(), null, null, null,
0077: null, null);
0078: }
0079:
0080: private static final int ALWAYS_STALE = 1;
0081: private static final int NEVER_STALE = 2;
0082: private static final int STALE = 3;
0083: private static final int NOT_STALE = 4;
0084:
0085: private static final int PERSIST_NEVER = -1;
0086: private static final int PERSIST_ON_TIMER = -2;
0087: private static final int PERSIST_ON_UPDATE = -3;
0088: private static final int PERSIST_NO_MORE_OFTEN_THAN = -4;
0089:
0090: private MBeanServer m_mbeanServer;
0091: private Object m_managedResource;
0092: private ModelMBeanInfo m_modelMBeanInfo;
0093: private NotificationBroadcasterSupport m_generalBroadcaster = new NotificationBroadcasterSupport();
0094:
0095: public RequiredModelMBean() throws MBeanException,
0096: RuntimeOperationsException {
0097: m_modelMBeanInfo = DEFAULT_INFO;
0098: }
0099:
0100: public RequiredModelMBean(ModelMBeanInfo info)
0101: throws MBeanException, RuntimeOperationsException {
0102: if (info == null)
0103: throw new RuntimeOperationsException(
0104: new IllegalArgumentException(
0105: "ModelMBeanInfo parameter can't be null"));
0106: else
0107: setModelMBeanInfo(info);
0108: }
0109:
0110: private Logger getLogger() {
0111: return Log.getLogger(getClass().getName());
0112: }
0113:
0114: public ObjectName preRegister(MBeanServer server, ObjectName name)
0115: throws Exception {
0116: if (name == null)
0117: throw new IllegalArgumentException("ObjectName is null");
0118: m_mbeanServer = server;
0119: return name;
0120: }
0121:
0122: public void postRegister(Boolean registrationDone) {
0123: if (!registrationDone.booleanValue())
0124: clear();
0125: }
0126:
0127: public void preDeregister() throws Exception {
0128: }
0129:
0130: public void postDeregister() {
0131: clear();
0132: }
0133:
0134: private void clear() {
0135: m_mbeanServer = null;
0136: // PENDING: also remove generic listeners, attribute change listeners, log4j appenders...
0137: }
0138:
0139: public void setModelMBeanInfo(ModelMBeanInfo modelMBeanInfo)
0140: throws MBeanException, RuntimeOperationsException {
0141: if (m_mbeanServer != null)
0142: throw new RuntimeOperationsException(
0143: new IllegalStateException(
0144: "setModelMBeanInfo cannot be called when ModelMBean is registered"));
0145: if (modelMBeanInfo == null)
0146: throw new RuntimeOperationsException(
0147: new IllegalArgumentException(
0148: "ModelMBeanInfo cannot be null"));
0149: if (!isModelMBeanInfoValid(modelMBeanInfo))
0150: throw new RuntimeOperationsException(
0151: new IllegalArgumentException(
0152: "ModelMBeanInfo is invalid"));
0153:
0154: m_modelMBeanInfo = new ModelMBeanInfoSupport(modelMBeanInfo);
0155:
0156: Logger logger = getLogger();
0157: if (logger.isEnabledFor(Logger.DEBUG))
0158: logger.debug("ModelMBeanInfo successfully set to: "
0159: + m_modelMBeanInfo);
0160: }
0161:
0162: private boolean isModelMBeanInfoValid(ModelMBeanInfo info) {
0163: if (info == null || info.getClassName() == null)
0164: return false;
0165: // PENDING: maybe more checks are needed
0166: return true;
0167: }
0168:
0169: public void setManagedResource(Object resource, String resourceType)
0170: throws MBeanException, RuntimeOperationsException,
0171: InstanceNotFoundException, InvalidTargetObjectTypeException {
0172: if (!isResourceTypeSupported(resourceType))
0173: throw new InvalidTargetObjectTypeException(resourceType);
0174:
0175: Logger logger = getLogger();
0176: if (logger.isEnabledFor(Logger.DEBUG))
0177: logger.debug("Setting managed resource to be: " + resource);
0178: m_managedResource = resource;
0179: }
0180:
0181: private boolean isResourceTypeSupported(String resourceType) {
0182: // For now only object reference is supported
0183: return OBJECT_RESOURCE_TYPE.equalsIgnoreCase(resourceType);
0184: }
0185:
0186: private Object getManagedResource() {
0187: return m_managedResource;
0188: }
0189:
0190: public MBeanInfo getMBeanInfo() {
0191: return m_modelMBeanInfo == null ? null
0192: : (MBeanInfo) m_modelMBeanInfo.clone();
0193: }
0194:
0195: public void addAttributeChangeNotificationListener(
0196: NotificationListener listener, String attributeName,
0197: Object handback) throws MBeanException,
0198: RuntimeOperationsException, IllegalArgumentException {
0199: if (listener == null)
0200: throw new IllegalArgumentException(
0201: "Listener cannot be null");
0202: AttributeChangeNotificationFilter filter = new AttributeChangeNotificationFilter();
0203: if (attributeName != null) {
0204: if (m_modelMBeanInfo.getAttribute(attributeName) == null)
0205: throw new RuntimeOperationsException(
0206: new IllegalArgumentException(
0207: "No attribute named " + attributeName));
0208: filter.enableAttribute(attributeName);
0209: } else {
0210: MBeanAttributeInfo[] ai = m_modelMBeanInfo.getAttributes();
0211: for (int i = 0; i < ai.length; i++) {
0212: Descriptor d = ((ModelMBeanAttributeInfo) ai[i])
0213: .getDescriptor();
0214: filter
0215: .enableAttribute((String) d
0216: .getFieldValue("name"));
0217: }
0218: }
0219:
0220: getAttributeChangeBroadcaster().addNotificationListener(
0221: listener, filter, handback);
0222:
0223: Logger logger = getLogger();
0224: if (logger.isEnabledFor(Logger.DEBUG))
0225: logger.debug("Listener " + listener + " for attribute "
0226: + attributeName
0227: + " added successfully, handback is " + handback);
0228: }
0229:
0230: public void addNotificationListener(NotificationListener listener,
0231: NotificationFilter filter, Object handback)
0232: throws IllegalArgumentException {
0233: if (listener == null)
0234: throw new IllegalArgumentException(
0235: "listener cannot be null");
0236: m_generalBroadcaster.addNotificationListener(listener, filter,
0237: handback);
0238: }
0239:
0240: public MBeanNotificationInfo[] getNotificationInfo() {
0241: MBeanNotificationInfo[] notifications = m_modelMBeanInfo
0242: .getNotifications();
0243: boolean hasGeneric = false;
0244: boolean hasAttribute = false;
0245: int toAdd = 2;
0246: for (int i = 0; i < notifications.length; i++) {
0247: String name = notifications[i].getName();
0248: if ("GENERIC".equals(name)) {
0249: hasGeneric = true;
0250: toAdd -= 1;
0251: if (hasAttribute)
0252: break;
0253: } else if ("ATTRIBUTE_CHANGE".equals(name)) {
0254: hasAttribute = true;
0255: toAdd -= 1;
0256: if (hasGeneric)
0257: break;
0258: }
0259: }
0260:
0261: // clone the array, adding in missing notifications
0262: MBeanNotificationInfo[] newNotifications = new MBeanNotificationInfo[notifications.length
0263: + toAdd];
0264: System.arraycopy(notifications, 0, newNotifications, toAdd,
0265: notifications.length);
0266: if (!hasAttribute)
0267: newNotifications[--toAdd] = ATTR_CHANGE_INFO;
0268: if (!hasGeneric)
0269: newNotifications[--toAdd] = GENERIC_INFO;
0270: return newNotifications;
0271: }
0272:
0273: public void removeAttributeChangeNotificationListener(
0274: NotificationListener listener, String attributeName)
0275: throws MBeanException, RuntimeOperationsException,
0276: ListenerNotFoundException {
0277: //todo there may be a problem here if the original handback was not null - should we go directly to removeListener(NotificationListener) ?
0278: removeAttributeChangeNotificationListener(listener,
0279: attributeName, null);
0280: }
0281:
0282: // Not in the spec but needed
0283: private void removeAttributeChangeNotificationListener(
0284: NotificationListener listener, String attributeName,
0285: Object handback) throws MBeanException,
0286: RuntimeOperationsException, ListenerNotFoundException {
0287: if (listener == null)
0288: throw new ListenerNotFoundException("listener is null");
0289: AttributeChangeNotificationFilter filter = new AttributeChangeNotificationFilter();
0290: if (attributeName != null) {
0291: if (m_modelMBeanInfo.getAttribute(attributeName) == null)
0292: throw new RuntimeOperationsException(
0293: new IllegalArgumentException(
0294: "No attribute named " + attributeName));
0295: filter.enableAttribute(attributeName);
0296: } else {
0297: MBeanAttributeInfo[] ai = m_modelMBeanInfo.getAttributes();
0298: for (int i = 0; i < ai.length; i++) {
0299: Descriptor d = ((ModelMBeanAttributeInfo) ai[i])
0300: .getDescriptor();
0301: filter
0302: .enableAttribute((String) d
0303: .getFieldValue("name"));
0304: }
0305: }
0306:
0307: getAttributeChangeBroadcaster().removeNotificationListener(
0308: listener, filter, handback);
0309:
0310: Logger logger = getLogger();
0311: if (logger.isEnabledFor(Logger.DEBUG))
0312: logger.debug("Listener " + listener + " for attribute "
0313: + attributeName
0314: + " removed successfully, handback is " + handback);
0315: }
0316:
0317: public void removeNotificationListener(NotificationListener listener)
0318: throws RuntimeOperationsException,
0319: ListenerNotFoundException {
0320: m_generalBroadcaster.removeNotificationListener(listener);
0321: }
0322:
0323: public void removeNotificationListener(
0324: NotificationListener listener, NotificationFilter filter,
0325: Object handback) throws RuntimeOperationsException,
0326: ListenerNotFoundException {
0327: m_generalBroadcaster.removeNotificationListener(listener,
0328: filter, handback);
0329: }
0330:
0331: public void sendAttributeChangeNotification(Attribute oldAttribute,
0332: Attribute newAttribute) throws MBeanException,
0333: RuntimeOperationsException {
0334: if (oldAttribute == null || newAttribute == null)
0335: throw new RuntimeOperationsException(
0336: new IllegalArgumentException(
0337: "Attribute cannot be null"));
0338: if (!oldAttribute.getName().equals(newAttribute.getName()))
0339: throw new RuntimeOperationsException(
0340: new IllegalArgumentException(
0341: "Attribute names cannot be different"));
0342:
0343: // TODO: the source must be the object name of the MBean if the listener was registered through MBeanServer
0344: Object oldValue = oldAttribute.getValue();
0345: AttributeChangeNotification n = new AttributeChangeNotification(
0346: this ,
0347: 1,
0348: System.currentTimeMillis(),
0349: "Attribute value changed",
0350: oldAttribute.getName(),
0351: oldValue == null ? null : oldValue.getClass().getName(),
0352: oldValue, newAttribute.getValue());
0353: sendAttributeChangeNotification(n);
0354: }
0355:
0356: public void sendAttributeChangeNotification(
0357: AttributeChangeNotification notification)
0358: throws MBeanException, RuntimeOperationsException {
0359: if (notification == null)
0360: throw new RuntimeOperationsException(
0361: new IllegalArgumentException(
0362: "Notification cannot be null"));
0363:
0364: getAttributeChangeBroadcaster().sendNotification(notification);
0365:
0366: Logger modelMBeanLogger = getModelMBeanLogger(notification
0367: .getType());
0368: if (modelMBeanLogger != null)
0369: if (modelMBeanLogger.isEnabledFor(Logger.DEBUG))
0370: modelMBeanLogger.debug("ModelMBean log: " + new Date()
0371: + " - " + notification);
0372:
0373: Logger logger = getLogger();
0374: if (logger.isEnabledFor(Logger.DEBUG))
0375: logger.debug("Attribute change notification "
0376: + notification + " sent");
0377: }
0378:
0379: public void sendNotification(String message) throws MBeanException,
0380: RuntimeOperationsException {
0381: if (message == null)
0382: throw new RuntimeOperationsException(
0383: new IllegalArgumentException("message is null"));
0384: Notification notification = new Notification(
0385: "jmx.modelmbean.generic", this , 1, message);
0386: sendNotification(notification);
0387: }
0388:
0389: public void sendNotification(Notification notification)
0390: throws MBeanException, RuntimeOperationsException {
0391: if (notification == null)
0392: throw new RuntimeOperationsException(
0393: new IllegalArgumentException("notification is null"));
0394: m_generalBroadcaster.sendNotification(notification);
0395: }
0396:
0397: public AttributeList getAttributes(String[] attributes) {
0398: if (attributes == null)
0399: throw new RuntimeOperationsException(
0400: new IllegalArgumentException(
0401: "Attribute names cannot be null"));
0402:
0403: Logger logger = getLogger();
0404:
0405: AttributeList list = new AttributeList();
0406: for (int i = 0; i < attributes.length; ++i) {
0407: String attrName = attributes[i];
0408: Attribute attribute = null;
0409: try {
0410: Object value = getAttribute(attrName);
0411: attribute = new Attribute(attrName, value);
0412: list.add(attribute);
0413: } catch (Exception x) {
0414: if (logger.isEnabledFor(Logger.TRACE))
0415: logger.trace("getAttribute for attribute "
0416: + attrName + " failed", x);
0417: // And go on with the next attribute
0418: }
0419: }
0420: return list;
0421: }
0422:
0423: public Object getAttribute(String attribute)
0424: throws AttributeNotFoundException, MBeanException,
0425: ReflectionException {
0426: if (attribute == null)
0427: throw new RuntimeOperationsException(
0428: new IllegalArgumentException(
0429: "Attribute name cannot be null"));
0430:
0431: Logger logger = getLogger();
0432:
0433: // I want the real info, not its clone
0434: ModelMBeanInfo info = getModelMBeanInfo();
0435: if (info == null)
0436: throw new AttributeNotFoundException(
0437: "ModelMBeanInfo is null");
0438: if (logger.isEnabledFor(Logger.DEBUG))
0439: logger.debug("ModelMBeanInfo is: " + info);
0440:
0441: // This is a clone, we use it read only
0442: ModelMBeanAttributeInfo attrInfo = info.getAttribute(attribute);
0443: if (attrInfo == null)
0444: throw new AttributeNotFoundException(
0445: "Cannot find ModelMBeanAttributeInfo for attribute "
0446: + attribute);
0447: if (logger.isEnabledFor(Logger.DEBUG))
0448: logger.debug("Attribute info is: " + attrInfo);
0449: if (!attrInfo.isReadable())
0450: throw new AttributeNotFoundException("Attribute "
0451: + attribute + " is not readable");
0452:
0453: // This returns a clone of the mbean descriptor, we use it read only
0454: Descriptor mbeanDescriptor = info.getMBeanDescriptor();
0455: if (mbeanDescriptor == null)
0456: throw new AttributeNotFoundException(
0457: "MBean descriptor cannot be null");
0458: if (logger.isEnabledFor(Logger.DEBUG))
0459: logger.debug("MBean descriptor is: " + mbeanDescriptor);
0460:
0461: // This descriptor is a clone
0462: Descriptor attributeDescriptor = attrInfo.getDescriptor();
0463: if (attributeDescriptor == null)
0464: throw new AttributeNotFoundException(
0465: "Attribute descriptor for attribute " + attribute
0466: + " cannot be null");
0467: if (logger.isEnabledFor(Logger.DEBUG))
0468: logger.debug("Attribute descriptor is: "
0469: + attributeDescriptor);
0470:
0471: Object returnValue = null;
0472:
0473: String lastUpdateField = "lastUpdatedTimeStamp";
0474:
0475: int staleness = getStaleness(attributeDescriptor,
0476: mbeanDescriptor, lastUpdateField);
0477:
0478: if (staleness == ALWAYS_STALE || staleness == STALE) {
0479: if (logger.isEnabledFor(Logger.TRACE))
0480: logger.trace("Value is stale");
0481:
0482: String getter = (String) attributeDescriptor
0483: .getFieldValue("getMethod");
0484: if (logger.isEnabledFor(Logger.DEBUG))
0485: logger.debug("getMethod field is: " + getter);
0486: if (getter == null) {
0487: // No getter, use default value
0488: returnValue = attributeDescriptor
0489: .getFieldValue("default");
0490:
0491: if (returnValue != null) {
0492: // Check if the return type is of the same type
0493: // As an extension allow covariant return type
0494: Class returned = returnValue.getClass();
0495: Class declared = loadClassWithContextClassLoader(attrInfo
0496: .getType());
0497:
0498: checkAssignability(returned, declared);
0499: }
0500:
0501: if (logger.isEnabledFor(Logger.DEBUG))
0502: logger.debug("getAttribute for attribute "
0503: + attribute + " returns default value: "
0504: + returnValue);
0505: } else {
0506: if (logger.isEnabledFor(Logger.TRACE))
0507: logger.trace("Invoking attribute getter...");
0508: // As an extension, allow attributes to be called on target objects also
0509: Object target = resolveTargetObject(attributeDescriptor);
0510: returnValue = invokeMethod(target, getter,
0511: new Class[0], new Object[0]);
0512: if (logger.isEnabledFor(Logger.DEBUG))
0513: logger.debug("Returned value is: " + returnValue);
0514:
0515: if (returnValue != null) {
0516: // Check if the return type is of the same type
0517: // As an extension allow covariant return type
0518: Class returned = returnValue.getClass();
0519: Class declared = loadClassWithContextClassLoader(attrInfo
0520: .getType());
0521:
0522: checkAssignability(returned, declared);
0523: }
0524:
0525: // Cache the new value only if caching is needed
0526: if (staleness != ALWAYS_STALE) {
0527: attributeDescriptor.setField("value", returnValue);
0528: attributeDescriptor.setField(lastUpdateField,
0529: new Long(System.currentTimeMillis()));
0530: if (logger.isEnabledFor(Logger.TRACE))
0531: logger.trace("Returned value has been cached");
0532:
0533: // And now replace the descriptor with the updated clone
0534: info
0535: .setDescriptor(attributeDescriptor,
0536: "attribute");
0537: }
0538:
0539: if (logger.isEnabledFor(Logger.DEBUG))
0540: logger.debug("getAttribute for attribute "
0541: + attribute + " returns invoked value: "
0542: + returnValue);
0543: }
0544: } else {
0545: // Return cached value
0546: returnValue = attributeDescriptor.getFieldValue("value");
0547:
0548: if (returnValue != null) {
0549: // Check if the return type is of the same type
0550: // As an extension allow covariant return type
0551: Class returned = returnValue.getClass();
0552: Class declared = loadClassWithContextClassLoader(attrInfo
0553: .getType());
0554:
0555: checkAssignability(returned, declared);
0556: }
0557:
0558: if (logger.isEnabledFor(Logger.DEBUG))
0559: logger.debug("getAttribute for attribute " + attribute
0560: + " returns cached value: " + returnValue);
0561: }
0562:
0563: // Puff, everything went ok
0564: return returnValue;
0565: }
0566:
0567: public AttributeList setAttributes(AttributeList attributes) {
0568: if (attributes == null)
0569: throw new RuntimeOperationsException(
0570: new IllegalArgumentException(
0571: "Attribute list cannot be null"));
0572:
0573: Logger logger = getLogger();
0574:
0575: AttributeList list = new AttributeList();
0576: for (Iterator i = attributes.iterator(); i.hasNext();) {
0577: Attribute attribute = (Attribute) i.next();
0578: String name = attribute.getName();
0579: try {
0580: setAttribute(attribute);
0581: list.add(attribute);
0582: } catch (Exception x) {
0583: if (logger.isEnabledFor(Logger.TRACE))
0584: logger.trace("setAttribute for attribute " + name
0585: + " failed", x);
0586: // And go on with the next one
0587: }
0588: }
0589: return list;
0590: }
0591:
0592: public void setAttribute(Attribute attribute)
0593: throws AttributeNotFoundException,
0594: InvalidAttributeValueException, MBeanException,
0595: ReflectionException {
0596: if (attribute == null)
0597: throw new RuntimeOperationsException(
0598: new IllegalArgumentException(
0599: "Attribute cannot be null"));
0600:
0601: Logger logger = getLogger();
0602:
0603: // No need to synchronize: I work mostly on clones
0604: // I want the real info, not its clone
0605: ModelMBeanInfo info = getModelMBeanInfo();
0606: if (info == null)
0607: throw new AttributeNotFoundException(
0608: "ModelMBeanInfo is null");
0609: if (logger.isEnabledFor(Logger.DEBUG))
0610: logger.debug("ModelMBeanInfo is: " + info);
0611:
0612: String attrName = attribute.getName();
0613: Object attrValue = attribute.getValue();
0614:
0615: // This is a clone, we use it read only
0616: ModelMBeanAttributeInfo attrInfo = info.getAttribute(attrName);
0617: if (attrInfo == null)
0618: throw new AttributeNotFoundException(
0619: "Cannot find ModelMBeanAttributeInfo for attribute "
0620: + attrName);
0621: if (logger.isEnabledFor(Logger.DEBUG))
0622: logger.debug("Attribute info is: " + attrInfo);
0623:
0624: if (!attrInfo.isWritable())
0625: throw new AttributeNotFoundException("Attribute "
0626: + attrName + " is not writable");
0627:
0628: // This returns a clone of the mbean descriptor, we use it read only
0629: Descriptor mbeanDescriptor = info.getMBeanDescriptor();
0630: if (mbeanDescriptor == null)
0631: throw new AttributeNotFoundException(
0632: "MBean descriptor cannot be null");
0633: if (logger.isEnabledFor(Logger.DEBUG))
0634: logger.debug("MBean descriptor is: " + mbeanDescriptor);
0635:
0636: // This descriptor is a clone
0637: Descriptor attributeDescriptor = attrInfo.getDescriptor();
0638: if (attributeDescriptor == null)
0639: throw new AttributeNotFoundException(
0640: "Attribute descriptor for attribute " + attrName
0641: + " cannot be null");
0642: if (logger.isEnabledFor(Logger.DEBUG))
0643: logger.debug("Attribute descriptor is: "
0644: + attributeDescriptor);
0645:
0646: String lastUpdateField = "lastUpdatedTimeStamp";
0647:
0648: Object oldValue = null;
0649: try {
0650: oldValue = getAttribute(attrName);
0651: if (logger.isEnabledFor(Logger.DEBUG))
0652: logger.debug("Previous value of attribute " + attrName
0653: + ": " + oldValue);
0654: } catch (Exception x) {
0655: if (logger.isEnabledFor(Logger.DEBUG))
0656: logger.debug("Cannot get previous value of attribute "
0657: + attrName, x);
0658: }
0659:
0660: // Check if setMethod is present
0661: String method = (String) attributeDescriptor
0662: .getFieldValue("setMethod");
0663: if (logger.isEnabledFor(Logger.DEBUG))
0664: logger.debug("setMethod field is: " + method);
0665: if (method != null) {
0666: Class declared = loadClassWithContextClassLoader(attrInfo
0667: .getType());
0668: if (attrValue != null) {
0669: Class parameter = attrValue.getClass();
0670: checkAssignability(parameter, declared);
0671: }
0672:
0673: // As an extension, allow attributes to be called on target objects also
0674: Object target = resolveTargetObject(attributeDescriptor);
0675: invokeMethod(target, method, new Class[] { declared },
0676: new Object[] { attrValue });
0677:
0678: // Cache the value only if currencyTimeLimit is not 0, ie it is not always stale
0679: int staleness = getStaleness(attributeDescriptor,
0680: mbeanDescriptor, lastUpdateField);
0681: if (staleness != ALWAYS_STALE) {
0682: attributeDescriptor.setField("value", attrValue);
0683: attributeDescriptor.setField(lastUpdateField, new Long(
0684: System.currentTimeMillis()));
0685: if (logger.isEnabledFor(Logger.TRACE))
0686: logger.trace("Attribute's value has been cached");
0687: } else {
0688: if (logger.isEnabledFor(Logger.TRACE))
0689: logger
0690: .trace("Always stale, avoiding to cache attribute's value");
0691: }
0692: } else {
0693: if (attrValue != null) {
0694: Class parameter = attrValue.getClass();
0695: Class declared = loadClassWithContextClassLoader(attrInfo
0696: .getType());
0697:
0698: checkAssignability(parameter, declared);
0699: }
0700:
0701: // Always store the value in the descriptor: no setMethod
0702: attributeDescriptor.setField("value", attrValue);
0703: }
0704:
0705: // And now replace the descriptor with the updated clone
0706: info.setDescriptor(attributeDescriptor, "attribute");
0707:
0708: // Send notifications to listeners
0709: if (logger.isEnabledFor(Logger.TRACE))
0710: logger.trace("Sending attribute change notifications");
0711: sendAttributeChangeNotification(new Attribute(attrName,
0712: oldValue), attribute);
0713:
0714: // Persist this ModelMBean
0715: boolean persistNow = shouldPersistNow(attributeDescriptor,
0716: mbeanDescriptor, lastUpdateField);
0717: if (persistNow) {
0718: if (logger.isEnabledFor(Logger.TRACE))
0719: logger.trace("Persisting this ModelMBean...");
0720: try {
0721: store();
0722: if (logger.isEnabledFor(Logger.TRACE))
0723: logger.trace("ModelMBean persisted successfully");
0724: } catch (Exception x) {
0725: logger
0726: .error(
0727: "Cannot store ModelMBean after setAttribute",
0728: x);
0729: if (x instanceof MBeanException)
0730: throw (MBeanException) x;
0731: else
0732: throw new MBeanException(x);
0733: }
0734: }
0735: }
0736:
0737: public Object invoke(String method, Object[] arguments,
0738: String[] params) throws MBeanException, ReflectionException {
0739: if (method == null)
0740: throw new RuntimeOperationsException(
0741: new IllegalArgumentException(
0742: "Method name cannot be null"));
0743: if (arguments == null)
0744: arguments = new Object[0];
0745: if (params == null)
0746: params = new String[0];
0747:
0748: Logger logger = getLogger();
0749:
0750: // Find operation descriptor
0751: ModelMBeanInfo info = getModelMBeanInfo();
0752: if (info == null)
0753: throw new MBeanException(new ServiceNotFoundException(
0754: "ModelMBeanInfo is null"));
0755: if (logger.isEnabledFor(Logger.DEBUG))
0756: logger.debug("ModelMBeanInfo is: " + info);
0757:
0758: // This is a clone, we use it read only
0759: ModelMBeanOperationInfo operInfo = info.getOperation(method);
0760: if (operInfo == null) {
0761: // Bug #940161 Required ModelMBean methods are not invoked
0762: try {
0763: // Look in RMMB public methods
0764: Class[] clzArgs = new Class[params.length];
0765: for (int i = 0; i < clzArgs.length; i++) {
0766: ClassLoader loader = getClass().getClassLoader();
0767: if (loader == null)
0768: loader = Thread.currentThread()
0769: .getContextClassLoader();
0770: clzArgs[i] = loader.loadClass(params[i]);
0771: }
0772:
0773: // Class.getMethod only returns public methods
0774: Method invocationMethod = getClass().getMethod(method,
0775: clzArgs);
0776: operInfo = new ModelMBeanOperationInfo("",
0777: invocationMethod);
0778: } catch (Exception e) {
0779: throw new MBeanException(new ServiceNotFoundException(
0780: "Cannot find ModelMBeanOperationInfo for operation "
0781: + method));
0782: }
0783: }
0784: if (logger.isEnabledFor(Logger.DEBUG))
0785: logger.debug("Operation info is: " + operInfo);
0786:
0787: // This descriptor is a clone
0788: Descriptor operationDescriptor = operInfo.getDescriptor();
0789: if (operationDescriptor == null)
0790: throw new MBeanException(new ServiceNotFoundException(
0791: "Operation descriptor for operation " + method
0792: + " cannot be null"));
0793: String role = (String) operationDescriptor
0794: .getFieldValue("role");
0795: if (role == null || !role.equals("operation"))
0796: throw new MBeanException(new ServiceNotFoundException(
0797: "Operation descriptor field 'role' must be 'operation', not "
0798: + role));
0799: if (logger.isEnabledFor(Logger.DEBUG))
0800: logger.debug("Operation descriptor is: "
0801: + operationDescriptor);
0802:
0803: // This returns a clone of the mbean descriptor, we use it read only
0804: Descriptor mbeanDescriptor = info.getMBeanDescriptor();
0805: if (mbeanDescriptor == null)
0806: throw new MBeanException(new ServiceNotFoundException(
0807: "MBean descriptor cannot be null"));
0808: if (logger.isEnabledFor(Logger.DEBUG))
0809: logger.debug("MBean descriptor is: " + mbeanDescriptor);
0810:
0811: Object returnValue = null;
0812:
0813: String lastUpdateField = "lastReturnedTimeStamp";
0814:
0815: // Check if the method should be invoked given the cache settings
0816: int staleness = getStaleness(operationDescriptor,
0817: mbeanDescriptor, lastUpdateField);
0818:
0819: if (staleness == ALWAYS_STALE || staleness == STALE) {
0820: if (logger.isEnabledFor(Logger.TRACE))
0821: logger.trace("Value is stale");
0822:
0823: // Find parameters classes
0824: Class[] parameters = null;
0825: try {
0826: parameters = Utils.loadClasses(Thread.currentThread()
0827: .getContextClassLoader(), params);
0828: } catch (ClassNotFoundException x) {
0829: logger.error(
0830: "Cannot find operation's parameter classes", x);
0831: throw new ReflectionException(x);
0832: }
0833:
0834: if (logger.isEnabledFor(Logger.TRACE))
0835: logger.trace("Invoking operation...");
0836:
0837: // Find target object
0838: Object target = resolveTargetObject(operationDescriptor);
0839: returnValue = invokeMethod(target, method, parameters,
0840: arguments);
0841:
0842: if (logger.isEnabledFor(Logger.DEBUG))
0843: logger.debug("Returned value is: " + returnValue);
0844:
0845: if (returnValue != null) {
0846: Class parameter = returnValue.getClass();
0847: Class declared = loadClassWithContextClassLoader(operInfo
0848: .getReturnType());
0849:
0850: checkAssignability(parameter, declared);
0851: }
0852:
0853: // Cache the new value only if caching is needed
0854: if (staleness != ALWAYS_STALE) {
0855: operationDescriptor.setField("lastReturnedValue",
0856: returnValue);
0857: operationDescriptor.setField(lastUpdateField, new Long(
0858: System.currentTimeMillis()));
0859: if (logger.isEnabledFor(Logger.TRACE)) {
0860: logger.trace("Returned value has been cached");
0861: }
0862:
0863: // And now replace the descriptor with the updated clone
0864: info.setDescriptor(operationDescriptor, "operation");
0865: }
0866:
0867: if (logger.isEnabledFor(Logger.DEBUG))
0868: logger.debug("invoke for operation " + method
0869: + " returns invoked value: " + returnValue);
0870: } else {
0871: // Return cached value
0872: returnValue = operationDescriptor
0873: .getFieldValue("lastReturnedValue");
0874:
0875: if (returnValue != null) {
0876: Class parameter = returnValue.getClass();
0877: Class declared = loadClassWithContextClassLoader(operInfo
0878: .getReturnType());
0879:
0880: checkAssignability(parameter, declared);
0881: }
0882:
0883: if (logger.isEnabledFor(Logger.DEBUG))
0884: logger.debug("invoke for operation " + method
0885: + " returns cached value: " + returnValue);
0886: }
0887:
0888: // As an extension, persist this model mbean also after operation invocation, but using only
0889: // settings provided in the operation descriptor, without falling back to defaults set in
0890: // the MBean descriptor
0891: boolean persistNow = shouldPersistNow(operationDescriptor,
0892: null, lastUpdateField);
0893: int impact = operInfo.getImpact();
0894: if (persistNow && impact != ModelMBeanOperationInfo.INFO) {
0895: if (logger.isEnabledFor(Logger.TRACE))
0896: logger.trace("Persisting this ModelMBean...");
0897: try {
0898: store();
0899: if (logger.isEnabledFor(Logger.TRACE))
0900: logger.trace("ModelMBean persisted successfully");
0901: } catch (Exception x) {
0902: logger
0903: .error(
0904: "Cannot store ModelMBean after operation invocation",
0905: x);
0906: if (x instanceof MBeanException)
0907: throw (MBeanException) x;
0908: else
0909: throw new MBeanException(x);
0910: }
0911: }
0912:
0913: return returnValue;
0914: }
0915:
0916: private Object resolveTargetObject(Descriptor descriptor)
0917: throws MBeanException {
0918: Logger logger = getLogger();
0919: Object target = descriptor.getFieldValue("targetObject");
0920: if (logger.isEnabledFor(Logger.TRACE))
0921: logger.trace("targetObject is: " + target);
0922: if (target == null) {
0923: target = getManagedResource();
0924: } else {
0925: String targetObjectType = (String) descriptor
0926: .getFieldValue("targetObjectType");
0927: if (logger.isEnabledFor(Logger.TRACE))
0928: logger
0929: .trace("targetObjectType is: "
0930: + targetObjectType);
0931: if (targetObjectType == null) {
0932: // Not defined, assume object reference
0933: targetObjectType = OBJECT_RESOURCE_TYPE;
0934: }
0935:
0936: if (!isResourceTypeSupported(targetObjectType))
0937: throw new MBeanException(
0938: new InvalidTargetObjectTypeException(
0939: targetObjectType));
0940: }
0941: return target;
0942: }
0943:
0944: public void load() throws MBeanException,
0945: RuntimeOperationsException, InstanceNotFoundException {
0946: PersisterMBean persister = findPersister();
0947: if (persister != null) {
0948: ModelMBeanInfo info = (ModelMBeanInfo) persister.load();
0949: setModelMBeanInfo(info);
0950: }
0951: }
0952:
0953: public void store() throws MBeanException,
0954: RuntimeOperationsException, InstanceNotFoundException {
0955: PersisterMBean persister = findPersister();
0956: if (persister != null) {
0957: // Take a clone to avoid synchronization problems
0958: ModelMBeanInfo info = (ModelMBeanInfo) getMBeanInfo();
0959: persister.store(info);
0960: }
0961: }
0962:
0963: protected ClassLoaderRepository getClassLoaderRepository() {
0964: if (m_mbeanServer != null)
0965: return m_mbeanServer.getClassLoaderRepository();
0966: else
0967: return null;
0968: }
0969:
0970: private boolean shouldPersistNow(Descriptor attribute,
0971: Descriptor mbean, String lastUpdateField) {
0972: int persist = getPersistPolicy(attribute, mbean);
0973: if (persist == PERSIST_NO_MORE_OFTEN_THAN) {
0974: Long period = getFieldTimeValue(attribute, mbean,
0975: "persistPeriod");
0976: long now = System.currentTimeMillis();
0977: Long lastUpdate = (Long) attribute
0978: .getFieldValue(lastUpdateField);
0979: if (now - lastUpdate.longValue() < period.longValue())
0980: return false;
0981: else
0982: return true;
0983: } else if (persist == PERSIST_NEVER) {
0984: return false;
0985: } else if (persist == PERSIST_ON_TIMER) {
0986: return false;
0987: } else if (persist == PERSIST_ON_UPDATE) {
0988: return true;
0989: } else {
0990: throw new ImplementationException("Invalid persist value");
0991: }
0992: }
0993:
0994: private int getPersistPolicy(Descriptor descriptor, Descriptor mbean) {
0995: Logger logger = getLogger();
0996:
0997: String persist = (String) descriptor
0998: .getFieldValue("persistPolicy");
0999: if (persist == null && mbean != null)
1000: persist = (String) mbean.getFieldValue("persistPolicy");
1001: if (persist == null) {
1002: if (logger.isEnabledFor(Logger.TRACE))
1003: logger
1004: .trace("No persist policy defined, assuming Never");
1005: return PERSIST_NEVER;
1006: } else {
1007: if (persist.equals("Never")) {
1008: if (logger.isEnabledFor(Logger.TRACE))
1009: logger.trace("Persist never");
1010: return PERSIST_NEVER;
1011: } else if (persist.equals("OnUpdate")) {
1012: if (logger.isEnabledFor(Logger.TRACE))
1013: logger.trace("Persist on update");
1014: return PERSIST_ON_UPDATE;
1015: } else if (persist.equals("OnTimer")) {
1016: if (logger.isEnabledFor(Logger.TRACE))
1017: logger.trace("Persist on update");
1018: return PERSIST_ON_TIMER;
1019: } else if (persist.equals("NoMoreOftenThan")) {
1020: if (logger.isEnabledFor(Logger.TRACE)) {
1021: Long period = getFieldTimeValue(descriptor, mbean,
1022: "persistPeriod");
1023: logger
1024: .trace("Persist no more often than "
1025: + period);
1026: }
1027: return PERSIST_NO_MORE_OFTEN_THAN;
1028: } else {
1029: // Garbage, assuming Never
1030: if (logger.isEnabledFor(Logger.TRACE))
1031: logger
1032: .trace("Invalid persist policy, assuming persist never");
1033: return PERSIST_NEVER;
1034: }
1035: }
1036: }
1037:
1038: private int getStaleness(Descriptor attribute, Descriptor mbean,
1039: String lastUpdateField) {
1040: Logger logger = getLogger();
1041:
1042: Long currencyTimeLimit = getFieldTimeValue(attribute, mbean,
1043: "currencyTimeLimit");
1044: if (currencyTimeLimit == null) {
1045: // No time limit defined
1046: if (logger.isEnabledFor(Logger.TRACE))
1047: logger
1048: .trace("No currencyTimeLimit defined, assuming always stale");
1049: return ALWAYS_STALE;
1050: } else {
1051: long ctl = currencyTimeLimit.longValue() * 1000;
1052: if (logger.isEnabledFor(Logger.TRACE))
1053: logger.trace("currencyTimeLimit is (ms): " + ctl);
1054:
1055: if (ctl == 0) {
1056: // Never stale
1057: if (logger.isEnabledFor(Logger.TRACE))
1058: logger.trace("Never stale");
1059: return NEVER_STALE;
1060: } else if (ctl < 0) // this should be == -1 but the other cases are in the air
1061: {
1062: // Always stale
1063: if (logger.isEnabledFor(Logger.TRACE))
1064: logger.trace("Always stale");
1065: return ALWAYS_STALE;
1066: } else {
1067: Long timestamp = (Long) attribute
1068: .getFieldValue(lastUpdateField);
1069: long luts = 0;
1070:
1071: if (timestamp != null)
1072: luts = timestamp.longValue();
1073: if (logger.isEnabledFor(Logger.DEBUG))
1074: logger.debug(lastUpdateField + " is: " + luts);
1075:
1076: long now = System.currentTimeMillis();
1077: if (now < luts + ctl) {
1078: // Seems to be not stale, but has been set at least once ?
1079: if (timestamp == null) {
1080: // Return stale to call it the first time
1081: if (logger.isEnabledFor(Logger.TRACE))
1082: logger.trace("Stale since was never set");
1083: return STALE;
1084: } else {
1085: if (logger.isEnabledFor(Logger.TRACE))
1086: logger.trace("Not stale");
1087: return NOT_STALE;
1088: }
1089: } else {
1090: // Stale
1091: if (logger.isEnabledFor(Logger.TRACE))
1092: logger.trace("Stale");
1093: return STALE;
1094: }
1095: }
1096: }
1097: }
1098:
1099: private Long getFieldTimeValue(Descriptor descriptor,
1100: Descriptor mbean, String field) {
1101: Logger logger = getLogger();
1102:
1103: Object value = descriptor.getFieldValue(field);
1104: if (logger.isEnabledFor(Logger.DEBUG))
1105: logger.debug("Descriptor's " + field + " field: " + value);
1106:
1107: if (value == null && mbean != null) {
1108: value = mbean.getFieldValue(field);
1109: if (logger.isEnabledFor(Logger.DEBUG))
1110: logger.debug("MBean's " + field + " field: " + value);
1111: if (value == null)
1112: return null;
1113: }
1114:
1115: if (value instanceof Number)
1116: return new Long(((Number) value).longValue());
1117:
1118: if (value instanceof String) {
1119: try {
1120: long ctl = Long.parseLong((String) value);
1121: return new Long(ctl);
1122: } catch (NumberFormatException x) {
1123: return new Long(0);
1124: }
1125: }
1126: return new Long(0);
1127: }
1128:
1129: private Object invokeMethod(Object target, String methodName,
1130: Class[] params, Object[] args) throws MBeanException,
1131: ReflectionException {
1132: // First try on this instance, then on the target
1133: Object realTarget = null;
1134: Method method = null;
1135: try {
1136: realTarget = this ;
1137: method = realTarget.getClass()
1138: .getMethod(methodName, params);
1139: } catch (NoSuchMethodException x) {
1140: realTarget = target;
1141: }
1142:
1143: if (realTarget == null)
1144: throw new MBeanException(new ServiceNotFoundException(
1145: "Could not find target"));
1146:
1147: if (method == null) {
1148: try {
1149: method = realTarget.getClass().getMethod(methodName,
1150: params);
1151: } catch (NoSuchMethodException x) {
1152: throw new ReflectionException(x);
1153: }
1154: }
1155:
1156: try {
1157: Object value = method.invoke(realTarget, args);
1158: Logger logger = getLogger();
1159: if (logger.isEnabledFor(Logger.DEBUG))
1160: logger.debug("Method invocation returned value: "
1161: + value);
1162: return value;
1163: } catch (IllegalAccessException x) {
1164: throw new ReflectionException(x);
1165: } catch (IllegalArgumentException x) {
1166: throw new MBeanException(x);
1167: } catch (InvocationTargetException x) {
1168: Throwable t = x.getTargetException();
1169: if (t instanceof Error)
1170: throw new MBeanException(new RuntimeErrorException(
1171: (Error) t));
1172: else
1173: throw new MBeanException((Exception) t);
1174: }
1175: }
1176:
1177: private Logger getModelMBeanLogger(String notificationType)
1178: throws MBeanException {
1179: // Get a copy to avoid synchronization
1180: ModelMBeanInfo info = getModelMBeanInfo();
1181:
1182: // First look if there is a suitable notification descriptor, otherwise use MBean descriptor
1183: Descriptor descriptor = null;
1184: Logger modelMBeanLogger = null;
1185: if (notificationType != null) {
1186: descriptor = info.getDescriptor(notificationType,
1187: "notification");
1188: modelMBeanLogger = findLogger(descriptor);
1189: }
1190:
1191: if (modelMBeanLogger == null) {
1192: descriptor = info.getMBeanDescriptor();
1193: modelMBeanLogger = findLogger(descriptor);
1194: if (modelMBeanLogger != null)
1195: return modelMBeanLogger;
1196: }
1197:
1198: return null;
1199: }
1200:
1201: private Logger findLogger(Descriptor descriptor) {
1202: Logger logger = getLogger();
1203:
1204: if (descriptor == null) {
1205: if (logger.isEnabledFor(Logger.TRACE))
1206: logger
1207: .trace("Can't find MBean logger, descriptor is null");
1208: return null;
1209: }
1210:
1211: String log = (String) descriptor.getFieldValue("log");
1212: String location = (String) descriptor.getFieldValue("logFile");
1213:
1214: if (logger.isEnabledFor(Logger.DEBUG))
1215: logger.debug("Log fields: log=" + log + ", file="
1216: + location);
1217:
1218: if (log == null || !Boolean.valueOf(log).booleanValue()) {
1219: if (logger.isEnabledFor(Logger.DEBUG))
1220: logger
1221: .debug("Logging is not supported by this ModelMBean");
1222: return null;
1223: }
1224: // Logger is supported, where log to ?
1225: if (location == null) {
1226: // As an extension, see if the field logMBean has been defined
1227: location = (String) descriptor.getFieldValue("logMBean");
1228: if (logger.isEnabledFor(Logger.DEBUG))
1229: logger.debug("Log fields: mbean=" + location);
1230:
1231: if (location == null) {
1232: if (logger.isEnabledFor(Logger.TRACE))
1233: logger
1234: .trace("Logging is not supported by this ModelMBean");
1235: return null;
1236: }
1237:
1238: // It seems that the user wants to delegate a registered mbean to log
1239: try {
1240: ObjectName objectName = new ObjectName(location);
1241: MBeanServer server = getMBeanServer();
1242: if (server == null)
1243: throw new MBeanException(new IllegalStateException(
1244: "RequiredModelMBean is not registered"));
1245: if (server.isRegistered(objectName)) {
1246: MBeanLogger l = new MBeanLogger(server, objectName);
1247: if (logger.isEnabledFor(Logger.DEBUG))
1248: logger
1249: .debug("ModelMBean log supported by delegating to this MBean: "
1250: + objectName);
1251: return l;
1252: }
1253:
1254: return null;
1255: } catch (MalformedObjectNameException x) {
1256: // Ah, was not a correct object name
1257: if (logger.isEnabledFor(Logger.DEBUG))
1258: logger
1259: .debug("Specified logMBean field does not contain a valid ObjectName: "
1260: + location);
1261: return null;
1262: } catch (MBeanException x) {
1263: if (logger.isEnabledFor(Logger.DEBUG))
1264: logger
1265: .debug(
1266: "logMBean field does not specify an MBean that supports logging delegation",
1267: x);
1268: return null;
1269: }
1270: } else {
1271: // User decided to log to a file
1272: if (logger.isEnabledFor(Logger.DEBUG))
1273: logger.debug("ModelMBean log supported on file system");
1274: return new FileLogger(location);
1275: }
1276: }
1277:
1278: private NotificationBroadcasterSupport getAttributeChangeBroadcaster() {
1279: return m_generalBroadcaster;
1280: }
1281:
1282: private MBeanServer getMBeanServer() {
1283: return m_mbeanServer;
1284: }
1285:
1286: private ModelMBeanInfo getModelMBeanInfo() {
1287: // No cloning performed
1288: return m_modelMBeanInfo;
1289: }
1290:
1291: private PersisterMBean findPersister() throws MBeanException,
1292: InstanceNotFoundException {
1293: Logger logger = getLogger();
1294:
1295: ModelMBeanInfo info = getModelMBeanInfo();
1296: if (info == null) {
1297: // Not yet initialized
1298: if (logger.isEnabledFor(Logger.TRACE))
1299: logger
1300: .trace("Can't find persister, ModelMBeanInfo is null");
1301: return null;
1302: }
1303: Descriptor mbeanDescriptor = info.getMBeanDescriptor();
1304: if (mbeanDescriptor == null) {
1305: // This is normally should not happen if ModelMBeanInfoSupport is used
1306: if (logger.isEnabledFor(Logger.TRACE))
1307: logger
1308: .trace("Can't find persister, MBean descriptor is null");
1309: return null;
1310: }
1311:
1312: String location = (String) mbeanDescriptor
1313: .getFieldValue("persistLocation");
1314: String name = (String) mbeanDescriptor
1315: .getFieldValue("persistName");
1316: String mbeanName = (String) mbeanDescriptor
1317: .getFieldValue("name");
1318: if (logger.isEnabledFor(Logger.DEBUG))
1319: logger.debug("Persistence fields: location=" + location
1320: + ", name=" + name);
1321:
1322: if (mbeanName == null && name == null) {
1323: if (logger.isEnabledFor(Logger.DEBUG))
1324: logger
1325: .debug("Persistence is not supported by this ModelMBean");
1326: return null;
1327: }
1328:
1329: // Try to see if this mbean should delegate to another mbean
1330: if (name != null) {
1331: try {
1332: ObjectName objectName = new ObjectName(name.trim());
1333: // OK, a valid object name
1334: MBeanServer server = getMBeanServer();
1335: if (server == null)
1336: throw new MBeanException(new IllegalStateException(
1337: "RequiredModelMBean is not registered"));
1338:
1339: if (server.isRegistered(objectName)
1340: && server.isInstanceOf(objectName,
1341: PersisterMBean.class.getName())) {
1342: // OK, the given mbean is registered with this mbean server
1343: PersisterMBean persister = new MBeanPersister(
1344: server, objectName);
1345: if (logger.isEnabledFor(Logger.DEBUG))
1346: logger
1347: .debug("Persistence is delegated to this MBean: "
1348: + objectName);
1349: return persister;
1350: } else {
1351: throw new InstanceNotFoundException(objectName
1352: .toString());
1353: }
1354: } catch (MalformedObjectNameException ignored) {
1355: // It does not delegates to another mbean, use default
1356: if (logger.isEnabledFor(Logger.TRACE))
1357: logger
1358: .trace("Persistence is not delegated to another MBean");
1359: }
1360:
1361: // Default is serialization to file
1362: FilePersister persister = new FilePersister(location, name);
1363: if (logger.isEnabledFor(Logger.DEBUG))
1364: logger
1365: .debug("Persistence is realized through file system in "
1366: + persister.getFileName());
1367: return persister;
1368: } else {
1369: // Only location given, use MBean name
1370: FilePersister persister = new FilePersister(location,
1371: mbeanName);
1372: if (logger.isEnabledFor(Logger.DEBUG))
1373: logger
1374: .debug("Persistence is realized through file system in "
1375: + persister.getFileName());
1376: return persister;
1377: }
1378: }
1379:
1380: private Class loadClassWithContextClassLoader(String name) {
1381: try {
1382: return Utils.loadClass(Thread.currentThread()
1383: .getContextClassLoader(), name);
1384: } catch (ClassNotFoundException x) {
1385: Logger logger = getLogger();
1386: if (logger.isEnabledFor(Logger.TRACE))
1387: logger
1388: .trace(
1389: "Cannot find attribute's declared return class",
1390: x);
1391: return null;
1392: }
1393: }
1394:
1395: private void checkAssignability(Class parameter, Class declared)
1396: throws MBeanException {
1397: Logger logger = getLogger();
1398:
1399: if (logger.isEnabledFor(Logger.DEBUG)) {
1400: logger.debug("The class of the parameter is: " + parameter);
1401: if (parameter != null)
1402: logger
1403: .debug("The classloder of the parameter's class is: "
1404: + parameter.getClassLoader());
1405: logger
1406: .debug("The class declared as type of the attribute is: "
1407: + declared);
1408: if (declared != null)
1409: logger
1410: .debug("The classloader of the declared parameter's class is: "
1411: + declared.getClassLoader());
1412: }
1413:
1414: boolean assignable = false;
1415:
1416: if (declared == null || parameter == null)
1417: assignable = false;
1418: else if (declared == boolean.class
1419: && parameter == Boolean.class)
1420: assignable = true;
1421: else if (declared == byte.class && parameter == Byte.class)
1422: assignable = true;
1423: else if (declared == char.class && parameter == Character.class)
1424: assignable = true;
1425: else if (declared == short.class && parameter == Short.class)
1426: assignable = true;
1427: else if (declared == int.class && parameter == Integer.class)
1428: assignable = true;
1429: else if (declared == long.class && parameter == Long.class)
1430: assignable = true;
1431: else if (declared == float.class && parameter == Float.class)
1432: assignable = true;
1433: else if (declared == double.class && parameter == Double.class)
1434: assignable = true;
1435: else
1436: assignable = declared.isAssignableFrom(parameter);
1437:
1438: if (!assignable) {
1439: if (logger.isEnabledFor(Logger.TRACE))
1440: logger
1441: .trace("Parameter value's class and attribute's declared return class are not assignable");
1442: throw new MBeanException(
1443: new InvalidAttributeValueException(
1444: "Returned type and declared type are not assignable"));
1445: }
1446: }
1447: }
|