diff options
author | Andrew John Hughes <gnu_andrew@member.fsf.org> | 2007-03-05 00:22:40 +0000 |
---|---|---|
committer | Andrew John Hughes <gnu_andrew@member.fsf.org> | 2007-03-05 00:22:40 +0000 |
commit | 5e7d7af8305ec32c022fd21d117638b3fa569d32 (patch) | |
tree | fd6b9c77d1d67a78854998a050b1e31cb31401c7 /javax | |
parent | 8755402234c333b689b541a32a66bbd759460635 (diff) | |
download | classpath-5e7d7af8305ec32c022fd21d117638b3fa569d32.tar.gz |
2007-03-05 Andrew John Hughs <gnu_andrew@member.fsf.org>
* gnu/java/lang/management/BeanImpl.java:
Reference the new Translator class.
(translate(String)): Moved to Translator.
* gnu/javax/management/Translator.java:
New file.
* javax/management/JMX.java:
Likewise.
* javax/management/MBeanServerInvocationHandler.java:
Likewise.
* javax/management/MXBean.java:
Likewise.
* javax/management/ObjectName.java:
(ObjectName(String)): Catch a key without a value.
* javax/management/StandardMBean.java:
(StandardMBean(Class<?>)): Handle MXBeans.
(StandardMBean(Object, Class<?>)): Likewise.
(invoke(String,Object[],String[])): Disallow
calling attribute methods and handle null signatures.
(setAttribute(Attribute)): Search for mutators
with the appropriate signature.
* javax/management/openmbean/OpenType.java:
Add generic typing.
(ALLOWED_CLASSNAMES_LIST): New field.
Diffstat (limited to 'javax')
-rw-r--r-- | javax/management/JMX.java | 342 | ||||
-rw-r--r-- | javax/management/MBeanServerInvocationHandler.java | 400 | ||||
-rw-r--r-- | javax/management/MXBean.java | 82 | ||||
-rw-r--r-- | javax/management/ObjectName.java | 3 | ||||
-rw-r--r-- | javax/management/StandardMBean.java | 79 | ||||
-rw-r--r-- | javax/management/openmbean/OpenType.java | 16 |
6 files changed, 897 insertions, 25 deletions
diff --git a/javax/management/JMX.java b/javax/management/JMX.java new file mode 100644 index 000000000..fb3bd2b66 --- /dev/null +++ b/javax/management/JMX.java @@ -0,0 +1,342 @@ +/* JMX.java -- Static methods pertaining to the management API. + Copyright (C) 2007 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.Proxy; + +/** + * Common static methods pertaining to the management + * API. There are no instances of this class. + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.6 + */ +public class JMX +{ + + /** + * The name of the defaultValue field. + */ + public static final String DEFAULT_VALUE_FIELD = "defaultValue"; + + /** + * The name of the immutableInfo field. + */ + public static final String IMMUTABLE_INFO_FIELD = "immutableInfo"; + + /** + * The name of the interfaceClassName field. + */ + public static final String INTERFACE_CLASS_NAME_FIELD = "interfaceClassName"; + + /** + * The name of the legalValues field. + */ + public static final String LEGAL_VALUES_FIELD = "legalValues"; + + /** + * The name of the maxValue field. + */ + public static final String MAX_VALUE_FIELD = "maxValue"; + + /** + * The name of the minValue field. + */ + public static final String MIN_VALUE_FIELD = "minValue"; + + /** + * The name of the mxbean field. + */ + public static final String MXBEAN_FIELD = "mxbean"; + + /** + * The name of the openType field. + */ + public static final String OPEN_TYPE_FIELD = "openType"; + + /** + * The name of the originalType field. + */ + public static final String ORIGINAL_TYPE_FIELD = "originalType"; + + /** + * Prevent instance creation. + */ + private JMX() + { + } + + /** + * <p> + * Returns true if the given class represents an {@link MXBean} + * interface. An interface is an {@link MXBean interface} if: + * </p> + * <ul> + * <li>It is annotated with {@code @MXBean} or + * {@code @MXBean(true)}</li>. + * <li>Its name ends in {@code "MXBean"} and it does not + * have an {@link MXBean} annotation.</li> + * </ul> + * + * @param iface the interface class that is to be checked + * for {@link MXBean} status. + * @return true if the interface represents an {@link MXBean}. + * @throws NullPointerException if {@code iface} is {@code null}. + */ + public static boolean isMXBeanInterface(Class<?> iface) + { + MXBean annotation = iface.getAnnotation(MXBean.class); + if (annotation != null) + return annotation.value(); + return iface.getName().endsWith("MXBean"); + } + + /** + * <p> + * Returns a proxy for a standard management bean, using + * the specified connection to access the named implementation. + * To create a proxy for the bean, {@code SomethingMBean}, a call to + * {@code JMX.newMBeanProxy(server, name, SomethingMBean.class)} + * is made, where {@code server} is a local or remote management + * server, and {@code name} is the registered {@link ObjectName} + * of the implementation of {@code SomethingMBean} to use. + * </p> + * <p> + * The proxy redirects calls to the methods of the interface, + * {@link SomethingMBean}, to the appropriate methods of the + * management server. If {@link SomethingMBean} is specified + * as follows: + * </p> + * <pre> + * public interface SomethingMBean + * { + * String getName(); + * void setName(String name); + * void doStuff(); + * } + * </pre> + * <p> + * The proxy created above will provide these three methods + * using an instance of {@link MBeanServerInvocationHandler}. + * The two methods, {@code getName} and {@code setName} define + * an attribute, {@code Name}, so a call to {@code getName()} + * will return the value of {@code server.getAttribute(name, + * "Name")}, while {@code setName(newName)} will result in a + * call to {@code server.setAttribute(name, new Attribute("Name", + * newName))}. Finally, {@code doStuff()}, as an operation, + * will cause the proxy to call {@link MBeanServer#invoke(ObjectName, + * String, Object[], String[])} as + * {@code server.invoke(name, "doStuff", null, null)}. + * </p> + * <p> + * Calling this method is equivalent to calling + * {@link #newMBeanProxy(MBeanServerConnection, ObjectName, Class, + * boolean)}. + * </p> + * + * @param conn the server connection over which to forward calls to + * the bean. + * @param name the registered name of the bean to use to implement + * the given interface. + * @param iface the interface to provide a proxy for. + * @return a proxy implementing the specified interface using calls + * to the methods of the bean registered with the supplied + * server using the given name. + * @see #newMBeanProxy(MBeanServerConnection, ObjectName, Class, + * boolean) + */ + public static <T> T newMBeanProxy(MBeanServerConnection conn, + ObjectName name, Class<T> iface) + { + return newMBeanProxy(conn, name, iface, false); + } + + /** + * Returns a proxy for a standard management bean, using + * the specified connection to access the named implementation, + * as with {@link #newMBeanProxy(MBeanServerConnection, ObjectName, + * Class)}. In addition, the proxy returned by this method will + * also implement {@link NotificationEmitter} if {@code bcast} is + * true, under the assumption that the implementation referenced by + * {@code name} implements this interface. Calls to the methods of + * {@link NotificationEmitter} will be forwarded to the bean + * implementation via the appropriate server methods. + * + * @param conn the server connection over which to forward calls to + * the bean. + * @param name the registered name of the bean to use to implement + * the given interface. + * @param iface the interface to provide a proxy for. + * @param bcast true if the proxy should implement + * {@link NotificationEmitter}. + * @return a proxy implementing the specified interface using calls + * to the methods of the bean registered with the supplied + * server using the given name. + * @see #newMBeanProxy(MBeanServerConnection, ObjectName, Class) + */ + public static <T> T newMBeanProxy(MBeanServerConnection conn, + ObjectName name, Class<T> iface, + boolean bcast) + { + return MBeanServerInvocationHandler.newProxyInstance(conn, name, + iface, bcast); + } + + /** + * <p> + * Returns a proxy for a {@link MXBean}, using the specified + * connection to access the named implementation. + * To create a proxy for the bean, {@code SomethingMXBean}, a call to + * {@code JMX.newMXBeanProxy(server, name, SomethingMXBean.class)} + * is made, where {@code server} is a local or remote management + * server, and {@code name} is the registered {@link ObjectName} + * of the implementation of {@code SomethingMBean} to use. + * </p> + * <p> + * The proxy redirects calls to the methods of the interface, + * {@link SomethingMXBean}, to the appropriate methods of the + * management server with appropriate conversion between + * Java and open types, according to the MXBean rules. If + * {@link SomethingMXBean} is specified as follows: + * </p> + * <pre> + * public interface SomethingMXBean + * { + * String getName(); + * void setName(String name); + * List<Double> getStatistics(); + * void setStatistics(List<Double> statistics); + * List<Double> getNamedStatistics(String, Map<String,Integer>); + * } + * </pre> + * <p> + * The proxy created above will provide these five methods + * using an instance of {@link MBeanServerInvocationHandler}. + * The two methods, {@code getName} and {@code setName} define + * an attribute, {@code Name}, so a call to {@code getName()} + * will return the value of {@code server.getAttribute(name, + * "Name")}, while {@code setName(newName)} will result in a + * call to {@code server.setAttribute(name, new Attribute("Name", + * newName))}. As this uses a simple type, {@link String}, no + * conversion is necessary. + * </p> + * <p> + * The two methods, {@code getStatistics} and {@code setStatistics} + * similarly define another attribute, {@code Statistics}. Calling + * {@code getStatistics()} will cause a call to the server to be + * made as before, {@code server.getAttribute(name, "Statistics")}. + * However, the type of the return value from this call will be + * an array of {@link Double} objects, as per the {@link MXBean} + * rules. The proxy converts this back in to a {@link java.util.List} + * of {@link Double} objects before returning it. + * </p> + * <p> + * The same process is applied in reverse for + * {@code setStatistics(newStats)}. The list is converted into + * an appropriate array before the call to + * {@link MBeanServerConnection#setAttribute(ObjectName, Attribute)} + * is made. Finally, a call to {@code getNamedStatistics} will require + * both a Java to open type conversion on the arguments, and then + * an open type to Java conversion of the return value. Thus, a proxy + * enables an {@link MXBean} to be used in cases where the appropriate + * Java types are available and the user wishes to access the bean + * using the types directly defined in its interface, just as with + * standard management beans. + * </p> + * <p> + * Calling this method is equivalent to calling + * {@link #newMXBeanProxy(MBeanServerConnection, ObjectName, Class, + * boolean)}. + * </p> + * + * @param conn the server connection over which to forward calls to + * the bean. + * @param name the registered name of the bean to use to implement + * the given interface. + * @param iface the interface to provide a proxy for. + * @return a proxy implementing the specified interface using calls + * to the methods of the bean registered with the supplied + * server using the given name. + * @see #newMXBeanProxy(MBeanServerConnection, ObjectName, Class, + * boolean) + */ + public static <T> T newMXBeanProxy(MBeanServerConnection conn, + ObjectName name, Class<T> iface) + { + return newMBeanProxy(conn, name, iface, false); + } + + /** + * Returns a proxy for a {@link MXBean}, using + * the specified connection to access the named implementation, + * as with {@link #newMXBeanProxy(MBeanServerConnection, ObjectName, + * Class)}. In addition, the proxy returned by this method will + * also implement {@link NotificationEmitter} if {@code bcast} is + * true, under the assumption that the implementation referenced by + * {@code name} implements this interface. Calls to the methods of + * {@link NotificationEmitter} will be forwarded to the bean + * implementation via the appropriate server methods. + * + * @param conn the server connection over which to forward calls to + * the bean. + * @param name the registered name of the bean to use to implement + * the given interface. + * @param iface the interface to provide a proxy for. + * @param bcast true if the proxy should implement + * {@link NotificationEmitter}. + * @return a proxy implementing the specified interface using calls + * to the methods of the bean registered with the supplied + * server using the given name. + * @see #newMXBeanProxy(MBeanServerConnection, ObjectName, Class) + */ + public static <T> T newMXBeanProxy(MBeanServerConnection conn, + ObjectName name, Class<T> iface, + boolean bcast) + { + if (bcast) + return (T) Proxy.newProxyInstance(iface.getClassLoader(), + new Class[] { iface, + NotificationEmitter.class }, + new MBeanServerInvocationHandler(conn,name,true)); + else + return (T) Proxy.newProxyInstance(iface.getClassLoader(), + new Class[] { iface }, + new MBeanServerInvocationHandler(conn,name,true)); + } + +} diff --git a/javax/management/MBeanServerInvocationHandler.java b/javax/management/MBeanServerInvocationHandler.java new file mode 100644 index 000000000..948996764 --- /dev/null +++ b/javax/management/MBeanServerInvocationHandler.java @@ -0,0 +1,400 @@ +/* MBeanServerInvocationHandler.java -- Provides a proxy for a bean. + Copyright (C) 2007 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 gnu.javax.management.Translator; + +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; + +/** + * <p> + * Provides a proxy for a management bean. The methods + * of the given interface are fulfilled by redirecting the + * calls over an {@link MBeanServerConnection} to the bean + * specified by the supplied {@link ObjectName}. + * </p> + * <p> + * The {@link java.lang.reflect.InvocationHandler} also makes + * provision for {@link MXBean}s by providing type conversion + * according to the rules defined for these beans. The input + * parameters are converted to their equivalent open type before + * calling the method, and then the return value is converted + * back from its open type to the appropriate Java type. For + * example, a method that takes an {@link Enum} as input and + * returns a {@link java.util.List} will have the input value + * converted from an {@link Enum} to a {@link String}, while + * the return value will be converted from its return type + * (an appropriately typed array) to a {@link java.util.List}. + * </p> + * <p> + * The proxy has special cases for the {@link Object#equals(Object)}, + * {@link Object#hashCode()} and {@link Object#toString()} methods. + * Unless they are specified explictly by the interface, the + * following behaviour is provided for these methods by the proxy: + * </p> + * <ul> + * <li><code>equals(Object)</code> returns true if the other object + * is an {@link MBeanServerInvocationHandler} with the same + * {@link MBeanServerConnection} and {@link ObjectName}. If an + * interface class was specified on construction for one of the + * proxies, then the same class must have also been specified + * for the other.</li> + * <li><code>hashCode()</code> returns the same value for + * equivalent proxies.</li> + * <li><code>toString()</code> returns a textual representation + * of the proxy.</li> + * </ul> + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.5 + */ +public class MBeanServerInvocationHandler + implements InvocationHandler +{ + + /** + * The connection used to make the calls. + */ + private MBeanServerConnection conn; + + /** + * The name of the bean to perform operations on. + */ + private ObjectName name; + + /** + * True if this proxy is for an {@link MXBean}. + */ + private boolean mxBean; + + /** + * The interface class associated with the bean. + */ + private Class<?> iface; + + /** + * Constructs a new {@link MBeanServerInvocationHandler} + * which forwards methods to the supplied bean via the + * given {@link MBeanServerConnection}. This constructor + * is used in preference to + * {@link JMX#newMBeanProxy(MBeanServerConnection, ObjectName, + * Class<T>)} if you wish to make your own call to + * {@link java.lang.reflect.Proxy#newInstance(ClassLoader, + * Class[], java.lang.reflect.InvocationHandler)} with + * a different {@link ClassLoader}. Calling this constructor + * is equivalent to <code>MBeanServerInvocationHandler(conn, + * name, false)</code>. The other constructor should be used + * instead if the bean being proxied is an {@link MXBean}. + * + * @param conn the connection through which methods will + * be forwarded to the bean. + * @param name the name of the bean to use to provide the + * actual calls. + */ + public MBeanServerInvocationHandler(MBeanServerConnection conn, + ObjectName name) + { + this(conn, name, false); + } + + /** + * Constructs a new {@link MBeanServerInvocationHandler} + * which forwards methods to the supplied bean via the + * given {@link MBeanServerConnection}. This constructor + * is used in preference to + * {@link JMX#newMBeanProxy(MBeanServerConnection, ObjectName, + * Class<T>)} if you wish to make your own call to + * {@link java.lang.reflect.Proxy#newInstance(ClassLoader, + * Class[], java.lang.reflect.InvocationHandler)} with + * a different {@link ClassLoader}. + * + * @param conn the connection through which methods will + * be forwarded to the bean. + * @param name the name of the bean to use to provide the + * actual calls. + * @param mxBean true if the bean being proxied is an + * {@link MXBean}. + * @since 1.6 + */ + public MBeanServerInvocationHandler(MBeanServerConnection conn, + ObjectName name, boolean mxBean) + { + this.conn = conn; + this.name = name; + this.mxBean = mxBean; + } + + /** + * Returns the connection through which the calls to the bean + * will be made. + * + * @return the connection being used to forward the calls to + * the bean. + * @since 1.6 + */ + public MBeanServerConnection getMBeanServerConnection() + { + return conn; + } + + /** + * Returns the name of the bean to which method calls are made. + * + * @return the bean which provides the actual method calls. + * @since 1.6 + */ + public ObjectName getObjectName() + { + return name; + } + + /** + * Called by the proxy class whenever a method is called. The method + * is emulated by retrieving an attribute from, setting an attribute on + * or invoking a method on the server connection as required. Translation + * between the Java data types supplied as arguments to the open types used + * by the bean is provided, as well as translation of the return value back + * in to the appropriate Java type if the bean is an {@link MXBean}. + * + * @param proxy the proxy on which the method was called. + * @param method the method which was called. + * @param args the arguments supplied to the method. + * @return the return value from the method. + * @throws Throwable if an exception is thrown in performing the + * method emulation. + */ + public Object invoke(Object proxy, Method method, Object[] args) + throws Throwable + { + String mName = method.getName(); + Class proxyClass = proxy.getClass(); + if (mName.equals("toString")) + { + if (inInterface(mName, proxyClass)) + return conn.invoke(name,mName,null,null); + else + return proxyClass.getName() + "[name=" + name + + ", conn=" + conn + "]"; + } + if (mName.equals("hashCode")) + { + if (inInterface(mName, proxyClass)) + return conn.invoke(name,mName,null,null); + else + return conn.hashCode() + name.hashCode() + + (iface == null ? 0 : iface.hashCode()); + } + if (mName.equals("equals")) + { + if (inInterface(mName, proxyClass, Object.class)) + return conn.invoke(name,mName,new Object[]{args[0]}, + new String[]{"java.lang.Object"}); + else + { + if (args[0].getClass() != proxy.getClass()) + return false; + InvocationHandler ih = Proxy.getInvocationHandler(args[0]); + if (ih instanceof MBeanServerInvocationHandler) + { + MBeanServerInvocationHandler h = + (MBeanServerInvocationHandler) ih; + return conn.equals(h.getMBeanServerConnection()) + && name.equals(h.getObjectName()) + && (iface == null ? h.iface == null + : iface.equals(h.iface)); + } + return false; + } + } + if (NotificationEmitter.class.isAssignableFrom(proxyClass)) + { + if (mName.equals("addNotificationListener")) + { + conn.addNotificationListener(name, + (NotificationListener) args[0], + (NotificationFilter) args[1], + args[2]); + return null; + } + if (mName.equals("getNotificationInfo")) + return conn.getMBeanInfo(name).getNotifications(); + if (mName.equals("removeNotificationListener")) + { + if (args.length == 1) + conn.removeNotificationListener(name, + (NotificationListener) + args[0]); + else + conn.removeNotificationListener(name, + (NotificationListener) + args[0], + (NotificationFilter) + args[1], args[2]); + return null; + } + } + String[] sigs; + if (args == null) + sigs = null; + else + { + sigs = new String[args.length]; + for (int a = 0; a < args.length; ++a) + sigs[a] = args[a].getClass().getName(); + } + String attrib = null; + if (mName.startsWith("get")) + attrib = mName.substring(3); + else if (mName.startsWith("is")) + attrib = mName.substring(2); + if (attrib != null) + { + Object val = conn.getAttribute(name, attrib); + if (mxBean) + return Translator.toJava(val, method); + else + return val; + } + else if (mName.startsWith("set")) + { + Object arg; + if (mxBean) + arg = Translator.fromJava(args, method)[0]; + else + arg = args[0]; + conn.setAttribute(name, new Attribute(mName.substring(3), arg)); + return null; + } + if (mxBean) + return Translator.toJava(conn.invoke(name, mName, + Translator.fromJava(args,method), + sigs), method); + else + return conn.invoke(name, mName, args, sigs); + } + + /** + * Returns true if this is a proxy for an {@link MXBean} + * and conversions must be applied to input parameters + * and return types, according to the rules for such beans. + * + * @return true if this is a proxy for an {@link MXBean}. + * @since 1.6 + */ + public boolean isMXBean() + { + return mxBean; + } + + /** + * <p> + * Returns a proxy for the specified bean. A proxy object is created + * using <code>Proxy.newProxyInstance(iface.getClassLoader(), + * new Class[] { iface }, handler)</code>. The + * {@link javax.management.NotificationEmitter} class is included as the + * second element of the array if <code>broadcaster</code> is true. + * <code>handler</code> refers to the invocation handler which forwards + * calls to the connection, which is created by a call to + * <code>new MBeanServerInvocationHandler(conn, name)</code>. + * </p> + * <p> + * <strong>Note</strong>: use of the proxy may result in + * {@link java.io.IOException}s from the underlying + * {@link MBeanServerConnection}. + * As of 1.6, the use of {@link JMX#newMBeanProxy(MBeanServerConnection, + * ObjectName,Class)} and {@link JMX#newMBeanProxy(MBeanServerConnection, + * ObjectName,Class,boolean)} is preferred. + * </p> + * + * @param conn the server connection to use to access the bean. + * @param name the {@link javax.management.ObjectName} of the + * bean to provide a proxy for. + * @param iface the interface for the bean being proxied. + * @param broadcaster true if the proxy should implement + * {@link NotificationEmitter}. + * @return a proxy for the specified bean. + * @see JMX#newMBeanProxy(MBeanServerConnection,ObjectName,Class) + */ + public static <T> T newProxyInstance(MBeanServerConnection conn, + ObjectName name, Class<T> iface, + boolean broadcaster) + { + if (broadcaster) + return (T) Proxy.newProxyInstance(iface.getClassLoader(), + new Class[] { iface, + NotificationEmitter.class }, + new MBeanServerInvocationHandler(conn,name)); + else + return (T) Proxy.newProxyInstance(iface.getClassLoader(), + new Class[] { iface }, + new MBeanServerInvocationHandler(conn,name)); + } + + /** + * Returns true if the specified method is specified + * by one of the proxy's interfaces. + * + * @param name the name of the method to search for. + * @param proxyClass the class of the proxy. + * @param args the arguments to the method. + * @return true if one of the interfaces specifies the + * given method. + */ + private boolean inInterface(String name, Class<?> proxyClass, + Class<?>... args) + { + for (Class<?> iface : proxyClass.getInterfaces()) + { + try + { + iface.getMethod(name, args); + return true; + } + catch (NoSuchMethodException e) + { + /* Ignored; this interface doesn't specify + the method. */ + } + } + return false; + } + +} + diff --git a/javax/management/MXBean.java b/javax/management/MXBean.java new file mode 100644 index 000000000..7b3af541c --- /dev/null +++ b/javax/management/MXBean.java @@ -0,0 +1,82 @@ +/* MXBean.java - Marks a management bean interface as an MXBean. + Copyright (C) 2007 Free Software Foundation + +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.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.RetentionPolicy.RUNTIME; +import static java.lang.annotation.ElementType.TYPE; + +/** + * <p> + * An annotation used to explictly mark an interface + * as defining (or not defining) an {@link MXBean}. By + * default, such beans are taken to be those whose interface + * has the suffix {@code "MXBean"}. The presence of this + * annotation overrides this intuition. The following + * interfaces would be classed as {@link MXBean}s: + * </p> + * <ul> + * <li>{@code public interface SomethingMXBean{}}</li> + * <li>{@code @MXBean public interface Someat{}}</li> + * <li>{@code @MXBean(true) public interface SomeatElse{}}</li> + * </ul> + * <p>The following would not:</p> + * <ul> + * <li>{@code public interface RandomInterface{}}</li> + * <li>{@code @MXBean(false) public interface SomethingMXBean{}}</li> + * </ul> + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.6 + */ +@Documented @Retention(RUNTIME) @Target(TYPE) +public @interface MXBean +{ + + /** + * Returns true if the annotated interface + * is an {@link MXBean}. + * + * @return true if the interface is an {@link MXBean}. + */ + boolean value(); + +} diff --git a/javax/management/ObjectName.java b/javax/management/ObjectName.java index 8259eab02..49d063543 100644 --- a/javax/management/ObjectName.java +++ b/javax/management/ObjectName.java @@ -167,6 +167,9 @@ public class ObjectName for (int a = 0; a < pairs.length; ++a) { int sep = pairs[a].indexOf('='); + if (sep == -1) + throw new MalformedObjectNameException("A key must be " + + "followed by a value."); String key = pairs[a].substring(0, sep); if (properties.containsKey(key)) throw new MalformedObjectNameException("The same key occurs " + diff --git a/javax/management/StandardMBean.java b/javax/management/StandardMBean.java index b31436c6e..9d9bce4cf 100644 --- a/javax/management/StandardMBean.java +++ b/javax/management/StandardMBean.java @@ -106,10 +106,19 @@ public class StandardMBean } catch (ClassNotFoundException e) { - throw (NotCompliantMBeanException) - (new NotCompliantMBeanException("An interface, " + className + - "MBean, for the class " + className + - " was not found.").initCause(e)); + for (Class<?> nextIface : getClass().getInterfaces()) + { + if (JMX.isMXBeanInterface(nextIface)) + { + iface = nextIface; + break; + } + } + if (iface == null) + throw (NotCompliantMBeanException) + (new NotCompliantMBeanException("An interface for the class " + + className + + " was not found.").initCause(e)); } } if (!(iface.isInstance(this))) @@ -140,18 +149,28 @@ public class StandardMBean throw new IllegalArgumentException("The specified implementation is null."); if (iface == null) { - String className = impl.getClass().getName(); + Class<?> implClass = impl.getClass(); + String className = implClass.getName(); try { this.iface = Class.forName(className + "MBean", true, - impl.getClass().getClassLoader()); + implClass.getClassLoader()); } catch (ClassNotFoundException e) { - throw (NotCompliantMBeanException) - (new NotCompliantMBeanException("An interface, " + className + - "MBean, for the class " + className + - " was not found.").initCause(e)); + for (Class<?> nextIface : implClass.getInterfaces()) + { + if (JMX.isMXBeanInterface(nextIface)) + { + this.iface = nextIface; + break; + } + } + if (this.iface == null) + throw (NotCompliantMBeanException) + (new NotCompliantMBeanException("An interface for the class " + + className + + " was not found.").initCause(e)); } } else @@ -753,19 +772,30 @@ public class StandardMBean public Object invoke(String name, Object[] params, String[] signature) throws MBeanException, ReflectionException { - Class[] sigTypes = new Class[signature.length]; + if (name.startsWith("get") || name.startsWith("is") || + name.startsWith("set")) + throw new ReflectionException(new NoSuchMethodException(), + "Invocation of an attribute " + + "method is disallowed."); 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."); - } + Class[] sigTypes; + if (signature != null) + { + sigTypes = new Class[signature.length]; + 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."); + } + } + else + sigTypes = null; Method method; try { @@ -826,11 +856,12 @@ public class StandardMBean { Method setter; String name = attribute.getName(); + Object val = attribute.getValue(); try { setter = iface.getMethod("set" + name.substring(0, 1).toUpperCase() + - name.substring(1), null); + name.substring(1), val.getClass()); } catch (NoSuchMethodException e) { @@ -840,7 +871,7 @@ public class StandardMBean } try { - setter.invoke(impl, new Object[] { attribute.getValue() }); + setter.invoke(impl, new Object[] { val }); } catch (IllegalAccessException e) { diff --git a/javax/management/openmbean/OpenType.java b/javax/management/openmbean/OpenType.java index 13c9e8a3e..2f827b59f 100644 --- a/javax/management/openmbean/OpenType.java +++ b/javax/management/openmbean/OpenType.java @@ -39,6 +39,9 @@ package javax.management.openmbean; import java.io.Serializable; +import java.util.Arrays; +import java.util.List; + /** * The superclass of all open types, which describe the * applicable data values for open MBeans. An open type @@ -48,7 +51,7 @@ import java.io.Serializable; * @author Andrew John Hughes (gnu_andrew@member.fsf.org) * @since 1.5 */ -public abstract class OpenType +public abstract class OpenType<T> implements Serializable { @@ -76,7 +79,10 @@ public abstract class OpenType * An array which defines the set of Java types which can be * used as open types. Note that each type is also available * in array form, possibly with multiple dimensions. + * + * @deprecated Use {@link ALLOWED_CLASSNAMES_LIST} instead. */ + @Deprecated public static final String[] ALLOWED_CLASSNAMES = { "java.lang.Void", "java.lang.Boolean", @@ -97,6 +103,14 @@ public abstract class OpenType }; /** + * A list which defines the set of Java types that may be + * used as open types. Note that each type is also available + * in array form, possibly with multiple dimensions. + */ + public static final List<String> ALLOWED_CLASSNAMES_LIST = + Arrays.asList(ALLOWED_CLASSNAMES); + + /** * Constructs a new {@link OpenType} for the specified class * with the given name and description. The name of the class * must be taken from the list of {@link ALLOWED_CLASSNAMES}. |