This adds the remainder of the MBeanInfo class
(via implementing MBeanOperationInfo), and also
allows me to commit the StandardMBean implementation
I wrote this weekend.

Changelog:

2006-07-26  Andrew John Hughes  <[EMAIL PROTECTED]>

        * javax/management/MBeanConstructorInfo.java:
        Documentation fix.
        * javax/management/MBeanInfo.java:
        (MBeanInfo(String,String,MBeanAttributeInfo[],
        MBeanConstructorInfo[], MBeanOperationInfo[],
        MBeanNotificationInfo[])): Implemented.
        (equals(Object)): Likewise.
        (getAttributes()): Likewise.
        (getConstructors()): Likewise.
        (getOperations()): Likewise.
        (hashCode()): Likewise.
        * javax/management/MBeanOperationInfo.java,
        * javax/management/NotCompliantMBeanException.java,
        * javax/management/StandardMBean.java:
        New files.

-- 
Andrew :-)

Escape the Java Trap with GNU Classpath!
http://www.gnu.org/philosophy/java-trap.html
public class gcj extends Freedom implements Java { ... }
Index: javax/management/MBeanConstructorInfo.java
===================================================================
RCS file: 
/cvsroot/classpath/classpath/javax/management/MBeanConstructorInfo.java,v
retrieving revision 1.1
diff -u -3 -p -u -r1.1 MBeanConstructorInfo.java
--- javax/management/MBeanConstructorInfo.java  25 Jul 2006 21:27:19 -0000      
1.1
+++ javax/management/MBeanConstructorInfo.java  26 Jul 2006 21:00:25 -0000
@@ -141,7 +141,7 @@ public class MBeanConstructorInfo
    * same order (but one may be longer than the other).
    *
    * @param obj the object to compare.
-   * @return true if the object is a [EMAIL PROTECTED] MBeanNotificationInfo}
+   * @return true if the object is a [EMAIL PROTECTED] MBeanConstructorInfo}
    *         instance, 
    *         <code>name.equals(object.getName())</code>,
    *         <code>description.equals(object.getDescription())</code>
Index: javax/management/MBeanInfo.java
===================================================================
RCS file: /cvsroot/classpath/classpath/javax/management/MBeanInfo.java,v
retrieving revision 1.2
diff -u -3 -p -u -r1.2 MBeanInfo.java
--- javax/management/MBeanInfo.java     16 Jul 2006 20:18:05 -0000      1.2
+++ javax/management/MBeanInfo.java     26 Jul 2006 21:00:25 -0000
@@ -39,6 +39,8 @@ package javax.management;
 
 import java.io.Serializable;
 
+import java.util.Arrays;
+
 /**
  * <p>
  * Describes the interface of a management bean.  This allows
@@ -104,6 +106,21 @@ public class MBeanInfo
   private String className;
 
   /**
+   * Descriptions of the attributes provided by the bean.
+   */
+  private MBeanAttributeInfo[] attributes;
+
+  /**
+   * Descriptions of the operations provided by the bean.
+   */
+  private MBeanOperationInfo[] operations;
+
+  /**
+   * Descriptions of the bean's constructors.
+   */
+  private MBeanConstructorInfo[] constructors;
+
+  /**
    * Descriptions of the notifications emitted by the bean.
    *
    * @serial The bean's notifications.
@@ -111,6 +128,51 @@ public class MBeanInfo
   private MBeanNotificationInfo[] notifications;
 
   /**
+   * Constructs a new [EMAIL PROTECTED] MBeanInfo} using the supplied
+   * class name and description with the given attributes,
+   * operations, constructors and notifications.  The class
+   * name does not have to actually specify a valid class that
+   * can be loaded by the MBean server or class loader; it merely
+   * has to be a syntactically correct class name.  Any of the
+   * arrays may be <code>null</code>; this will be treated as if
+   * an empty array was supplied.
+   *
+   * @param name the name of the class this instance describes.
+   * @param desc a description of the bean.
+   * @param attribs the attribute descriptions for the bean,
+   *                or <code>null</code>.
+   * @param cons the constructor descriptions for the bean,
+   *             or <code>null</code>.
+   * @param ops the operation descriptions for the bean,
+   *            or <code>null</code>.
+   * @param notifs the notification descriptions for the bean,
+   *               or <code>null</code>.
+   */
+  public MBeanInfo(String name, String desc, MBeanAttributeInfo[] attribs,
+                  MBeanConstructorInfo[] cons, MBeanOperationInfo[] ops,
+                  MBeanNotificationInfo[] notifs)
+  {
+    className = name;
+    description = desc;
+    if (attribs == null)
+      attributes = new MBeanAttributeInfo[0];
+    else
+      attributes = attribs;
+    if (cons == null)
+      constructors = new MBeanConstructorInfo[0];
+    else
+      constructors = cons;
+    if (ops == null)
+      operations = new MBeanOperationInfo[0];
+    else
+      operations = ops;
+    if (notifs == null)
+      notifications = new MBeanNotificationInfo[0];
+    else
+      notifications = notifs;
+  }
+
+  /**
    * Returns a shallow clone of the information.  This is
    * simply a new copy of each string and a clone
    * of each array, which still references the same objects,
@@ -137,6 +199,82 @@ public class MBeanInfo
   }
 
   /**
+   * Compares this feature with the supplied object.  This returns
+   * true iff the object is an instance of [EMAIL PROTECTED] MBeanInfo} and
+   * [EMAIL PROTECTED] Object#equals()} returns true for a comparison of the
+   * class name and description, and the arrays each contain the same
+   * elements in the same order (but one may be longer than the
+   * other).
+   *
+   * @param obj the object to compare.
+   * @return true if the object is a [EMAIL PROTECTED] MBeanInfo}
+   *         instance, 
+   *         <code>className.equals(object.getClassName())</code>,
+   *         <code>description.equals(object.getDescription())</code>
+   *         and the corresponding elements of the arrays are
+   *         equal.
+   */
+  public boolean equals(Object obj)
+  {
+    if (!(obj instanceof MBeanInfo))
+      return false;
+    if (!(super.equals(obj)))
+      return false;
+    MBeanInfo o = (MBeanInfo) obj;
+    MBeanAttributeInfo[] attr = o.getAttributes();
+    for (int a = 0; a < attributes.length; ++a)
+      {
+       if (a == attr.length)
+         return true;
+       if (!(attributes[a].equals(attr[a])))
+         return false;
+      }
+    MBeanConstructorInfo[] cons = o.getConstructors();
+    for (int a = 0; a < constructors.length; ++a)
+      {
+       if (a == cons.length)
+         return true;
+       if (!(constructors[a].equals(cons[a])))
+         return false;
+      }
+    MBeanOperationInfo[] ops = o.getOperations();
+    for (int a = 0; a < operations.length; ++a)
+      {
+       if (a == ops.length)
+         return true;
+       if (!(operations[a].equals(ops[a])))
+         return false;
+      }
+    MBeanNotificationInfo[] notifs = o.getNotifications();
+    for (int a = 0; a < notifications.length; ++a)
+      {
+       if (a == notifs.length)
+         return true;
+       if (!(notifications[a].equals(notifs[a])))
+         return false;
+      }
+    return (className.equals(o.getClassName()) &&
+           description.equals(o.getDescription()));
+  }
+
+  /**
+   * Returns descriptions of each of the attributes provided
+   * by this management bean.  The returned value is a shallow
+   * copy of the attribute array maintained by this instance.
+   * Hence, changing the elements of the returned array will not
+   * affect the attribute array, and the elements (instances
+   * of the [EMAIL PROTECTED] MBeanAttributeInfo} class) are immutable.
+   *
+   * @return an array of [EMAIL PROTECTED] MBeanAttributeInfo} objects,
+   *         representing the attributes emitted by this
+   *         management bean.
+   */
+  public MBeanAttributeInfo[] getAttributes()
+  {
+    return (MBeanAttributeInfo[]) attributes.clone();
+  }
+
+  /**
    * Returns the class name of the management bean.
    *
    * @return the bean's class name.
@@ -147,6 +285,23 @@ public class MBeanInfo
   }
 
   /**
+   * Returns descriptions of each of the constructors provided
+   * by this management bean.  The returned value is a shallow
+   * copy of the constructor array maintained by this instance.
+   * Hence, changing the elements of the returned array will not
+   * affect the constructor array, and the elements (instances
+   * of the [EMAIL PROTECTED] MBeanConstructorInfo} class) are immutable.
+   *
+   * @return an array of [EMAIL PROTECTED] MBeanConstructorInfo} objects,
+   *         representing the constructors emitted by this
+   *         management bean.
+   */
+  public MBeanConstructorInfo[] getConstructors()
+  {
+    return (MBeanConstructorInfo[]) constructors.clone();
+  }
+
+  /**
    * Returns a description of the management bean.
    *
    * @return the bean's description.
@@ -173,4 +328,34 @@ public class MBeanInfo
     return (MBeanNotificationInfo[]) notifications.clone();
   }
 
+  /**
+   * Returns descriptions of each of the operations provided
+   * by this management bean.  The returned value is a shallow
+   * copy of the operation array maintained by this instance.
+   * Hence, changing the elements of the returned array will not
+   * affect the operation array, and the elements (instances
+   * of the [EMAIL PROTECTED] MBeanOperationInfo} class) are immutable.
+   *
+   * @return an array of [EMAIL PROTECTED] MBeanOperationInfo} objects,
+   *         representing the operations emitted by this
+   *         management bean.
+   */
+  public MBeanOperationInfo[] getOperations()
+  {
+    return (MBeanOperationInfo[]) operations.clone();
+  }
+
+  /**
+   * Returns the hashcode of the information as the sum of the
+   * hashcode of the classname, description and each array.
+   *
+   * @return the hashcode of the information.
+   */
+  public int hashCode()
+  {
+    return className.hashCode() + description.hashCode()
+      + Arrays.hashCode(attributes) + Arrays.hashCode(constructors)
+      + Arrays.hashCode(operations) + Arrays.hashCode(notifications);
+  }
+
 }
Index: javax/management/MBeanOperationInfo.java
===================================================================
RCS file: javax/management/MBeanOperationInfo.java
diff -N javax/management/MBeanOperationInfo.java
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ javax/management/MBeanOperationInfo.java    26 Jul 2006 21:00:25 -0000
@@ -0,0 +1,295 @@
+/* MBeanOperationInfo.java -- Information about a bean's operations.
+   Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+package javax.management;
+
+import java.lang.reflect.Method;
+
+import java.util.Arrays;
+
+/**
+ * Describes the operations of a management bean.
+ * The information in this class is immutable as standard.
+ * Of course, subclasses may change this, but this
+ * behaviour is not recommended.
+ *
+ * @author Andrew John Hughes ([EMAIL PROTECTED])
+ * @since 1.5
+ */
+public class MBeanOperationInfo
+  extends MBeanFeatureInfo
+  implements Cloneable
+{
+
+  /**
+   * Compatible with JDK 1.5
+   */
+  private static final long serialVersionUID = -6178860474881375330L;
+
+  /**
+   * Used to signify that the operation merely provides information
+   * (akin to an accessor).
+   */
+  public static final int INFO = 0;
+
+  /**
+   * Used to signify that the operation makes some change to the
+   * state of the bean (akin to a mutator).
+   */
+  public static final int ACTION = 1;
+
+  /**
+   * Used to signify that the operation makes some state change
+   * to the bean and also returns information.
+   */
+  public static final int ACTION_INFO = 2;
+
+  /**
+   * Used to signify that the behaviour of the operation is
+   * unknown.
+   */
+  public static final int UNKNOWN = 3;
+
+  /**
+   * The return type of the method, in the form of its class name.
+   */
+  private String type;
+
+  /**
+   * The signature of the constructor i.e. the argument types.
+   */
+  private MBeanParameterInfo[] signature;
+
+  /**
+   * The impact of the method, as one of [EMAIL PROTECTED] #INFO}, [EMAIL 
PROTECTED] #ACTION},
+   * [EMAIL PROTECTED] #ACTION_INFO} and [EMAIL PROTECTED] #UNKNOWN}.
+   */
+  private int impact;
+
+  /**
+   * Constructs a @link{MBeanOperationInfo} with the specified
+   * description using the given method.  Each parameter is
+   * described merely by its type; the name and description are
+   * <code>null</code>.  The return type and impact of the
+   * method are determined from the [EMAIL PROTECTED] Method} instance.
+   *
+   * @param desc a description of the attribute.
+   * @param method the method.
+   */
+  public MBeanOperationInfo(String desc, Method method)
+  {
+    super(method.getName(), desc);
+    Class[] paramTypes = method.getParameterTypes();
+    signature = new MBeanParameterInfo[paramTypes.length];
+    for (int a = 0; a < paramTypes.length; ++a)
+      signature[a] = new MBeanParameterInfo(null,
+                                           paramTypes[a].getName(),
+                                           null);
+    type = method.getReturnType().getName();
+    if (method.getReturnType() == Void.TYPE)
+      {
+       if (paramTypes.length == 0)
+         impact = UNKNOWN;
+       else
+         impact = ACTION;
+      }
+    else
+      {
+       if (paramTypes.length == 0)
+         impact = INFO;
+       else
+         impact = ACTION_INFO;
+      }
+  }
+
+  /**
+   * Constructs a @link{MBeanOperationInfo} with the specified name,
+   * description, parameter information, return type and impact. A
+   * <code>null</code> value for the parameter information is the same
+   * as passing in an empty array.
+   *
+   * @param name the name of the constructor.
+   * @param desc a description of the attribute.
+   * @param sig the signature of the method, as a series
+   *            of [EMAIL PROTECTED] MBeanParameterInfo} objects, one for
+   *            each parameter.
+   * @param type the return type of the method, as the class name.
+   * @param impact the impact of performing the operation.
+   */
+  public MBeanOperationInfo(String name, String desc,
+                           MBeanParameterInfo[] sig, String type,
+                           int impact)
+  {
+    super(name, desc);
+    if (sig == null)
+      signature = new MBeanParameterInfo[0];
+    else
+      signature = sig;
+    this.type = type;
+    this.impact = impact;
+  }
+
+  /**
+   * Returns a clone of this instance.  The clone is created
+   * using just the method provided by [EMAIL PROTECTED] java.lang.Object}.
+   * Thus, the clone is just a shallow clone as returned by
+   * that method, and does not contain any deeper cloning based
+   * on the subject of this class.
+   *
+   * @return a clone of this instance.
+   * @see java.lang.Cloneable
+   */
+  public Object clone()
+  {
+    try
+      {
+       return super.clone();
+      }
+    catch (CloneNotSupportedException e)
+      {
+       /* This shouldn't happen; we implement Cloneable */
+       throw new IllegalStateException("clone() called on " +
+                                       "non-cloneable object.");
+      }
+  }
+
+  /**
+   * Compares this feature with the supplied object.  This returns
+   * true iff the object is an instance of [EMAIL PROTECTED]
+   * MBeanConstructorInfo}, [EMAIL PROTECTED] Object#equals()} returns true 
for a
+   * comparison of both the name and description of this notification
+   * with that of the specified object (performed by the superclass),
+   * the return type and impact are equal and the two signature arrays
+   * contain the same elements in the same order (but one may be
+   * longer than the other).
+   *
+   * @param obj the object to compare.
+   * @return true if the object is a [EMAIL PROTECTED] MBeanOperationInfo}
+   *         instance, 
+   *         <code>name.equals(object.getName())</code>,
+   *         <code>description.equals(object.getDescription())</code>,
+   *         <code>type.equals(object.getReturnType())</code>,
+   *         <code>impact == object.getImpact()</code>,
+   *         and the corresponding elements of the signature arrays are
+   *         equal.
+   */
+  public boolean equals(Object obj)
+  {
+    if (!(obj instanceof MBeanOperationInfo))
+      return false;
+    if (!(super.equals(obj)))
+      return false;
+    MBeanOperationInfo o = (MBeanOperationInfo) obj;
+    MBeanParameterInfo[] sig = o.getSignature();
+    for (int a = 0; a < signature.length; ++a)
+      {
+       if (a == sig.length)
+         return true;
+       if (!(signature[a].equals(sig[a])))
+         return false;
+      }
+    return (type.equals(o.getReturnType()) &&
+           impact == o.getImpact());
+  }
+  
+  /**
+   * <p>
+   * Returns the impact of performing this operation.
+   * The value is equal to one of the following:
+   * </p>
+   * <ol>
+   * <li>[EMAIL PROTECTED] #INFO} &mdash; the method just returns
+   * information (akin to an accessor).</li>
+   * <li>[EMAIL PROTECTED] #ACTION} &mdash; the method just alters
+   * the state of the bean, without returning a value
+   * (akin to a mutator).</li>
+   * <li>[EMAIL PROTECTED] #ACTION_INFO} &mdash; the method both makes
+   * state changes and returns a value.</li>
+   * <li>[EMAIL PROTECTED] #UNKNOWN} &mdash; the behaviour of the operation
+   * is unknown.</li>
+   * </ol>
+   *
+   * @return the impact of performing the operation.
+   */
+  public int getImpact()
+  {
+    return impact;
+  }
+
+  /**
+   * Returns the return type of the operation, as the class
+   * name.
+   *
+   * @return the return type.
+   */
+  public String getReturnType()
+  {
+    return type;
+  }
+
+  /**
+   * Returns the operation's signature, in the form of
+   * information on each parameter.  Each parameter is
+   * described by an instance of [EMAIL PROTECTED] MBeanParameterInfo}.
+   * The returned array is a shallow copy of the array used
+   * by this instance, so changing which elements are stored
+   * in the array won't affect the array used by this, but
+   * changing the actual elements will affect the ones used
+   * here.
+   *
+   * @return an array of [EMAIL PROTECTED] MBeanParameterInfo} objects,
+   *         describing the operation parameters.
+   */
+  public MBeanParameterInfo[] getSignature()
+  {
+    return (MBeanParameterInfo[]) signature.clone();
+  }
+
+  /**
+   * Returns the hashcode of the operation information as the sum of
+   * the hashcode of the superclass, the parameter array, the return
+   * type and the impact factor.
+   *
+   * @return the hashcode of the operation information.
+   */
+  public int hashCode()
+  {
+    return super.hashCode() + Arrays.hashCode(signature)
+      + type.hashCode() + Integer.valueOf(impact).hashCode();
+  }
+
+}
Index: javax/management/NotCompliantMBeanException.java
===================================================================
RCS file: javax/management/NotCompliantMBeanException.java
diff -N javax/management/NotCompliantMBeanException.java
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ javax/management/NotCompliantMBeanException.java    26 Jul 2006 21:00:25 
-0000
@@ -0,0 +1,78 @@
+/* NotCompliantMBeanException.java -- Thrown due to a non-compliant bean.
+   Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+package javax.management;
+
+/**
+ * Thrown when a management bean is passed to a method
+ * (e.g. to an MBean server to be registered) and it
+ * fails to comply with the specifications for such
+ * a bean.
+ *
+ * @author Andrew John Hughes ([EMAIL PROTECTED])
+ * @since 1.5
+ */
+public class NotCompliantMBeanException
+  extends OperationsException
+{
+
+  /**
+   * Compatible with JDK 1.5
+   */
+  private static final long serialVersionUID = 5175579583207963577L;
+
+  /**
+   * Constructs a new <code>NotCompliantMBeanException</code>.
+   */
+  public NotCompliantMBeanException()
+  {
+    super();
+  }
+
+  /**
+   * Constructs a new <code>NotCompliantMBeanException</code>
+   * with the specified message.
+   *
+   * @param message the error message to give to the user.
+   */
+  public NotCompliantMBeanException(String message)
+  {
+    super(message);
+  }
+
+}
+
Index: javax/management/StandardMBean.java
===================================================================
RCS file: javax/management/StandardMBean.java
diff -N javax/management/StandardMBean.java
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ javax/management/StandardMBean.java 26 Jul 2006 21:00:25 -0000
@@ -0,0 +1,919 @@
+/* StandardMBean.java -- A standard reflection-based management bean.
+   Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+package javax.management;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Provides a dynamic management bean by using reflection on an
+ * interface and an implementing class.  By default, a bean instance
+ * is paired up with its interface based on specific naming
+ * conventions (if the implementation is called X, the interface must
+ * be XMBean).  Using this class removes the need to use a specific
+ * naming system to match up the two.  Instead, an instance of this
+ * bean is created either via explicit construction or subclassing,
+ * and this provides access to the attributes, constructors and
+ * operations of the implementation via reflection.  Various hooks are
+ * provided in order to allow customization of this process.
+ *
+ * @author Andrew John Hughes ([EMAIL PROTECTED])
+ * @since 1.5
+ */
+public class StandardMBean
+  implements DynamicMBean
+{
+
+  /**
+   * The interface for this bean.
+   */
+  private Class iface;
+
+  /**
+   * The implementation of the interface.
+   */
+  private Object impl;
+
+  /**
+   * Cached bean information.
+   */
+  private MBeanInfo info;
+
+  /**
+   * Constructs a new [EMAIL PROTECTED] StandardMBean} using the specified
+   * interface and <code>this</code> as the instance.  This should
+   * be used to create an instance via subclassing.
+   * 
+   * @param iface the interface this bean implements, or <code>null</code>
+   *              if the interface should be determined using the naming
+   *              convention (class X has interface XMBean).
+   * @throws NotCompliantMBeanException if this class doesn't implement
+   *                                    the interface or a method appears
+   *                                    in the interface that doesn't comply
+   *                                    with the naming conventions.
+   */
+  protected StandardMBean(Class iface)
+    throws NotCompliantMBeanException
+  {
+    if (iface == null)
+      {
+       String className = getClass().getName();
+       try
+         {
+           iface = Class.forName(className + "MBean");
+         }
+       catch (ClassNotFoundException e)
+         {
+           throw (NotCompliantMBeanException) 
+             (new NotCompliantMBeanException("An interface for the class " +
+                                             className + " was not 
found.").initCause(e));
+         }
+      }
+    if (!(iface.isInstance(this)))
+      throw new NotCompliantMBeanException("The instance, " + impl + 
+                                          ", is not an instance of " + iface);
+    impl = this;
+    this.iface = iface;
+  }
+
+  /**
+   * Constructs a new [EMAIL PROTECTED] StandardMBean} using the specified
+   * interface and the supplied instance as the implementation.
+   * 
+   * @param impl the implementation.
+   * @param iface the interface the bean implements, or <code>null</code>
+   *              if the interface should be determined using the naming
+   *              convention (class X has interface XMBean).
+   * @throws IllegalArgumentException if <code>impl</code> is 
<code>null</code>.
+   * @throws NotCompliantMBeanException if <code>impl</code> doesn't implement
+   *                                    the interface or a method appears
+   *                                    in the interface that doesn't comply
+   *                                    with the naming conventions.
+   */
+  public StandardMBean(Object impl, Class iface)
+    throws NotCompliantMBeanException
+  {
+    if (impl == null)
+      throw new IllegalArgumentException("The specified implementation is 
null.");
+    if (iface == null)
+      {
+       String className = impl.getClass().getName();
+       try
+         {
+           iface = Class.forName(className + "MBean");
+         }
+       catch (ClassNotFoundException e)
+         {
+           throw (NotCompliantMBeanException) 
+             (new NotCompliantMBeanException("An interface for the class " +
+                                             className + " was not 
found.").initCause(e));
+         }
+      }
+    if (!(iface.isInstance(impl)))
+      throw new NotCompliantMBeanException("The instance, " + impl + 
+                                          ", is not an instance of " + iface);
+    this.impl = impl;
+    this.iface = iface;
+  }
+
+  /**
+   * Caches the [EMAIL PROTECTED] MBeanInfo} instance for this object.  This 
is a
+   * customization hook, so that subclasses can choose the caching policy
+   * used.  The default implementation caches the value in the instance
+   * itself.  Subclasses may override this so as to not cache the data
+   * at all, or so as to use a cache shared between multiple beans.
+   *
+   * @param info the [EMAIL PROTECTED] MBeanInfo} instance to cache, or 
<code>null</code>
+   *             if there is no new value to cache.  When the value is not
+   *             <code>null</code>, the cache should replace the current value
+   *             with the value supplied here.
+   * @see #getCachedMBeanInfo()
+   */
+  protected void cacheMBeanInfo(MBeanInfo info)
+  {
+    if (info != null)
+      this.info = info;
+  }
+
+  /**
+   * Obtains the value of the specified attribute of the
+   * management bean.  The management bean should perform
+   * a lookup for the named attribute, and return its value
+   * by calling the appropriate getter method, if possible.
+   *
+   * @param name the name of the attribute to retrieve.
+   * @return the value of the specified attribute.
+   * @throws AttributeNotFoundException if the name does not
+   *                                    correspond to an attribute
+   *                                    of the bean.
+   * @throws MBeanException if retrieving the attribute causes
+   *                        the bean to throw an exception (which
+   *                        becomes the cause of this exception).
+   * @throws ReflectionException if an exception occurred in trying
+   *                             to use the reflection interface
+   *                             to lookup the attribute.  The
+   *                             thrown exception is the cause of
+   *                             this exception.
+   * @see #setAttribute(String)
+   */
+  public Object getAttribute(String name)
+    throws AttributeNotFoundException, MBeanException,
+          ReflectionException
+  {
+    Method getter;
+    try 
+      {
+       getter = iface.getMethod("get" +
+                                name.substring(0, 1).toUpperCase() +
+                                name.substring(1), null);
+      }
+    catch (NoSuchMethodException e)
+      {
+       try 
+         {
+           getter = iface.getMethod("is" +
+                                    name.substring(0, 1).toUpperCase() +
+                                    name.substring(1), null);
+         }
+       catch (NoSuchMethodException ex)
+         {
+           throw ((AttributeNotFoundException) 
+                  new AttributeNotFoundException("The attribute, " + name +
+                                                 ", was not 
found.").initCause(ex));
+         }
+      }
+    Object result;
+    try
+      {
+       result = getter.invoke(impl, null);
+      }
+    catch (IllegalAccessException e)
+      {
+       throw new ReflectionException(e, "Failed to retrieve " + name);
+      }
+    catch (IllegalArgumentException e)
+      {
+       throw new ReflectionException(e, "Failed to retrieve " + name);
+      }
+    catch (InvocationTargetException e)
+      {
+       throw new MBeanException((Exception) e.getCause(),
+                                "The getter of " + name +
+                                " threw an exception");
+      }
+    return result;
+  }
+
+  /**
+   * Obtains the values of each of the specified attributes
+   * of the management bean.  The returned list includes
+   * those attributes that were retrieved and their
+   * corresponding values.
+   *
+   * @param names the names of the attributes to retrieve.
+   * @return a list of the retrieved attributes.
+   * @see #setAttributes(AttributeList)
+   */
+  public AttributeList getAttributes(String[] names)
+  {
+    AttributeList list = new AttributeList(names.length);
+    for (int a = 0; a < names.length; ++a)
+      {
+       try
+         {
+           Object value = getAttribute(names[a]);
+           list.add(new Attribute(names[a], value));
+         }
+       catch (AttributeNotFoundException e)
+         {
+           /* Ignored */
+         }
+       catch (ReflectionException e)
+         {
+           /* Ignored */
+         }
+       catch (MBeanException e)
+         {
+           /* Ignored */
+         }
+      }
+    return list;
+  }
+
+  /**
+   * Returns the cached [EMAIL PROTECTED] MBeanInfo} instance for this object. 
 This is a
+   * customization hook, so that subclasses can choose the caching policy
+   * used.  The default implementation caches the value in the instance
+   * itself, and returns this value on calls to this method.
+   *
+   * @return the cached [EMAIL PROTECTED] MBeanInfo} instance, or 
<code>null</code>
+   *         if no value is cached.
+   * @see #cacheMBeanInfo(javax.management.MBeanInfo)
+   */
+  protected MBeanInfo getCachedMBeanInfo()
+  {
+    return info;
+  }
+
+  /**
+   * Returns the class name that will be used in the [EMAIL PROTECTED] 
MBeanInfo}
+   * instance.  This is a customization hook, so that subclasses can
+   * provide a custom class name.  By default, this returns the class
+   * name from the supplied [EMAIL PROTECTED] MBeanInfo} instance.
+   *
+   * @param info the [EMAIL PROTECTED] MBeanInfo} instance constructed via
+   *             reflection.
+   * @return the class name to use in the instance.
+   */
+  protected String getClassName(MBeanInfo info)
+  {
+    return info.getClassName();
+  }
+
+  /**
+   * Returns information on the constructors that will be used in
+   * the [EMAIL PROTECTED] MBeanInfo} instance.  This is a customization hook,
+   * so that subclasses can provide their own information on the
+   * bean's constructors, if necessary.  By default, this method
+   * returns <code>null</code> unless the implementation supplied
+   * is either <code>null</code> or <code>this</code>.  This default
+   * implementation prevents the use of
+   * [EMAIL PROTECTED] MBeanServer#createMBean} in cases where the bean is
+   * not created as a subclass of [EMAIL PROTECTED] StandardMBean}.
+   *
+   * @param constructors the constructor information created via
+   *                     reflection.
+   * @param impl the implementation, or <code>null</code> if this
+   *             should be ignored.
+   * @return the constructor information to use.
+   */
+  protected MBeanConstructorInfo[] getConstructors(MBeanConstructorInfo[]
+                                                  constructors, Object impl)
+  {
+    if (impl == null || impl == this)
+      return constructors;
+    return null;
+  }
+
+  /**
+   * Returns the description of the attribute that will be used in
+   * the supplied [EMAIL PROTECTED] MBeanAttributeInfo} instance.  This is a
+   * customization hook, so that subclasses can provide a custom
+   * description.  By default, this calls
+   * [EMAIL PROTECTED] #getDescription(MBeanFeatureInfo)} with the supplied
+   * [EMAIL PROTECTED] MBeanAttributeInfo} instance.
+   *
+   * @param info the [EMAIL PROTECTED] MBeanAttributeInfo} instance constructed
+   *             via reflection.
+   * @return the description to use in the instance.
+   */
+  protected String getDescription(MBeanAttributeInfo info)
+  {
+    return getDescription((MBeanFeatureInfo) info);
+  }
+
+  /**
+   * Returns the description of the constructor that will be used in
+   * the supplied [EMAIL PROTECTED] MBeanConstructorInfo} instance.  This is a
+   * customization hook, so that subclasses can provide a custom
+   * description.  By default, this calls
+   * [EMAIL PROTECTED] #getDescription(MBeanFeatureInfo)} with the supplied
+   * [EMAIL PROTECTED] MBeanConstructorInfo} instance.
+   *
+   * @param info the [EMAIL PROTECTED] MBeanConstructorInfo} instance 
constructed
+   *             via reflection.
+   * @return the description to use in the instance.
+   */
+  protected String getDescription(MBeanConstructorInfo info)
+  {
+    return getDescription((MBeanFeatureInfo) info);
+  }
+
+  /**
+   * Returns the description of the nth parameter of the constructor
+   * that will be used in the supplied [EMAIL PROTECTED] MBeanParameterInfo}
+   * instance.  This is a customization hook, so that subclasses
+   * can provide a custom description.  By default, this calls
+   * <code>param.getDescription()</code>.
+   *
+   * @param info the [EMAIL PROTECTED] MBeanConstructorInfo} instance 
constructed
+   *             via reflection.
+   * @param param the [EMAIL PROTECTED] MBeanParameterInfo} instance 
constructed
+   *             via reflection.
+   * @param n the number of the parameter, in order to link it to the
+   *          information on the constructor.
+   * @return the description to use in the instance.
+   */
+  protected String getDescription(MBeanConstructorInfo info,
+                                 MBeanParameterInfo param, int n)
+  {
+    return param.getDescription();
+  }
+
+  /**
+   * Returns the description of the supplied feature that
+   * will be used in the supplied [EMAIL PROTECTED] MBeanFeatureInfo}
+   * instance.  This is a customization hook, so that subclasses
+   * can provide a custom description.  By default, this calls
+   * <code>info.getDescription()</code>.  This method is also called
+   * by default for the more specific description methods for attributes,
+   * constructors and operations.
+   *
+   * @param info the [EMAIL PROTECTED] MBeanFeatureInfo} instance constructed
+   *             via reflection.
+   * @return the description to use in the instance.
+   */
+  protected String getDescription(MBeanFeatureInfo info)
+  {
+    return info.getDescription();
+  }
+
+  /**
+   * Returns the description of the bean that will be used in the
+   * supplied [EMAIL PROTECTED] MBeanInfo} instance.  This is a customization
+   * hook, so that subclasses can provide a custom description.  By
+   * default, this calls <code>info.getDescription()</code>.
+   *
+   * @param info the [EMAIL PROTECTED] MBeanInfo} instance constructed
+   *             via reflection.
+   * @return the description to use in the instance.
+   */
+  protected String getDescription(MBeanInfo info)
+  {
+    return info.getDescription();
+  }
+
+  /**
+   * Returns the description of the operation that will be used in
+   * the supplied [EMAIL PROTECTED] MBeanOperationInfo} instance.  This is a
+   * customization hook, so that subclasses can provide a custom
+   * description.  By default, this calls
+   * [EMAIL PROTECTED] #getDescription(MBeanFeatureInfo)} with the supplied
+   * [EMAIL PROTECTED] MBeanOperationInfo} instance.
+   *
+   * @param info the [EMAIL PROTECTED] MBeanOperationInfo} instance constructed
+   *             via reflection.
+   * @return the description to use in the instance.
+   */
+  protected String getDescription(MBeanOperationInfo info)
+  {
+    return getDescription((MBeanFeatureInfo) info);
+  }
+
+  /**
+   * Returns the description of the nth parameter of the operation
+   * that will be used in the supplied [EMAIL PROTECTED] MBeanParameterInfo}
+   * instance.  This is a customization hook, so that subclasses
+   * can provide a custom description.  By default, this calls
+   * <code>param.getDescription()</code>.
+   *
+   * @param info the [EMAIL PROTECTED] MBeanOperationInfo} instance constructed
+   *             via reflection.
+   * @param param the [EMAIL PROTECTED] MBeanParameterInfo} instance 
constructed
+   *             via reflection.
+   * @param n the number of the parameter, in order to link it to the
+   *          information on the operation.
+   * @return the description to use in the instance.
+   */
+  protected String getDescription(MBeanOperationInfo info,
+                                 MBeanParameterInfo param, int n)
+  {
+    return param.getDescription();
+  }
+
+  /**
+   * Returns the impact of the operation that will be used in the
+   * supplied [EMAIL PROTECTED] MBeanOperationInfo} instance.  This is a
+   * customization hook, so that subclasses can provide a custom
+   * impact flag.  By default, this returns
+   * <code>info.getImpact()</code>.
+   *
+   * @param info the [EMAIL PROTECTED] MBeanOperationInfo} instance constructed
+   *             via reflection.
+   * @return the impact flag to use in the instance.
+   */
+  protected int getImpact(MBeanOperationInfo info)
+  {
+    return info.getImpact();
+  }
+
+  /**
+   * Returns the instance that implements this bean.
+   *
+   * @return the implementation.
+   */
+  public Object getImplementation()
+  {
+    return impl;
+  }
+
+  /**
+   * Returns the class of the instance that implements this bean.
+   *
+   * @return the implementation class.
+   */
+  public Class getImplementationClass()
+  {
+    return impl.getClass();
+  }
+
+  /**
+   * <p>
+   * Returns an information object which lists the attributes
+   * and actions associated with the management bean.  This
+   * implementation proceeds as follows:
+   * </p>
+   * <ol>
+   * <li>[EMAIL PROTECTED] #getCachedMBeanInfo()} is called to obtain
+   * the cached instance.  If this returns a non-null value,
+   * this value is returned.</li>
+   * <li>If there is no cached value, then the method proceeds
+   * to create one. During this process, the customization hooks
+   * detailed in this class are called to allow the values used
+   * to be overrided:
+   * <ul>
+   * <li>For each attribute, 
+   * [EMAIL PROTECTED] #getDescription(MBeanAttributeInfo)} is called.</li>
+   * <li>For each constructor,
+   * [EMAIL PROTECTED] #getDescription(MBeanConstructorInfo)} is called,
+   * along with [EMAIL PROTECTED] #getDescription(MBeanConstructorInfo,
+   * MBeanParameterInfo, int)} and
+   * [EMAIL PROTECTED] #getParameterName(MBeanConstructorInfo,
+   * MBeanParameterInfo, int)} for each parameter.</li>
+   * <li>The constructors may be replaced as a whole by
+   * a call to
+   * [EMAIL PROTECTED] #getConstructors(MBeanConstructorInfo[], Object)}.</li>
+   * <li>For each operation,
+   * [EMAIL PROTECTED] #getDescription(MBeanOperationInfo)} and
+   * [EMAIL PROTECTED] #getImpact(MBeanOperationInfo)} are called,
+   * along with [EMAIL PROTECTED] #getDescription(MBeanOperationInfo,
+   * MBeanParameterInfo, int)} and
+   * [EMAIL PROTECTED] #getParameterName(MBeanOperationInfo,
+   * MBeanParameterInfo, int)} for each parameter.</li>
+   * <li>[EMAIL PROTECTED] #getClassName(MBeanInfo)} and
+   * [EMAIL PROTECTED] #getDescription(MBeanInfo)} are called to customise
+   * the basic information about the class.</li>
+   * </ul>
+   * </li>
+   * <li>Finally, [EMAIL PROTECTED] #cacheMBeanInfo(MBeanInfo)} is called
+   * with the created instance before it is returned.</li>
+   * </ol>
+   *
+   * @return a description of the management bean, including
+   *         all exposed attributes and actions.
+   */
+  public MBeanInfo getMBeanInfo()
+  {
+    MBeanInfo info = getCachedMBeanInfo();
+    if (info != null)
+      return info;
+    Method[] methods = iface.getMethods();
+    Map attributes = new HashMap();
+    List operations = new ArrayList();
+    for (int a = 0; a < methods.length; ++a)
+      {
+       String name = methods[a].getName();
+       if (((name.startsWith("get") &&
+             methods[a].getReturnType() != Void.TYPE) ||
+            (name.startsWith("is") &&
+             methods[a].getReturnType() == Boolean.TYPE)) &&
+           methods[a].getParameterTypes().length == 0)
+         {
+           Method[] amethods;
+           String attrib = name.substring(3);
+           if (attributes.containsKey(attrib))
+             amethods = (Method[]) attributes.get(attrib);
+           else
+             {
+               amethods = new Method[2];
+               attributes.put(attrib, amethods);
+             }
+           amethods[0] = methods[a];
+         }
+       else if (name.startsWith("set") &&
+                methods[a].getReturnType() == Void.TYPE &&
+                methods[a].getParameterTypes().length == 1)
+         {
+           Method[] amethods;
+           String attrib = name.substring(3);
+           if (attributes.containsKey(attrib))
+             amethods = (Method[]) attributes.get(attrib);
+           else
+             {
+               amethods = new Method[2];
+               attributes.put(attrib, amethods);
+             }
+           amethods[1] = methods[a];
+         }
+       else
+         operations.add(new MBeanOperationInfo("", methods[a]));
+      }
+    List attribs = new ArrayList(attributes.size());
+    Iterator it = attributes.entrySet().iterator();
+    while (it.hasNext())
+      {
+       Map.Entry entry = (Map.Entry) it.next();
+       Method[] amethods = (Method[]) entry.getValue();
+       try
+         {
+           attribs.add(new MBeanAttributeInfo((String) entry.getKey(), "",
+                                              amethods[0], amethods[1]));
+         }
+       catch (IntrospectionException e)
+         {
+           /* Shouldn't happen; both shouldn't be null */
+           throw new IllegalStateException("The two methods passed to " +
+                                           "the MBeanAttributeInfo " +
+                                           "constructor for " + entry +
+                                           "were null.", e);
+         }
+      }
+    MBeanAttributeInfo[] ainfo = new MBeanAttributeInfo[attribs.size()];
+    for (int a = 0; a < ainfo.length; ++a)
+      {
+       MBeanAttributeInfo oldInfo = (MBeanAttributeInfo) attribs.get(a);
+       String desc = getDescription(oldInfo);
+       ainfo[a] = new MBeanAttributeInfo(oldInfo.getName(),
+                                         oldInfo.getType(), desc,
+                                         oldInfo.isReadable(),
+                                         oldInfo.isWritable(),
+                                         oldInfo.isIs());
+      }
+    Constructor[] cons = impl.getClass().getConstructors();
+    MBeanConstructorInfo[] cinfo = new MBeanConstructorInfo[cons.length];
+    for (int a = 0; a < cinfo.length; ++a)
+      {
+       MBeanConstructorInfo oldInfo = new MBeanConstructorInfo("",
+                                                               cons[a]);
+       String desc = getDescription(oldInfo);
+       MBeanParameterInfo[] params = oldInfo.getSignature();
+       MBeanParameterInfo[] pinfo = new MBeanParameterInfo[params.length];
+       for (int b = 0; b < pinfo.length; ++b)
+         {
+           String pdesc = getDescription(oldInfo, params[b], b);
+           String pname = getParameterName(oldInfo, params[b], b);
+           pinfo[b] = new MBeanParameterInfo(pname, params[b].getType(),
+                                             pdesc);
+         }
+       cinfo[a] = new MBeanConstructorInfo(oldInfo.getName(), desc,
+                                           pinfo);
+      }
+    cinfo = getConstructors(cinfo, impl);
+    MBeanOperationInfo[] oinfo = new MBeanOperationInfo[operations.size()];
+    for (int a = 0; a < oinfo.length; ++a)
+      {
+       MBeanOperationInfo oldInfo = (MBeanOperationInfo) operations.get(a);
+       String desc = getDescription(oldInfo);
+       int impact = getImpact(oldInfo);
+       MBeanParameterInfo[] params = oldInfo.getSignature();
+       MBeanParameterInfo[] pinfo = new MBeanParameterInfo[params.length];
+       for (int b = 0; b < pinfo.length; ++b)
+         {
+           String pdesc = getDescription(oldInfo, params[b], b);
+           String pname = getParameterName(oldInfo, params[b], b);
+           pinfo[b] = new MBeanParameterInfo(pname, params[b].getType(),
+                                             pdesc);
+         }
+       oinfo[a] = new MBeanOperationInfo(oldInfo.getName(), desc, pinfo,
+                                         oldInfo.getReturnType(), impact);
+      }
+    info = new MBeanInfo(impl.getClass().getName(), "", ainfo, cinfo,
+                        oinfo, null);
+    String cname = getClassName(info);
+    String desc = getDescription(info);
+    info = new MBeanInfo(cname, desc, ainfo, cinfo, oinfo, null);
+    cacheMBeanInfo(info);
+    return info;
+  }
+
+  /**
+   * Returns the interface for this management bean.
+   *
+   * @return the management interface.
+   */
+  public Class getMBeanInterface()
+  {
+    return iface;
+  }
+
+  /**
+   * Returns the name of the nth parameter of the constructor
+   * that will be used in the supplied [EMAIL PROTECTED] MBeanParameterInfo}
+   * instance.  This is a customization hook, so that subclasses
+   * can provide a custom name.  By default, this calls
+   * <code>param.getName()</code>.
+   *
+   * @param info the [EMAIL PROTECTED] MBeanConstructorInfo} instance 
constructed
+   *             via reflection.
+   * @param param the [EMAIL PROTECTED] MBeanParameterInfo} instance 
constructed
+   *             via reflection.
+   * @param n the number of the parameter, in order to link it to the
+   *          information on the constructor.
+   * @return the name to use in the instance.
+   */
+  protected String getParameterName(MBeanConstructorInfo info,
+                                   MBeanParameterInfo param, int n)
+  {
+    return param.getName();
+  }
+
+  /**
+   * Returns the name of the nth parameter of the operation
+   * that will be used in the supplied [EMAIL PROTECTED] MBeanParameterInfo}
+   * instance.  This is a customization hook, so that subclasses
+   * can provide a custom name.  By default, this calls
+   * <code>param.getName()</code>.
+   *
+   * @param info the [EMAIL PROTECTED] MBeanOperationInfo} instance constructed
+   *             via reflection.
+   * @param param the [EMAIL PROTECTED] MBeanParameterInfo} instance 
constructed
+   *             via reflection.
+   * @param n the number of the parameter, in order to link it to the
+   *          information on the operation.
+   * @return the name to use in the instance.
+   */
+  protected String getParameterName(MBeanOperationInfo info,
+                                   MBeanParameterInfo param, int n)
+  {
+    return param.getName();
+  }
+
+  /**
+   * Invokes the specified action on the management bean using
+   * the supplied parameters.  The signature of the action is
+   * specified by a [EMAIL PROTECTED] String} array, which lists the classes
+   * corresponding to each parameter.  The class loader used to
+   * load these classes is the same as that used for loading the
+   * management bean itself.
+   * 
+   * @param name the name of the action to invoke.
+   * @param params the parameters used to call the action.
+   * @param signature the signature of the action.
+   * @return the return value of the action.
+   * @throws MBeanException if the action throws an exception.  The
+   *                        thrown exception is the cause of this
+   *                        exception.
+   * @throws ReflectionException if an exception occurred in trying
+   *                             to use the reflection interface
+   *                             to invoke the action.  The
+   *                             thrown exception is the cause of
+   *                             this exception.
+   */
+  public Object invoke(String name, Object[] params, String[] signature)
+    throws MBeanException, ReflectionException
+  {
+    Class[] sigTypes = new Class[signature.length];
+    ClassLoader loader = getClass().getClassLoader();
+    for (int a = 0; a < signature.length; ++a)
+      try 
+       {
+         sigTypes[a] = Class.forName(signature[a], true, loader);
+       }
+      catch (ClassNotFoundException e)
+       {
+         throw new ReflectionException(e, "The class, " + signature[a] + 
+                                       ", in the method signature " +
+                                       "could not be loaded.");
+       }
+    Method method;
+    try
+      {
+       method = iface.getMethod(name, sigTypes);
+      }
+    catch (NoSuchMethodException e)
+      {
+       throw new ReflectionException(e, "The method, " + name +
+                                     ", could not be found.");
+      }
+    Object result;
+    try
+      {
+       result = method.invoke(impl, params);
+      }
+    catch (IllegalAccessException e)
+      {
+       throw new ReflectionException(e, "Failed to call " + name);
+      }
+    catch (IllegalArgumentException e)
+      {
+       throw new ReflectionException(e, "Failed to call " + name);
+      }
+    catch (InvocationTargetException e)
+      {
+       throw new MBeanException((Exception) e.getCause(), "The method "
+                                + name + " threw an exception");
+      }
+    return result;
+  }
+
+  /**
+   * Sets the value of the specified attribute of the
+   * management bean.  The management bean should perform
+   * a lookup for the named attribute, and sets its value
+   * using the associated setter method, if possible.
+   *
+   * @param attribute the attribute to set.
+   * @throws AttributeNotFoundException if the attribute does not
+   *                                    correspond to an attribute
+   *                                    of the bean.
+   * @throws InvalidAttributeValueException if the value is invalid
+   *                                        for this particular
+   *                                        attribute of the bean.
+   * @throws MBeanException if setting the attribute causes
+   *                        the bean to throw an exception (which
+   *                        becomes the cause of this exception).
+   * @throws ReflectionException if an exception occurred in trying
+   *                             to use the reflection interface
+   *                             to lookup the attribute.  The
+   *                             thrown exception is the cause of
+   *                             this exception.
+   * @see #getAttribute(String)
+   */
+  public void setAttribute(Attribute attribute)
+    throws AttributeNotFoundException, InvalidAttributeValueException,
+          MBeanException, ReflectionException
+  {
+    Method setter;
+    String name = attribute.getName();
+    try 
+      {
+       setter = iface.getMethod("set" +
+                                name.substring(0, 1).toUpperCase() +
+                                name.substring(1), null);
+      }
+    catch (NoSuchMethodException e)
+      {
+       throw ((AttributeNotFoundException) 
+              new AttributeNotFoundException("The attribute, " + name +
+                                             ", was not found.").initCause(e));
+      }
+    try
+      {
+       setter.invoke(impl, new Object[] { attribute.getValue() });
+      }
+    catch (IllegalAccessException e)
+      {
+       throw new ReflectionException(e, "Failed to set " + name);
+      }
+    catch (IllegalArgumentException e)
+      {
+       throw ((InvalidAttributeValueException)
+              new InvalidAttributeValueException(attribute.getValue() +
+                                                 " is an invalid value for " +
+                                                 name).initCause(e));
+      }
+    catch (InvocationTargetException e)
+      {
+       throw new MBeanException((Exception) e.getCause(), "The getter of "
+                                + name + " threw an exception");
+      }
+  }
+
+  /**
+   * Sets the value of each of the specified attributes
+   * to that supplied by the [EMAIL PROTECTED] Attribute} object.
+   * The returned list contains the attributes that were
+   * set and their new values.
+   *
+   * @param attributes the attributes to set.
+   * @return a list of the changed attributes.
+   * @see #getAttributes(AttributeList)
+   */
+  public AttributeList setAttributes(AttributeList attributes)
+  {
+    AttributeList list = new AttributeList(attributes.size());
+    Iterator it = attributes.iterator();
+    while (it.hasNext())
+      {
+       try
+         {
+           Attribute attrib = (Attribute) it.next();
+           setAttribute(attrib);
+           list.add(attrib);
+         }
+       catch (AttributeNotFoundException e)
+         {
+           /* Ignored */
+         }
+       catch (InvalidAttributeValueException e)
+         {
+           /* Ignored */
+         }
+       catch (ReflectionException e)
+         {
+           /* Ignored */
+         }
+       catch (MBeanException e)
+         {
+           /* Ignored */
+         }
+      }
+    return list;
+  }
+
+  /**
+   * Replaces the implementation of the interface used by this
+   * instance with the one specified.  The new implementation
+   * must be non-null and implement the interface specified on
+   * construction of this instance.
+   *
+   * @throws IllegalArgumentException if <code>impl</code> is 
<code>null</code>.
+   * @throws NotCompliantMBeanException if <code>impl</code> doesn't implement
+   *                                    the interface or a method appears
+   *                                    in the interface that doesn't comply
+   *                                    with the naming conventions.
+   */
+  public void setImplementation(Object impl)
+    throws NotCompliantMBeanException
+  {
+    if (impl == null)
+      throw new IllegalArgumentException("The specified implementation is 
null.");
+    if (!(iface.isInstance(impl)))
+      throw new NotCompliantMBeanException("The instance, " + impl + 
+                                          ", is not an instance of " + iface);
+    this.impl = impl;
+  }
+
+}

Attachment: signature.asc
Description: Digital signature

Reply via email to