001: /*
002: * JBoss, Home of Professional Open Source.
003: * Copyright 2006, Red Hat Middleware LLC, and individual contributors
004: * as indicated by the @author tags. See the copyright.txt file in the
005: * distribution for a full listing of individual contributors.
006: *
007: * This is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as
009: * published by the Free Software Foundation; either version 2.1 of
010: * the License, or (at your option) any later version.
011: *
012: * This software is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this software; if not, write to the Free
019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021: */
022: package org.jboss.mx.modelmbean;
023:
024: import java.beans.BeanInfo;
025: import java.beans.IntrospectionException;
026: import java.beans.Introspector;
027: import java.beans.PropertyDescriptor;
028: import java.beans.PropertyEditor;
029: import java.beans.PropertyEditorManager;
030: import java.lang.reflect.Constructor;
031: import java.lang.reflect.Method;
032: import java.util.ArrayList;
033: import java.util.HashMap;
034: import java.util.Iterator;
035: import java.util.List;
036: import java.util.Map;
037:
038: import javax.management.Attribute;
039: import javax.management.AttributeChangeNotification;
040: import javax.management.AttributeChangeNotificationFilter;
041: import javax.management.Descriptor;
042: import javax.management.InstanceNotFoundException;
043: import javax.management.JMException;
044: import javax.management.ListenerNotFoundException;
045: import javax.management.MBeanAttributeInfo;
046: import javax.management.MBeanException;
047: import javax.management.MBeanInfo;
048: import javax.management.MBeanNotificationInfo;
049: import javax.management.MBeanOperationInfo;
050: import javax.management.MBeanServer;
051: import javax.management.Notification;
052: import javax.management.NotificationFilter;
053: import javax.management.NotificationListener;
054: import javax.management.ObjectName;
055: import javax.management.RuntimeErrorException;
056: import javax.management.RuntimeOperationsException;
057: import javax.management.modelmbean.InvalidTargetObjectTypeException;
058: import javax.management.modelmbean.ModelMBean;
059: import javax.management.modelmbean.ModelMBeanAttributeInfo;
060: import javax.management.modelmbean.ModelMBeanInfo;
061: import javax.management.modelmbean.ModelMBeanInfoSupport;
062: import javax.management.modelmbean.ModelMBeanOperationInfo;
063:
064: import org.jboss.logging.Logger;
065: import org.jboss.mx.interceptor.AbstractInterceptor;
066: import org.jboss.mx.interceptor.Interceptor;
067: import org.jboss.mx.interceptor.ModelMBeanAttributeInterceptor;
068: import org.jboss.mx.interceptor.ModelMBeanInfoInterceptor;
069: import org.jboss.mx.interceptor.ModelMBeanInterceptor;
070: import org.jboss.mx.interceptor.ModelMBeanOperationInterceptor;
071: import org.jboss.mx.interceptor.NullInterceptor;
072: import org.jboss.mx.interceptor.ObjectReferenceInterceptor;
073: import org.jboss.mx.interceptor.PersistenceInterceptor;
074: import org.jboss.mx.interceptor.PersistenceInterceptor2;
075: import org.jboss.mx.persistence.NullPersistence;
076: import org.jboss.mx.persistence.PersistenceManager;
077: import org.jboss.mx.server.AbstractMBeanInvoker;
078: import org.jboss.mx.server.Invocation;
079: import org.jboss.mx.server.InvocationContext;
080: import org.jboss.mx.server.MBeanInvoker;
081: import org.jboss.mx.util.JBossNotificationBroadcasterSupport;
082:
083: /**
084: * An extension of the {@link org.jboss.mx.server.MBeanInvoker MBeanInvoker}
085: * that implements the base Model MBean functionality, essentially making the
086: * Model MBean just another invoker of managed resources.
087: *
088: * @see javax.management.modelmbean.ModelMBean
089: * @see org.jboss.mx.server.MBeanInvoker
090: *
091: * @author <a href="mailto:juha@jboss.org">Juha Lindfors</a>.
092: * @author <a href="mailto:dimitris@jboss.org">Dimitris Andreadis</a>.
093: * @author Matt Munz
094: * @version $Revision: 57200 $
095: */
096: public abstract class ModelMBeanInvoker extends AbstractMBeanInvoker
097: implements ModelMBean, ModelMBeanConstants {
098: Logger log = Logger.getLogger(ModelMBeanInvoker.class.getName());
099:
100: // Attributes ----------------------------------------------------
101:
102: /**
103: * The resource type string of the managed resource, such as
104: * {@link ModelMBeanConstants#OBJECT_REF} or
105: * {@link XMBeanConstants#STANDARD_INTERFACE}. This type string can be
106: * used by the invoker to determine the behavior implemented by the
107: * invocation chain and how the managed resource is exposed to the client
108: * programs.
109: */
110: protected String resourceType = null;
111:
112: /**
113: * Persistence manager.
114: */
115: protected PersistenceManager persistence = new NullPersistence();
116:
117: /**
118: * Notification broadcaster for this Model MBean.
119: */
120: protected JBossNotificationBroadcasterSupport notifier = new JBossNotificationBroadcasterSupport();
121:
122: /**
123: * Notification sequence number for generic Model MBean notifications.
124: */
125: protected long notifierSequence = 1;
126:
127: /**
128: * Notification sequence number for attribute change notifications.
129: */
130: protected long attrNotifierSequence = 1;
131:
132: // Constructors --------------------------------------------------
133:
134: /**
135: * Default constructor.
136: */
137: public ModelMBeanInvoker() {
138: }
139:
140: /**
141: * Creates a Model MBean instance and initializes it with the given
142: * Model MBean metadata.
143: *
144: * @param info Model MBean metadata
145: */
146: public ModelMBeanInvoker(ModelMBeanInfo info) throws MBeanException {
147: setModelMBeanInfo(info);
148: }
149:
150: // ModelMBean implementation -------------------------------------
151:
152: /**
153: * Sets the MBean metadata for this Model MBean instance.
154: *
155: * @param info Model MBean metadata
156: */
157: public void setModelMBeanInfo(ModelMBeanInfo info)
158: throws MBeanException, RuntimeOperationsException {
159: if (info == null)
160: throw new RuntimeOperationsException(
161: new IllegalArgumentException(
162: "MBeanInfo cannot be null"));
163:
164: // need to type to an instance of MBeanInfo -- therefore the extra copy here
165: this .info = new ModelMBeanInfoSupport(info);
166:
167: // Apply the MBeanInfo injection if requested
168: ModelMBeanInfo minfo = info;
169: Descriptor mbeanDescriptor = null;
170: try {
171: mbeanDescriptor = minfo.getDescriptor("",
172: ModelMBeanConstants.MBEAN_DESCRIPTOR);
173: } catch (MBeanException e) {
174: log.warn("Failed to obtain descriptor: "
175: + ModelMBeanConstants.MBEAN_DESCRIPTOR, e);
176: return;
177: }
178:
179: String type = (String) mbeanDescriptor
180: .getFieldValue(ModelMBeanConstants.MBEAN_INFO_INJECTION_TYPE);
181: if (type != null) {
182: inject(ModelMBeanConstants.MBEAN_INFO_INJECTION_TYPE, type,
183: MBeanInfo.class, info);
184: }
185: }
186:
187: /**
188: * Sets the managed resource for this Model MBean instance. The resource
189: * type must be known to the Model MBean implementation (see
190: * {@link #isSupportedResourceType} for more information).
191: *
192: * @param ref reference to the managed resource
193: * @param resourceType resource type identification string
194: */
195: public void setManagedResource(Object ref, String resourceType)
196: throws MBeanException, InstanceNotFoundException,
197: InvalidTargetObjectTypeException {
198: if (!isSupportedResourceType(ref, resourceType))
199: throw new InvalidTargetObjectTypeException(
200: "Unsupported resource type: " + resourceType);
201:
202: setResource(ref);
203: this .resourceType = resourceType;
204:
205: if (getServer() != null) {
206: try {
207: this .init(getServer(), resourceEntry.getObjectName());
208: } catch (Exception e) {
209: throw new MBeanException(e,
210: "Failed to init from resource");
211: }
212: }
213: }
214:
215: // ModelMBeanNotificationBroadcaster implementation --------------
216:
217: public void addNotificationListener(NotificationListener listener,
218: NotificationFilter filter, Object handback) {
219: notifier.addNotificationListener(listener, filter, handback);
220: }
221:
222: public void removeNotificationListener(NotificationListener listener)
223: throws ListenerNotFoundException {
224: notifier.removeNotificationListener(listener);
225: }
226:
227: public void removeNotificationListener(
228: NotificationListener listener, NotificationFilter filter,
229: Object handback) throws ListenerNotFoundException {
230: notifier.removeNotificationListener(listener, filter, handback);
231: }
232:
233: /**
234: * Sends a notification with a given string message. The notification
235: * type will be set as
236: * {@link ModelMBeanConstants#GENERIC_MODELMBEAN_NOTIFICATION GENERIC_MODELMBEAN_NOTIFICATION}.
237: *
238: * @param ntfyText notification message
239: */
240: public void sendNotification(String ntfyText)
241: throws MBeanException, RuntimeOperationsException {
242: if (ntfyText == null) {
243: throw new RuntimeOperationsException(
244: new IllegalArgumentException(
245: "ntfyText cannot be null"));
246: }
247: Notification notif = new Notification(
248: GENERIC_MODELMBEAN_NOTIFICATION, // type
249: this , // source
250: 1, // always 1 - by spec
251: ntfyText // message
252: );
253:
254: sendNotification(notif);
255: }
256:
257: /**
258: * Sends a notification.
259: *
260: * @param ntfyObj notification to send
261: */
262: public void sendNotification(Notification ntfyObj)
263: throws MBeanException, RuntimeOperationsException {
264: if (ntfyObj == null) {
265: throw new RuntimeOperationsException(
266: new IllegalArgumentException(
267: "ntfyText cannot be null"));
268: }
269: notifier.sendNotification(ntfyObj);
270: }
271:
272: /**
273: * Sends an attribute change notification.
274: *
275: * @param notification attribute change notification to send
276: */
277: public void sendAttributeChangeNotification(
278: AttributeChangeNotification notification)
279: throws MBeanException {
280: if (notification == null) {
281: throw new RuntimeOperationsException(
282: new IllegalArgumentException(
283: "notification cannot be null"));
284: }
285: notifier.sendNotification(notification);
286: }
287:
288: /**
289: * Sends an attribute change notification.
290: *
291: * @param oldValue attribute with the old value
292: * @param newValue attribute with the new value
293: * @throws IllegalArgumentException - An Attribute object passed in parameter
294: * is null or the names of the two Attribute objects in parameter are not
295: * the same.
296: */
297: public void sendAttributeChangeNotification(Attribute oldValue,
298: Attribute newValue) throws MBeanException,
299: RuntimeOperationsException {
300: if (oldValue == null || newValue == null) {
301: throw new RuntimeOperationsException(
302: new IllegalArgumentException(
303: "Attribute cannot be null"));
304: }
305: if (!(oldValue.getName().equals(newValue.getName()))) {
306: throw new RuntimeOperationsException(
307: new IllegalArgumentException(
308: "Attribute name mismatch between oldvalue and newvalue"));
309: }
310:
311: String attr = oldValue.getName();
312: String type = ((ModelMBeanInfo) info).getAttribute(attr)
313: .getType();
314:
315: AttributeChangeNotification notif = new AttributeChangeNotification(
316: this , // source
317: 1, // always 1 - by spec
318: System.currentTimeMillis(), // time stamp
319: "" + attr + " changed from " + oldValue + " to "
320: + newValue, attr, type, // name & type
321: oldValue.getValue(), newValue.getValue() // values
322: );
323:
324: notifier.sendNotification(notif);
325: }
326:
327: public MBeanNotificationInfo[] getNotificationInfo() {
328: return info.getNotifications();
329: }
330:
331: /**
332: */
333: public void addAttributeChangeNotificationListener(
334: NotificationListener listener, String attributeName,
335: Object handback) throws MBeanException {
336: // Check the attribute info
337: ModelMBeanInfo minfo = (ModelMBeanInfo) info;
338: AttributeChangeNotificationFilter filter = null;
339: if (attributeName != null) {
340: ModelMBeanAttributeInfo ainfo = minfo
341: .getAttribute(attributeName);
342: if (ainfo == null) {
343: throw new RuntimeOperationsException(
344: new IllegalArgumentException(
345: "Attribute does not exist: "
346: + attributeName));
347: }
348: filter = new AttributeChangeNotificationFilter();
349: filter.enableAttribute(attributeName);
350: } else {
351: filter = new AttributeChangeNotificationFilter();
352: MBeanAttributeInfo[] allAttributes = minfo.getAttributes();
353: for (int i = 0; i < allAttributes.length; ++i)
354: filter.enableAttribute(allAttributes[i].getName());
355: }
356: notifier.addNotificationListener(listener, filter, handback);
357: }
358:
359: /**
360: */
361: public void removeAttributeChangeNotificationListener(
362: NotificationListener listener, String attributeName)
363: throws MBeanException, ListenerNotFoundException {
364: if (attributeName != null) {
365: // Check the attribute info
366: ModelMBeanInfo minfo = (ModelMBeanInfo) info;
367: ModelMBeanAttributeInfo ainfo = minfo
368: .getAttribute(attributeName);
369: if (ainfo == null) {
370: throw new RuntimeOperationsException(
371: new IllegalArgumentException(
372: "Attribute does not exist: "
373: + attributeName));
374: }
375: }
376: notifier.removeNotificationListener(listener);
377: }
378:
379: // PersistentMBean implementation --------------------------------
380: public void load() throws MBeanException, InstanceNotFoundException {
381: if (info == null)
382: return;
383:
384: persistence.load(this , info);
385: }
386:
387: public void store() throws MBeanException,
388: InstanceNotFoundException {
389: persistence.store(info);
390: }
391:
392: // MBeanRegistration implementation ------------------------------
393:
394: /**
395: * The default implementation of <tt>preRegister</tt> invokes the
396: * {@link #configureInterceptorStack} method which sets up the interceptors
397: * for this Model MBean instance. Subclasses may override the
398: * <tt>configureInterceptorStack()</tt> method to implement their own
399: * interceptor stack configurations. See the JavaDoc for
400: * <tt>configureInterceptorStack()</tt> for more information. <p>
401: *
402: * After the interceptor configuration, this implementation invokes the
403: * {@link #load} method on this Model MBean instance. This will attempt
404: * to load a pre-existing management attribute state for this Model MBean
405: * instance. See the Javadoc for <tt>load()</tt> for more information.
406: */
407: public ObjectName invokePreRegister(MBeanServer server,
408: ObjectName name) throws Exception {
409: // Check for null metadata and prevent registration if metadata
410: // has not been set
411: if (info == null) {
412: throw new RuntimeErrorException(new Error(
413: "MBeanInfo has not been set."));
414: }
415:
416: // Set the mbean descriptor on the info context for use by interceptor config
417: final ModelMBeanInfo minfo = (ModelMBeanInfo) info;
418: Descriptor mbeanDescriptor = minfo.getMBeanDescriptor();
419: getMBeanInfoCtx = new InvocationContext();
420: getMBeanInfoCtx.setInvoker(this );
421: getMBeanInfoCtx.setDescriptor(mbeanDescriptor);
422: getMBeanInfoCtx.setDispatcher(new AbstractInterceptor(
423: "MBeanInfo Dispatcher") {
424: public Object invoke(Invocation invocation)
425: throws Throwable {
426: return minfo;
427: }
428: });
429: // JBAS-33 - No need to register the "getMBeanInfo" context to the operationsContextMap,
430: // this is only accessible through AbstractMBeanInvoker.getMBeanInfo().
431: // Registering it will result in duplicate interceptor construction.
432:
433: // Need to install the setManagedResource op
434: // TODO, this is probably uneccessary now so revisit this
435: String[] signature = new String[] { "java.lang.Object",
436: "java.lang.String" };
437: OperationKey opKey = new OperationKey("setManagedResource",
438: signature);
439: InvocationContext ctx = new InvocationContext();
440: ctx.setInvoker(this );
441: ctx.setDispatcher(new AbstractInterceptor(
442: "SetMangedResource Dispatcher") {
443: public Object invoke(Invocation invocation)
444: throws Throwable {
445: Object[] args = invocation.getArgs();
446: setManagedResource(args[0], (String) args[1]);
447: return null;
448: }
449: });
450: operationContextMap.put(opKey, ctx);
451:
452: if (getResource() == null) {
453: return name;
454: } else {
455: init(server, name);
456: }
457:
458: return super .invokePreRegister(server, name);
459: }
460:
461: // Protected ---------------------------------------------------
462:
463: /**
464: *
465: * @param server
466: * @param name
467: * @throws Exception
468: */
469: protected void init(MBeanServer server, ObjectName name)
470: throws Exception {
471: ModelMBeanInfo minfo = (ModelMBeanInfo) info;
472: configureInterceptorStack(minfo, server, name);
473: initDispatchers();
474:
475: // add the resource classname to the MBean info
476: Object resource = getResource();
477: if (resource != null) {
478: Descriptor mbeanDescriptor = minfo.getMBeanDescriptor();
479: String resClassName = getResource().getClass().getName();
480: mbeanDescriptor.setField(
481: ModelMBeanConstants.RESOURCE_CLASS, resClassName);
482: minfo.setMBeanDescriptor(mbeanDescriptor);
483: }
484:
485: //Set initial values provided in descriptors
486: setValuesFromMBeanInfo();
487:
488: initPersistence(server, name);
489:
490: //Set (and override) values from mbean persistence store.
491: load();
492: }
493:
494: /**
495: * initializes the persistence manager based on the info for this bean.
496: * If this is successful, loads the bean from the persistence store.
497: */
498: protected void initPersistence(MBeanServer server, ObjectName name)
499: throws MBeanException, InstanceNotFoundException {
500: Descriptor[] descriptors;
501: ModelMBeanInfo minfo = (ModelMBeanInfo) getMetaData();
502:
503: try {
504: descriptors = minfo.getDescriptors(MBEAN_DESCRIPTOR);
505: } catch (MBeanException e) {
506: log.error("Failed to obtain MBEAN_DESCRIPTORs", e);
507: return;
508: }
509:
510: if (descriptors == null) {
511: return;
512: }
513: String persistMgrName = null;
514: for (int i = 0; ((i < descriptors.length) && (persistMgrName == null)); i++) {
515: persistMgrName = (String) descriptors[i]
516: .getFieldValue(PERSISTENCE_MANAGER);
517: }
518: if (persistMgrName == null) {
519: log
520: .trace("No "
521: + PERSISTENCE_MANAGER
522: + " descriptor found, null persistence will be used");
523: return;
524: }
525:
526: try {
527: persistence = (PersistenceManager) server
528: .instantiate(persistMgrName);
529: log.debug("Loaded persistence mgr: " + persistMgrName);
530:
531: // Add the ObjectName to the ModelMBean Descriptor
532: // so that it can be used by the PersistentManager (if needed)
533: Descriptor descriptor = minfo.getMBeanDescriptor();
534: descriptor.setField(ModelMBeanConstants.OBJECT_NAME, name);
535: minfo.setMBeanDescriptor(descriptor);
536: } catch (Exception cause) {
537: log.error("Unable to instantiate the persistence manager:"
538: + persistMgrName, cause);
539: }
540: }
541:
542: protected void initOperationContexts(MBeanOperationInfo[] operations) {
543: // make sure we invoke the super class initialization sequence first
544: super .initOperationContexts(operations);
545:
546: for (int i = 0; i < operations.length; ++i) {
547: OperationKey key = new OperationKey(operations[i]);
548:
549: InvocationContext ctx = (InvocationContext) operationContextMap
550: .get(key);
551: ModelMBeanOperationInfo info = (ModelMBeanOperationInfo) operations[i];
552: ctx.setDescriptor(info.getDescriptor());
553: }
554: }
555:
556: protected void initAttributeContexts(MBeanAttributeInfo[] attributes) {
557: super .initAttributeContexts(attributes);
558:
559: for (int i = 0; i < attributes.length; ++i) {
560: ModelMBeanAttributeInfo info = (ModelMBeanAttributeInfo) attributes[i];
561: String name = info.getName();
562: InvocationContext ctx = (InvocationContext) attributeContextMap
563: .get(name);
564: ctx.setDescriptor(info.getDescriptor());
565: ctx.setReadable(info.isReadable());
566: ctx.setWritable(info.isWritable());
567: }
568: }
569:
570: /**
571: * Build the getMBeanInfo, operation, and attribute interceptor stacks
572: * and associated these with the corresponding InvocationContexts.
573: *
574: * @param info - the ModelMBean metadata
575: * @param server - the MBeanServer the ModelMBean is registering with
576: * @param name - the ModelMBean name
577: * @throws Exception
578: */
579: protected void configureInterceptorStack(ModelMBeanInfo info,
580: MBeanServer server, ObjectName name) throws Exception {
581: // Get the MBeanInfo accessor interceptor stack. This is the interceptor
582: // stack declared at the model mbean level. In 3.2.3 and earlier this was
583: // the interceptor stack for all operation and attribute access so we
584: // use this as the default interceptor stack, for all attributes/operations.
585:
586: List defaultInterceptors = getInterceptors(getMBeanInfoCtx
587: .getDescriptor());
588:
589: List interceptors = null;
590: if (defaultInterceptors != null) {
591: interceptors = new ArrayList(defaultInterceptors);
592: }
593: if (interceptors == null) {
594: // Set the default interceptor stack
595: interceptors = getMBeanInfoCtx.getInterceptors();
596: }
597: // We always add the ModelMBeanInfoInterceptor as we expect that
598: // users are specifying additional interceptors, not overriding the
599: // source of the ModelMBeanInfo.
600:
601: String mbeanName = name != null ? name.toString() : info
602: .getClassName();
603: interceptors.add(new ModelMBeanInfoInterceptor(mbeanName));
604: getMBeanInfoCtx.setInterceptors(interceptors);
605:
606: // Get any custom interceptors specified at the attribute level
607: for (Iterator it = attributeContextMap.entrySet().iterator(); it
608: .hasNext();) {
609: Map.Entry entry = (Map.Entry) it.next();
610:
611: InvocationContext ctx = (InvocationContext) entry
612: .getValue();
613: List list = getInterceptors(ctx.getDescriptor());
614: if (list == null) {
615: // Use the mbean inteceptors if sepecified
616: if (defaultInterceptors != null) {
617: list = new ArrayList(defaultInterceptors);
618: } else {
619: list = new ArrayList();
620: }
621: }
622: // Add the attribute accessor semantic interceptors
623: list.add(new PersistenceInterceptor());
624: list.add(new ModelMBeanAttributeInterceptor());
625: ctx.setInterceptors(list);
626: }
627:
628: // Get any custom interceptors specified at the operation level
629: for (Iterator it = operationContextMap.entrySet().iterator(); it
630: .hasNext();) {
631: Map.Entry entry = (Map.Entry) it.next();
632:
633: InvocationContext ctx = (InvocationContext) entry
634: .getValue();
635: List list = getInterceptors(ctx.getDescriptor());
636: if (list == null && defaultInterceptors != null)
637: list = new ArrayList(defaultInterceptors);
638:
639: // Add operation caching (not for standard mbeans)
640: if (dynamicResource) {
641: if (list == null) {
642: list = new ArrayList();
643: }
644: list.add(new ModelMBeanOperationInterceptor());
645: }
646:
647: if (list != null) {
648: // Add a noop interceptor since the 3.2.3- interceptors always had
649: // to delegate to the next in order to dispatch the operation. Now
650: // there is no interceptor for this so this prevents NPEs.
651:
652: list.add(new NullInterceptor());
653: ctx.setInterceptors(list);
654: }
655: }
656: }
657:
658: /**
659: *
660: * @param d
661: * @return
662: * @throws Exception
663: */
664: protected List getInterceptors(Descriptor d) throws Exception {
665: if (d == null)
666: return null;
667: Descriptor[] interceptorDescriptors = (Descriptor[]) d
668: .getFieldValue(INTERCEPTORS);
669: if (interceptorDescriptors == null)
670: return null;
671:
672: ArrayList interceptors = new ArrayList();
673: ClassLoader loader = Thread.currentThread()
674: .getContextClassLoader();
675: for (int i = 0; i < interceptorDescriptors.length; i++) {
676: Descriptor desc = interceptorDescriptors[i];
677: String code = (String) desc.getFieldValue("code");
678: // Ignore the legacy required interceptors
679: if (code.equals(ModelMBeanInterceptor.class.getName())
680: || code.equals(ObjectReferenceInterceptor.class
681: .getName())
682: || code.equals(PersistenceInterceptor2.class
683: .getName())) {
684: log.debug("Ignoring obsolete legacy interceptor: "
685: + code);
686: continue;
687: }
688:
689: Class interceptorClass = loader.loadClass(code);
690: Interceptor interceptor = null;
691: // Check for a ctor(MBeanInvoker)
692: Class[] ctorSig = { MBeanInvoker.class };
693: try {
694: Constructor ctor = interceptorClass
695: .getConstructor(ctorSig);
696: Object[] ctorArgs = { this };
697: interceptor = (Interceptor) ctor.newInstance(ctorArgs);
698: } catch (Throwable t) {
699: log.debug("Could not invoke CTOR(MBeanInvoker) for '"
700: + interceptorClass + "', trying default CTOR: "
701: + t.getMessage());
702:
703: // Try the default ctor
704: interceptor = (Interceptor) interceptorClass
705: .newInstance();
706: }
707: interceptors.add(interceptor);
708:
709: // Apply any interceptor attributes
710: String[] names = desc.getFieldNames();
711: HashMap propertyMap = new HashMap();
712: if (names.length > 1) {
713: BeanInfo beanInfo = Introspector
714: .getBeanInfo(interceptorClass);
715: PropertyDescriptor[] props = beanInfo
716: .getPropertyDescriptors();
717: for (int p = 0; p < props.length; p++) {
718: String fieldName = props[p].getName();
719: propertyMap.put(fieldName, props[p]);
720: }
721: // Map each attribute to the corresponding interceptor property
722: for (int n = 0; n < names.length; n++) {
723: String name = names[n];
724: if (name.equals("code"))
725: continue;
726: String text = (String) desc.getFieldValue(name);
727: PropertyDescriptor pd = (PropertyDescriptor) propertyMap
728: .get(name);
729: if (pd == null)
730: throw new IntrospectionException(
731: "No PropertyDescriptor for attribute:"
732: + name);
733: Method setter = pd.getWriteMethod();
734: if (setter != null) {
735: Class ptype = pd.getPropertyType();
736: PropertyEditor editor = PropertyEditorManager
737: .findEditor(ptype);
738: if (editor == null)
739: throw new IntrospectionException(
740: "Cannot convert string to interceptor attribute:"
741: + name);
742: editor.setAsText(text);
743: Object args[] = { editor.getValue() };
744: setter.invoke(interceptor, args);
745: }
746: }
747: }
748: }
749:
750: if (interceptors.size() == 0)
751: interceptors = null;
752: return interceptors;
753: }
754:
755: protected void setValuesFromMBeanInfo() throws JMException {
756: for (Iterator it = attributeContextMap.entrySet().iterator(); it
757: .hasNext();) {
758: Map.Entry entry = (Map.Entry) it.next();
759: String key = (String) entry.getKey();
760:
761: InvocationContext ctx = (InvocationContext) entry
762: .getValue();
763: //Initialize value from descriptor.
764: Object value = ctx.getDescriptor().getFieldValue(
765: XMBeanConstants.CACHED_VALUE);
766: if (value != null) {
767: setAttribute(new Attribute(key, value));
768: } // end of if ()
769: }
770:
771: }
772:
773: protected boolean isSupportedResourceType(Object resource,
774: String resourceType) {
775: if (resourceType.equalsIgnoreCase(OBJECT_REF))
776: return true;
777:
778: return false;
779: }
780:
781: protected void override(Invocation invocation)
782: throws MBeanException {
783: // Do we allow for dynamic descriptor changes
784: if (dynamicResource && info != null) {
785: Descriptor current = invocation.getDescriptor();
786: if (current != null) {
787: ModelMBeanInfo mminfo = (ModelMBeanInfo) info;
788: Descriptor descriptor = mminfo
789: .getDescriptor((String) current
790: .getFieldValue(NAME), (String) current
791: .getFieldValue(DESCRIPTOR_TYPE));
792: if (descriptor != null)
793: invocation.setDescriptor(descriptor);
794: }
795: }
796: }
797:
798: }
|