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