KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > mx > server > AbstractMBeanInvoker


1 /*
2  * JBoss, Home of Professional Open Source
3  * Copyright 2005, JBoss Inc., and individual contributors as indicated
4  * by the @authors tag. See the copyright.txt in the distribution for a
5  * 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.server;
23
24 import java.lang.reflect.Method JavaDoc;
25 import java.lang.reflect.Modifier JavaDoc;
26 import java.util.ArrayList JavaDoc;
27 import java.util.HashMap JavaDoc;
28 import java.util.Iterator JavaDoc;
29 import java.util.List JavaDoc;
30 import java.util.Map JavaDoc;
31
32 import javax.management.Attribute JavaDoc;
33 import javax.management.AttributeList JavaDoc;
34 import javax.management.AttributeNotFoundException JavaDoc;
35 import javax.management.Descriptor JavaDoc;
36 import javax.management.InvalidAttributeValueException JavaDoc;
37 import javax.management.JMRuntimeException JavaDoc;
38 import javax.management.ListenerNotFoundException JavaDoc;
39 import javax.management.MBeanAttributeInfo JavaDoc;
40 import javax.management.MBeanException JavaDoc;
41 import javax.management.MBeanInfo JavaDoc;
42 import javax.management.MBeanNotificationInfo JavaDoc;
43 import javax.management.MBeanOperationInfo JavaDoc;
44 import javax.management.MBeanParameterInfo JavaDoc;
45 import javax.management.MBeanRegistration JavaDoc;
46 import javax.management.MBeanServer JavaDoc;
47 import javax.management.NotificationBroadcaster JavaDoc;
48 import javax.management.NotificationEmitter JavaDoc;
49 import javax.management.NotificationFilter JavaDoc;
50 import javax.management.NotificationListener JavaDoc;
51 import javax.management.ObjectName JavaDoc;
52 import javax.management.ReflectionException JavaDoc;
53 import javax.management.RuntimeErrorException JavaDoc;
54 import javax.management.RuntimeMBeanException JavaDoc;
55 import javax.management.RuntimeOperationsException JavaDoc;
56 import javax.management.modelmbean.ModelMBeanInfo JavaDoc;
57 import javax.management.modelmbean.ModelMBeanInfoSupport JavaDoc;
58
59 import org.jboss.logging.Logger;
60 import org.jboss.mx.interceptor.AttributeDispatcher;
61 import org.jboss.mx.interceptor.Interceptor;
62 import org.jboss.mx.interceptor.ReflectedDispatcher;
63 import org.jboss.mx.metadata.StandardMetaData;
64 import org.jboss.mx.modelmbean.ModelMBeanConstants;
65 import org.jboss.mx.server.InvocationContext.NullDispatcher;
66 import org.jboss.mx.server.registry.MBeanEntry;
67 import org.jboss.util.Strings;
68
69 /**
70  * A base MBeanInvoker class that provides common state
71  *
72  * @author <a HREF="mailto:juha@jboss.org">Juha Lindfors</a>.
73  * @author <a HREF="mailto:scott.stark@jboss.org">Scott Stark</a>.
74  * @author <a HREF="mailto:dimitris@jboss.org">Dimitris Andreadis</a>.
75  * @version $Revision: 43658 $
76  */

77 public abstract class AbstractMBeanInvoker
78    implements MBeanInvoker
79 {
80    /**
81     * Used to propagate the MBeanEntry during the preRegister callback
82     */

83    static ThreadLocal JavaDoc preRegisterInfo = new ThreadLocal JavaDoc();
84
85    // Attributes ----------------------------------------------------
86

87    /**
88     * The target object for this invoker.
89     */

90    private Object JavaDoc resource = null;
91    /**
92     * The mbean server register entry used for the TCL
93     */

94    protected MBeanEntry resourceEntry = null;
95
96    /**
97     * Whether this is a dynamic resource
98     */

99    protected boolean dynamicResource = true;
100
101    /**
102     * The metadata describing this MBean.
103     */

104    protected MBeanInfo JavaDoc info = null;
105
106    protected Map JavaDoc attributeContextMap = new HashMap JavaDoc();
107    protected Map JavaDoc operationContextMap = new HashMap JavaDoc();
108    protected Map JavaDoc constructorContextMap = new HashMap JavaDoc();
109
110    protected InvocationContext getMBeanInfoCtx = null;
111    protected InvocationContext preRegisterCtx = null;
112    protected InvocationContext postRegisterCtx = null;
113    protected InvocationContext preDeregisterCtx = null;
114    protected InvocationContext postDeregisterCtx = null;
115
116    // TODO: allow to config invoker specific logs
117
// : multitarget mbean for invoker + log?
118

119    protected Logger log = Logger.getLogger(AbstractMBeanInvoker.class);
120
121    /**
122     * The MBeanServer passed in to preRegister
123     */

124
125    private MBeanServer JavaDoc server;
126
127    /**
128     * Set the MBeanEntry thread local value.
129     * @param entry - the entry that will be used on successful registration
130     */

131    public static void setMBeanEntry(MBeanEntry entry)
132    {
133       preRegisterInfo.set(entry);
134    }
135
136    /**
137     * An accessor for the MBeanEntry thread local
138     * @return
139     */

140    public static MBeanEntry getMBeanEntry()
141    {
142       return (MBeanEntry) preRegisterInfo.get();
143    }
144    // Constructors --------------------------------------------------
145

146    /**
147     * Constructs a new invoker.
148     */

149    public AbstractMBeanInvoker()
150    {
151    }
152
153    /**
154     * Constructs a new invoker with a given target resource.
155     */

156    public AbstractMBeanInvoker(Object JavaDoc resource)
157    {
158       this.resource = resource;
159    }
160
161    /**
162     * Constructs an invoker with the target resource entry.
163     * @param resourceEntry
164     */

165    public AbstractMBeanInvoker(MBeanEntry resourceEntry)
166    {
167       this.resourceEntry = resourceEntry;
168       this.resource = resourceEntry.getResourceInstance();
169    }
170
171    // DynamicMBean implementation -----------------------------------
172

173    /**
174     * Invokes the target resource. The default invocation used by this invoker
175     * implement sends the invocation through a stack of interceptors before
176     * reaching the target method.
177     * @param operationName name of the target method
178     * @param args argumetns for the target method
179     * @param signature signature of the target method
180     * @throws MBeanException if the target method raised a hecked exception
181     * @throws ReflectionException if there was an error trying to resolve or
182     * invoke the target method
183     * @throws RuntimeMBeanException if the target method raised an unchecked
184     * exception
185     */

186    public Object JavaDoc invoke(String JavaDoc operationName, Object JavaDoc[] args, String JavaDoc[] signature)
187       throws MBeanException JavaDoc, ReflectionException JavaDoc
188    {
189
190       // TODO: __JBOSSMX_INVOCATION
191

192       if (operationName == null)
193          throw new ReflectionException JavaDoc(new IllegalArgumentException JavaDoc("Null operation name"));
194       
195       // If we have dynamic capability, check for a dynamic invocation
196
String JavaDoc opName = operationName;
197       if (dynamicResource)
198       {
199          int dot = operationName.lastIndexOf('.');
200          if (dot != -1)
201          {
202             if (dot < operationName.length() - 1)
203                opName = operationName.substring(dot + 1);
204          }
205       }
206       
207       // get the server side invocation context
208
OperationKey key = new OperationKey(opName, signature);
209       InvocationContext ctx = (InvocationContext) operationContextMap.get(key);
210
211       // if the server does not contain this context, we do not have the operation
212
if (ctx == null)
213       {
214          // This is just stupid - the RI is fundamentally broken and hence the spec
215
boolean operationExists = false;
216          if (dynamicResource)
217          {
218             for (Iterator JavaDoc i = operationContextMap.keySet().iterator(); i.hasNext();)
219             {
220                OperationKey thisKey = (OperationKey) i.next();
221                if (opName.equals(thisKey.keys[0]))
222                {
223                   operationExists = true;
224                   break;
225                }
226             }
227             if (operationExists)
228                throw new ReflectionException JavaDoc(new NoSuchMethodException JavaDoc("Unable to find operation " + operationName +
229                   getSignatureString(signature)));
230          }
231          throw new ReflectionException JavaDoc(new IllegalArgumentException JavaDoc("Unable to find operation " + operationName +
232             getSignatureString(signature)));
233       }
234
235       // create the invocation object
236
Invocation invocation = new Invocation();
237
238       // copy the server's invocation context to the invocation
239
invocation.addContext(ctx);
240
241       // set the invocation's entry point
242
invocation.setType(InvocationContext.OP_INVOKE);
243
244       // Use the passed operation
245
invocation.setName(operationName);
246       
247       // set the args
248
invocation.setArgs(args);
249
250       override(invocation);
251
252       ClassLoader JavaDoc mbeanTCL = resourceEntry.getClassLoader();
253       final ClassLoader JavaDoc ccl = TCLAction.UTIL.getContextClassLoader();
254       boolean setCl = ccl != mbeanTCL && mbeanTCL != null;
255       if (setCl)
256       {
257          TCLAction.UTIL.setContextClassLoader(mbeanTCL);
258       }
259
260       try
261       {
262          // the default invocation implementation will invoke each interceptor
263
// declared in the invocation context before invoking the target method
264
return invocation.invoke();
265       }
266       catch (MBeanException JavaDoc e)
267       {
268          throw e;
269       }
270       catch (ReflectionException JavaDoc e)
271       {
272          throw e;
273       }
274       catch (JMRuntimeException JavaDoc e)
275       {
276          throw e;
277       }
278       catch (Throwable JavaDoc t)
279       {
280          rethrowAsMBeanException(t);
281          return null;
282       }
283
284          // TODO: should be fixed by adding invocation return value object
285
finally
286       {
287          Descriptor JavaDoc descriptor = invocation.getDescriptor();
288          if (descriptor != null)
289          {
290             ctx.setDescriptor(descriptor);
291             if (dynamicResource && ModelMBeanConstants.OPERATION_DESCRIPTOR.equals(descriptor.getFieldValue(ModelMBeanConstants.DESCRIPTOR_TYPE)))
292             {
293                ModelMBeanInfoSupport JavaDoc minfo = (ModelMBeanInfoSupport JavaDoc) info;
294                minfo.setDescriptor(descriptor, ModelMBeanConstants.OPERATION_DESCRIPTOR);
295             }
296          }
297          invocation.setArgs(null);
298          invocation.setDescriptor(null);
299          invocation.setDispatcher(null);
300
301          if (setCl)
302          {
303             TCLAction.UTIL.setContextClassLoader(ccl);
304          }
305       }
306
307    }
308
309    /**
310     * Returns an attribte value. The request for the value is forced through a
311     * set of interceptors before the value is returned.
312     * @param attribute attribute name
313     * @return attribute value
314     * @throws AttributeNotFoundException if the requested attribute is not part
315     * of the MBean's management interface
316     * @throws MBeanException if retrieving the attribute value causes an
317     * application exception
318     * @throws ReflectionException if there was an error trying to retrieve the
319     * attribute value
320     */

321    public Object JavaDoc getAttribute(String JavaDoc attribute)
322       throws AttributeNotFoundException JavaDoc, MBeanException JavaDoc, ReflectionException JavaDoc
323    {
324       // TODO: __JBOSSMX_INVOCATION
325

326       if (attribute == null)
327          throw new RuntimeOperationsException JavaDoc(new IllegalArgumentException JavaDoc("Cannot get null attribute"));
328
329       // lookup the server side invocation context
330
InvocationContext ctx = (InvocationContext) attributeContextMap.get(attribute);
331
332       // if we don't have a server side invocation context for the attribute,
333
// it does not exist as far as we are concerned
334
if (ctx == null)
335          throw new AttributeNotFoundException JavaDoc("not found: " + attribute);
336
337       if (ctx.isReadable() == false)
338          throw new AttributeNotFoundException JavaDoc("Attribute '" + attribute + "' found, but it is not readable");
339
340       // create the invocation object
341
Invocation invocation = new Invocation();
342
343       // copy the server's invocation context to the invocation
344
invocation.addContext(ctx);
345
346       // indicate the invocation access point was getAttribute() method
347
invocation.setType(InvocationContext.OP_GETATTRIBUTE);
348       invocation.setArgs(null);
349
350       override(invocation);
351
352       ClassLoader JavaDoc mbeanTCL = resourceEntry.getClassLoader();
353       final ClassLoader JavaDoc ccl = TCLAction.UTIL.getContextClassLoader();
354       boolean setCl = ccl != mbeanTCL && mbeanTCL != null;
355       if (setCl)
356       {
357          TCLAction.UTIL.setContextClassLoader(mbeanTCL);
358       }
359
360       try
361       {
362          return invocation.invoke();
363       }
364       catch (AttributeNotFoundException JavaDoc e)
365       {
366          throw e;
367       }
368       catch (MBeanException JavaDoc e)
369       {
370          throw e;
371       }
372       catch (ReflectionException JavaDoc e)
373       {
374          throw e;
375       }
376       catch (JMRuntimeException JavaDoc e)
377       {
378          throw e;
379       }
380       catch (Throwable JavaDoc t)
381       {
382          rethrowAsMBeanException(t);
383          return null;
384       }
385
386          // TODO: should be fixed by adding invocation return value object
387
finally
388       {
389          Descriptor JavaDoc attrDesc = invocation.getDescriptor();
390          ctx.setDescriptor(attrDesc);
391          updateAttributeInfo(attrDesc);
392
393          if (setCl)
394          {
395             TCLAction.UTIL.setContextClassLoader(ccl);
396          }
397       }
398    }
399
400    /**
401     * Sets an attribute value. The operation is forced through a set of
402     * interceptors before the new value for the attribute is set.
403     * @param attribute new attribute value
404     * @throws AttributeNotFoundException if the requested attribute is not part
405     * of the MBean's management interface
406     * @throws InvalidAttributeValueException if the attribute contains a value
407     * not suitable for the attribute
408     * @throws MBeanException if setting the attribute value causes an
409     * application exception
410     * @throws ReflectionException if there was an error trying to set the
411     * attribute value.
412     */

413    public void setAttribute(Attribute JavaDoc attribute) throws AttributeNotFoundException JavaDoc,
414       InvalidAttributeValueException JavaDoc, MBeanException JavaDoc, ReflectionException JavaDoc
415    {
416       // TODO: __JBOSSMX_INVOCATION
417

418       if (attribute == null)
419          throw new InvalidAttributeValueException JavaDoc("null attribute");
420
421       // lookup the server side invocation context
422
String JavaDoc name = attribute.getName();
423       InvocationContext ctx = (InvocationContext) attributeContextMap.get(name);
424
425       // if we don't have a server side invocation context for the attribute,
426
// it does not exist as far as we are concerned
427
if (ctx == null)
428          throw new AttributeNotFoundException JavaDoc("not found: " + name);
429       else if (ctx.isWritable() == false)
430       {
431          throw new AttributeNotFoundException JavaDoc("Attribute '" + name
432             + "' is not writable");
433       }
434
435       // create the invocation object
436
Invocation invocation = new Invocation();
437
438       // copy the server context to the invocation
439
invocation.addContext(ctx);
440
441       // indicate the access point as setAttribute()
442
invocation.setType(InvocationContext.OP_SETATTRIBUTE);
443
444       // set the attribute value as the argument
445
invocation.setArgs(new Object JavaDoc[]{attribute.getValue()});
446
447       override(invocation);
448
449       ClassLoader JavaDoc mbeanTCL = resourceEntry.getClassLoader();
450       final ClassLoader JavaDoc ccl = TCLAction.UTIL.getContextClassLoader();
451       boolean setCl = ccl != mbeanTCL && mbeanTCL != null;
452       if (setCl)
453       {
454          TCLAction.UTIL.setContextClassLoader(mbeanTCL);
455       }
456
457       try
458       {
459          // the default invocation implementation will invoke each interceptor
460
// declared in the invocation context before invoking the target method
461
invocation.invoke();
462       }
463       catch (AttributeNotFoundException JavaDoc e)
464       {
465          throw e;
466       }
467       catch (InvalidAttributeValueException JavaDoc e)
468       {
469          throw e;
470       }
471       catch (MBeanException JavaDoc e)
472       {
473          throw e;
474       }
475       catch (ReflectionException JavaDoc e)
476       {
477          throw e;
478       }
479       catch (JMRuntimeException JavaDoc e)
480       {
481          throw e;
482       }
483       catch (Throwable JavaDoc t)
484       {
485          rethrowAsMBeanException(t);
486       }
487
488          // TODO: should be fixed by adding invocation return value object
489
finally
490       {
491          /* Obtain the updated attribute descriptor and propagate to the
492          invocation context and ModelMBeanInfo. The latter is required in
493          order for getMBeanInfo() to show an updated view.
494          */

495          Descriptor JavaDoc attrDesc = invocation.getDescriptor();
496          ctx.setDescriptor(attrDesc);
497          updateAttributeInfo(attrDesc);
498
499          if (setCl)
500          {
501             TCLAction.UTIL.setContextClassLoader(ccl);
502          }
503       }
504    }
505
506    public MBeanInfo JavaDoc getMBeanInfo()
507    {
508       // create the invocation object
509
Invocation invocation = new Invocation(getMBeanInfoCtx);
510
511       // set the invocation's access point as getMBeanInfo()
512
invocation.setType(InvocationContext.OP_GETMBEANINFO);
513
514       if (resourceEntry == null)
515          resourceEntry = getMBeanEntry();
516       ClassLoader JavaDoc mbeanTCL = resourceEntry.getClassLoader();
517       final ClassLoader JavaDoc ccl = TCLAction.UTIL.getContextClassLoader();
518       boolean setCl = ccl != mbeanTCL && mbeanTCL != null;
519       if (setCl)
520       {
521          TCLAction.UTIL.setContextClassLoader(mbeanTCL);
522       }
523
524       try
525       {
526          MBeanInfo JavaDoc info = (MBeanInfo JavaDoc) invocation.invoke();
527          return info;
528       }
529       catch (JMRuntimeException JavaDoc e)
530       {
531          throw e;
532       }
533       catch (Throwable JavaDoc t)
534       {
535          rethrowAsRuntimeMBeanException(t);
536          return null;
537       }
538       finally
539       {
540          if (setCl)
541          {
542             TCLAction.UTIL.setContextClassLoader(ccl);
543          }
544       }
545    }
546
547    public AttributeList JavaDoc getAttributes(java.lang.String JavaDoc[] attributes)
548    {
549       if (attributes == null)
550          throw new IllegalArgumentException JavaDoc("null array");
551
552       AttributeList JavaDoc list = new AttributeList JavaDoc();
553
554       for (int i = 0; i < attributes.length; ++i)
555       {
556          try
557          {
558             list.add(new Attribute JavaDoc(attributes[i], getAttribute(attributes[i])));
559          }
560          catch (Throwable JavaDoc ignored)
561          {
562             // if the attribute could not be retrieved, skip it
563
}
564       }
565
566       return list;
567    }
568
569    public AttributeList JavaDoc setAttributes(AttributeList JavaDoc attributes)
570    {
571       if (attributes == null)
572          throw new IllegalArgumentException JavaDoc("null list");
573
574       AttributeList JavaDoc results = new AttributeList JavaDoc();
575       Iterator JavaDoc it = attributes.iterator();
576
577       while (it.hasNext())
578       {
579          Attribute JavaDoc attr = (Attribute JavaDoc) it.next();
580          try
581          {
582             setAttribute(attr);
583             results.add(attr);
584          }
585          catch (Throwable JavaDoc ignored)
586          {
587             // if unable to set the attribute, skip it
588
if (log.isTraceEnabled())
589                log.trace("Unhandled setAttribute() for attribute: " + attr.getName(), ignored);
590          }
591       }
592
593       return results;
594    }
595
596
597    // MBeanRegistration implementation ------------------------------
598

599    /**
600     * Initializes this invoker. At the registration time we can be sure that all
601     * of the metadata is available and initialize the invoker and cache the data
602     * accordingly. <p>
603     *
604     * Subclasses that override the <tt>preRegister</tt> method must make sure
605     * they call <tt>super.preRegister()</tt> in their implementation to ensure
606     * proper initialization of the invoker.
607     */

608    public ObjectName JavaDoc preRegister(MBeanServer JavaDoc server, ObjectName JavaDoc name) throws Exception JavaDoc
609    {
610       this.resourceEntry = (MBeanEntry) preRegisterInfo.get();
611       this.server = server;
612
613       ObjectName JavaDoc mbeanName = null;
614       Descriptor JavaDoc mbeanDescriptor = null;
615       if( info instanceof ModelMBeanInfo JavaDoc )
616       {
617          ModelMBeanInfo JavaDoc minfo = (ModelMBeanInfo JavaDoc) info;
618          try
619          {
620             mbeanDescriptor = minfo.getDescriptor("",
621                            ModelMBeanConstants.MBEAN_DESCRIPTOR);
622             String JavaDoc type = (String JavaDoc) mbeanDescriptor.getFieldValue(
623                ModelMBeanConstants.MBEAN_SERVER_INJECTION_TYPE);
624             if( type != null )
625             {
626                inject(ModelMBeanConstants.MBEAN_SERVER_INJECTION_TYPE,
627                   type, MBeanServer JavaDoc.class, getServer());
628             }
629          }
630          catch (MBeanException JavaDoc e)
631          {
632             log.warn("Failed to obtain descriptor: "+ModelMBeanConstants.MBEAN_DESCRIPTOR, e);
633          }
634
635       }
636
637       ClassLoader JavaDoc mbeanTCL = resourceEntry.getClassLoader();
638       final ClassLoader JavaDoc ccl = TCLAction.UTIL.getContextClassLoader();
639       boolean setCl = ccl != mbeanTCL && mbeanTCL != null;
640       if (setCl)
641       {
642          TCLAction.UTIL.setContextClassLoader(mbeanTCL);
643       }
644
645       try
646       {
647          initAttributeContexts(info.getAttributes());
648
649          initOperationContexts(info.getOperations());
650
651          if (resource != null)
652             initDispatchers();
653
654          mbeanName = invokePreRegister(server, name);
655          if( mbeanDescriptor != null )
656          {
657             Object JavaDoc value = mbeanDescriptor.getFieldValue(
658             ModelMBeanConstants.OBJECT_NAME_INJECTION_TYPE);
659             String JavaDoc type = (String JavaDoc) value;
660             if( type != null )
661             {
662                inject(ModelMBeanConstants.OBJECT_NAME_INJECTION_TYPE,
663                   type, ObjectName JavaDoc.class, mbeanName);
664             }
665          }
666       }
667       finally
668       {
669          if (setCl)
670          {
671             TCLAction.UTIL.setContextClassLoader(ccl);
672          }
673       }
674       return mbeanName;
675    }
676
677    /**
678     */

679    public void postRegister(Boolean JavaDoc registrationSuccessful)
680    {
681       invokePostRegister(registrationSuccessful);
682    }
683
684    /**
685     */

686    public void preDeregister() throws Exception JavaDoc
687    {
688       invokePreDeregister();
689    }
690
691    /**
692     */

693    public void postDeregister()
694    {
695       invokePostDeregister();
696       this.server = null;
697    }
698
699
700    // NotificationEmitter implementation ------------------------
701

702    public void addNotificationListener(NotificationListener JavaDoc listener,
703       NotificationFilter JavaDoc filter, Object JavaDoc handback)
704    {
705       addNotificationListenerToResource(listener, filter, handback);
706    }
707
708    protected void addNotificationListenerToResource(NotificationListener JavaDoc listener, NotificationFilter JavaDoc filter, Object JavaDoc handback)
709    {
710       if (resource instanceof NotificationBroadcaster JavaDoc)
711       {
712          ((NotificationBroadcaster JavaDoc) resource).addNotificationListener(listener, filter, handback);
713       }
714       else
715       {
716          throw new RuntimeMBeanException JavaDoc(new IllegalArgumentException JavaDoc("Target XXX is not a notification broadcaster"
717
718             // FIXME: add the XXX object name, store from registration
719
));
720       }
721    }
722
723    public void removeNotificationListener(NotificationListener JavaDoc listener)
724       throws ListenerNotFoundException JavaDoc
725    {
726       removeNotificationListenerFromResource(listener);
727    }
728
729    protected void removeNotificationListenerFromResource(NotificationListener JavaDoc listener)
730       throws ListenerNotFoundException JavaDoc
731    {
732       if (resource instanceof NotificationBroadcaster JavaDoc)
733       {
734          ((NotificationBroadcaster JavaDoc) resource).removeNotificationListener(listener);
735       }
736       else
737       {
738          throw new RuntimeMBeanException JavaDoc(new IllegalArgumentException JavaDoc("Target XXX is not a notification broadcaster"
739
740             // FIXME: add the XXX object name, store from registration
741
));
742       }
743    }
744
745    public void removeNotificationListener(NotificationListener JavaDoc listener,
746       NotificationFilter JavaDoc filter,
747       Object JavaDoc handback)
748       throws ListenerNotFoundException JavaDoc
749    {
750       removeNotificationListenerFromResource(listener, filter, handback);
751    }
752
753    protected void removeNotificationListenerFromResource(NotificationListener JavaDoc listener,
754       NotificationFilter JavaDoc filter,
755       Object JavaDoc handback)
756       throws ListenerNotFoundException JavaDoc
757    {
758       if (resource instanceof NotificationEmitter JavaDoc)
759       {
760          ((NotificationEmitter JavaDoc) resource).removeNotificationListener(listener, filter, handback);
761       }
762       else if (resource instanceof NotificationBroadcaster JavaDoc)
763       {
764          //JGH NOTE: looks like a listener against the MBeanServer is
765
//wrapped as a XMBean which has a broadcaster that is an NotificationEmitter
766
//but this resource target is a NotificationBroadcaster, in which case,
767
//w/o this .. you'll get a resource failure below
768
removeNotificationListener(listener);
769       }
770       else
771       {
772          throw new RuntimeMBeanException JavaDoc(new IllegalArgumentException JavaDoc("Target XXX is not a notification emitter"
773
774             // FIXME: add the XXX object name, store from registration
775
));
776       }
777    }
778
779    public MBeanNotificationInfo JavaDoc[] getNotificationInfo()
780    {
781       return getNotificationInfoFromResource();
782    }
783
784    protected MBeanNotificationInfo JavaDoc[] getNotificationInfoFromResource()
785    {
786       if (resource instanceof NotificationBroadcaster JavaDoc)
787       {
788          return ((NotificationBroadcaster JavaDoc) resource).getNotificationInfo();
789       }
790       else
791          return new MBeanNotificationInfo JavaDoc[]{};
792    }
793
794
795    // MBeanInvoker implementation -----------------------------------
796

797    public MBeanInfo JavaDoc getMetaData()
798    {
799       return info;
800    }
801    
802    public Object JavaDoc getResource()
803    {
804       return resource;
805    }
806
807    /**
808     * Sets the XMBean resource and optionally allows the resource to interact
809     * with the jmx microkernel via the following injection points:
810     * #ModelMBeanConstants.MBEAN_SERVER_INJECTION_TYPE
811     * #ModelMBeanConstants.MBEAN_INFO_INJECTION_TYPE
812     * #ModelMBeanConstants.OBJECT_NAME_INJECTION_TYPE
813     * @param resource - the model mbean resource
814     */

815    public void setResource(Object JavaDoc resource)
816    {