OSDN Git Service

0434a40b8cc3169a0ffe73c5230da62e3348ff62
[pf3gnuchains/gcc-fork.git] / libjava / classpath / javax / management / StandardMBean.java
1 /* StandardMBean.java -- A standard reflection-based management bean.
2    Copyright (C) 2006 Free Software Foundation, Inc.
3
4 This file is part of GNU Classpath.
5
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING.  If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
20
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library.  Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
25
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module.  An independent module is a module which is not derived from
33 or based on this library.  If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so.  If you do not wish to do so, delete this
36 exception statement from your version. */
37
38 package javax.management;
39
40 import java.lang.reflect.Constructor;
41 import java.lang.reflect.InvocationTargetException;
42 import java.lang.reflect.Method;
43
44 import java.util.ArrayList;
45 import java.util.HashMap;
46 import java.util.Iterator;
47 import java.util.List;
48 import java.util.Map;
49
50 /**
51  * Provides a dynamic management bean by using reflection on an
52  * interface and an implementing class.  By default, a bean instance
53  * is paired up with its interface based on specific naming
54  * conventions (if the implementation is called X, the interface must
55  * be XMBean).  Using this class removes the need to use a specific
56  * naming system to match up the two.  Instead, an instance of this
57  * bean is created either via explicit construction or subclassing,
58  * and this provides access to the attributes, constructors and
59  * operations of the implementation via reflection.  Various hooks are
60  * provided in order to allow customization of this process.
61  *
62  * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
63  * @since 1.5
64  */
65 public class StandardMBean
66   implements DynamicMBean
67 {
68
69   /**
70    * The interface for this bean.
71    */
72   private Class iface;
73
74   /**
75    * The implementation of the interface.
76    */
77   private Object impl;
78
79   /**
80    * Cached bean information.
81    */
82   private MBeanInfo info;
83
84   /**
85    * Constructs a new {@link StandardMBean} using the specified
86    * interface and <code>this</code> as the instance.  This should
87    * be used to create an instance via subclassing.
88    * 
89    * @param iface the interface this bean implements, or <code>null</code>
90    *              if the interface should be determined using the naming
91    *              convention (class X has interface XMBean).
92    * @throws NotCompliantMBeanException if this class doesn't implement
93    *                                    the interface or a method appears
94    *                                    in the interface that doesn't comply
95    *                                    with the naming conventions.
96    */
97   protected StandardMBean(Class iface)
98     throws NotCompliantMBeanException
99   {
100     if (iface == null)
101       {
102         String className = getClass().getName();
103         try
104           {
105             iface = Class.forName(className + "MBean");
106           }
107         catch (ClassNotFoundException e)
108           {
109             throw (NotCompliantMBeanException) 
110               (new NotCompliantMBeanException("An interface, " + className +
111                                               "MBean, for the class " + className +
112                                               " was not found.").initCause(e));
113           }
114       }
115     if (!(iface.isInstance(this)))
116       throw new NotCompliantMBeanException("The instance, " + impl + 
117                                            ", is not an instance of " + iface);
118     impl = this;
119     this.iface = iface;
120   }
121
122   /**
123    * Constructs a new {@link StandardMBean} using the specified
124    * interface and the supplied instance as the implementation.
125    * 
126    * @param impl the implementation.
127    * @param iface the interface the bean implements, or <code>null</code>
128    *              if the interface should be determined using the naming
129    *              convention (class X has interface XMBean).
130    * @throws IllegalArgumentException if <code>impl</code> is <code>null</code>.
131    * @throws NotCompliantMBeanException if <code>impl</code> doesn't implement
132    *                                    the interface or a method appears
133    *                                    in the interface that doesn't comply
134    *                                    with the naming conventions.
135    */
136   public StandardMBean(Object impl, Class iface)
137     throws NotCompliantMBeanException
138   {
139     if (impl == null)
140       throw new IllegalArgumentException("The specified implementation is null.");
141     if (iface == null)
142       {
143         String className = impl.getClass().getName();
144         try
145           {
146             iface = Class.forName(className + "MBean", true,
147                                   impl.getClass().getClassLoader());
148           }
149         catch (ClassNotFoundException e)
150           {
151             throw (NotCompliantMBeanException) 
152               (new NotCompliantMBeanException("An interface, " + className +
153                                               "MBean, for the class " + className +
154                                               " was not found.").initCause(e));
155           }
156       }
157     if (!(iface.isInstance(impl)))
158       throw new NotCompliantMBeanException("The instance, " + impl + 
159                                            ", is not an instance of " + iface);
160     this.impl = impl;
161     this.iface = iface;
162   }
163
164   /**
165    * Caches the {@link MBeanInfo} instance for this object.  This is a
166    * customization hook, so that subclasses can choose the caching policy
167    * used.  The default implementation caches the value in the instance
168    * itself.  Subclasses may override this so as to not cache the data
169    * at all, or so as to use a cache shared between multiple beans.
170    *
171    * @param info the {@link MBeanInfo} instance to cache, or <code>null</code>
172    *             if there is no new value to cache.  When the value is not
173    *             <code>null</code>, the cache should replace the current value
174    *             with the value supplied here.
175    * @see #getCachedMBeanInfo()
176    */
177   protected void cacheMBeanInfo(MBeanInfo info)
178   {
179     if (info != null)
180       this.info = info;
181   }
182
183   /**
184    * Obtains the value of the specified attribute of the
185    * management bean.  The management bean should perform
186    * a lookup for the named attribute, and return its value
187    * by calling the appropriate getter method, if possible.
188    *
189    * @param name the name of the attribute to retrieve.
190    * @return the value of the specified attribute.
191    * @throws AttributeNotFoundException if the name does not
192    *                                    correspond to an attribute
193    *                                    of the bean.
194    * @throws MBeanException if retrieving the attribute causes
195    *                        the bean to throw an exception (which
196    *                        becomes the cause of this exception).
197    * @throws ReflectionException if an exception occurred in trying
198    *                             to use the reflection interface
199    *                             to lookup the attribute.  The
200    *                             thrown exception is the cause of
201    *                             this exception.
202    * @see #setAttribute(String)
203    */
204   public Object getAttribute(String name)
205     throws AttributeNotFoundException, MBeanException,
206            ReflectionException
207   {
208     Method getter;
209     try 
210       {
211         getter = iface.getMethod("get" + name, null);
212       }
213     catch (NoSuchMethodException e)
214       {
215         try 
216           {
217             getter = iface.getMethod("is" + name, null);
218           }
219         catch (NoSuchMethodException ex)
220           {
221             throw ((AttributeNotFoundException) 
222                    new AttributeNotFoundException("The attribute, " + name +
223                                                   ", was not found.").initCause(ex));
224           }
225       }
226     Object result;
227     try
228       {
229         result = getter.invoke(impl, null);
230       }
231     catch (IllegalAccessException e)
232       {
233         throw new ReflectionException(e, "Failed to retrieve " + name);
234       }
235     catch (IllegalArgumentException e)
236       {
237         throw new ReflectionException(e, "Failed to retrieve " + name);
238       }
239     catch (InvocationTargetException e)
240       {
241         throw new MBeanException((Exception) e.getCause(),
242                                  "The getter of " + name +
243                                  " threw an exception");
244       }
245     return result;
246   }
247
248   /**
249    * Obtains the values of each of the specified attributes
250    * of the management bean.  The returned list includes
251    * those attributes that were retrieved and their
252    * corresponding values.
253    *
254    * @param names the names of the attributes to retrieve.
255    * @return a list of the retrieved attributes.
256    * @see #setAttributes(AttributeList)
257    */
258   public AttributeList getAttributes(String[] names)
259   {
260     AttributeList list = new AttributeList(names.length);
261     for (int a = 0; a < names.length; ++a)
262       {
263         try
264           {
265             Object value = getAttribute(names[a]);
266             list.add(new Attribute(names[a], value));
267           }
268         catch (AttributeNotFoundException e)
269           {
270             /* Ignored */
271           }
272         catch (ReflectionException e)
273           {
274             /* Ignored */
275           }
276         catch (MBeanException e)
277           {
278             /* Ignored */
279           }
280       }
281     return list;
282   }
283
284   /**
285    * Returns the cached {@link MBeanInfo} instance for this object.  This is a
286    * customization hook, so that subclasses can choose the caching policy
287    * used.  The default implementation caches the value in the instance
288    * itself, and returns this value on calls to this method.
289    *
290    * @return the cached {@link MBeanInfo} instance, or <code>null</code>
291    *         if no value is cached.
292    * @see #cacheMBeanInfo(javax.management.MBeanInfo)
293    */
294   protected MBeanInfo getCachedMBeanInfo()
295   {
296     return info;
297   }
298
299   /**
300    * Returns the class name that will be used in the {@link MBeanInfo}
301    * instance.  This is a customization hook, so that subclasses can
302    * provide a custom class name.  By default, this returns the class
303    * name from the supplied {@link MBeanInfo} instance.
304    *
305    * @param info the {@link MBeanInfo} instance constructed via
306    *             reflection.
307    * @return the class name to use in the instance.
308    */
309   protected String getClassName(MBeanInfo info)
310   {
311     return info.getClassName();
312   }
313
314   /**
315    * Returns information on the constructors that will be used in
316    * the {@link MBeanInfo} instance.  This is a customization hook,
317    * so that subclasses can provide their own information on the
318    * bean's constructors, if necessary.  By default, this method
319    * returns <code>null</code> unless the implementation supplied
320    * is either <code>null</code> or <code>this</code>.  This default
321    * implementation prevents the use of
322    * {@link MBeanServer#createMBean} in cases where the bean is
323    * not created as a subclass of {@link StandardMBean}.
324    *
325    * @param constructors the constructor information created via
326    *                     reflection.
327    * @param impl the implementation, or <code>null</code> if this
328    *             should be ignored.
329    * @return the constructor information to use.
330    */
331   protected MBeanConstructorInfo[] getConstructors(MBeanConstructorInfo[]
332                                                    constructors, Object impl)
333   {
334     if (impl == null || impl == this)
335       return constructors;
336     return null;
337   }
338
339   /**
340    * Returns the description of the attribute that will be used in
341    * the supplied {@link MBeanAttributeInfo} instance.  This is a
342    * customization hook, so that subclasses can provide a custom
343    * description.  By default, this calls
344    * {@link #getDescription(MBeanFeatureInfo)} with the supplied
345    * {@link MBeanAttributeInfo} instance.
346    *
347    * @param info the {@link MBeanAttributeInfo} instance constructed
348    *             via reflection.
349    * @return the description to use in the instance.
350    */
351   protected String getDescription(MBeanAttributeInfo info)
352   {
353     return getDescription((MBeanFeatureInfo) info);
354   }
355
356   /**
357    * Returns the description of the constructor that will be used in
358    * the supplied {@link MBeanConstructorInfo} instance.  This is a
359    * customization hook, so that subclasses can provide a custom
360    * description.  By default, this calls
361    * {@link #getDescription(MBeanFeatureInfo)} with the supplied
362    * {@link MBeanConstructorInfo} instance.
363    *
364    * @param info the {@link MBeanConstructorInfo} instance constructed
365    *             via reflection.
366    * @return the description to use in the instance.
367    */
368   protected String getDescription(MBeanConstructorInfo info)
369   {
370     return getDescription((MBeanFeatureInfo) info);
371   }
372
373   /**
374    * Returns the description of the nth parameter of the constructor
375    * that will be used in the supplied {@link MBeanParameterInfo}
376    * instance.  This is a customization hook, so that subclasses
377    * can provide a custom description.  By default, this calls
378    * <code>param.getDescription()</code>.
379    *
380    * @param info the {@link MBeanConstructorInfo} instance constructed
381    *             via reflection.
382    * @param param the {@link MBeanParameterInfo} instance constructed
383    *             via reflection.
384    * @param n the number of the parameter, in order to link it to the
385    *          information on the constructor.
386    * @return the description to use in the instance.
387    */
388   protected String getDescription(MBeanConstructorInfo info,
389                                   MBeanParameterInfo param, int n)
390   {
391     return param.getDescription();
392   }
393
394   /**
395    * Returns the description of the supplied feature that
396    * will be used in the supplied {@link MBeanFeatureInfo}
397    * instance.  This is a customization hook, so that subclasses
398    * can provide a custom description.  By default, this calls
399    * <code>info.getDescription()</code>.  This method is also called
400    * by default for the more specific description methods for attributes,
401    * constructors and operations.
402    *
403    * @param info the {@link MBeanFeatureInfo} instance constructed
404    *             via reflection.
405    * @return the description to use in the instance.
406    */
407   protected String getDescription(MBeanFeatureInfo info)
408   {
409     return info.getDescription();
410   }
411
412   /**
413    * Returns the description of the bean that will be used in the
414    * supplied {@link MBeanInfo} instance.  This is a customization
415    * hook, so that subclasses can provide a custom description.  By
416    * default, this calls <code>info.getDescription()</code>.
417    *
418    * @param info the {@link MBeanInfo} instance constructed
419    *             via reflection.
420    * @return the description to use in the instance.
421    */
422   protected String getDescription(MBeanInfo info)
423   {
424     return info.getDescription();
425   }
426
427   /**
428    * Returns the description of the operation that will be used in
429    * the supplied {@link MBeanOperationInfo} instance.  This is a
430    * customization hook, so that subclasses can provide a custom
431    * description.  By default, this calls
432    * {@link #getDescription(MBeanFeatureInfo)} with the supplied
433    * {@link MBeanOperationInfo} instance.
434    *
435    * @param info the {@link MBeanOperationInfo} instance constructed
436    *             via reflection.
437    * @return the description to use in the instance.
438    */
439   protected String getDescription(MBeanOperationInfo info)
440   {
441     return getDescription((MBeanFeatureInfo) info);
442   }
443
444   /**
445    * Returns the description of the nth parameter of the operation
446    * that will be used in the supplied {@link MBeanParameterInfo}
447    * instance.  This is a customization hook, so that subclasses
448    * can provide a custom description.  By default, this calls
449    * <code>param.getDescription()</code>.
450    *
451    * @param info the {@link MBeanOperationInfo} instance constructed
452    *             via reflection.
453    * @param param the {@link MBeanParameterInfo} instance constructed
454    *             via reflection.
455    * @param n the number of the parameter, in order to link it to the
456    *          information on the operation.
457    * @return the description to use in the instance.
458    */
459   protected String getDescription(MBeanOperationInfo info,
460                                   MBeanParameterInfo param, int n)
461   {
462     return param.getDescription();
463   }
464
465   /**
466    * Returns the impact of the operation that will be used in the
467    * supplied {@link MBeanOperationInfo} instance.  This is a
468    * customization hook, so that subclasses can provide a custom
469    * impact flag.  By default, this returns
470    * <code>info.getImpact()</code>.
471    *
472    * @param info the {@link MBeanOperationInfo} instance constructed
473    *             via reflection.
474    * @return the impact flag to use in the instance.
475    */
476   protected int getImpact(MBeanOperationInfo info)
477   {
478     return info.getImpact();
479   }
480
481   /**
482    * Returns the instance that implements this bean.
483    *
484    * @return the implementation.
485    */
486   public Object getImplementation()
487   {
488     return impl;
489   }
490
491   /**
492    * Returns the class of the instance that implements this bean.
493    *
494    * @return the implementation class.
495    */
496   public Class getImplementationClass()
497   {
498     return impl.getClass();
499   }
500
501   /**
502    * <p>
503    * Returns an information object which lists the attributes
504    * and actions associated with the management bean.  This
505    * implementation proceeds as follows:
506    * </p>
507    * <ol>
508    * <li>{@link #getCachedMBeanInfo()} is called to obtain
509    * the cached instance.  If this returns a non-null value,
510    * this value is returned.</li>
511    * <li>If there is no cached value, then the method proceeds
512    * to create one. During this process, the customization hooks
513    * detailed in this class are called to allow the values used
514    * to be overrided:
515    * <ul>
516    * <li>For each attribute, 
517    * {@link #getDescription(MBeanAttributeInfo)} is called.</li>
518    * <li>For each constructor,
519    * {@link #getDescription(MBeanConstructorInfo)} is called,
520    * along with {@link #getDescription(MBeanConstructorInfo,
521    * MBeanParameterInfo, int)} and
522    * {@link #getParameterName(MBeanConstructorInfo,
523    * MBeanParameterInfo, int)} for each parameter.</li>
524    * <li>The constructors may be replaced as a whole by
525    * a call to
526    * {@link #getConstructors(MBeanConstructorInfo[], Object)}.</li>
527    * <li>For each operation,
528    * {@link #getDescription(MBeanOperationInfo)} and
529    * {@link #getImpact(MBeanOperationInfo)} are called,
530    * along with {@link #getDescription(MBeanOperationInfo,
531    * MBeanParameterInfo, int)} and
532    * {@link #getParameterName(MBeanOperationInfo,
533    * MBeanParameterInfo, int)} for each parameter.</li>
534    * <li>{@link #getClassName(MBeanInfo)} and
535    * {@link #getDescription(MBeanInfo)} are called to customise
536    * the basic information about the class.</li>
537    * </ul>
538    * </li>
539    * <li>Finally, {@link #cacheMBeanInfo(MBeanInfo)} is called
540    * with the created instance before it is returned.</li>
541    * </ol>
542    *
543    * @return a description of the management bean, including
544    *         all exposed attributes and actions.
545    */
546   public MBeanInfo getMBeanInfo()
547   {
548     MBeanInfo info = getCachedMBeanInfo();
549     if (info != null)
550       return info;
551     Method[] methods = iface.getMethods();
552     Map attributes = new HashMap();
553     List operations = new ArrayList();
554     for (int a = 0; a < methods.length; ++a)
555       {
556         String name = methods[a].getName();
557         if (((name.startsWith("get") &&
558               methods[a].getReturnType() != Void.TYPE) ||
559              (name.startsWith("is") &&
560               methods[a].getReturnType() == Boolean.TYPE)) &&
561             methods[a].getParameterTypes().length == 0)
562           {
563             Method[] amethods;
564             String attrib;
565             if (name.startsWith("is"))
566               attrib = name.substring(2);
567             else
568               attrib = name.substring(3);
569             if (attributes.containsKey(attrib))
570               amethods = (Method[]) attributes.get(attrib);
571             else
572               {
573                 amethods = new Method[2];
574                 attributes.put(attrib, amethods);
575               }
576             amethods[0] = methods[a];
577           }
578         else if (name.startsWith("set") &&
579                  methods[a].getReturnType() == Void.TYPE &&
580                  methods[a].getParameterTypes().length == 1)
581           {
582             Method[] amethods;
583             String attrib = name.substring(3);
584             if (attributes.containsKey(attrib))
585               amethods = (Method[]) attributes.get(attrib);
586             else
587               {
588                 amethods = new Method[2];
589                 attributes.put(attrib, amethods);
590               }
591             amethods[1] = methods[a];
592           }
593         else
594           operations.add(new MBeanOperationInfo(methods[a].getName(),
595                                                 methods[a]));
596       }
597     List attribs = new ArrayList(attributes.size());
598     Iterator it = attributes.entrySet().iterator();
599     while (it.hasNext())
600       {
601         Map.Entry entry = (Map.Entry) it.next();
602         Method[] amethods = (Method[]) entry.getValue();
603         try
604           {
605             attribs.add(new MBeanAttributeInfo((String) entry.getKey(),
606                                                (String) entry.getKey(),
607                                                amethods[0], amethods[1]));
608           }
609         catch (IntrospectionException e)
610           {
611             /* Shouldn't happen; both shouldn't be null */
612             throw new IllegalStateException("The two methods passed to " +
613                                             "the MBeanAttributeInfo " +
614                                             "constructor for " + entry +
615                                             "were null.", e);
616           }
617       }
618     MBeanAttributeInfo[] ainfo = new MBeanAttributeInfo[attribs.size()];
619     for (int a = 0; a < ainfo.length; ++a)
620       {
621         MBeanAttributeInfo oldInfo = (MBeanAttributeInfo) attribs.get(a);
622         String desc = getDescription(oldInfo);
623         ainfo[a] = new MBeanAttributeInfo(oldInfo.getName(),
624                                           oldInfo.getType(), desc,
625                                           oldInfo.isReadable(),
626                                           oldInfo.isWritable(),
627                                           oldInfo.isIs());
628       }
629     Constructor[] cons = impl.getClass().getConstructors();
630     MBeanConstructorInfo[] cinfo = new MBeanConstructorInfo[cons.length];
631     for (int a = 0; a < cinfo.length; ++a)
632       {
633         MBeanConstructorInfo oldInfo = new MBeanConstructorInfo(cons[a].getName(),
634                                                                 cons[a]);
635         String desc = getDescription(oldInfo);
636         MBeanParameterInfo[] params = oldInfo.getSignature();
637         MBeanParameterInfo[] pinfo = new MBeanParameterInfo[params.length];
638         for (int b = 0; b < pinfo.length; ++b)
639           {
640             String pdesc = getDescription(oldInfo, params[b], b);
641             String pname = getParameterName(oldInfo, params[b], b);
642             pinfo[b] = new MBeanParameterInfo(pname, params[b].getType(),
643                                               pdesc);
644           }
645         cinfo[a] = new MBeanConstructorInfo(oldInfo.getName(), desc,
646                                             pinfo);
647       }
648     cinfo = getConstructors(cinfo, impl);
649     MBeanOperationInfo[] oinfo = new MBeanOperationInfo[operations.size()];
650     for (int a = 0; a < oinfo.length; ++a)
651       {
652         MBeanOperationInfo oldInfo = (MBeanOperationInfo) operations.get(a);
653         String desc = getDescription(oldInfo);
654         int impact = getImpact(oldInfo);
655         MBeanParameterInfo[] params = oldInfo.getSignature();
656         MBeanParameterInfo[] pinfo = new MBeanParameterInfo[params.length];
657         for (int b = 0; b < pinfo.length; ++b)
658           {
659             String pdesc = getDescription(oldInfo, params[b], b);
660             String pname = getParameterName(oldInfo, params[b], b);
661             pinfo[b] = new MBeanParameterInfo(pname, params[b].getType(),
662                                               pdesc);
663           }
664         oinfo[a] = new MBeanOperationInfo(oldInfo.getName(), desc, pinfo,
665                                           oldInfo.getReturnType(), impact);
666       }
667     info = new MBeanInfo(impl.getClass().getName(), impl.getClass().getName(),
668                          ainfo, cinfo, oinfo, null);
669     String cname = getClassName(info);
670     String desc = getDescription(info);
671     MBeanNotificationInfo[] ninfo = null;
672     if (impl instanceof NotificationBroadcaster)
673       ninfo = ((NotificationBroadcaster) impl).getNotificationInfo();
674     info = new MBeanInfo(cname, desc, ainfo, cinfo, oinfo, ninfo);
675     cacheMBeanInfo(info);
676     return info;
677   }
678
679   /**
680    * Returns the interface for this management bean.
681    *
682    * @return the management interface.
683    */
684   public final Class getMBeanInterface()
685   {
686     return iface;
687   }
688
689   /**
690    * Returns the name of the nth parameter of the constructor
691    * that will be used in the supplied {@link MBeanParameterInfo}
692    * instance.  This is a customization hook, so that subclasses
693    * can provide a custom name.  By default, this calls
694    * <code>param.getName()</code>.
695    *
696    * @param info the {@link MBeanConstructorInfo} instance constructed
697    *             via reflection.
698    * @param param the {@link MBeanParameterInfo} instance constructed
699    *             via reflection.
700    * @param n the number of the parameter, in order to link it to the
701    *          information on the constructor.
702    * @return the name to use in the instance.
703    */
704   protected String getParameterName(MBeanConstructorInfo info,
705                                     MBeanParameterInfo param, int n)
706   {
707     return param.getName();
708   }
709
710   /**
711    * Returns the name of the nth parameter of the operation
712    * that will be used in the supplied {@link MBeanParameterInfo}
713    * instance.  This is a customization hook, so that subclasses
714    * can provide a custom name.  By default, this calls
715    * <code>param.getName()</code>.
716    *
717    * @param info the {@link MBeanOperationInfo} instance constructed
718    *             via reflection.
719    * @param param the {@link MBeanParameterInfo} instance constructed
720    *             via reflection.
721    * @param n the number of the parameter, in order to link it to the
722    *          information on the operation.
723    * @return the name to use in the instance.
724    */
725   protected String getParameterName(MBeanOperationInfo info,
726                                     MBeanParameterInfo param, int n)
727   {
728     return param.getName();
729   }
730
731   /**
732    * Invokes the specified action on the management bean using
733    * the supplied parameters.  The signature of the action is
734    * specified by a {@link String} array, which lists the classes
735    * corresponding to each parameter.  The class loader used to
736    * load these classes is the same as that used for loading the
737    * management bean itself.
738    * 
739    * @param name the name of the action to invoke.
740    * @param params the parameters used to call the action.
741    * @param signature the signature of the action.
742    * @return the return value of the action.
743    * @throws MBeanException if the action throws an exception.  The
744    *                        thrown exception is the cause of this
745    *                        exception.
746    * @throws ReflectionException if an exception occurred in trying
747    *                             to use the reflection interface
748    *                             to invoke the action.  The
749    *                             thrown exception is the cause of
750    *                             this exception.
751    */
752   public Object invoke(String name, Object[] params, String[] signature)
753     throws MBeanException, ReflectionException
754   {
755     Class[] sigTypes = new Class[signature.length];
756     ClassLoader loader = getClass().getClassLoader();
757     for (int a = 0; a < signature.length; ++a)
758       try 
759         {
760           sigTypes[a] = Class.forName(signature[a], true, loader);
761         }
762       catch (ClassNotFoundException e)
763         {
764           throw new ReflectionException(e, "The class, " + signature[a] + 
765                                         ", in the method signature " +
766                                         "could not be loaded.");
767         }
768     Method method;
769     try
770       {
771         method = iface.getMethod(name, sigTypes);
772       }
773     catch (NoSuchMethodException e)
774       {
775         throw new ReflectionException(e, "The method, " + name +
776                                       ", could not be found.");
777       }
778     Object result;
779     try
780       {
781         result = method.invoke(impl, params);
782       }
783     catch (IllegalAccessException e)
784       {
785         throw new ReflectionException(e, "Failed to call " + name);
786       }
787     catch (IllegalArgumentException e)
788       {
789         throw new ReflectionException(e, "Failed to call " + name);
790       }
791     catch (InvocationTargetException e)
792       {
793         throw new MBeanException((Exception) e.getCause(), "The method "
794                                  + name + " threw an exception");
795       }
796     return result;
797   }
798
799   /**
800    * Sets the value of the specified attribute of the
801    * management bean.  The management bean should perform
802    * a lookup for the named attribute, and sets its value
803    * using the associated setter method, if possible.
804    *
805    * @param attribute the attribute to set.
806    * @throws AttributeNotFoundException if the attribute does not
807    *                                    correspond to an attribute
808    *                                    of the bean.
809    * @throws InvalidAttributeValueException if the value is invalid
810    *                                        for this particular
811    *                                        attribute of the bean.
812    * @throws MBeanException if setting the attribute causes
813    *                        the bean to throw an exception (which
814    *                        becomes the cause of this exception).
815    * @throws ReflectionException if an exception occurred in trying
816    *                             to use the reflection interface
817    *                             to lookup the attribute.  The
818    *                             thrown exception is the cause of
819    *                             this exception.
820    * @see #getAttribute(String)
821    */
822   public void setAttribute(Attribute attribute)
823     throws AttributeNotFoundException, InvalidAttributeValueException,
824            MBeanException, ReflectionException
825   {
826     Method setter;
827     String name = attribute.getName();
828     try 
829       {
830         setter = iface.getMethod("set" +
831                                  name.substring(0, 1).toUpperCase() +
832                                  name.substring(1), null);
833       }
834     catch (NoSuchMethodException e)
835       {
836         throw ((AttributeNotFoundException) 
837                new AttributeNotFoundException("The attribute, " + name +
838                                               ", was not found.").initCause(e));
839       }
840     try
841       {
842         setter.invoke(impl, new Object[] { attribute.getValue() });
843       }
844     catch (IllegalAccessException e)
845       {
846         throw new ReflectionException(e, "Failed to set " + name);
847       }
848     catch (IllegalArgumentException e)
849       {
850         throw ((InvalidAttributeValueException)
851                new InvalidAttributeValueException(attribute.getValue() +
852                                                   " is an invalid value for " +
853                                                   name).initCause(e));
854       }
855     catch (InvocationTargetException e)
856       {
857         throw new MBeanException((Exception) e.getCause(), "The getter of "
858                                  + name + " threw an exception");
859       }
860   }
861
862   /**
863    * Sets the value of each of the specified attributes
864    * to that supplied by the {@link Attribute} object.
865    * The returned list contains the attributes that were
866    * set and their new values.
867    *
868    * @param attributes the attributes to set.
869    * @return a list of the changed attributes.
870    * @see #getAttributes(AttributeList)
871    */
872   public AttributeList setAttributes(AttributeList attributes)
873   {
874     AttributeList list = new AttributeList(attributes.size());
875     Iterator it = attributes.iterator();
876     while (it.hasNext())
877       {
878         try
879           {
880             Attribute attrib = (Attribute) it.next();
881             setAttribute(attrib);
882             list.add(attrib);
883           }
884         catch (AttributeNotFoundException e)
885           {
886             /* Ignored */
887           }
888         catch (InvalidAttributeValueException e)
889           {
890             /* Ignored */
891           }
892         catch (ReflectionException e)
893           {
894             /* Ignored */
895           }
896         catch (MBeanException e)
897           {
898             /* Ignored */
899           }
900       }
901     return list;
902   }
903
904   /**
905    * Replaces the implementation of the interface used by this
906    * instance with the one specified.  The new implementation
907    * must be non-null and implement the interface specified on
908    * construction of this instance.
909    *
910    * @throws IllegalArgumentException if <code>impl</code> is <code>null</code>.
911    * @throws NotCompliantMBeanException if <code>impl</code> doesn't implement
912    *                                    the interface or a method appears
913    *                                    in the interface that doesn't comply
914    *                                    with the naming conventions.
915    */
916   public void setImplementation(Object impl)
917     throws NotCompliantMBeanException
918   {
919     if (impl == null)
920       throw new IllegalArgumentException("The specified implementation is null.");
921     if (!(iface.isInstance(impl)))
922       throw new NotCompliantMBeanException("The instance, " + impl + 
923                                            ", is not an instance of " + iface);
924     this.impl = impl;
925   }
926
927 }