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    {
817       this.resource = resource;
818    }
819
820    public ObjectName JavaDoc getObjectName()
821    {
822       if (resourceEntry == null)
823          return null;
824       else
825          return resourceEntry.getObjectName();
826    }
827
828    public void updateAttributeInfo(Descriptor JavaDoc attrDesc) throws MBeanException JavaDoc
829    {
830       ModelMBeanInfoSupport JavaDoc minfo = (ModelMBeanInfoSupport JavaDoc) info;
831       minfo.setDescriptor(attrDesc, ModelMBeanConstants.ATTRIBUTE_DESCRIPTOR);
832    }
833    
834    /**
835     * Add dynamically an operation interceptor, first in the chain.
836     */

837    public void addOperationInterceptor(Interceptor interceptor)
838    {
839       if (operationContextMap != null && interceptor != null)
840       {
841          // Go through all the operation InvocationContext and add the interceptor
842
for (Iterator JavaDoc it = operationContextMap.entrySet().iterator(); it.hasNext();)
843          {
844             Map.Entry JavaDoc entry = (Map.Entry JavaDoc) it.next();
845    
846             InvocationContext ctx = (InvocationContext) entry.getValue();
847             List JavaDoc list = ctx.getInterceptors();
848
849             // to make the interceptor list update atomic, make a new ArrayList,
850
// add the new interceptor first and copy over the old ones,
851
// then update the context
852
List JavaDoc newList = new ArrayList JavaDoc();
853             newList.add(interceptor);
854             
855             if (list != null)
856             {
857                newList.addAll(list);
858             }
859             
860             ctx.setInterceptors(newList);
861          }
862       }
863    }
864    
865    /**
866     * Remove the specified operation interceptor
867     */

868    public void removeOperationInterceptor(Interceptor interceptor)
869    {
870       if (operationContextMap != null && interceptor != null)
871       {
872          // Go through all the operation InvocationContext and remove the interceptor
873
for (Iterator JavaDoc it = operationContextMap.entrySet().iterator(); it.hasNext();)
874          {
875             Map.Entry JavaDoc entry = (Map.Entry JavaDoc) it.next();
876
877             InvocationContext ctx = (InvocationContext) entry.getValue();
878             List JavaDoc list = ctx.getInterceptors();
879             
880             // to make the interceptor list update atomic, make a copy of the list
881
// remove the interceptor (if found), then update the context
882
if (list != null)
883             {
884                List JavaDoc newList = new ArrayList JavaDoc(list);
885
886                // this should probably work, whether or not equals() is implemented
887
// it'll remove the first occurence
888
newList.remove(interceptor);
889                
890                ctx.setInterceptors(newList);
891             }
892          }
893       }
894    }
895    
896    // Other Public Methods ------------------------------------------
897

898    public void suspend()
899    {
900    }
901
902    public void suspend(long wait) throws TimeoutException
903    {
904    }
905
906    public void suspend(boolean force)
907    {
908    }
909
910    public boolean isSuspended()
911    {
912       return false;
913    }
914
915    public void setInvocationTimeout(long time)
916    {
917    }
918
919    public long getInvocationTimeout()
920    {
921       return 0l;
922    }
923
924    public void resume()
925    {
926    }
927
928    public MBeanServer JavaDoc getServer()
929    {
930       return server;
931    }
932
933    // Protected -----------------------------------------------------
934

935    /**
936     * Inject context from the xmbean layer to the resource
937     * @param type - the type of injection
938     * @param name - the setter method name of the resource
939     * @param argType - the injection data type
940     * @param value - the injection data value to pass to the setter
941     */

942    protected void inject(String JavaDoc type, String JavaDoc name, Class JavaDoc argType, Object JavaDoc value)
943    {
944       try
945       {
946          Class JavaDoc resClass = resource.getClass();
947          Class JavaDoc[] sig = {argType};
948          Method JavaDoc setter = resClass.getMethod(name, sig);
949          Object JavaDoc[] args = {value};
950          setter.invoke(resource, args);
951       }
952       catch(NoSuchMethodException JavaDoc e)
953       {
954          log.debug("Setter not found: "+name+"("+argType+")", e);
955       }
956       catch(Exception JavaDoc e)
957       {
958          log.warn("Failed to inject type: "+type+" using setter: "+name, e);
959       }
960    }
961
962    protected ObjectName JavaDoc invokePreRegister(MBeanServer JavaDoc server, ObjectName JavaDoc name)
963       throws Exception JavaDoc
964    {
965       if (resource instanceof MBeanRegistration JavaDoc)
966          return ((MBeanRegistration JavaDoc) resource).preRegister(server, name);
967
968       return name;
969    }
970
971    protected void invokePostRegister(Boolean JavaDoc b)
972    {
973       if (resource instanceof MBeanRegistration JavaDoc)
974          ((MBeanRegistration JavaDoc) resource).postRegister(b);
975    }
976
977    protected void invokePreDeregister() throws Exception JavaDoc
978    {
979       if (resource instanceof MBeanRegistration JavaDoc)
980          ((MBeanRegistration JavaDoc) resource).preDeregister();
981    }
982
983    protected void invokePostDeregister()
984    {
985       if (resource instanceof MBeanRegistration JavaDoc)
986          ((MBeanRegistration JavaDoc) resource).postDeregister();
987    }
988
989    protected void initAttributeContexts(MBeanAttributeInfo JavaDoc[] attributes)
990    {
991       // create invocation contexts for attributes
992
for (int i = 0; i < attributes.length; ++i)
993       {
994          InvocationContext ctx = new InvocationContext();
995
996          // fill in some default values, the attribute name
997
ctx.setName(attributes[i].getName());
998
999          ctx.setAttributeType(attributes[i].getType());
1000
1001         // set myself as the invoker
1002
ctx.setInvoker(this);
1003
1004         //ctx.add(InvocationContext.ATTRIBUTE_ACCESS, getAccessCode(attributes[i]));
1005

1006         // store
1007
attributeContextMap.put(attributes[i].getName(), ctx);
1008      }
1009      if (log.isTraceEnabled())
1010         log.trace(getObjectName() + " configured attribute contexts: " + operationContextMap);
1011   }
1012
1013   protected void initOperationContexts(MBeanOperationInfo JavaDoc[] operations)
1014   {
1015      // create invocation contexts for operations
1016
for (int i = 0; i < operations.length; ++i)
1017      {
1018         InvocationContext ctx = new InvocationContext();
1019
1020         // extract operation name + signature
1021
String JavaDoc opName = operations[i].getName();
1022         MBeanParameterInfo JavaDoc[] signature = operations[i].getSignature();
1023         String JavaDoc returnType = operations[i].getReturnType();
1024
1025         // name is unchanged, fill in the context
1026
ctx.setName(opName);
1027
1028         // signature doesn't change..
1029
ctx.setSignature(signature);
1030
1031         // return type
1032
ctx.setReturnType(returnType);
1033         
1034         // set myself as the invoker
1035
ctx.setInvoker(this);
1036
1037         // add impact as part of ctx map (rarely accessed information)
1038
//ctx.add(InvocationContext.OPERATION_IMPACT, operations[i].getImpact());
1039

1040         // create an operation key consisting of the name + signature
1041
// (required for overloaded operations)
1042
OperationKey opKey = new OperationKey(opName, signature);
1043
1044         // store
1045
operationContextMap.put(opKey, ctx);
1046      }
1047      
1048      if (log.isTraceEnabled())
1049         log.trace(getObjectName() + " configured operation contexts: " + operationContextMap);
1050   }
1051
1052   protected void initDispatchers()
1053   {
1054      boolean trace = log.isTraceEnabled();
1055      
1056      // locate the resource class to receive the invocations
1057
Class JavaDoc clazz = null;
1058      if (resource != null)
1059      {
1060         clazz = resource.getClass();
1061         
1062         // JBAS-1704, if the target class is *not* public, look for
1063
// an exposed MBean interface, if one exists.
1064
// This should be checking if we are dealing with a standard
1065
// mbean (but not a standard mbean deployed as a model mbean)
1066
// but it doesn't look convenient from this baseclass.
1067
if (Modifier.isPublic(clazz.getModifiers()) == false)
1068         {
1069            clazz = StandardMetaData.findStandardInterface(clazz);
1070         }
1071      }
1072      
1073      // map the Methods on the target resource for easy access
1074
MethodMapper mmap = new MethodMapper(clazz);
1075      if (trace)
1076         log.trace(getObjectName() + " " + clazz + " map=" + mmap);
1077      
1078      MBeanOperationInfo JavaDoc[] operations = info.getOperations();
1079      
1080      // Set the dispatchers for the operations
1081
for (int i = 0; i < operations.length; ++i)
1082      {
1083         MBeanOperationInfo JavaDoc op = operations[i];
1084         OperationKey opKey = new OperationKey(op.getName(), op.getSignature());
1085         InvocationContext ctx = (InvocationContext) operationContextMap.get(opKey);
1086
1087         Interceptor dispatcher = ctx.getDispatcher();
1088         
1089         // Reconfigure if we have a Null or Reflected dispatcher
1090
if (dispatcher instanceof NullDispatcher || (dispatcher instanceof ReflectedDispatcher))
1091         {
1092            Object JavaDoc target = null;
1093            dispatcher = null;
1094            Method JavaDoc m = mmap.lookupOperation(op);
1095            if (m == null)
1096            {
1097               // Look for an method on the model mbean
1098
m = MethodMapper.lookupOperation(op, this);
1099               if (m != null)
1100               {
1101                  // operation found on the 'this' invoker
1102
target = this;
1103                  dispatcher = new ReflectedDispatcher(m, dynamicResource);
1104               }
1105               else
1106               {
1107                  // operation not found, use late binding
1108
// What is this late binding attempt and should there be a warning?
1109
dispatcher = new ReflectedDispatcher(dynamicResource);
1110               }
1111            }
1112            else
1113            {
1114               // operation found on the resource
1115
target = resource;
1116               dispatcher = new ReflectedDispatcher(m, dynamicResource);
1117            }
1118            if (trace)
1119               log.trace(getObjectName() + " will dispatch op=" + opKey +
1120                  " to " + Strings.defaultToString(target) +
1121                  " method= " + m);
1122            ctx.setTarget(target);
1123            ctx.setDispatcher(dispatcher);
1124         }
1125      }
1126
1127      // Set the dispatchers for the attributes with getters/setters
1128
MBeanAttributeInfo JavaDoc[] attributes = info.getAttributes();
1129      for (int i = 0; i < attributes.length; ++i)
1130      {
1131         MBeanAttributeInfo JavaDoc attribute = attributes[i];
1132         String JavaDoc name = attribute.getName();
1133         InvocationContext ctx = (InvocationContext) attributeContextMap.get(name);
1134
1135         Method JavaDoc getter = mmap.lookupGetter(attribute);
1136         Method JavaDoc setter = mmap.lookupSetter(attribute);
1137         ctx.setDispatcher(new AttributeDispatcher(getter, setter, dynamicResource));
1138         ctx.setTarget(resource);
1139      }
1140   }
1141
1142   /**
1143    * Placeholder to allow subclasses to override the invocation
1144    * @param invocation the invocation
1145    * @throws MBeanException for any error
1146    */

1147   protected void override(Invocation invocation) throws MBeanException JavaDoc
1148   {
1149   }
1150
1151   protected String JavaDoc getSignatureString(String JavaDoc[] signature)
1152   {
1153      if (signature == null)
1154         return "()";
1155      if (signature.length == 0)
1156         return "()";
1157
1158      StringBuffer JavaDoc sbuf = new StringBuffer JavaDoc(512);
1159
1160      sbuf.append("(");
1161      for (int i = 0; i < signature.length - 1; ++i)
1162      {
1163         sbuf.append(signature[i]);
1164         sbuf.append(",");
1165      }
1166      sbuf.append(signature[signature.length - 1]);
1167      sbuf.append(")");
1168
1169      return sbuf.toString();
1170   }
1171
1172
1173   // Inner classes -------------------------------------------------
1174
protected final class OperationKey
1175   {
1176      String JavaDoc[] keys = null;
1177      int hash = 0;
1178
1179      public OperationKey(final String JavaDoc name, final String JavaDoc type)
1180      {
1181         if (type != null)
1182         {
1183            keys = new String JavaDoc[2];
1184
1185            keys[0] = name;
1186            keys[1] = type;
1187
1188            hash = name.hashCode();
1189         }
1190
1191         else
1192         {
1193            keys = new String JavaDoc[]{name};
1194            hash = name.hashCode();
1195         }
1196      }
1197
1198      public OperationKey(final String JavaDoc name, final String JavaDoc[] signature)
1199      {
1200         if (signature != null)
1201         {
1202            keys = new String JavaDoc[signature.length + 1];
1203
1204            keys[0] = name;
1205
1206            System.arraycopy(signature, 0, keys, 1, signature.length);
1207
1208            hash = name.hashCode();
1209         }
1210
1211         else
1212         {
1213            keys = new String JavaDoc[]{name};
1214            hash = name.hashCode();
1215         }
1216      }
1217
1218      public OperationKey(String JavaDoc name, MBeanParameterInfo JavaDoc[] signature)
1219      {
1220         if (signature == null)
1221            signature = new MBeanParameterInfo JavaDoc[0];
1222
1223         keys = new String JavaDoc[signature.length + 1];
1224
1225         keys[0] = name;
1226
1227         for (int i = 0; i < signature.length; ++i)
1228         {
1229            keys[i + 1] = signature[i].getType();
1230         }
1231
1232         hash = name.hashCode();
1233      }
1234
1235      public OperationKey(MBeanOperationInfo JavaDoc info)
1236      {
1237         this(info.getName(), info.getSignature());
1238      }
1239
1240      public int hashCode()
1241      {
1242         return hash;
1243      }
1244
1245      public boolean equals(Object JavaDoc o)
1246      {
1247         OperationKey target = (OperationKey) o;
1248
1249         if (target.keys.length != keys.length)
1250            return false;
1251
1252         for (int i = 0; i < keys.length; ++i)
1253         {
1254            if (!(keys[i].equals(target.keys[i])))
1255               return false;
1256         }
1257
1258         return true;
1259      }
1260
1261      public String JavaDoc toString()
1262      {
1263         StringBuffer JavaDoc buffer = new StringBuffer JavaDoc(50);
1264         buffer.append(keys[0]).append("(");
1265
1266         for (int i = 1; i < keys.length - 1; ++i)
1267         {
1268            buffer.append(keys[i]).append(',');
1269         }
1270
1271         if (keys.length > 1)
1272            buffer.append(keys[keys.length - 1]);
1273         buffer.append(")");
1274         return buffer.toString();
1275      }
1276   }
1277
1278   private void rethrowAsMBeanException(Throwable JavaDoc t) throws MBeanException JavaDoc
1279   {
1280      if (t instanceof RuntimeException JavaDoc)
1281         throw new RuntimeMBeanException JavaDoc((RuntimeException JavaDoc) t);
1282      else if (t instanceof Error JavaDoc)
1283         throw new RuntimeErrorException JavaDoc((Error JavaDoc) t);
1284      else
1285         throw new MBeanException JavaDoc((Exception JavaDoc) t);
1286   }
1287
1288   private void rethrowAsRuntimeMBeanException(Throwable JavaDoc t)
1289   {
1290      if (t instanceof RuntimeException JavaDoc)
1291         throw new RuntimeMBeanException JavaDoc((RuntimeException JavaDoc) t);
1292      else if (t instanceof Error JavaDoc)
1293         throw new RuntimeErrorException JavaDoc((Error JavaDoc) t);
1294      else
1295         throw new RuntimeMBeanException JavaDoc(new RuntimeException JavaDoc("Unhandled exception", t));
1296   }
1297}
Popular Tags