Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: org/mortbay/util/jmx/ModelMBeanImpl.java


1   // ========================================================================
2   // Copyright (c) 1999 Mort Bay Consulting (Australia) Pty. Ltd.
3   // $Id: ModelMBeanImpl.java,v 1.8 2003/10/05 23:46:29 gregwilkins Exp $
4   // ========================================================================
5   
6   package org.mortbay.util.jmx;
7   
8   import java.lang.reflect.InvocationTargetException;
9   import java.lang.reflect.Method;
10  import java.lang.reflect.Modifier;
11  import java.util.ArrayList;
12  import java.util.HashMap;
13  import java.util.Iterator;
14  import java.util.Locale;
15  import java.util.Map;
16  import java.util.ResourceBundle;
17  
18  import javax.management.Attribute;
19  import javax.management.AttributeChangeNotification;
20  import javax.management.AttributeList;
21  import javax.management.AttributeNotFoundException;
22  import javax.management.InstanceNotFoundException;
23  import javax.management.InvalidAttributeValueException;
24  import javax.management.ListenerNotFoundException;
25  import javax.management.MBeanException;
26  import javax.management.MBeanInfo;
27  import javax.management.MBeanNotificationInfo;
28  import javax.management.MBeanOperationInfo;
29  import javax.management.MBeanParameterInfo;
30  import javax.management.MBeanRegistration;
31  import javax.management.MBeanServer;
32  import javax.management.Notification;
33  import javax.management.NotificationFilter;
34  import javax.management.NotificationListener;
35  import javax.management.ObjectName;
36  import javax.management.ReflectionException;
37  import javax.management.RuntimeOperationsException;
38  import javax.management.modelmbean.InvalidTargetObjectTypeException;
39  import javax.management.modelmbean.ModelMBean;
40  import javax.management.modelmbean.ModelMBeanAttributeInfo;
41  import javax.management.modelmbean.ModelMBeanInfo;
42  import javax.management.modelmbean.ModelMBeanInfoSupport;
43  import javax.management.modelmbean.ModelMBeanNotificationInfo;
44  import javax.management.modelmbean.ModelMBeanOperationInfo;
45  
46  import org.apache.commons.logging.Log;
47  import org.apache.commons.logging.LogFactory;
48  import org.mortbay.util.LogSupport;
49  import org.mortbay.util.TypeUtil;
50  
51  
52  /* ------------------------------------------------------------ */
53  /** Model MBean Implementation.
54   * This implementation of the JMX Model MBean API is designed to allow
55   * easy creation of Model MBeans. From minimal descriptions of
56   * operations and attributes, reflection is used to determine the full
57   * signature and ResourceBundles are used to determine other meta data.
58   *
59   * This class is normally used in one of the following patterns:<UL>
60   * <LI>As a base class for a real MBean that contains the actual
61   * attributes and operations of the MBean.  Such an Object is only
62   * usable in a JMX environment.
63   * <LI>As a proxy MBean to another non-JMX object. The attributes and
64   * operations of the proxied object are defined in the MBean.  This
65   * pattern is used when an existing non-JMX objects API is to be
66   * exposed as an MBean.
67   * <LI>As a base class for a proxy MBean. The attributes and oepration
68   * of the MBean are implemented by the derived class but delegate to
69   * one or more other objects. This pattern is used if existing objects
70   * are to be managed by JMX, but a new management API needs to be
71   * defined.
72   * </UL>
73   *
74   * @version $Revision: 1.8 $
75   * @author Greg Wilkins (gregw)
76   */
77  public class ModelMBeanImpl
78      implements ModelMBean,
79                 MBeanRegistration
80  {
81      private static Log log = LogFactory.getLog(ModelMBeanImpl.class);
82  
83      public final static int IMPACT_ACTION = MBeanOperationInfo.ACTION;
84      public final static int IMPACT_ACTION_INFO = MBeanOperationInfo.ACTION_INFO;
85      public final static int IMPACT_INFO = MBeanOperationInfo.INFO;
86      public final static int IMPACT_UNKOWN = MBeanOperationInfo.UNKNOWN;
87  
88      public final static String STRING="java.lang.String";
89      public final static String OBJECT="java.lang.Object";
90      public final static String INT="int";
91      
92      public final static String[] NO_PARAMS=new String[0];
93  
94      public final static boolean READ_WRITE=true;
95      public final static boolean READ_ONLY=false;
96      public final static boolean ON_MBEAN=true;
97      public final static boolean ON_OBJECT=false;
98      
99      
100     private static HashMap __objectId = new HashMap();
101 
102     private static String __defaultDomain="org.mortbay";
103     
104     protected ModelMBeanInfoSupport _beanInfo;
105     private MBeanServer _mBeanServer;
106     private Object _object;
107     private ObjectName _objectName;
108     
109     private boolean _dirty=false;
110     private HashMap _getter = new HashMap(4);
111     private HashMap _setter = new HashMap(4);
112     private HashMap _method = new HashMap(4);
113     private ArrayList _attributes = new ArrayList(4);
114     private ArrayList _operations = new ArrayList(4);
115     private ArrayList _notifications = new ArrayList(4);
116     private String _baseObjectName=null;
117     private Map _components = new HashMap(4);
118 
119     /* ------------------------------------------------------------ */
120     /* ------------------------------------------------------------ */
121     /** Create MBean for Object.
122      * Attempts to create an MBean for the object by searching the
123      * package and class name space.  For example an object of the
124      * type <PRE>
125      *   class com.acme.MyClass extends com.acme.util.BaseClass
126      * </PRE>
127      * Then this method would look for the following
128      * classes:<UL>
129      * <LI>com.acme.MyClassMBean
130      * <LI>com.acme.jmx.MyClassMBean
131      * <LI>com.acme.util.BaseClassMBean
132      * <LI>com.acme.util.jmx.BaseClassMBean
133      * </UL>
134      * @param o The object
135      * @return A new instance of an MBean for the object or null.
136      */
137     public static ModelMBean mbeanFor(Object o)
138     {
139         try
140         {
141             Class oClass = o.getClass();
142             ClassLoader loader =oClass.getClassLoader();
143 
144             ModelMBean mbean = null;
145             boolean jmx=false;
146             Class[] interfaces=null;
147             int i=0;
148             
149             while (mbean==null && oClass!=null)
150             {
151                 Class focus=interfaces==null?oClass:interfaces[i];
152                 String pName = focus.getPackage().getName();
153                 String cName = focus.getName().substring(pName.length()+1);
154                 String mName=pName+(jmx?".jmx.":".")+cName+"MBean";
155 
156                 try{
157                     Class mClass=loader.loadClass(mName);
158         if(LogSupport.isTraceEnabled(log))log.trace("mbeanFor "+o+" mClass="+mClass);
159                     mbean=(ModelMBean)mClass.newInstance();
160                     mbean.setManagedResource(o,"objectReference");
161         if(log.isDebugEnabled())log.debug("mbeanFor "+o+" is "+mbean);
162                     return mbean;
163                 }
164                 catch(ClassNotFoundException e)
165                 {
166                     if (e.toString().endsWith("MBean"))
167         { if(LogSupport.isTraceEnabled(log))log.trace(e.toString());}
168                     else
169                         log.warn(LogSupport.EXCEPTION,e);
170                 }
171                 catch(Error e)
172                 {
173                     log.warn(LogSupport.EXCEPTION,e);
174                     mbean=null;
175                 }
176                 catch(Exception e)
177                 {
178                     log.warn(LogSupport.EXCEPTION,e);
179                     mbean=null;
180                 }
181 
182                 if (jmx)
183                 {
184                     if (interfaces!=null)
185                     {
186                         i++;
187                         if (i>=interfaces.length)
188                         {
189                             interfaces=null;
190                             oClass=oClass.getSuperclass();
191                         }
192                     }
193                     else
194                     {
195                         interfaces=oClass.getInterfaces();
196                         i=0;
197                         if (interfaces==null || interfaces.length==0)
198                         {
199                             interfaces=null;
200                             oClass=oClass.getSuperclass();
201                         }
202                     }
203                 }
204                 jmx=!jmx;
205             }
206         }
207         catch(Exception e)
208         {
209             LogSupport.ignore(log,e);
210         }
211         return null;
212     }
213     
214     /* ------------------------------------------------------------ */
215     /** MBean Constructor.
216      * No proxy object is defined.  Attributes and operations are
217      * defined on this instance. 
218      */
219     public ModelMBeanImpl()
220     {}
221     
222     /* ------------------------------------------------------------ */
223     /** Proxy MBean Constructor. 
224      * @param proxyObject The actual object on which attributes and
225      * operations are to be defined and called. 
226      */
227     public ModelMBeanImpl(Object proxyObject)
228     {
229         try
230         {
231             setManagedResource(proxyObject,"objectReference");
232         }
233         catch(Exception e)
234         {
235             log.warn(LogSupport.EXCEPTION,e);
236             throw new IllegalArgumentException(e.toString());
237         }
238     }
239     
240     
241     /* ------------------------------------------------------------ */
242     public static String getDefaultDomain()    { return __defaultDomain; }
243     
244     /* ------------------------------------------------------------ */
245     public static void setDefaultDomain(String d)   { __defaultDomain=d; }
246     
247     /* ------------------------------------------------------------ */
248     public MBeanServer getMBeanServer()       { return _mBeanServer; }
249 
250     /* ------------------------------------------------------------ */
251     public ObjectName getObjectName()          { return _objectName; }
252     
253     /* ------------------------------------------------------------ */
254     public Object getManagedResource()             { return _object; }
255   
256     /* ------------------------------------------------------------ */
257     public void setManagedResource(Object proxyObject, String type)
258         throws MBeanException,
259                RuntimeOperationsException,
260                InstanceNotFoundException,
261                InvalidTargetObjectTypeException
262     {
263         if (proxyObject==null)
264         {
265             proxyObject=null;
266             return;
267         }
268         
269         log.debug("setManagedResource");
270         if (!"objectreference".equalsIgnoreCase(type))
271             throw new InvalidTargetObjectTypeException(type);
272 
273         if (_object==null)
274         {
275             // first set so define attributes etc.
276             _object=proxyObject;
277             
278             defineManagedResource();
279         }
280         else
281             _object=proxyObject;    
282     }
283 
284     /* ------------------------------------------------------------ */
285     /** Define the Managed Resource.
286      * This method is called the first time setManagedResource is
287      * called with a non-null object. It should be implemented by a
288      * derived ModelMBean to define the attributes and operations
289      * after an initial object has been set.
290      */
291     protected void defineManagedResource()
292     {}
293     
294     /* ------------------------------------------------------------ */
295     /** Not Supported.
296      * Use RequiredModelMBean for this style of MBean creation.
297      */
298     public void setModelMBeanInfo(ModelMBeanInfo info)
299         throws MBeanException,
300                RuntimeOperationsException
301     {
302         throw new Error("setModelMBeanInfo not supported");
303     }
304     
305     /* ------------------------------------------------------------ */
306     /** Define an attribute on the managed object.
307      * The meta data is defined by looking for standard getter and
308      * setter methods. Descriptions are obtained with a call to
309      * findDescription with the attribute name.
310      * @param name The name of the attribute. Normal java bean
311      * capitlization is enforced on this name.
312      */
313     public synchronized void defineAttribute(String name)
314     {
315         defineAttribute(name,true,false);
316     }
317     
318     /* ------------------------------------------------------------ */
319     /** Define an attribute on the managed object.
320      * The meta data is defined by looking for standard getter and
321      * setter methods. Descriptions are obtained with a call to
322      * findDescription with the attribute name.
323      * @param name The name of the attribute. Normal java bean
324      * capitlization is enforced on this name.
325      * @param writable If false, do not look for a setter.
326      */
327     public synchronized void defineAttribute(String name, boolean writable)
328     {
329         defineAttribute(name,writable,false);
330     }
331     
332     /* ------------------------------------------------------------ */
333     /** Define an attribute on the managed object.
334      * The meta data is defined by looking for standard getter and
335      * setter methods. Descriptions are obtained with a call to
336      * findDescription with the attribute name.
337      * @param name The name of the attribute. Normal java bean
338      * capitlization is enforced on this name.
339      * @param writable If false, do not look for a setter.
340      * @param onMBean .
341      */
342     public synchronized void defineAttribute(String name,
343                                              boolean writable,
344                                              boolean onMBean)
345     {
346         _dirty=true;
347         
348         String uName=name.substring(0,1).toUpperCase()+name.substring(1);
349         name=java.beans.Introspector.decapitalize(name);
350         Class oClass=onMBean?this.getClass():_object.getClass();
351 
352         Class type=null;
353         Method getter=null;
354         Method setter=null;
355         Method[] methods=oClass.getMethods();
356         for (int m=0;m<methods.length;m++)
357         {
358             if ((methods[m].getModifiers()&Modifier.PUBLIC)==0)
359                 continue;
360 
361             // Look for a getter
362             if (methods[m].getName().equals("get"+uName) &&
363                 methods[m].getParameterTypes().length==0)
364             {
365                 if (getter!=null)
366                     throw new IllegalArgumentException("Multiple getters for attr "+name);
367                 getter=methods[m];
368                 if (type!=null &&
369                     !type.equals(methods[m].getReturnType()))
370                     throw new IllegalArgumentException("Type conflict for attr "+name);
371                 type=methods[m].getReturnType();
372             }
373 
374             // Look for an is getter
375             if (methods[m].getName().equals("is"+uName) &&
376                 methods[m].getParameterTypes().length==0)
377             {
378                 if (getter!=null)
379                     throw new IllegalArgumentException("Multiple getters for attr "+name);
380                 getter=methods[m];
381                 if (type!=null &&
382                     !type.equals(methods[m].getReturnType()))
383                     throw new IllegalArgumentException("Type conflict for attr "+name);
384                 type=methods[m].getReturnType();
385             }
386 
387             // look for a setter
388             if (writable &&
389                 methods[m].getName().equals("set"+uName) &&
390                 methods[m].getParameterTypes().length==1)
391             {
392                 if (setter!=null)
393                     throw new IllegalArgumentException("Multiple setters for attr "+name);
394                 setter=methods[m];
395                 if (type!=null &&
396                     !type.equals(methods[m].getParameterTypes()[0]))
397                     throw new IllegalArgumentException("Type conflict for attr "+name);
398                 type=methods[m].getParameterTypes()[0];
399             }
400         }
401 
402         if (getter==null && setter==null)
403             throw new IllegalArgumentException("No getter or setters found for "+name);
404         
405         try
406         {
407             // Remember the methods
408             _getter.put(name,getter);
409             _setter.put(name,setter);
410             // create and add the info
411             _attributes.add(new ModelMBeanAttributeInfo(name,
412                                                         findDescription(name),
413                                                         getter,
414                                                         setter));
415         }
416         catch(Exception e)
417         {
418             log.warn(LogSupport.EXCEPTION,e);
419             throw new IllegalArgumentException(e.toString());
420         }
421     }
422 
423     /* ------------------------------------------------------------ */
424     /** Define an attribute.
425      * Explicit definition of an attribute. Reflection is used to
426      * locate the actual getter and setter methods.
427      * @param attrInfo ModelMBeanAttributeInfo.
428      */
429     public synchronized void defineAttribute(ModelMBeanAttributeInfo attrInfo)
430     {
431         if (_object==null)
432             throw new IllegalStateException("No Object");
433         
434         _dirty=true;
435         
436         String name=attrInfo.getName();
437         String uName=name.substring(0,1).toUpperCase()+name.substring(1);
438         Class oClass=_object.getClass();
439 
440         try
441         {
442             Class type=TypeUtil.fromName(attrInfo.getType());
443             if (type==null)
444                 type=Thread.currentThread().getContextClassLoader().loadClass(attrInfo.getType());
445         
446             Method getter=null;
447             Method setter=null;
448             
449             if (attrInfo.isReadable())
450                 getter=oClass.getMethod((attrInfo.isIs()?"is":"get")+uName,null);
451             
452             if (attrInfo.isWritable())
453                 setter=oClass.getMethod("set"+uName,new Class[] {type});
454             
455             _getter.put(name,getter);
456             _setter.put(name,setter);
457             _attributes.add(attrInfo);
458         }
459         catch(Exception e)
460         {
461             log.warn(LogSupport.EXCEPTION,e);
462             throw new IllegalArgumentException(e.toString());
463         }
464     }
465     
466     /* ------------------------------------------------------------ */
467     /** Define an operation on the managed object.
468      * Defines an operation with no parameters. Refection is used to
469      * determine the return type and the description is found with a
470      * call to findDescription on "name()".
471      * @param name  Name of the method call
472      * @param impact Impact as defined in MBeanOperationInfo
473      */
474     public synchronized void defineOperation(String name,int impact)
475     {
476         defineOperation(name,null,impact);
477     }
478     
479     /* ------------------------------------------------------------ */
480     /** Define an operation on the managed object.
481      * Defines an operation with parameters. Refection is used to
482      * determine find the method and it's return type. The description
483      * of the method is found with a call to findDescription on
484      * "name(signature)". The name and description of each parameter
485      * is found with a call to findDescription with
486      * "name(partialSignature", the returned description is for the
487      * last parameter of the partial signature and is assumed to start
488      * with the parameter name, followed by a colon.
489      * @param name The name of the method call.
490      * @param signature The types of the operation parameters.
491      * @param impact Impact as defined in MBeanOperationInfo
492      */
493     public synchronized void defineOperation(String name,
494                                              String[] signature,
495                                              int impact)
496     {
497         _dirty=true;        
498         Class oClass=_object.getClass();
499         if (signature==null) signature=new String[0];
500 
501         try
502         {
503             Class[] types = new Class[signature.length];
504             MBeanParameterInfo[] pInfo = new
505                 MBeanParameterInfo[signature.length];
506 
507             // Check types and build methodKey
508             String methodKey=name+"(";
509             for (int i=0;i<signature.length;i++)
510             {
511                 Class type=TypeUtil.fromName(signature[i]);
512                 if (type==null)
513                     type=Thread.currentThread().getContextClassLoader().loadClass(signature[i]);
514                 types[i]=type;
515                 signature[i]=type.isPrimitive()?TypeUtil.toName(type):signature[i];
516                 methodKey+=(i>0?",":"")+signature[i];
517             }
518             methodKey+=")";
519 
520             // Build param infos
521             for (int i=0;i<signature.length;i++)
522             {
523                 String description=findDescription(methodKey+"["+i+"]");
524                 int colon=description.indexOf(":");
525                 if (colon<0)
526                 {
527                     description="param"+i+":"+description;
528                     colon=description.indexOf(":");
529                 }
530                 pInfo[i]=new
531                     MBeanParameterInfo(description.substring(0,colon).trim(),
532                                        signature[i],
533                                        description.substring(colon+1).trim());
534             }
535 
536             // build the operation info
537             Method method=oClass.getMethod(name,types);
538             Class returnClass=method.getReturnType();
539             _method.put(methodKey,method);
540             _operations.add(new ModelMBeanOperationInfo
541                 (name,
542                  findDescription(methodKey),
543                  pInfo,
544                  returnClass.isPrimitive()?TypeUtil.toName(returnClass):(returnClass.getName()),
545                  impact));
546         }
547         catch(Exception e)
548         {
549             log.warn("operation "+name,e);
550             throw new IllegalArgumentException(e.toString());
551         }
552         
553     }
554     
555     /* ------------------------------------------------------------ */
556     /** Define an operation.
557      * Explicit definition of an operation. Reflection is used to
558      * locate method called.
559      * @param opInfo 
560      */
561     public synchronized void defineOperation(ModelMBeanOperationInfo opInfo)
562     {
563         _dirty=true;        
564         Class oClass=_object.getClass();
565         
566         try
567         {
568             MBeanParameterInfo[] pInfo = opInfo.getSignature();
569             
570             Class[] types = new Class[pInfo.length];
571             String method=opInfo.getName()+"(";
572             for (int i=0;i<pInfo.length;i++)
573             {
574                 Class type=TypeUtil.fromName(pInfo[i].getType());
575                 if (type==null)
576                     type=Thread.currentThread().getContextClassLoader().loadClass(pInfo[i].getType());
577                 types[i]=type;
578                 method+=(i>0?",":"")+pInfo[i].getType();
579             }
580             method+=")";
581 
582             _method.put(method,oClass.getMethod(opInfo.getName(),types));
583             _operations.add(opInfo);
584         }
585         catch(Exception e)
586         {
587             log.warn(LogSupport.EXCEPTION,e);
588             throw new IllegalArgumentException(e.toString());
589         }   
590     }
591     
592     /* ------------------------------------------------------------ */
593     public synchronized MBeanInfo getMBeanInfo()
594     {
595         log.debug("getMBeanInfo");
596 
597         if (_dirty)
598         {
599             _dirty=false;
600             ModelMBeanAttributeInfo[] attributes = (ModelMBeanAttributeInfo[])
601                 _attributes.toArray(new ModelMBeanAttributeInfo[0]);
602             ModelMBeanOperationInfo[] operations = (ModelMBeanOperationInfo[])
603                 _operations.toArray(new ModelMBeanOperationInfo[0]);
604             ModelMBeanNotificationInfo[] notifications =(ModelMBeanNotificationInfo[])
605                 _notifications.toArray(new ModelMBeanNotificationInfo[0]);
606 
607             _beanInfo =
608                 new ModelMBeanInfoSupport(_object.getClass().getName(),
609                                           findDescription(null),
610                                           attributes,
611                                           null,
612                                           operations,
613                                           notifications);            
614         }
615             
616         return _beanInfo;
617     }
618   
619     /* ------------------------------------------------------------ */
620     public Object getAttribute(String name)
621         throws AttributeNotFoundException,
622                MBeanException,
623                ReflectionException
624     {
625         if(log.isDebugEnabled())log.debug("getAttribute "+name);
626         Method getter = (Method)_getter.get(name);
627         if (getter==null)
628             throw new AttributeNotFoundException(name);
629         try
630         {
631             Object o=_object;
632             if (getter.getDeclaringClass().isInstance(this))
633                 o=this;
634             return getter.invoke(o,null);
635         }
636         catch(IllegalAccessException e)
637         {
638             log.warn(LogSupport.EXCEPTION,e);
639             throw new AttributeNotFoundException(e.toString());
640         }
641         catch(InvocationTargetException e)
642         {
643             log.warn(LogSupport.EXCEPTION,e);
644             throw new ReflectionException((Exception)e.getTargetException());
645         }
646     }
647     
648     /* ------------------------------------------------------------ */
649     public AttributeList getAttributes(String[] names)
650     {
651         log.debug("getAttributes");
652         AttributeList results=new AttributeList(names.length);
653         for (int i=0;i<names.length;i++)
654         {
655             try
656             {
657                 results.add(new Attribute(names[i],
658                                           getAttribute(names[i])));
659             }
660             catch(Exception e)
661             {
662                 log.warn(LogSupport.EXCEPTION,e);
663             }
664         }
665         return results;
666     }
667     
668     
669     /* ------------------------------------------------------------ */
670     public void setAttribute(Attribute attr)
671         throws AttributeNotFoundException,
672                InvalidAttributeValueException,
673                MBeanException,
674                ReflectionException
675     {
676         if(log.isDebugEnabled())log.debug("setAttribute "+attr.getName()+"="+attr.getValue());
677         Method setter = (Method)_setter.get(attr.getName());
678         if (setter==null)
679             throw new AttributeNotFoundException(attr.getName());
680         try
681         {
682             Object o=_object;
683             if (setter.getDeclaringClass().isInstance(this))
684                 o=this;
685             setter.invoke(o,new Object[]{attr.getValue()});
686         }
687         catch(IllegalAccessException e)
688         {
689             log.warn(LogSupport.EXCEPTION,e);
690             throw new AttributeNotFoundException(e.toString());
691         }
692         catch(InvocationTargetException e)
693         {
694             log.warn(LogSupport.EXCEPTION,e);
695             throw new ReflectionException((Exception)e.getTargetException());
696         }
697     }
698     
699     /* ------------------------------------------------------------ */
700     public AttributeList setAttributes(AttributeList attrs)
701     {
702         log.debug("setAttributes");
703 
704         AttributeList results=new AttributeList(attrs.size());
705         Iterator iter = attrs.iterator();
706         while(iter.hasNext())
707         {
708             try
709             {
710                 Attribute attr=(Attribute)iter.next();
711                 setAttribute(attr);
712                 results.add(new Attribute(attr.getName(),
713                                           getAttribute(attr.getName())));
714             }
715             catch(Exception e)
716             {
717                 log.warn(LogSupport.EXCEPTION,e);
718             }
719         }
720         return results;
721     }
722 
723     /* ------------------------------------------------------------ */
724     public Object invoke(String name, Object[] params, String[] signature)
725         throws MBeanException,
726                ReflectionException
727     {
728         if(log.isDebugEnabled())log.debug("invoke "+name);
729 
730         String methodKey=name+"(";
731         for (int i=0;i<signature.length;i++)
732             methodKey+=(i>0?",":"")+signature[i];
733         methodKey+=")";
734 
735         try
736         {
737             Method method = (Method)_method.get(methodKey);
738             if (method==null)
739                 throw new NoSuchMethodException(methodKey);
740 
741             return method.invoke(_object,params);
742         }
743         catch(NoSuchMethodException e)
744         {
745             log.warn(LogSupport.EXCEPTION,e);
746             throw new ReflectionException(e);
747         }
748         catch(IllegalAccessException e)
749         {
750             log.warn(LogSupport.EXCEPTION,e);
751             throw new MBeanException(e);
752         }
753         catch(InvocationTargetException e)
754         {
755             log.warn(LogSupport.EXCEPTION,e);
756             throw new ReflectionException((Exception)e.getTargetException());
757         }
758         
759     }
760     
761     /* ------------------------------------------------------------ */
762     public void load()
763         throws MBeanException,
764                RuntimeOperationsException,
765                InstanceNotFoundException
766     {
767         log.debug("load");
768     }
769     
770     /* ------------------------------------------------------------ */
771     public void store()
772         throws MBeanException,
773                RuntimeOperationsException,
774                InstanceNotFoundException
775     {
776         log.debug("store");
777     }
778 
779     /* ------------------------------------------------------------ */
780     public void addNotificationListener(NotificationListener listener,
781                                         NotificationFilter filter,
782                                         Object handback)
783         throws IllegalArgumentException
784     {
785         log.debug("addNotificationListener");
786     }
787     
788     /* ------------------------------------------------------------ */
789     public MBeanNotificationInfo[] getNotificationInfo()
790     {
791         log.debug("getNotificationInfo");
792         return null;
793     }
794     
795     /* ------------------------------------------------------------ */
796     public void removeNotificationListener(NotificationListener listener)
797         throws ListenerNotFoundException
798     {
799         log.debug("removeNotificationListener");
800     }
801 
802     /* ------------------------------------------------------------ */
803     public void addAttributeChangeNotificationListener(NotificationListener listener,
804                                                String name,
805                                                Object handback)
806         throws MBeanException,
807                RuntimeOperationsException,
808                IllegalArgumentException
809     {
810         log.debug("addAttributeChangeNotificationListener");
811     }
812     
813     /* ------------------------------------------------------------ */
814     public void removeAttributeChangeNotificationListener(NotificationListener listener,
815                                                           String name)
816         throws MBeanException,
817                RuntimeOperationsException,
818                ListenerNotFoundException
819     {
820         log.debug("removeAttributeChangeNotificationListener");
821     }
822     
823     /* ------------------------------------------------------------ */
824     public void sendAttributeChangeNotification(Attribute oldAttr,
825                                                 Attribute newAttr)
826         throws MBeanException,
827                RuntimeOperationsException
828     {
829         log.debug("sendAttributeChangeNotification");
830     }
831     
832     /* ------------------------------------------------------------ */
833     public void sendAttributeChangeNotification(AttributeChangeNotification notify)
834         throws MBeanException,
835                RuntimeOperationsException
836     {
837         log.debug("sendAttributeChangeNotification");
838     }
839     
840     /* ------------------------------------------------------------ */
841     public void sendNotification(String notify)
842         throws MBeanException,
843                RuntimeOperationsException
844     {
845         log.debug("sendNotification");
846     }
847     
848     /* ------------------------------------------------------------ */
849     public void sendNotification(Notification notify)
850         throws MBeanException,
851                RuntimeOperationsException
852     {
853         log.debug("sendNotification");
854     }
855 
856     /* ------------------------------------------------------------ */
857     /* Find MBean descriptions.
858      * MBean descriptions are searched for in ResourceBundles. Bundles
859      * are looked for in a mbean.property files within each package of
860      * the MBean class inheritance hierachy.
861      * Once a bundle is found, the key is added to object names in the
862      * following order: fully qualied managed resource class name, tail
863      * managed resource class name, tail mbean class name. The string
864      * "MBean" is stripped from the tail of any name.
865      * <P>For example, if the class a.b.C is managed by a MBean
866      * p.q.RMBean which is derived from p.SMBean, then the seach order
867      * for a key x is as follows:<PRE>
868      *   bundle: p.q.mbean    name: a.b.C.x
869      *   bundle: p.q.mbean    name: C.x
870      *   bundle: p.q.mbean    name: R.x
871      *   bundle: p.mbean      name: a.b.C.x
872      *   bundle: p.mbean      name: C.x
873      *   bundle: p.mbean      name: S.x
874      * </PRE>
875      * <P>The convention used for keys passed to this method are:<PRE>
876      *   null or empty         - Object description
877      *   xxx                   - Attribute xxx description
878      *   xxx()                 - Simple operation xxx description
879      *   xxx(type,..)          - Operation xxx with signature desciption
880      *   xxx(type,..)[n]       - Param n of operation xxx description
881      * </PRE>
882      * @param key 
883      * @return Description string.
884      */
885     private String findDescription(String key)
886     {
887         Class lookIn = this.getClass();
888 
889         // Array of possible objectNames
890         String[] objectNames=new String[3];
891         objectNames[0]=_object.getClass().getName();
892         if (objectNames[0].indexOf(".")>=0)
893             objectNames[1]=objectNames[0].substring(objectNames[0].lastIndexOf(".")+1);
894 
895         while(lookIn!=null)
896         {
897             String pkg=lookIn.getName();
898             int lastDot= pkg.lastIndexOf(".");
899             if (lastDot>0)
900             {
901                 objectNames[2]=pkg.substring(lastDot+1);
902                 pkg=pkg.substring(0,lastDot);
903             }
904             else
905             {
906                 objectNames[2]=pkg;
907                 pkg=null;
908             }
909 
910             String resource=(pkg==null?"mbean":(pkg.replace('.','/')+"/mbean"));
911             if(LogSupport.isTraceEnabled(log))log.trace("Look for: "+resource);
912 
913             try
914             {
915                 ResourceBundle bundle=
916                     ResourceBundle.getBundle(resource,
917                                              Locale.getDefault(),
918                                              _object.getClass().getClassLoader());
919             
920                 if(LogSupport.isTraceEnabled(log))log.trace("Bundle "+resource);
921                 
922                 for (int i=0;i<objectNames.length;i++)
923                 {
924                     String name=objectNames[i];
925                     
926                     if (name==null)
927                         continue;
928                     if (name.endsWith("MBean"))
929                         name=name.substring(0,name.length()-5);
930                     if (key!=null && key.length()>0)
931                         name+="."+key;
932 
933                     try{
934                         String description=bundle.getString(name);
935                         if (description!=null && description.length()>0)
936                             return description;
937                     }
938                     catch(Exception e) { if(LogSupport.isTraceEnabled(log))log.trace(e.toString()); }
939                 }
940             }
941             catch(Exception e) { if(LogSupport.isTraceEnabled(log))log.trace(e.toString()); }
942 
943             lookIn=lookIn.getSuperclass();
944         }
945 
946         if (key==null || key.length()==0)
947             return objectNames[0];
948         
949         return key;
950     }
951     
952     /* ------------------------------------------------------------ */
953     /** Create a new ObjectName.
954      * Return a new object name. The default implementation is the
955      * results of uniqueObjectName(baseObjectName), if baseObjectName
956      * is not set, then the results of uniqueObjectName(defaultDomain+":");
957      * @return The Object name
958      */
959     protected ObjectName newObjectName(MBeanServer server)
960     {
961         // Create own ObjectName of the form:
962         // package:class=id
963         if (_baseObjectName!=null)
964         {
965             if (_baseObjectName.indexOf(':')>=0)
966                 return uniqueObjectName(server,_baseObjectName);
967             return uniqueObjectName(server,getDefaultDomain()+":"+
968                                     _baseObjectName);
969         }
970         return uniqueObjectName(server,getDefaultDomain()+":");
971     }
972 
973     /* ------------------------------------------------------------ */
974     public void setBaseObjectName(String s)
975     {
976         _baseObjectName=s;
977     }
978     
979     /* ------------------------------------------------------------ */
980     public String getBaseObjectName()
981     {
982         return _baseObjectName;
983     }
984     
985     /* ------------------------------------------------------------ */
986     /** Pre registration notification.
987      * If this method is specialized by a derived class that may set
988      * the objectName, then it should call this implementation with
989      * the new objectName.
990      * @param server 
991      * @param oName 
992      * @return The ObjectName to use.
993      */
994     public synchronized ObjectName preRegister(MBeanServer server, ObjectName oName)
995     {
996         _mBeanServer=server;
997         _objectName=oName;
998         if (_objectName==null)
999         {
1000            try{oName=newObjectName(server);}
1001            catch(Exception e){log.warn(LogSupport.EXCEPTION,e);}
1002        }
1003        if(log.isDebugEnabled())log.debug("preRegister "+_objectName+" -> "+oName);
1004        _objectName=oName;
1005
1006        return _objectName;
1007    }
1008    
1009
1010    /* ------------------------------------------------------------ */
1011    public void postRegister(Boolean ok)
1012    {
1013        if (ok.booleanValue())
1014            log.info("Registered "+_objectName);
1015        else
1016        {
1017            _mBeanServer=null;
1018            _objectName=null;
1019        }
1020    }
1021
1022    /* ------------------------------------------------------------ */
1023    public void preDeregister()
1024    {
1025        log.info("Deregister "+_objectName);
1026        getComponentMBeans(null,_components);
1027        _components.clear();
1028    }
1029    
1030    /* ------------------------------------------------------------ */
1031    /** Post Deregister.
1032     * This implementation destroys this MBean and it cannot be used again.
1033     */
1034    public void postDeregister()
1035    {
1036        _beanInfo=null;
1037        _mBeanServer=null;
1038        _object=null;
1039        _objectName=null;
1040        if (_getter!=null)
1041            _getter.clear();
1042        _getter=null;
1043        if (_setter!=null)
1044            _setter.clear();
1045        _setter=null;
1046        if (_method!=null)
1047            _method.clear();
1048        _method=null;
1049        if (_attributes!=null)
1050            _attributes.clear();
1051        _attributes=null;
1052        if (_operations!=null)
1053            _operations.clear();
1054        _operations=null;
1055        if (_notifications!=null)
1056            _notifications.clear();
1057        _notifications=null;
1058    }
1059
1060    /* ------------------------------------------------------------ */
1061    /** Add an id clause to a JMX object name.
1062     * Used to make unique objectnames when there are no other
1063     * distinguishing attributes.
1064     * If the passed object name ends with '=', just a unique ID is
1065     * added.  Otherwise and classname= clause is added.
1066     * @param objectName 
1067     * @return objectName with id= class.
1068     */
1069    public synchronized ObjectName uniqueObjectName(MBeanServer server,
1070                                                    String objectName)
1071    {
1072        return uniqueObjectName(server,_object,objectName);
1073    }
1074    
1075    /* ------------------------------------------------------------ */
1076    public synchronized ObjectName uniqueObjectName(MBeanServer server,
1077                                                    Object object,
1078                                                    String objectName)
1079    {
1080        if (!objectName.endsWith("="))
1081        {
1082            String className = object.getClass().getName();
1083            if (className.indexOf(".")>0)
1084                className=className.substring(className.lastIndexOf(".")+1);
1085            if (className.endsWith("MBean"))
1086                className=className.substring(0,className.length()-5);
1087            if (!objectName.endsWith(":"))
1088                objectName+=",";
1089            objectName+=className+"=";
1090        }
1091
1092        ObjectName oName=null;
1093        try
1094        {
1095            while(true)
1096            {
1097                Integer id=(Integer)__objectId.get(objectName);
1098                if (id==null)
1099                    id=new Integer(0);
1100                oName=new ObjectName(objectName+id);
1101                id=new Integer(id.intValue()+1);
1102                __objectId.put(objectName,id);
1103                
1104                // If no server, this must be unique
1105                if (server==null)
1106                    break;
1107                
1108                // Otherwise let's check it is unique
1109                // if not found then it is unique
1110                if (!server.isRegistered(oName))
1111                    break;
1112            }
1113        }
1114        catch(Exception e)
1115        {
1116            log.warn(LogSupport.EXCEPTION,e);
1117        }
1118
1119        return oName;
1120    }
1121
1122
1123    /* ------------------------------------------------------------ */
1124    /** Get Component MBeans.
1125     * Creates, registers and deregisters MBeans for an array of components.
1126     * On each call the passed map is used to determine components that have
1127     * already been registers and those that need to be deregistered.
1128     * @param components the components.
1129     * @param map A map of previously registered components to object
1130     * name. If null is passed, a default map for the mbean is used.
1131     * @return An array of ObjectNames for each component. 
1132     */
1133    protected ObjectName[] getComponentMBeans(Object[] components, Map map)
1134    {
1135        if (map==null)
1136            map=_components;
1137        ObjectName[] beans=null;   
1138        if (components==null)
1139            beans = new ObjectName[0];
1140        else
1141        {
1142            beans = new ObjectName[components==null?0:components.length];
1143
1144            // Add new beans
1145            for (int i=0;i<components.length;i++)
1146            {
1147                ObjectName on = (ObjectName)map.get(components[i]);
1148                if (on==null)
1149                {
1150                    ModelMBean mbean = mbeanFor(components[i]);
1151                    if (mbean==null)
1152                        log.warn("No mbean for "+components[i]);
1153                    else
1154                    {
1155                        try
1156                        {
1157                            if (mbean instanceof ModelMBeanImpl)
1158                            {
1159                                ((ModelMBeanImpl)mbean).setBaseObjectName(getObjectName().toString());
1160                                on=getMBeanServer().registerMBean(mbean,null).getObjectName();
1161                            }
1162                            else
1163                            {
1164                                on=uniqueObjectName(getMBeanServer(),
1165                                                    components[i],
1166                                                    getObjectName().toString());
1167                                on=getMBeanServer().registerMBean(mbean,on).getObjectName();
1168                            }
1169                            map.put(components[i],on);
1170                        }
1171                        catch (Exception e)
1172                        {
1173                            log.warn(LogSupport.EXCEPTION,e);
1174                        }
1175                    }
1176                }
1177                beans[i]=on;
1178            }
1179        }
1180        
1181        // Delete old beans
1182        if (components==null || map.size()>components.length)
1183        {
1184            Object[] to_delete=new Object[map.size()-beans.length];
1185            int d=0;
1186            Iterator iter = map.keySet().iterator();
1187            keys:
1188            while(iter.hasNext())
1189            {
1190                Object bean = iter.next();
1191                if (components!=null)
1192                {
1193                    for(int i=0;i<components.length;i++)
1194                        if (components[i]==bean)
1195                            continue keys;
1196                }
1197                to_delete[d++]=bean;
1198            }
1199
1200            for (;d-->0;)
1201            {
1202                try{getMBeanServer().unregisterMBean((ObjectName)map.remove(to_delete[d]));}
1203                catch (Exception e) {log.warn(LogSupport.EXCEPTION,e);}
1204            }
1205        }
1206        
1207        return beans;
1208    }
1209}