libjava/ChangeLog:
[official-gcc.git] / libjava / classpath / javax / management / StandardMBean.java
blob13e95bd396d0dd6f5691f5914a5ba5a710a359c8
1 /* StandardMBean.java -- A standard reflection-based management bean.
2 Copyright (C) 2006 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
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.
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.
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.
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.
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. */
38 package javax.management;
40 import java.lang.reflect.Constructor;
41 import java.lang.reflect.InvocationTargetException;
42 import java.lang.reflect.Method;
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;
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.
62 * @author Andrew John Hughes (gnu_andrew@member.fsf.org)
63 * @since 1.5
65 public class StandardMBean
66 implements DynamicMBean
69 /**
70 * The interface for this bean.
72 private Class<?> iface;
74 /**
75 * The implementation of the interface.
77 private Object impl;
79 /**
80 * Cached bean information.
82 private MBeanInfo info;
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.
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.
97 protected StandardMBean(Class<?> iface)
98 throws NotCompliantMBeanException
100 if (iface == null)
102 String className = getClass().getName();
105 iface = Class.forName(className + "MBean");
107 catch (ClassNotFoundException e)
109 for (Class<?> nextIface : getClass().getInterfaces())
111 if (JMX.isMXBeanInterface(nextIface))
113 iface = nextIface;
114 break;
117 if (iface == null)
118 throw (NotCompliantMBeanException)
119 (new NotCompliantMBeanException("An interface for the class "
120 + className +
121 " was not found.").initCause(e));
124 if (!(iface.isInstance(this)))
125 throw new NotCompliantMBeanException("The instance, " + impl +
126 ", is not an instance of " + iface);
127 impl = this;
128 this.iface = iface;
132 * Constructs a new {@link StandardMBean} using the specified
133 * interface and the supplied instance as the implementation.
135 * @param impl the implementation.
136 * @param iface the interface the bean implements, or <code>null</code>
137 * if the interface should be determined using the naming
138 * convention (class X has interface XMBean).
139 * @throws IllegalArgumentException if <code>impl</code> is <code>null</code>.
140 * @throws NotCompliantMBeanException if <code>impl</code> doesn't implement
141 * the interface or a method appears
142 * in the interface that doesn't comply
143 * with the naming conventions.
145 public <T> StandardMBean(T impl, Class<T> iface)
146 throws NotCompliantMBeanException
148 if (impl == null)
149 throw new IllegalArgumentException("The specified implementation is null.");
150 if (iface == null)
152 Class<?> implClass = impl.getClass();
153 String className = implClass.getName();
156 this.iface = Class.forName(className + "MBean", true,
157 implClass.getClassLoader());
159 catch (ClassNotFoundException e)
161 for (Class<?> nextIface : implClass.getInterfaces())
163 if (JMX.isMXBeanInterface(nextIface))
165 this.iface = nextIface;
166 break;
169 if (this.iface == null)
170 throw (NotCompliantMBeanException)
171 (new NotCompliantMBeanException("An interface for the class " +
172 className +
173 " was not found.").initCause(e));
176 else
177 this.iface = iface;
178 if (!(this.iface.isInstance(impl)))
179 throw new NotCompliantMBeanException("The instance, " + impl +
180 ", is not an instance of " + iface);
181 this.impl = impl;
185 * Caches the {@link MBeanInfo} instance for this object. This is a
186 * customization hook, so that subclasses can choose the caching policy
187 * used. The default implementation caches the value in the instance
188 * itself. Subclasses may override this so as to not cache the data
189 * at all, or so as to use a cache shared between multiple beans.
191 * @param info the {@link MBeanInfo} instance to cache, or <code>null</code>
192 * if there is no new value to cache. When the value is not
193 * <code>null</code>, the cache should replace the current value
194 * with the value supplied here.
195 * @see #getCachedMBeanInfo()
197 protected void cacheMBeanInfo(MBeanInfo info)
199 if (info != null)
200 this.info = info;
204 * Obtains the value of the specified attribute of the
205 * management bean. The management bean should perform
206 * a lookup for the named attribute, and return its value
207 * by calling the appropriate getter method, if possible.
209 * @param name the name of the attribute to retrieve.
210 * @return the value of the specified attribute.
211 * @throws AttributeNotFoundException if the name does not
212 * correspond to an attribute
213 * of the bean.
214 * @throws MBeanException if retrieving the attribute causes
215 * the bean to throw an exception (which
216 * becomes the cause of this exception).
217 * @throws ReflectionException if an exception occurred in trying
218 * to use the reflection interface
219 * to lookup the attribute. The
220 * thrown exception is the cause of
221 * this exception.
222 * @see #setAttribute(String)
224 public Object getAttribute(String name)
225 throws AttributeNotFoundException, MBeanException,
226 ReflectionException
228 Method getter;
229 try
231 getter = iface.getMethod("get" + name);
233 catch (NoSuchMethodException e)
235 try
237 getter = iface.getMethod("is" + name);
239 catch (NoSuchMethodException ex)
241 throw ((AttributeNotFoundException)
242 new AttributeNotFoundException("The attribute, " + name +
243 ", was not found.").initCause(ex));
246 Object result;
249 result = getter.invoke(impl);
251 catch (IllegalAccessException e)
253 throw new ReflectionException(e, "Failed to retrieve " + name);
255 catch (IllegalArgumentException e)
257 throw new ReflectionException(e, "Failed to retrieve " + name);
259 catch (InvocationTargetException e)
261 throw new MBeanException((Exception) e.getCause(),
262 "The getter of " + name +
263 " threw an exception");
265 return result;
269 * Obtains the values of each of the specified attributes
270 * of the management bean. The returned list includes
271 * those attributes that were retrieved and their
272 * corresponding values.
274 * @param names the names of the attributes to retrieve.
275 * @return a list of the retrieved attributes.
276 * @see #setAttributes(AttributeList)
278 public AttributeList getAttributes(String[] names)
280 AttributeList list = new AttributeList(names.length);
281 for (int a = 0; a < names.length; ++a)
285 Object value = getAttribute(names[a]);
286 list.add(new Attribute(names[a], value));
288 catch (AttributeNotFoundException e)
290 /* Ignored */
292 catch (ReflectionException e)
294 /* Ignored */
296 catch (MBeanException e)
298 /* Ignored */
301 return list;
305 * Returns the cached {@link MBeanInfo} instance for this object. This is a
306 * customization hook, so that subclasses can choose the caching policy
307 * used. The default implementation caches the value in the instance
308 * itself, and returns this value on calls to this method.
310 * @return the cached {@link MBeanInfo} instance, or <code>null</code>
311 * if no value is cached.
312 * @see #cacheMBeanInfo(javax.management.MBeanInfo)
314 protected MBeanInfo getCachedMBeanInfo()
316 return info;
320 * Returns the class name that will be used in the {@link MBeanInfo}
321 * instance. This is a customization hook, so that subclasses can
322 * provide a custom class name. By default, this returns the class
323 * name from the supplied {@link MBeanInfo} instance.
325 * @param info the {@link MBeanInfo} instance constructed via
326 * reflection.
327 * @return the class name to use in the instance.
329 protected String getClassName(MBeanInfo info)
331 return info.getClassName();
335 * Returns information on the constructors that will be used in
336 * the {@link MBeanInfo} instance. This is a customization hook,
337 * so that subclasses can provide their own information on the
338 * bean's constructors, if necessary. By default, this method
339 * returns <code>null</code> unless the implementation supplied
340 * is either <code>null</code> or <code>this</code>. This default
341 * implementation prevents the use of
342 * {@link MBeanServer#createMBean} in cases where the bean is
343 * not created as a subclass of {@link StandardMBean}.
345 * @param constructors the constructor information created via
346 * reflection.
347 * @param impl the implementation, or <code>null</code> if this
348 * should be ignored.
349 * @return the constructor information to use.
351 protected MBeanConstructorInfo[] getConstructors(MBeanConstructorInfo[]
352 constructors, Object impl)
354 if (impl == null || impl == this)
355 return constructors;
356 return null;
360 * Returns the description of the attribute that will be used in
361 * the supplied {@link MBeanAttributeInfo} instance. This is a
362 * customization hook, so that subclasses can provide a custom
363 * description. By default, this calls
364 * {@link #getDescription(MBeanFeatureInfo)} with the supplied
365 * {@link MBeanAttributeInfo} instance.
367 * @param info the {@link MBeanAttributeInfo} instance constructed
368 * via reflection.
369 * @return the description to use in the instance.
371 protected String getDescription(MBeanAttributeInfo info)
373 return getDescription((MBeanFeatureInfo) info);
377 * Returns the description of the constructor that will be used in
378 * the supplied {@link MBeanConstructorInfo} instance. This is a
379 * customization hook, so that subclasses can provide a custom
380 * description. By default, this calls
381 * {@link #getDescription(MBeanFeatureInfo)} with the supplied
382 * {@link MBeanConstructorInfo} instance.
384 * @param info the {@link MBeanConstructorInfo} instance constructed
385 * via reflection.
386 * @return the description to use in the instance.
388 protected String getDescription(MBeanConstructorInfo info)
390 return getDescription((MBeanFeatureInfo) info);
394 * Returns the description of the nth parameter of the constructor
395 * that will be used in the supplied {@link MBeanParameterInfo}
396 * instance. This is a customization hook, so that subclasses
397 * can provide a custom description. By default, this calls
398 * <code>param.getDescription()</code>.
400 * @param info the {@link MBeanConstructorInfo} instance constructed
401 * via reflection.
402 * @param param the {@link MBeanParameterInfo} instance constructed
403 * via reflection.
404 * @param n the number of the parameter, in order to link it to the
405 * information on the constructor.
406 * @return the description to use in the instance.
408 protected String getDescription(MBeanConstructorInfo info,
409 MBeanParameterInfo param, int n)
411 return param.getDescription();
415 * Returns the description of the supplied feature that
416 * will be used in the supplied {@link MBeanFeatureInfo}
417 * instance. This is a customization hook, so that subclasses
418 * can provide a custom description. By default, this calls
419 * <code>info.getDescription()</code>. This method is also called
420 * by default for the more specific description methods for attributes,
421 * constructors and operations.
423 * @param info the {@link MBeanFeatureInfo} instance constructed
424 * via reflection.
425 * @return the description to use in the instance.
427 protected String getDescription(MBeanFeatureInfo info)
429 return info.getDescription();
433 * Returns the description of the bean that will be used in the
434 * supplied {@link MBeanInfo} instance. This is a customization
435 * hook, so that subclasses can provide a custom description. By
436 * default, this calls <code>info.getDescription()</code>.
438 * @param info the {@link MBeanInfo} instance constructed
439 * via reflection.
440 * @return the description to use in the instance.
442 protected String getDescription(MBeanInfo info)
444 return info.getDescription();
448 * Returns the description of the operation that will be used in
449 * the supplied {@link MBeanOperationInfo} instance. This is a
450 * customization hook, so that subclasses can provide a custom
451 * description. By default, this calls
452 * {@link #getDescription(MBeanFeatureInfo)} with the supplied
453 * {@link MBeanOperationInfo} instance.
455 * @param info the {@link MBeanOperationInfo} instance constructed
456 * via reflection.
457 * @return the description to use in the instance.
459 protected String getDescription(MBeanOperationInfo info)
461 return getDescription((MBeanFeatureInfo) info);
465 * Returns the description of the nth parameter of the operation
466 * that will be used in the supplied {@link MBeanParameterInfo}
467 * instance. This is a customization hook, so that subclasses
468 * can provide a custom description. By default, this calls
469 * <code>param.getDescription()</code>.
471 * @param info the {@link MBeanOperationInfo} instance constructed
472 * via reflection.
473 * @param param the {@link MBeanParameterInfo} instance constructed
474 * via reflection.
475 * @param n the number of the parameter, in order to link it to the
476 * information on the operation.
477 * @return the description to use in the instance.
479 protected String getDescription(MBeanOperationInfo info,
480 MBeanParameterInfo param, int n)
482 return param.getDescription();
486 * Returns the impact of the operation that will be used in the
487 * supplied {@link MBeanOperationInfo} instance. This is a
488 * customization hook, so that subclasses can provide a custom
489 * impact flag. By default, this returns
490 * <code>info.getImpact()</code>.
492 * @param info the {@link MBeanOperationInfo} instance constructed
493 * via reflection.
494 * @return the impact flag to use in the instance.
496 protected int getImpact(MBeanOperationInfo info)
498 return info.getImpact();
502 * Returns the instance that implements this bean.
504 * @return the implementation.
506 public Object getImplementation()
508 return impl;
512 * Returns the class of the instance that implements this bean.
514 * @return the implementation class.
516 public Class<?> getImplementationClass()
518 return impl.getClass();
522 * <p>
523 * Returns an information object which lists the attributes
524 * and actions associated with the management bean. This
525 * implementation proceeds as follows:
526 * </p>
527 * <ol>
528 * <li>{@link #getCachedMBeanInfo()} is called to obtain
529 * the cached instance. If this returns a non-null value,
530 * this value is returned.</li>
531 * <li>If there is no cached value, then the method proceeds
532 * to create one. During this process, the customization hooks
533 * detailed in this class are called to allow the values used
534 * to be overrided:
535 * <ul>
536 * <li>For each attribute,
537 * {@link #getDescription(MBeanAttributeInfo)} is called.</li>
538 * <li>For each constructor,
539 * {@link #getDescription(MBeanConstructorInfo)} is called,
540 * along with {@link #getDescription(MBeanConstructorInfo,
541 * MBeanParameterInfo, int)} and
542 * {@link #getParameterName(MBeanConstructorInfo,
543 * MBeanParameterInfo, int)} for each parameter.</li>
544 * <li>The constructors may be replaced as a whole by
545 * a call to
546 * {@link #getConstructors(MBeanConstructorInfo[], Object)}.</li>
547 * <li>For each operation,
548 * {@link #getDescription(MBeanOperationInfo)} and
549 * {@link #getImpact(MBeanOperationInfo)} are called,
550 * along with {@link #getDescription(MBeanOperationInfo,
551 * MBeanParameterInfo, int)} and
552 * {@link #getParameterName(MBeanOperationInfo,
553 * MBeanParameterInfo, int)} for each parameter.</li>
554 * <li>{@link #getClassName(MBeanInfo)} and
555 * {@link #getDescription(MBeanInfo)} are called to customise
556 * the basic information about the class.</li>
557 * </ul>
558 * </li>
559 * <li>Finally, {@link #cacheMBeanInfo(MBeanInfo)} is called
560 * with the created instance before it is returned.</li>
561 * </ol>
563 * @return a description of the management bean, including
564 * all exposed attributes and actions.
566 public MBeanInfo getMBeanInfo()
568 MBeanInfo info = getCachedMBeanInfo();
569 if (info != null)
570 return info;
571 Method[] methods = iface.getMethods();
572 Map<String,Method[]> attributes = new HashMap<String,Method[]>();
573 List<MBeanOperationInfo> operations = new ArrayList<MBeanOperationInfo>();
574 for (int a = 0; a < methods.length; ++a)
576 String name = methods[a].getName();
577 if (((name.startsWith("get") &&
578 methods[a].getReturnType() != Void.TYPE) ||
579 (name.startsWith("is") &&
580 methods[a].getReturnType() == Boolean.TYPE)) &&
581 methods[a].getParameterTypes().length == 0)
583 Method[] amethods;
584 String attrib;
585 if (name.startsWith("is"))
586 attrib = name.substring(2);
587 else
588 attrib = name.substring(3);
589 if (attributes.containsKey(attrib))
590 amethods = (Method[]) attributes.get(attrib);
591 else
593 amethods = new Method[2];
594 attributes.put(attrib, amethods);
596 amethods[0] = methods[a];
598 else if (name.startsWith("set") &&
599 methods[a].getReturnType() == Void.TYPE &&
600 methods[a].getParameterTypes().length == 1)
602 Method[] amethods;
603 String attrib = name.substring(3);
604 if (attributes.containsKey(attrib))
605 amethods = (Method[]) attributes.get(attrib);
606 else
608 amethods = new Method[2];
609 attributes.put(attrib, amethods);
611 amethods[1] = methods[a];
613 else
614 operations.add(new MBeanOperationInfo(methods[a].getName(),
615 methods[a]));
617 List<MBeanAttributeInfo> attribs = new ArrayList<MBeanAttributeInfo>(attributes.size());
618 for (Map.Entry<String,Method[]> entry : attributes.entrySet())
620 Method[] amethods = entry.getValue();
623 attribs.add(new MBeanAttributeInfo(entry.getKey(),
624 entry.getKey(),
625 amethods[0], amethods[1]));
627 catch (IntrospectionException e)
629 /* Shouldn't happen; both shouldn't be null */
630 throw new IllegalStateException("The two methods passed to " +
631 "the MBeanAttributeInfo " +
632 "constructor for " + entry +
633 "were null.", e);
636 MBeanAttributeInfo[] ainfo = new MBeanAttributeInfo[attribs.size()];
637 for (int a = 0; a < ainfo.length; ++a)
639 MBeanAttributeInfo oldInfo = (MBeanAttributeInfo) attribs.get(a);
640 String desc = getDescription(oldInfo);
641 ainfo[a] = new MBeanAttributeInfo(oldInfo.getName(),
642 oldInfo.getType(), desc,
643 oldInfo.isReadable(),
644 oldInfo.isWritable(),
645 oldInfo.isIs());
647 Constructor<?>[] cons = impl.getClass().getConstructors();
648 MBeanConstructorInfo[] cinfo = new MBeanConstructorInfo[cons.length];
649 for (int a = 0; a < cinfo.length; ++a)
651 MBeanConstructorInfo oldInfo = new MBeanConstructorInfo(cons[a].getName(),
652 cons[a]);
653 String desc = getDescription(oldInfo);
654 MBeanParameterInfo[] params = oldInfo.getSignature();
655 MBeanParameterInfo[] pinfo = new MBeanParameterInfo[params.length];
656 for (int b = 0; b < pinfo.length; ++b)
658 String pdesc = getDescription(oldInfo, params[b], b);
659 String pname = getParameterName(oldInfo, params[b], b);
660 pinfo[b] = new MBeanParameterInfo(pname, params[b].getType(),
661 pdesc);
663 cinfo[a] = new MBeanConstructorInfo(oldInfo.getName(), desc,
664 pinfo);
666 cinfo = getConstructors(cinfo, impl);
667 MBeanOperationInfo[] oinfo = new MBeanOperationInfo[operations.size()];
668 for (int a = 0; a < oinfo.length; ++a)
670 MBeanOperationInfo oldInfo = (MBeanOperationInfo) operations.get(a);
671 String desc = getDescription(oldInfo);
672 int impact = getImpact(oldInfo);
673 MBeanParameterInfo[] params = oldInfo.getSignature();
674 MBeanParameterInfo[] pinfo = new MBeanParameterInfo[params.length];
675 for (int b = 0; b < pinfo.length; ++b)
677 String pdesc = getDescription(oldInfo, params[b], b);
678 String pname = getParameterName(oldInfo, params[b], b);
679 pinfo[b] = new MBeanParameterInfo(pname, params[b].getType(),
680 pdesc);
682 oinfo[a] = new MBeanOperationInfo(oldInfo.getName(), desc, pinfo,
683 oldInfo.getReturnType(), impact);
685 info = new MBeanInfo(impl.getClass().getName(), impl.getClass().getName(),
686 ainfo, cinfo, oinfo, null);
687 String cname = getClassName(info);
688 String desc = getDescription(info);
689 MBeanNotificationInfo[] ninfo = null;
690 if (impl instanceof NotificationBroadcaster)
691 ninfo = ((NotificationBroadcaster) impl).getNotificationInfo();
692 info = new MBeanInfo(cname, desc, ainfo, cinfo, oinfo, ninfo);
693 cacheMBeanInfo(info);
694 return info;
698 * Returns the interface for this management bean.
700 * @return the management interface.
702 public final Class<?> getMBeanInterface()
704 return iface;
708 * Returns the name of the nth parameter of the constructor
709 * that will be used in the supplied {@link MBeanParameterInfo}
710 * instance. This is a customization hook, so that subclasses
711 * can provide a custom name. By default, this calls
712 * <code>param.getName()</code>.
714 * @param info the {@link MBeanConstructorInfo} instance constructed
715 * via reflection.
716 * @param param the {@link MBeanParameterInfo} instance constructed
717 * via reflection.
718 * @param n the number of the parameter, in order to link it to the
719 * information on the constructor.
720 * @return the name to use in the instance.
722 protected String getParameterName(MBeanConstructorInfo info,
723 MBeanParameterInfo param, int n)
725 return param.getName();
729 * Returns the name of the nth parameter of the operation
730 * that will be used in the supplied {@link MBeanParameterInfo}
731 * instance. This is a customization hook, so that subclasses
732 * can provide a custom name. By default, this calls
733 * <code>param.getName()</code>.
735 * @param info the {@link MBeanOperationInfo} instance constructed
736 * via reflection.
737 * @param param the {@link MBeanParameterInfo} instance constructed
738 * via reflection.
739 * @param n the number of the parameter, in order to link it to the
740 * information on the operation.
741 * @return the name to use in the instance.
743 protected String getParameterName(MBeanOperationInfo info,
744 MBeanParameterInfo param, int n)
746 return param.getName();
750 * Invokes the specified action on the management bean using
751 * the supplied parameters. The signature of the action is
752 * specified by a {@link String} array, which lists the classes
753 * corresponding to each parameter. The class loader used to
754 * load these classes is the same as that used for loading the
755 * management bean itself.
757 * @param name the name of the action to invoke.
758 * @param params the parameters used to call the action.
759 * @param signature the signature of the action.
760 * @return the return value of the action.
761 * @throws MBeanException if the action throws an exception. The
762 * thrown exception is the cause of this
763 * exception.
764 * @throws ReflectionException if an exception occurred in trying
765 * to use the reflection interface
766 * to invoke the action. The
767 * thrown exception is the cause of
768 * this exception.
770 public Object invoke(String name, Object[] params, String[] signature)
771 throws MBeanException, ReflectionException
773 if (name.startsWith("get") || name.startsWith("is") ||
774 name.startsWith("set"))
775 throw new ReflectionException(new NoSuchMethodException(),
776 "Invocation of an attribute " +
777 "method is disallowed.");
778 ClassLoader loader = getClass().getClassLoader();
779 Class<?>[] sigTypes;
780 if (signature != null)
782 sigTypes = new Class<?>[signature.length];
783 for (int a = 0; a < signature.length; ++a)
784 try
786 sigTypes[a] = Class.forName(signature[a], true, loader);
788 catch (ClassNotFoundException e)
790 throw new ReflectionException(e, "The class, " + signature[a] +
791 ", in the method signature " +
792 "could not be loaded.");
795 else
796 sigTypes = null;
797 Method method;
800 method = iface.getMethod(name, sigTypes);
802 catch (NoSuchMethodException e)
804 throw new ReflectionException(e, "The method, " + name +
805 ", could not be found.");
807 Object result;
810 result = method.invoke(impl, params);
812 catch (IllegalAccessException e)
814 throw new ReflectionException(e, "Failed to call " + name);
816 catch (IllegalArgumentException e)
818 throw new ReflectionException(e, "Failed to call " + name);
820 catch (InvocationTargetException e)
822 throw new MBeanException((Exception) e.getCause(), "The method "
823 + name + " threw an exception");
825 return result;
829 * Sets the value of the specified attribute of the
830 * management bean. The management bean should perform
831 * a lookup for the named attribute, and sets its value
832 * using the associated setter method, if possible.
834 * @param attribute the attribute to set.
835 * @throws AttributeNotFoundException if the attribute does not
836 * correspond to an attribute
837 * of the bean.
838 * @throws InvalidAttributeValueException if the value is invalid
839 * for this particular
840 * attribute of the bean.
841 * @throws MBeanException if setting the attribute causes
842 * the bean to throw an exception (which
843 * becomes the cause of this exception).
844 * @throws ReflectionException if an exception occurred in trying
845 * to use the reflection interface
846 * to lookup the attribute. The
847 * thrown exception is the cause of
848 * this exception.
849 * @see #getAttribute(String)
851 public void setAttribute(Attribute attribute)
852 throws AttributeNotFoundException, InvalidAttributeValueException,
853 MBeanException, ReflectionException
855 String name = attribute.getName();
856 String attName = name.substring(0, 1).toUpperCase() + name.substring(1);
857 Object val = attribute.getValue();
860 getMutator(attName, val.getClass()).invoke(impl, new Object[] { val });
862 catch (IllegalAccessException e)
864 throw new ReflectionException(e, "Failed to set " + name);
866 catch (IllegalArgumentException e)
868 throw ((InvalidAttributeValueException)
869 new InvalidAttributeValueException(attribute.getValue() +
870 " is an invalid value for " +
871 name).initCause(e));
873 catch (InvocationTargetException e)
875 throw new MBeanException(e, "The getter of " + name +
876 " threw an exception");
881 * Sets the value of each of the specified attributes
882 * to that supplied by the {@link Attribute} object.
883 * The returned list contains the attributes that were
884 * set and their new values.
886 * @param attributes the attributes to set.
887 * @return a list of the changed attributes.
888 * @see #getAttributes(AttributeList)
890 public AttributeList setAttributes(AttributeList attributes)
892 AttributeList list = new AttributeList(attributes.size());
893 Iterator<Object> it = attributes.iterator();
894 while (it.hasNext())
898 Attribute attrib = (Attribute) it.next();
899 setAttribute(attrib);
900 list.add(attrib);
902 catch (AttributeNotFoundException e)
904 /* Ignored */
906 catch (InvalidAttributeValueException e)
908 /* Ignored */
910 catch (ReflectionException e)
912 /* Ignored */
914 catch (MBeanException e)
916 /* Ignored */
919 return list;
923 * Replaces the implementation of the interface used by this
924 * instance with the one specified. The new implementation
925 * must be non-null and implement the interface specified on
926 * construction of this instance.
928 * @throws IllegalArgumentException if <code>impl</code> is <code>null</code>.
929 * @throws NotCompliantMBeanException if <code>impl</code> doesn't implement
930 * the interface or a method appears
931 * in the interface that doesn't comply
932 * with the naming conventions.
934 public void setImplementation(Object impl)
935 throws NotCompliantMBeanException
937 if (impl == null)
938 throw new IllegalArgumentException("The specified implementation is null.");
939 if (!(iface.isInstance(impl)))
940 throw new NotCompliantMBeanException("The instance, " + impl +
941 ", is not an instance of " + iface);
942 this.impl = impl;
946 * Returns the mutator method for a particular attribute name
947 * with a parameter type matching that of the given value.
949 * @param name the name of the attribute.
950 * @param type the type of the parameter.
951 * @return the appropriate mutator method.
952 * @throws AttributeNotFoundException if a method can't be found.
954 private Method getMutator(String name, Class<?> type)
955 throws AttributeNotFoundException
957 String mutator = "set" + name;
958 Exception ex = null;
959 try
961 return iface.getMethod(mutator, type);
963 catch (NoSuchMethodException e)
965 /* Ignored; we'll try harder instead */
966 ex = e;
968 /* Special cases */
969 if (type == Boolean.class)
972 return iface.getMethod(mutator, Boolean.TYPE);
974 catch (NoSuchMethodException e)
976 throw ((AttributeNotFoundException)
977 new AttributeNotFoundException("The attribute, " + name +
978 ", was not found.").initCause(e));
980 if (type == Byte.class)
983 return iface.getMethod(mutator, Byte.TYPE);
985 catch (NoSuchMethodException e)
987 throw ((AttributeNotFoundException)
988 new AttributeNotFoundException("The attribute, " + name +
989 ", was not found.").initCause(e));
991 if (type == Character.class)
994 return iface.getMethod(mutator, Character.TYPE);
996 catch (NoSuchMethodException e)
998 throw ((AttributeNotFoundException)
999 new AttributeNotFoundException("The attribute, " + name +
1000 ", was not found.").initCause(e));
1002 if (type == Double.class)
1005 return iface.getMethod(mutator, Double.TYPE);
1007 catch (NoSuchMethodException e)
1009 throw ((AttributeNotFoundException)
1010 new AttributeNotFoundException("The attribute, " + name +
1011 ", was not found.").initCause(e));
1013 if (type == Float.class)
1016 return iface.getMethod(mutator, Float.TYPE);
1018 catch (NoSuchMethodException e)
1020 throw ((AttributeNotFoundException)
1021 new AttributeNotFoundException("The attribute, " + name +
1022 ", was not found.").initCause(e));
1024 if (type == Integer.class)
1027 return iface.getMethod(mutator, Integer.TYPE);
1029 catch (NoSuchMethodException e)
1031 throw ((AttributeNotFoundException)
1032 new AttributeNotFoundException("The attribute, " + name +
1033 ", was not found.").initCause(e));
1035 if (type == Long.class)
1038 return iface.getMethod(mutator, Long.TYPE);
1040 catch (NoSuchMethodException e)
1042 throw ((AttributeNotFoundException)
1043 new AttributeNotFoundException("The attribute, " + name +
1044 ", was not found.").initCause(e));
1046 if (type == Short.class)
1049 return iface.getMethod(mutator, Short.TYPE);
1051 catch (NoSuchMethodException e)
1053 throw ((AttributeNotFoundException)
1054 new AttributeNotFoundException("The attribute, " + name +
1055 ", was not found.").initCause(e));
1057 /* Superclasses and interfaces */
1058 for (Class<?> i : type.getInterfaces())
1061 return getMutator(name, i);
1063 catch (AttributeNotFoundException e)
1065 ex = e;
1067 Class<?> sclass = type.getSuperclass();
1068 if (sclass != null && sclass != Object.class)
1071 return getMutator(name, sclass);
1073 catch (AttributeNotFoundException e)
1075 ex = e;
1077 /* If we get this far, give up */
1078 throw ((AttributeNotFoundException)
1079 new AttributeNotFoundException("The attribute, " + name +
1080 ", was not found.").initCause(ex));