diff options
author | upstream source tree <ports@midipix.org> | 2015-03-15 20:14:05 -0400 |
---|---|---|
committer | upstream source tree <ports@midipix.org> | 2015-03-15 20:14:05 -0400 |
commit | 554fd8c5195424bdbcabf5de30fdc183aba391bd (patch) | |
tree | 976dc5ab7fddf506dadce60ae936f43f58787092 /libjava/classpath/gnu/javax/management | |
download | cbb-gcc-4.6.4-554fd8c5195424bdbcabf5de30fdc183aba391bd.tar.bz2 cbb-gcc-4.6.4-554fd8c5195424bdbcabf5de30fdc183aba391bd.tar.xz |
obtained gcc-4.6.4.tar.bz2 from upstream website;upstream
verified gcc-4.6.4.tar.bz2.sig;
imported gcc-4.6.4 source tree from verified upstream tarball.
downloading a git-generated archive based on the 'upstream' tag
should provide you with a source tree that is binary identical
to the one extracted from the above tarball.
if you have obtained the source via the command 'git clone',
however, do note that line-endings of files in your working
directory might differ from line-endings of the respective
files in the upstream repository.
Diffstat (limited to 'libjava/classpath/gnu/javax/management')
-rw-r--r-- | libjava/classpath/gnu/javax/management/ListenerData.java | 136 | ||||
-rw-r--r-- | libjava/classpath/gnu/javax/management/Server.java | 2233 | ||||
-rw-r--r-- | libjava/classpath/gnu/javax/management/Translator.java | 550 |
3 files changed, 2919 insertions, 0 deletions
diff --git a/libjava/classpath/gnu/javax/management/ListenerData.java b/libjava/classpath/gnu/javax/management/ListenerData.java new file mode 100644 index 000000000..31fdeccf0 --- /dev/null +++ b/libjava/classpath/gnu/javax/management/ListenerData.java @@ -0,0 +1,136 @@ +/* ListenerData.java - Class to contain data about management bean listeners + Copyright (C) 2006 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 gnu.javax.management; + +import javax.management.NotificationFilter; +import javax.management.NotificationListener; + +/** + * Container for data on management listeners. Wraps + * a {@link javax.management.NotificationListener}, + * {@link javax.management.NotificationFilter} and + * passback object in one class. + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.5 + */ +public class ListenerData +{ + /** + * The listener itself. + */ + private NotificationListener listener; + + /** + * A filter to apply to incoming events. + */ + private NotificationFilter filter; + + /** + * An object to pass back to the listener on an + * event occurring. + */ + private Object passback; + + /** + * Constructs a new {@link ListenerData} with the specified + * listener, filter and passback object. + * + * @param listener the listener itself. + * @param filter the filter for incoming events. + * @param passback the object to passback on an incoming event. + */ + public ListenerData(NotificationListener listener, + NotificationFilter filter, Object passback) + { + this.listener = listener; + this.filter = filter; + this.passback = passback; + } + + /** + * Returns the listener. + * + * @return the listener. + */ + public NotificationListener getListener() + { + return listener; + } + + /** + * Returns the filter. + * + * @return the filter. + */ + public NotificationFilter getFilter() + { + return filter; + } + + /** + * Returns the passback object. + * + * @return the passback object. + */ + public Object getPassback() + { + return passback; + } + + /** + * Returns true if the supplied object is an instance of + * {@link ListenerData} and has the same listener, filter + * and passback object. + * + * @param obj the object to check. + * @return true if <code>obj</code> is equal to this. + */ + public boolean equals(Object obj) + { + if (obj instanceof ListenerData) + { + ListenerData data = (ListenerData) obj; + return (data.getListener() == listener && + data.getFilter() == filter && + data.getPassback() == passback); + } + return false; + } + +} diff --git a/libjava/classpath/gnu/javax/management/Server.java b/libjava/classpath/gnu/javax/management/Server.java new file mode 100644 index 000000000..50252d4dd --- /dev/null +++ b/libjava/classpath/gnu/javax/management/Server.java @@ -0,0 +1,2233 @@ +/* Server.java -- A GNU Classpath management server. + 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 gnu.javax.management; + +import java.io.ByteArrayInputStream; +import java.io.InputStream; +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectStreamClass; +import java.io.StreamCorruptedException; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.ConcurrentHashMap; + +import javax.management.Attribute; +import javax.management.AttributeList; +import javax.management.AttributeNotFoundException; +import javax.management.BadAttributeValueExpException; +import javax.management.BadBinaryOpValueExpException; +import javax.management.BadStringOperationException; +import javax.management.DynamicMBean; +import javax.management.InstanceAlreadyExistsException; +import javax.management.InstanceNotFoundException; +import javax.management.IntrospectionException; +import javax.management.InvalidApplicationException; +import javax.management.InvalidAttributeValueException; +import javax.management.ListenerNotFoundException; +import javax.management.MalformedObjectNameException; +import javax.management.MBeanException; +import javax.management.MBeanInfo; +import javax.management.MBeanPermission; +import javax.management.MBeanRegistration; +import javax.management.MBeanRegistrationException; +import javax.management.MBeanServer; +import javax.management.MBeanServerDelegate; +import javax.management.MBeanServerNotification; +import javax.management.MBeanTrustPermission; +import javax.management.NotCompliantMBeanException; +import javax.management.Notification; +import javax.management.NotificationBroadcaster; +import javax.management.NotificationEmitter; +import javax.management.NotificationFilter; +import javax.management.NotificationListener; +import javax.management.ObjectInstance; +import javax.management.ObjectName; +import javax.management.OperationsException; +import javax.management.QueryExp; +import javax.management.ReflectionException; +import javax.management.RuntimeOperationsException; +import javax.management.StandardMBean; + +import javax.management.loading.ClassLoaderRepository; + +/** + * This class provides an {@link javax.management.MBeanServer} + * implementation for GNU Classpath. + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.5 + */ +public class Server + implements MBeanServer +{ + + /** + * The name of the delegate bean. + */ + private static final ObjectName DELEGATE_NAME; + + /** + * The registered beans, represented as a map of + * {@link javax.management.ObjectName}s to + * {@link gnu.javax.management.Server.ServerInfo}s. + */ + private final ConcurrentHashMap<ObjectName,ServerInfo> beans = + new ConcurrentHashMap<ObjectName,ServerInfo>(); + + /** + * The default domain. + */ + private final String defaultDomain; + + /** + * The outer server. + */ + private final MBeanServer outer; + + /** + * The class loader repository. + */ + private ClassLoaderRepository repository; + + /** + * The map of listener delegates to the true + * listener. We wrap this in an inner class + * to delay initialisation until a listener + * is actually added. + */ + private static class LazyListenersHolder + { + private static final Map<NotificationListener,NotificationListener> listeners = + new ConcurrentHashMap<NotificationListener,NotificationListener>(); + } + + /** + * An MBean that emits notifications when an MBean is registered and + * unregistered with this server. + * + */ + private final MBeanServerDelegate delegate; + + /** + * Provides sequencing for notifications about registrations. + */ + private static final AtomicLong sequenceNumber = new AtomicLong(1); + + /** + * Initialise the delegate name. + */ + static + { + try + { + DELEGATE_NAME = + new ObjectName("JMImplementation:type=MBeanServerDelegate"); + } + catch (MalformedObjectNameException e) + { + throw (Error) + (new InternalError("Failed to construct " + + "the delegate's object name.").initCause(e)); + } + } + + /** + * Constructs a new management server using the specified + * default domain, delegate bean and outer server. + * + * @param defaultDomain the default domain to use for beans constructed + * with no specified domain. + * @param outer an {@link javax.management.MBeanServer} to pass + * to beans implementing the {@link MBeanRegistration} + * interface, or <code>null</code> if <code>this</code> + * should be passed. + * @param delegate the delegate bean for this server. + */ + public Server(String defaultDomain, MBeanServer outer, + MBeanServerDelegate delegate) + { + this.defaultDomain = defaultDomain; + this.outer = outer; + this.delegate = delegate; + try + { + registerMBean(delegate, DELEGATE_NAME); + } + catch (InstanceAlreadyExistsException e) + { + throw (Error) + (new InternalError("The delegate bean is " + + "already registered.").initCause(e)); + } + catch (MBeanRegistrationException e) + { + throw (Error) + (new InternalError("The delegate bean's preRegister " + + "methods threw an exception.").initCause(e)); + } + catch (NotCompliantMBeanException e) + { + throw (Error) + (new InternalError("The delegate bean is " + + "not compliant.").initCause(e)); + } + } + + /** + * Checks for the necessary security privileges to perform an + * operation. + * + * @param name the name of the bean being accessed. + * @param member the name of the operation or attribute being + * accessed, or <code>null</code> if one is not + * involved. + * @param action the action being performed. + * @throws SecurityException if the action is denied. + */ + private void checkSecurity(ObjectName name, String member, + String action) + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + try + { + MBeanInfo info = null; + if (name != null) + { + Object bean = getBean(name); + Method method = bean.getClass().getMethod("getMBeanInfo"); + info = (MBeanInfo) method.invoke(bean); + } + sm.checkPermission(new MBeanPermission((info == null) ? + null : info.getClassName(), + member, name, action)); + } + catch (InstanceNotFoundException e) + { + throw (Error) + (new InternalError("Failed to get bean.").initCause(e)); + } + catch (NoSuchMethodException e) + { + throw (Error) + (new InternalError("Failed to get bean info.").initCause(e)); + } + catch (IllegalAccessException e) + { + throw (Error) + (new InternalError("Failed to get bean info.").initCause(e)); + } + catch (IllegalArgumentException e) + { + throw (Error) + (new InternalError("Failed to get bean info.").initCause(e)); + } + catch (InvocationTargetException e) + { + throw (Error) + (new InternalError("Failed to get bean info.").initCause(e)); + } + } + + /** + * Retrieves the specified bean. + * + * @param name the name of the bean. + * @return the bean. + * @throws InstanceNotFoundException if the name of the management bean + * could not be resolved. + */ + private Object getBean(ObjectName name) + throws InstanceNotFoundException + { + ServerInfo bean = beans.get(name); + if (bean == null) + throw new InstanceNotFoundException("The bean, " + name + + ", was not found."); + return bean.getObject(); + } + + /** + * Registers the supplied listener with the specified management + * bean. Notifications emitted by the management bean are forwarded + * to the listener via the server, which will convert an MBean + * references in the source to a portable {@link ObjectName} + * instance. The notification is otherwise unchanged. + * + * @param name the name of the management bean with which the listener + * should be registered. + * @param listener the listener which will handle notifications from + * the bean. + * @param filter the filter to apply to incoming notifications, or + * <code>null</code> if no filtering should be applied. + * @param passback an object to be passed to the listener when a + * notification is emitted. + * @throws InstanceNotFoundException if the name of the management bean + * could not be resolved. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * <code>MBeanPermission(className, null, name, + * "addNotificationListener")</code>}. + * @see #removeNotificationListener(ObjectName, NotificationListener) + * @see #removeNotificationListener(ObjectName, NotificationListener, + * NotificationFilter, Object) + * @see NotificationBroadcaster#addNotificationListener(NotificationListener, + * NotificationFilter, + * Object) + */ + public void addNotificationListener(ObjectName name, NotificationListener listener, + NotificationFilter filter, Object passback) + throws InstanceNotFoundException + { + Object bean = getBean(name); + checkSecurity(name, null, "addNotificationListener"); + if (bean instanceof NotificationBroadcaster) + { + NotificationBroadcaster bbean = (NotificationBroadcaster) bean; + NotificationListener indirection = new ServerNotificationListener(bean, name, + listener); + bbean.addNotificationListener(indirection, filter, passback); + LazyListenersHolder.listeners.put(listener, indirection); + } + } + + /** + * <p> + * Registers the supplied listener with the specified management + * bean. Notifications emitted by the management bean are forwarded + * to the listener via the server, which will convert any MBean + * references in the source to portable {@link ObjectName} + * instances. The notification is otherwise unchanged. + * </p> + * <p> + * The listener that receives notifications will be the one that is + * registered with the given name at the time this method is called. + * Even if it later unregisters and ceases to use that name, it will + * still receive notifications. + * </p> + * + * @param name the name of the management bean with which the listener + * should be registered. + * @param listener the name of the listener which will handle + * notifications from the bean. + * @param filter the filter to apply to incoming notifications, or + * <code>null</code> if no filtering should be applied. + * @param passback an object to be passed to the listener when a + * notification is emitted. + * @throws InstanceNotFoundException if the name of the management bean + * could not be resolved. + * @throws RuntimeOperationsException if the bean associated with the given + * object name is not a + * {@link NotificationListener}. This + * exception wraps an + * {@link IllegalArgumentException}. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * <code>MBeanPermission(className, null, name, + * "addNotificationListener")</code>}. + * @see #removeNotificationListener(ObjectName, NotificationListener) + * @see #removeNotificationListener(ObjectName, NotificationListener, + * NotificationFilter, Object) + * @see NotificationBroadcaster#addNotificationListener(NotificationListener, + * NotificationFilter, + * Object) + */ + public void addNotificationListener(ObjectName name, ObjectName listener, + NotificationFilter filter, Object passback) + throws InstanceNotFoundException + { + Object lbean = getBean(listener); + if (!(lbean instanceof NotificationListener)) + { + RuntimeException e = + new IllegalArgumentException("The supplied listener name does not " + + "correspond to a notification listener."); + throw new RuntimeOperationsException(e); + } + addNotificationListener(name, ((NotificationListener) lbean), filter, passback); + } + + /** + * <p> + * Instantiates a new instance of the specified management bean + * using the default constructor and registers it with the server + * under the supplied name. The class is loaded using the + * {@link javax.management.loading.ClassLoaderRepository default + * loader repository} of the server. + * </p> + * <p> + * If the name supplied is <code>null</code>, then the bean is + * expected to implement the {@link MBeanRegistration} interface. + * The {@link MBeanRegistration#preRegister preRegister} method + * of this interface will be used to obtain the name in this case. + * </p> + * <p> + * This method is equivalent to calling {@link + * #createMBean(String, ObjectName, Object[], String[]) + * <code>createMBean(className, name, (Object[]) null, + * (String[]) null)</code>} with <code>null</code> parameters + * and signature. + * </p> + * + * @param className the class of the management bean, of which + * an instance should be created. + * @param name the name to register the new bean with. + * @return an {@link ObjectInstance} containing the {@link ObjectName} + * and Java class name of the created instance. + * @throws ReflectionException if an exception occurs in creating + * an instance of the bean. + * @throws InstanceAlreadyExistsException if a matching instance + * already exists. + * @throws MBeanRegistrationException if an exception occurs in + * calling the preRegister + * method. + * @throws MBeanException if the bean's constructor throws an exception. + * @throws NotCompliantMBeanException if the created bean is not + * compliant with the JMX specification. + * @throws RuntimeOperationsException if an {@link IllegalArgumentException} + * is thrown by the server due to a + * <code>null</code> class name or object + * name or if the object name is a pattern. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply the + * use of the <code>instantiate</code> + * and <code>registerMBean</code> methods. + * @see #createMBean(String, ObjectName, Object[], String[]) + */ + public ObjectInstance createMBean(String className, ObjectName name) + throws ReflectionException, InstanceAlreadyExistsException, + MBeanRegistrationException, MBeanException, + NotCompliantMBeanException + { + return createMBean(className, name, (Object[]) null, (String[]) null); + } + + /** + * <p> + * Instantiates a new instance of the specified management bean + * using the given constructor and registers it with the server + * under the supplied name. The class is loaded using the + * {@link javax.management.loading.ClassLoaderRepository default + * loader repository} of the server. + * </p> + * <p> + * If the name supplied is <code>null</code>, then the bean is + * expected to implement the {@link MBeanRegistration} interface. + * The {@link MBeanRegistration#preRegister preRegister} method + * of this interface will be used to obtain the name in this case. + * </p> + * + * @param className the class of the management bean, of which + * an instance should be created. + * @param name the name to register the new bean with. + * @param params the parameters for the bean's constructor. + * @param sig the signature of the constructor to use. + * @return an {@link ObjectInstance} containing the {@link ObjectName} + * and Java class name of the created instance. + * @throws ReflectionException if an exception occurs in creating + * an instance of the bean. + * @throws InstanceAlreadyExistsException if a matching instance + * already exists. + * @throws MBeanRegistrationException if an exception occurs in + * calling the preRegister + * method. + * @throws MBeanException if the bean's constructor throws an exception. + * @throws NotCompliantMBeanException if the created bean is not + * compliant with the JMX specification. + * @throws RuntimeOperationsException if an {@link IllegalArgumentException} + * is thrown by the server due to a + * <code>null</code> class name or object + * name or if the object name is a pattern. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply the + * use of the <code>instantiate</code> + * and <code>registerMBean</code> methods. + */ + public ObjectInstance createMBean(String className, ObjectName name, + Object[] params, String[] sig) + throws ReflectionException, InstanceAlreadyExistsException, + MBeanRegistrationException, MBeanException, + NotCompliantMBeanException + { + return registerMBean(instantiate(className, params, sig), name); + } + + /** + * <p> + * Instantiates a new instance of the specified management bean + * using the default constructor and registers it with the server + * under the supplied name. The class is loaded using the + * given class loader. If this argument is <code>null</code>, + * then the same class loader as was used to load the server + * is used. + * </p> + * <p> + * If the name supplied is <code>null</code>, then the bean is + * expected to implement the {@link MBeanRegistration} interface. + * The {@link MBeanRegistration#preRegister preRegister} method + * of this interface will be used to obtain the name in this case. + * </p> + * <p> + * This method is equivalent to calling {@link + * #createMBean(String, ObjectName, ObjectName, Object[], String) + * <code>createMBean(className, name, loaderName, (Object[]) null, + * (String) null)</code>} with <code>null</code> parameters + * and signature. + * </p> + * + * @param className the class of the management bean, of which + * an instance should be created. + * @param name the name to register the new bean with. + * @param loaderName the name of the class loader. + * @return an {@link ObjectInstance} containing the {@link ObjectName} + * and Java class name of the created instance. + * @throws ReflectionException if an exception occurs in creating + * an instance of the bean. + * @throws InstanceAlreadyExistsException if a matching instance + * already exists. + * @throws MBeanRegistrationException if an exception occurs in + * calling the preRegister + * method. + * @throws MBeanException if the bean's constructor throws an exception. + * @throws NotCompliantMBeanException if the created bean is not + * compliant with the JMX specification. + * @throws InstanceNotFoundException if the specified class loader is not + * registered with the server. + * @throws RuntimeOperationsException if an {@link IllegalArgumentException} + * is thrown by the server due to a + * <code>null</code> class name or object + * name or if the object name is a pattern. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply the + * use of the <code>instantiate</code> + * and <code>registerMBean</code> methods. + * @see #createMBean(String, ObjectName, ObjectName, Object[], String[]) + */ + public ObjectInstance createMBean(String className, ObjectName name, + ObjectName loaderName) + throws ReflectionException, InstanceAlreadyExistsException, + MBeanRegistrationException, MBeanException, + NotCompliantMBeanException, InstanceNotFoundException + { + return createMBean(className, name, loaderName, (Object[]) null, + (String[]) null); + } + + /** + * <p> + * Instantiates a new instance of the specified management bean + * using the given constructor and registers it with the server + * under the supplied name. The class is loaded using the + * given class loader. If this argument is <code>null</code>, + * then the same class loader as was used to load the server + * is used. + * </p> + * <p> + * If the name supplied is <code>null</code>, then the bean is + * expected to implement the {@link MBeanRegistration} interface. + * The {@link MBeanRegistration#preRegister preRegister} method + * of this interface will be used to obtain the name in this case. + * </p> + * + * @param className the class of the management bean, of which + * an instance should be created. + * @param name the name to register the new bean with. + * @param loaderName the name of the class loader. + * @param params the parameters for the bean's constructor. + * @param sig the signature of the constructor to use. + * @return an {@link ObjectInstance} containing the {@link ObjectName} + * and Java class name of the created instance. + * @throws ReflectionException if an exception occurs in creating + * an instance of the bean. + * @throws InstanceAlreadyExistsException if a matching instance + * already exists. + * @throws MBeanRegistrationException if an exception occurs in + * calling the preRegister + * method. + * @throws MBeanException if the bean's constructor throws an exception. + * @throws NotCompliantMBeanException if the created bean is not + * compliant with the JMX specification. + * @throws InstanceNotFoundException if the specified class loader is not + * registered with the server. + * @throws RuntimeOperationsException if an {@link IllegalArgumentException} + * is thrown by the server due to a + * <code>null</code> class name or object + * name or if the object name is a pattern. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply the + * use of the <code>instantiate</code> + * and <code>registerMBean</code> methods. + */ + public ObjectInstance createMBean(String className, ObjectName name, + ObjectName loaderName, Object[] params, + String[] sig) + throws ReflectionException, InstanceAlreadyExistsException, + MBeanRegistrationException, MBeanException, + NotCompliantMBeanException, InstanceNotFoundException + { + return registerMBean(instantiate(className, loaderName, params, sig), + name); + } + + /** + * Deserializes a byte array using the class loader of the specified + * management bean as its context. + * + * @param name the name of the bean whose class loader should be used. + * @param data the byte array to be deserialized. + * @return the deserialized object stream. + * @deprecated {@link #getClassLoaderFor(ObjectName)} should be used + * to obtain the class loader of the bean, which can then + * be used to perform deserialization in the user's code. + * @throws InstanceNotFoundException if the specified bean is not + * registered with the server. + * @throws OperationsException if any I/O error is thrown by the + * deserialization process. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * <code>MBeanPermission(className, null, name, + * "getClassLoaderFor")</code> + */ + public ObjectInputStream deserialize(ObjectName name, byte[] data) + throws InstanceNotFoundException, OperationsException + { + try + { + return new ServerInputStream(new ByteArrayInputStream(data), + getClassLoaderFor(name)); + } + catch (IOException e) + { + throw new OperationsException("An I/O error occurred: " + e); + } + } + + /** + * Deserializes a byte array using the same class loader for its context + * as was used to load the given class. This class loader is obtained by + * loading the specified class using the {@link + * javax.management.loading.ClassLoaderRepository Class Loader Repository} + * and then using the class loader of the resulting {@link Class} instance. + * + * @param name the name of the class which should be loaded to obtain the + * class loader. + * @param data the byte array to be deserialized. + * @return the deserialized object stream. + * @deprecated {@link #getClassLoaderRepository} should be used + * to obtain the class loading repository, which can then + * be used to obtain the {@link Class} instance and deserialize + * the array using its class loader. + * @throws OperationsException if any I/O error is thrown by the + * deserialization process. + * @throws ReflectionException if an error occurs in obtaining the + * {@link Class} instance. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * <code>MBeanPermission(null, null, null, + * "getClassLoaderRepository")</code> + */ + public ObjectInputStream deserialize(String name, byte[] data) + throws OperationsException, ReflectionException + { + try + { + Class<?> c = getClassLoaderRepository().loadClass(name); + return new ServerInputStream(new ByteArrayInputStream(data), + c.getClassLoader()); + } + catch (IOException e) + { + throw new OperationsException("An I/O error occurred: " + e); + } + catch (ClassNotFoundException e) + { + throw new ReflectionException(e, "The class could not be found."); + } + } + + /** + * Deserializes a byte array using the same class loader for its context + * as was used to load the given class. The name of the class loader to + * be used is supplied, and may be <code>null</code> if the server's + * class loader should be used instead. + * + * @param name the name of the class which should be loaded to obtain the + * class loader. + * @param loader the name of the class loader to use, or <code>null</code> + * if the class loader of the server should be used. + * @param data the byte array to be deserialized. + * @return the deserialized object stream. + * @deprecated {@link #getClassLoader(ObjectName} can be used to obtain + * the named class loader and deserialize the array. + * @throws InstanceNotFoundException if the specified class loader is not + * registered with the server. + * @throws OperationsException if any I/O error is thrown by the + * deserialization process. + * @throws ReflectionException if an error occurs in obtaining the + * {@link Class} instance. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * <code>MBeanPermission(className, null, loader, + * "getClassLoader")</code> + */ + public ObjectInputStream deserialize(String name, ObjectName loader, byte[] data) + throws InstanceNotFoundException, ReflectionException, + OperationsException + { + try + { + Class<?> c = getClassLoader(loader).loadClass(name); + return new ServerInputStream(new ByteArrayInputStream(data), + c.getClassLoader()); + } + catch (IOException e) + { + throw new OperationsException("An I/O error occurred: " + e); + } + catch (ClassNotFoundException e) + { + throw new ReflectionException(e, "The class could not be found."); + } + } + + /** + * Returns the value of the supplied attribute from the specified + * management bean. + * + * @param bean the bean to retrieve the value from. + * @param name the name of the attribute to retrieve. + * @return the value of the attribute. + * @throws AttributeNotFoundException if the attribute could not be + * accessed from the bean. + * @throws MBeanException if the management bean's accessor throws + * an exception. + * @throws InstanceNotFoundException if the bean can not be found. + * @throws ReflectionException if an exception was thrown in trying + * to invoke the bean's accessor. + * @throws RuntimeOperationsException if an {@link IllegalArgumentException} + * is thrown by the server due to a + * <code>null</code> bean or attribute + * name. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * <code>MBeanPermission(className, name, bean, + * "getAttribute")</code>}. + * @see DynamicMBean#getAttribute(String) + */ + public Object getAttribute(ObjectName bean, String name) + throws MBeanException, AttributeNotFoundException, + InstanceNotFoundException, ReflectionException + { + if (bean == null || name == null) + { + RuntimeException e = + new IllegalArgumentException("One of the supplied arguments was null."); + throw new RuntimeOperationsException(e); + } + Object abean = getBean(bean); + checkSecurity(bean, name, "getAttribute"); + if (abean instanceof DynamicMBean) + return ((DynamicMBean) abean).getAttribute(name); + else + try + { + return new StandardMBean(abean, null).getAttribute(name); + } + catch (NotCompliantMBeanException e) + { + throw (Error) + (new InternalError("Failed to create dynamic bean.").initCause(e)); + } + } + + + /** + * Returns the values of the named attributes from the specified + * management bean. + * + * @param bean the bean to retrieve the value from. + * @param names the names of the attributes to retrieve. + * @return the values of the attributes. + * @throws InstanceNotFoundException if the bean can not be found. + * @throws ReflectionException if an exception was thrown in trying + * to invoke the bean's accessor. + * @throws RuntimeOperationsException if an {@link IllegalArgumentException} + * is thrown by the server due to a + * <code>null</code> bean or attribute + * name. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * <code>MBeanPermission(className, null, bean, + * "getAttribute")</code>}. Additionally, + * for an attribute name, <code>n</code>, the + * caller's permission must imply {@link + * MBeanPermission(String,String,ObjectName,String) + * <code>MBeanPermission(className, n, bean, + * "getAttribute")</code>} or that attribute will + * not be included. + * + * @see DynamicMBean#getAttributes(String[]) + */ + public AttributeList getAttributes(ObjectName bean, String[] names) + throws InstanceNotFoundException, ReflectionException + { + if (bean == null || names == null) + { + RuntimeException e = + new IllegalArgumentException("One of the supplied arguments was null."); + throw new RuntimeOperationsException(e); + } + Object abean = getBean(bean); + checkSecurity(bean, null, "getAttribute"); + AttributeList list = new AttributeList(names.length); + for (int a = 0; a < names.length; ++a) + { + if (names[a] == null) + { + RuntimeException e = + new IllegalArgumentException("Argument " + a + " was null."); + throw new RuntimeOperationsException(e); + } + checkSecurity(bean, names[a], "getAttribute"); + try + { + Object value; + if (abean instanceof DynamicMBean) + value = ((DynamicMBean) abean).getAttribute(names[a]); + else + try + { + value = new StandardMBean(abean, null).getAttribute(names[a]); + } + catch (NotCompliantMBeanException e) + { + throw (Error) + (new InternalError("Failed to create dynamic bean.").initCause(e)); + } + list.add(new Attribute(names[a], value)); + } + catch (AttributeNotFoundException e) + { + /* Ignored */ + } + catch (MBeanException e) + { + /* Ignored */ + } + } + return list; + } + + + /** + * Returns the specified class loader. If the specified value is + * <code>null</code>, then the class loader of the server will be + * returned. If <code>l</code> is the requested class loader, + * and <code>r</code> is the actual class loader returned, then + * either <code>l</code> and <code>r</code> will be identical, + * or they will at least return the same class from + * {@link ClassLoader#loadClass(String)} for any given string. + * They may not be identical due to one or the other + * being wrapped in another class loader (e.g. for security). + * + * @param name the name of the class loader to return. + * @return the class loader. + * @throws InstanceNotFoundException if the class loader can not + * be found. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * <code>MBeanPermission(className, null, name, + * "getClassLoader")</code> + */ + public ClassLoader getClassLoader(ObjectName name) + throws InstanceNotFoundException + { + if (name == null) + { + checkSecurity(null, null, "getClassLoader"); + return getClass().getClassLoader(); + } + Object bean = getBean(name); + checkSecurity(name, null, "getClassLoader"); + return (ClassLoader) bean; + } + + /** + * Returns the class loader of the specified management bean. If + * <code>l</code> is the requested class loader, and <code>r</code> + * is the actual class loader returned, then either <code>l</code> + * and <code>r</code> will be identical, or they will at least + * return the same class from {@link ClassLoader#loadClass(String)} + * for any given string. They may not be identical due to one or + * the other being wrapped in another class loader (e.g. for + * security). + * + * @param name the name of the bean whose class loader should be + * returned. + * @return the class loader. + * @throws InstanceNotFoundException if the bean is not registered + * with the server. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * <code>MBeanPermission(className, null, name, + * "getClassLoaderFor")</code> + */ + public ClassLoader getClassLoaderFor(ObjectName name) + throws InstanceNotFoundException + { + Object bean = getBean(name); + checkSecurity(name, null, "getClassLoaderFor"); + return bean.getClass().getClassLoader(); + } + + /** + * Returns the class loader repository used by this server. + * + * @return the class loader repository. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * <code>MBeanPermission(null, null, null, + * "getClassLoaderRepository")</code> + */ + public ClassLoaderRepository getClassLoaderRepository() + { + return repository; + } + + /** + * Returns the default domain this server applies to beans that have + * no specified domain. + * + * @return the default domain. + */ + public String getDefaultDomain() + { + return defaultDomain; + } + + /** + * Returns an array containing all the domains used by beans registered + * with this server. The ordering of the array is undefined. + * + * @return the list of domains. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * <code>MBeanPermission(null, null, name, + * "getDomains")</code>}. Additionally, + * for an domain, <code>d</code>, the + * caller's permission must imply {@link + * MBeanPermission(String,String,ObjectName,String) + * <code>MBeanPermission(null, null, + * new ObjectName("d:x=x"), "getDomains")</code>} + * or that domain will not be included. Note + * that "x=x" is an arbitrary key-value pair + * provided to satisfy the constructor. + * @see ObjectName#getDomain() + */ + public String[] getDomains() + { + checkSecurity(null, null, "getDomains"); + Set<String> domains = new HashSet<String>(); + Iterator<ObjectName> iterator = beans.keySet().iterator(); + while (iterator.hasNext()) + { + String d = iterator.next().getDomain(); + try + { + checkSecurity(new ObjectName(d + ":x=x"), null, "getDomains"); + domains.add(d); + } + catch (MalformedObjectNameException e) + { + /* Ignored */ + } + } + return domains.toArray(new String[domains.size()]); + } + + /** + * Returns the number of management beans registered with this server. + * This may be less than the real number if the caller's access is + * restricted. + * + * @return the number of registered beans. + */ + public Integer getMBeanCount() + { + return Integer.valueOf(beans.size()); + } + + /** + * Returns information on the given management bean. + * + * @param name the name of the management bean. + * @return an instance of {@link MBeanInfo} for the bean. + * @throws IntrospectionException if an exception occurs in examining + * the bean. + * @throws InstanceNotFoundException if the bean can not be found. + * @throws ReflectionException if an exception occurs when trying + * to invoke {@link DynamicMBean#getMBeanInfo()} + * on the bean. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * <code>MBeanPermission(className, null, name, + * "getMBeanInfo")</code>}. + * @see DynamicMBean#getMBeanInfo() + */ + public MBeanInfo getMBeanInfo(ObjectName name) + throws InstanceNotFoundException, IntrospectionException, + ReflectionException + { + Object bean = getBean(name); + checkSecurity(name, null, "getMBeanInfo"); + try + { + Method method = bean.getClass().getMethod("getMBeanInfo"); + return (MBeanInfo) method.invoke(bean); + } + catch (NoSuchMethodException e) + { + try + { + return new StandardMBean(bean, null).getMBeanInfo(); + } + catch (NotCompliantMBeanException ex) + { + throw new IntrospectionException("An error occurred in executing " + + "getMBeanInfo on the bean: " + ex + "."); + } + } + catch (IllegalAccessException e) + { + throw new ReflectionException(e, "Failed to call getMBeanInfo"); + } + catch (IllegalArgumentException e) + { + throw new ReflectionException(e, "Failed to call getMBeanInfo"); + } + catch (InvocationTargetException e) + { + throw new ReflectionException(e, "The method threw an exception"); + } + } + + /** + * Returns the {@link ObjectInstance} created for the specified + * management bean on registration. + * + * @param name the name of the bean. + * @return the corresponding {@link ObjectInstance} instance. + * @throws InstanceNotFoundException if the bean can not be found. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * <code>MBeanPermission(className, null, name, + * "getObjectInstance")</code> + * @see #createMBean(String, ObjectName) + */ + public ObjectInstance getObjectInstance(ObjectName name) + throws InstanceNotFoundException + { + ServerInfo bean = beans.get(name); + if (bean == null) + throw new InstanceNotFoundException("The bean, " + name + + ", was not found."); + return bean.getInstance(); + } + + /** + * <p> + * Creates an instance of the specified class using the list of + * class loaders from the {@link + * javax.management.loading.ClassLoaderRepository Class Loader + * Repository}. The class should have a public constructor + * with no arguments. A reference to the new instance is returned, + * but the instance is not yet registered with the server. + * </p> + * <p> + * This method is equivalent to calling {@link + * #instantiate(String, Object[], String[]) + * <code>instantiate(name, (Object[]) null, (String[]) null)</code>} + * with <code>null</code> parameters and signature. + * </p> + * + * @param name the name of the class of bean to be instantiated. + * @return an instance of the given class. + * @throws ReflectionException if an exception is thrown during + * loading the class or calling the + * constructor. + * @throws MBeanException if the constructor throws an exception. + * @throws RuntimeOperationsException if an {@link IllegalArgumentException} + * is thrown by the server due to a + * <code>null</code> name. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * <code>MBeanPermission(className, null, null, + * "instantiate")</code>}. + * @see #instantiate(String, Object[], String[]) + */ + public Object instantiate(String name) + throws ReflectionException, MBeanException + { + return instantiate(name, (Object[]) null, (String[]) null); + } + + /** + * Creates an instance of the specified class using the list of + * class loaders from the {@link + * javax.management.loading.ClassLoaderRepository Class Loader + * Repository}. The class should have a public constructor + * matching the supplied signature. A reference to the new + * instance is returned, but the instance is not yet + * registered with the server. + * + * @param name the name of the class of bean to be instantiated. + * @param params the parameters for the constructor. + * @param sig the signature of the constructor. + * @return an instance of the given class. + * @throws ReflectionException if an exception is thrown during + * loading the class or calling the + * constructor. + * @throws MBeanException if the constructor throws an exception. + * @throws RuntimeOperationsException if an {@link IllegalArgumentException} + * is thrown by the server due to a + * <code>null</code> name. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * <code>MBeanPermission(className, null, null, + * "instantiate")</code>}. + */ + public Object instantiate(String name, Object[] params, String[] sig) + throws ReflectionException, MBeanException + { + checkSecurity(null, null, "instantiate"); + if (name == null) + { + RuntimeException e = + new IllegalArgumentException("The name was null."); + throw new RuntimeOperationsException(e); + } + Class<?>[] sigTypes = new Class[sig.length]; + for (int a = 0; a < sigTypes.length; ++a) + { + try + { + sigTypes[a] = repository.loadClass(sig[a]); + } + catch (ClassNotFoundException e) + { + throw new ReflectionException(e, "The class, " + sigTypes[a] + + ", in the method signature " + + "could not be loaded."); + } + } + try + { + Constructor<?> cons = + repository.loadClass(name).getConstructor(sigTypes); + return cons.newInstance(params); + } + catch (ClassNotFoundException e) + { + throw new ReflectionException(e, "The class, " + name + + ", of the constructor " + + "could not be loaded."); + } + catch (NoSuchMethodException e) + { + throw new ReflectionException(e, "The method, " + name + + ", could not be found."); + } + catch (IllegalAccessException e) + { + throw new ReflectionException(e, "Failed to instantiate the object"); + } + catch (InstantiationException e) + { + throw new ReflectionException(e, "Failed to instantiate the object"); + } + catch (InvocationTargetException e) + { + throw new MBeanException((Exception) e.getCause(), "The constructor " + + name + " threw an exception"); + } + } + + /** + * <p> + * Creates an instance of the specified class using the supplied + * class loader. If the class loader given is <code>null</code>, + * then the class loader of the server will be used. The class + * should have a public constructor with no arguments. A reference + * to the new instance is returned, but the instance is not yet + * registered with the server. + * </p> + * <p> + * This method is equivalent to calling {@link + * #instantiate(String, ObjectName, Object[], String[]) + * <code>instantiate(name, loaderName, (Object[]) null, + * (String[]) null)</code>} with <code>null</code> parameters + * and signature. + * </p> + * + * @param name the name of the class of bean to be instantiated. + * @param loaderName the name of the class loader to use. + * @return an instance of the given class. + * @throws InstanceNotFoundException if the class loader is not + * registered with the server. + * @throws ReflectionException if an exception is thrown during + * loading the class or calling the + * constructor. + * @throws MBeanException if the constructor throws an exception. + * @throws RuntimeOperationsException if an {@link IllegalArgumentException} + * is thrown by the server due to a + * <code>null</code> name. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * <code>MBeanPermission(className, null, null, + * "instantiate")</code>}. + * @see #instantiate(String, Object[], String[]) + */ + public Object instantiate(String name, ObjectName loaderName) + throws InstanceNotFoundException, ReflectionException, + MBeanException + { + return instantiate(name, loaderName); + } + + /** + * Creates an instance of the specified class using the supplied + * class loader. If the class loader given is <code>null</code>, + * then the class loader of the server will be used. The class + * should have a public constructor matching the supplied + * signature. A reference to the new instance is returned, + * but the instance is not yet registered with the server. + * + * @param name the name of the class of bean to be instantiated. + * @param loaderName the name of the class loader to use. + * @param params the parameters for the constructor. + * @param sig the signature of the constructor. + * @return an instance of the given class. + * @throws InstanceNotFoundException if the class loader is not + * registered with the server. + * @throws ReflectionException if an exception is thrown during + * loading the class or calling the + * constructor. + * @throws MBeanException if the constructor throws an exception. + * @throws RuntimeOperationsException if an {@link IllegalArgumentException} + * is thrown by the server due to a + * <code>null</code> name. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * <code>MBeanPermission(className, null, null, + * "instantiate")</code>}. + */ + public Object instantiate(String name, ObjectName loaderName, + Object[] params, String[] sig) + throws InstanceNotFoundException, ReflectionException, + MBeanException + { + checkSecurity(null, null, "instantiate"); + if (name == null) + { + RuntimeException e = + new IllegalArgumentException("The name was null."); + throw new RuntimeOperationsException(e); + } + ClassLoader loader = getClassLoader(loaderName); + Class<?>[] sigTypes = new Class[sig.length]; + for (int a = 0; a < sig.length; ++a) + { + try + { + sigTypes[a] = Class.forName(sig[a], true, loader); + } + catch (ClassNotFoundException e) + { + throw new ReflectionException(e, "The class, " + sig[a] + + ", in the method signature " + + "could not be loaded."); + } + } + try + { + Constructor<?> cons = + Class.forName(name, true, loader).getConstructor(sigTypes); + return cons.newInstance(params); + } + catch (ClassNotFoundException e) + { + throw new ReflectionException(e, "The class, " + name + + ", of the constructor " + + "could not be loaded."); + } + catch (NoSuchMethodException e) + { + throw new ReflectionException(e, "The method, " + name + + ", could not be found."); + } + catch (IllegalAccessException e) + { + throw new ReflectionException(e, "Failed to instantiate the object"); + } + catch (InstantiationException e) + { + throw new ReflectionException(e, "Failed to instantiate the object"); + } + catch (InvocationTargetException e) + { + throw new MBeanException((Exception) e.getCause(), "The constructor " + + name + " threw an exception"); + } + } + + /** + * Invokes the supplied operation on the specified management + * bean. The class objects specified in the signature are loaded + * using the same class loader as was used for the management bean. + * + * @param bean the management bean whose operation should be invoked. + * @param name the name of the operation to invoke. + * @param params the parameters of the operation. + * @param sig the signature of the operation. + * @return the return value of the method. + * @throws InstanceNotFoundException if the bean can not be found. + * @throws MBeanException if the method invoked throws an exception. + * @throws RuntimeOperationsException if an {@link IllegalArgumentException} + * is thrown by the server due to a + * <code>null</code> name. + * @throws ReflectionException if an exception is thrown in invoking the + * method. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * <code>MBeanPermission(className, name, bean, + * "invoke")</code>}. + * @see DynamicMBean#invoke(String, Object[], String[]) + */ + public Object invoke(ObjectName bean, String name, Object[] params, String[] sig) + throws InstanceNotFoundException, MBeanException, + ReflectionException + { + if (bean == null) + { + RuntimeException e = + new IllegalArgumentException("The bean was null."); + throw new RuntimeOperationsException(e); + } + Object abean = getBean(bean); + checkSecurity(bean, name, "invoke"); + if (abean instanceof DynamicMBean) + return ((DynamicMBean) abean).invoke(name, params, sig); + else + try + { + return new StandardMBean(abean, null).invoke(name, params, sig); + } + catch (NotCompliantMBeanException e) + { + throw (Error) + (new InternalError("Failed to create dynamic bean.").initCause(e)); + } + } + + /** + * <p> + * Returns true if the specified management bean is an instance + * of the supplied class. + * </p> + * <p> + * A bean, B, is an instance of a class, C, if either of the following + * conditions holds: + * </p> + * <ul> + * <li>The class name in B's {@link MBeanInfo} is equal to the supplied + * name.</li> + * <li>Both the class of B and C were loaded by the same class loader, + * and B is assignable to C.</li> + * </ul> + * + * @param name the name of the management bean. + * @param className the name of the class to test if <code>name</code> is + * an instance of. + * @return true if either B is directly an instance of the named class, + * or B is assignable to the class, given that both it and B's + * current class were loaded using the same class loader. + * @throws InstanceNotFoundException if the bean can not be found. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * <code>MBeanPermission(className, null, name, + * "isInstanceOf")</code> + */ + public boolean isInstanceOf(ObjectName name, String className) + throws InstanceNotFoundException + { + Object bean = getBean(name); + checkSecurity(name, null, "isInstanceOf"); + MBeanInfo info; + if (bean instanceof DynamicMBean) + info = ((DynamicMBean) bean).getMBeanInfo(); + else + try + { + info = new StandardMBean(bean, null).getMBeanInfo(); + } + catch (NotCompliantMBeanException e) + { + throw (Error) + (new InternalError("Failed to create dynamic bean.").initCause(e)); + } + if (info.getClassName().equals(className)) + return true; + Class<?> bclass = bean.getClass(); + try + { + Class<?> oclass = Class.forName(className); + return (bclass.getClassLoader().equals(oclass.getClassLoader()) && + oclass.isAssignableFrom(bclass)); + } + catch (ClassNotFoundException e) + { + return false; + } + } + + /** + * Returns true if the specified management bean is registered with + * the server. + * + * @param name the name of the management bean. + * @return true if the bean is registered. + * @throws RuntimeOperationsException if an {@link IllegalArgumentException} + * is thrown by the server due to a + * <code>null</code> bean name. + */ + public boolean isRegistered(ObjectName name) + { + if (name == null) + { + RuntimeException e = + new IllegalArgumentException("The name was null."); + throw new RuntimeOperationsException(e); + } + return beans.containsKey(name); + } + + /** + * <p> + * Returns a set of {@link ObjectInstance}s matching the specified + * criteria. The full set of beans registered with the server + * are passed through two filters: + * </p> + * <ol> + * <li>Pattern matching is performed using the supplied + * {@link ObjectName}.</li> + * <li>The supplied query expression is applied.</li> + * </ol> + * <p> + * If both the object name and the query expression are <code>null</code>, + * or the object name has no domain and no key properties, + * no filtering will be performed and all beans are returned. + * </p> + * + * @param name an {@link ObjectName} to use as a filter. + * @param query a query expression to apply to each of the beans that match + * the given object name. + * @return a set of {@link ObjectInstance}s matching the filtered beans. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * <code>MBeanPermission(null, null, name, + * "queryMBeans")</code>}. Additionally, + * for an bean, <code>b</code>, the + * caller's permission must imply {@link + * MBeanPermission(String,String,ObjectName,String) + * <code>MBeanPermission(className, b, name, + * "queryMBeans")</code>} or that bean will + * not be included. Such an exception may also + * arise from the execution of the query, in which + * case that particular bean will again be excluded. + */ + public Set<ObjectInstance> queryMBeans(ObjectName name, QueryExp query) + { + checkSecurity(name, null, "queryMBeans"); + Set<ObjectInstance> results = new HashSet<ObjectInstance>(); + for (Map.Entry<ObjectName,ServerInfo> entry : beans.entrySet()) + { + ObjectName nextName = entry.getKey(); + checkSecurity(name, nextName.toString(), "queryMBeans"); + try + { + if ((name == null || name.apply(nextName)) && + (query == null || query.apply(nextName))) + results.add(entry.getValue().getInstance()); + } + catch (BadStringOperationException e) + { + /* Ignored -- assume false result */ + } + catch (BadBinaryOpValueExpException e) + { + /* Ignored -- assume false result */ + } + catch (BadAttributeValueExpException e) + { + /* Ignored -- assume false result */ + } + catch (InvalidApplicationException e) + { + /* Ignored -- assume false result */ + } + } + return results; + } + + /** + * <p> + * Returns a set of {@link ObjectName}s matching the specified + * criteria. The full set of beans registered with the server + * are passed through two filters: + * </p> + * <ol> + * <li>Pattern matching is performed using the supplied + * {@link ObjectName}.</li> + * <li>The supplied query expression is applied.</li> + * </ol> + * <p> + * If both the object name and the query expression are <code>null</code>, + * or the object name has no domain and no key properties, + * no filtering will be performed and all beans are returned. + * </p> + * + * @param name an {@link ObjectName} to use as a filter. + * @param query a query expression to apply to each of the beans that match + * the given object name. + * @return a set of {@link ObjectName}s matching the filtered beans. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * <code>MBeanPermission(null, null, name, + * "queryNames")</code>}. Additionally, + * for an name, <code>n</code>, the + * caller's permission must imply {@link + * MBeanPermission(String,String,ObjectName,String) + * <code>MBeanPermission(className, n, name, + * "queryNames")</code>} or that name will + * not be included. Such an exception may also + * arise from the execution of the query, in which + * case that particular bean will again be excluded. + * Note that these permissions are implied if the + * <code>queryMBeans</code> permissions are available. + */ + public Set<ObjectName> queryNames(ObjectName name, QueryExp query) + { + checkSecurity(name, null, "queryNames"); + Set<ObjectName> results = new HashSet<ObjectName>(); + for (ObjectName nextName : beans.keySet()) + { + checkSecurity(name, nextName.toString(), "queryNames"); + try + { + if ((name == null || name.apply(nextName)) && + (query == null || query.apply(nextName))) + results.add(nextName); + } + catch (BadStringOperationException e) + { + /* Ignored -- assume false result */ + } + catch (BadBinaryOpValueExpException e) + { + /* Ignored -- assume false result */ + } + catch (BadAttributeValueExpException e) + { + /* Ignored -- assume false result */ + } + catch (InvalidApplicationException e) + { + /* Ignored -- assume false result */ + } + } + return results; + } + + /** + * Registers the supplied instance with the server, using the specified + * {@link ObjectName}. If the name given is <code>null</code>, then + * the bean supplied is expected to implement the {@link MBeanRegistration} + * interface and provide the name via the + * {@link MBeanRegistration#preRegister preRegister} method + * of this interface. + * + * @param obj the object to register with the server. + * @param name the name under which to register the object, + * or <code>null</code> if the {@link MBeanRegistration} + * interface should be used. + * @return an {@link ObjectInstance} containing the supplied + * {@link ObjectName} along with the name of the bean's class. + * @throws InstanceAlreadyExistsException if a matching instance + * already exists. + * @throws MBeanRegistrationException if an exception occurs in + * calling the preRegister + * method. + * @throws NotCompliantMBeanException if the created bean is not + * compliant with the JMX specification. + * @throws RuntimeOperationsException if an {@link IllegalArgumentException} + * is thrown by the server due to a + * <code>null</code> object. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * <code>MBeanPermission(className, null, name, + * "registerMBean")</code>}. <code>className</code> + * here corresponds to the result of + * {@link MBeanInfo#getClassName()} for objects of + * this class. If this check succeeds, a check + * is also made on its + * {@link java.security.ProtectionDomain} to ensure + * it implies {@link MBeanTrustPermission(String) + * <code>MBeanTrustPermission("register")</code>}. + * The use of the {@link MBeanRegistration} interface + * results in another {@link MBeanPermission} check + * being made on the returned {@link ObjectName}. + */ + public ObjectInstance registerMBean(Object obj, ObjectName name) + throws InstanceAlreadyExistsException, MBeanRegistrationException, + NotCompliantMBeanException + { + SecurityManager sm = System.getSecurityManager(); + Class<?> cl = obj.getClass(); + String className = cl.getName(); + if (sm != null) + { + sm.checkPermission(new MBeanPermission(className, null, name, + "registerMBean")); + if (!(cl.getProtectionDomain().implies(new MBeanTrustPermission("register")))) + throw new SecurityException("The protection domain of the object's class" + + "does not imply the trust permission," + + "register"); + } + if (obj == null) + { + RuntimeException e = + new IllegalArgumentException("The object was null."); + throw new RuntimeOperationsException(e); + } + MBeanRegistration register = null; + if (obj instanceof MBeanRegistration) + register = (MBeanRegistration) obj; + if (name == null && register == null) + { + RuntimeException e = + new IllegalArgumentException("The name was null and " + + "the bean does not implement " + + "MBeanRegistration."); + throw new RuntimeOperationsException(e); + } + if (register != null) + { + try + { + name = register.preRegister(this, name); + if (name == null) + { + RuntimeException e = + new NullPointerException("The name returned by " + + "MBeanRegistration.preRegister() " + + "was null"); + throw e; + } + if (sm != null) + sm.checkPermission(new MBeanPermission(className, null, name, + "registerMBean")); + } + catch (SecurityException e) + { + register.postRegister(Boolean.FALSE); + throw e; + } + catch (Exception e) + { + register.postRegister(Boolean.FALSE); + throw new MBeanRegistrationException(e, "Pre-registration failed."); + } + } + ObjectInstance obji = new ObjectInstance(name, className); + if (beans.putIfAbsent(name, new ServerInfo(obji, obj)) != null) + { + if (register != null) + register.postRegister(Boolean.FALSE); + throw new InstanceAlreadyExistsException(name + "is already registered."); + } + if (register != null) + register.postRegister(Boolean.TRUE); + notify(name, MBeanServerNotification.REGISTRATION_NOTIFICATION); + return obji; + } + + /** + * Removes the specified listener from the list of recipients + * of notifications from the supplied bean. This includes all + * combinations of filters and passback objects registered for + * this listener. For more specific removal of listeners, see + * {@link #removeNotificationListener(ObjectName, + * NotificationListener,NotificationFilter,Object)} + * + * @param name the name of the management bean from which the + * listener should be removed. + * @param listener the listener to remove. + * @throws InstanceNotFoundException if the bean can not be found. + * @throws ListenerNotFoundException if the specified listener + * is not registered with the bean. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * <code>MBeanPermission(className, null, name, + * "removeNotificationListener")</code>}. + * @see #addNotificationListener(NotificationListener, NotificationFilter, + * java.lang.Object) + * @see NotificationBroadcaster#removeNotificationListener(NotificationListener) + */ + public void removeNotificationListener(ObjectName name, + NotificationListener listener) + throws InstanceNotFoundException, ListenerNotFoundException + { + Object bean = getBean(name); + checkSecurity(name, null, "removeNotificationListener"); + if (bean instanceof NotificationBroadcaster) + { + NotificationBroadcaster bbean = (NotificationBroadcaster) bean; + bbean.removeNotificationListener(listener); + LazyListenersHolder.listeners.remove(listener); + } + } + + /** + * Removes the specified listener from the list of recipients + * of notifications from the supplied bean. Only the first instance with + * the supplied filter and passback object is removed. + * <code>null</code> is used as a valid value for these parameters, + * rather than as a way to remove all registration instances for + * the specified listener; for this behaviour instead, see + * {@link #removeNotificationListener(ObjectName, NotificationListener)}. + * + * @param name the name of the management bean from which the + * listener should be removed. + * @param listener the listener to remove. + * @param filter the filter of the listener to remove. + * @param passback the passback object of the listener to remove. + * @throws InstanceNotFoundException if the bean can not be found. + * @throws ListenerNotFoundException if the specified listener + * is not registered with the bean. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * <code>MBeanPermission(className, null, name, + * "removeNotificationListener")</code>}. + * @see #addNotificationListener(ObjectName, NotificationListener, + * NotificationFilter, Object) + * @see NotificationEmitter#removeNotificationListener(NotificationListener, + * NotificationFilter, + * Object) + */ + public void removeNotificationListener(ObjectName name, + NotificationListener listener, + NotificationFilter filter, + Object passback) + throws InstanceNotFoundException, ListenerNotFoundException + { + Object bean = getBean(name); + checkSecurity(name, null, "removeNotificationListener"); + if (bean instanceof NotificationEmitter) + { + NotificationEmitter bbean = (NotificationEmitter) bean; + bbean.removeNotificationListener(listener, filter, passback); + LazyListenersHolder.listeners.remove(listener); + } + } + + /** + * Removes the specified listener from the list of recipients + * of notifications from the supplied bean. This includes all + * combinations of filters and passback objects registered for + * this listener. For more specific removal of listeners, see + * {@link #removeNotificationListener(ObjectName, + * ObjectName,NotificationFilter,Object)} + * + * @param name the name of the management bean from which the + * listener should be removed. + * @param listener the name of the listener to remove. + * @throws InstanceNotFoundException if a name doesn't match a registered + * bean. + * @throws ListenerNotFoundException if the specified listener + * is not registered with the bean. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * <code>MBeanPermission(className, null, name, + * "removeNotificationListener")</code>}. + * @see #addNotificationListener(NotificationListener, NotificationFilter, + * java.lang.Object) + * @see NotificationBroadcaster#removeNotificationListener(NotificationListener) + */ + public void removeNotificationListener(ObjectName name, ObjectName listener) + throws InstanceNotFoundException, ListenerNotFoundException + { + Object lbean = getBean(listener); + if (!(lbean instanceof NotificationListener)) + { + RuntimeException e = + new IllegalArgumentException("The supplied listener name does not " + + "correspond to a notification listener."); + throw new RuntimeOperationsException(e); + } + removeNotificationListener(name, ((NotificationListener) lbean)); + } + + /** + * Removes the specified listener from the list of recipients + * of notifications from the supplied bean. Only the first instance with + * the supplied filter and passback object is removed. + * <code>null</code> is used as a valid value for these parameters, + * rather than as a way to remove all registration instances for + * the specified listener; for this behaviour instead, see + * {@link #removeNotificationListener(ObjectName, ObjectName)}. + * + * @param name the name of the management bean from which the + * listener should be removed. + * @param listener the name of the listener to remove. + * @param filter the filter of the listener to remove. + * @param passback the passback object of the listener to remove. + * @throws InstanceNotFoundException if a name doesn't match a registered + * bean. + * @throws ListenerNotFoundException if the specified listener + * is not registered with the bean. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * <code>MBeanPermission(className, null, name, + * "removeNotificationListener")</code>}. + * @see #addNotificationListener(ObjectName, NotificationListener, + * NotificationFilter, Object) + * @see NotificationEmitter#removeNotificationListener(NotificationListener, + * NotificationFilter, + * Object) + */ + public void removeNotificationListener(ObjectName name, + ObjectName listener, + NotificationFilter filter, + Object passback) + throws InstanceNotFoundException, ListenerNotFoundException + { + Object lbean = getBean(listener); + if (!(lbean instanceof NotificationListener)) + { + RuntimeException e = + new IllegalArgumentException("The supplied listener name does not " + + "correspond to a notification listener."); + throw new RuntimeOperationsException(e); + } + removeNotificationListener(name, ((NotificationListener) lbean), filter, + passback); + } + + /** + * Sets the value of the specified attribute of the supplied + * management bean. + * + * @param name the name of the management bean. + * @param attribute the attribute to set. + * @throws InstanceNotFoundException if the bean can not be found. + * @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. + * @throws RuntimeOperationsException if an {@link IllegalArgumentException} + * is thrown by the server due to a + * <code>null</code> bean or attribute + * name. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * <code>MBeanPermission(className, name, bean, + * "setAttribute")</code>}. + * @see #getAttribute(ObjectName, String) + * @see DynamicMBean#setAttribute(Attribute) + */ + public void setAttribute(ObjectName name, Attribute attribute) + throws InstanceNotFoundException, AttributeNotFoundException, + InvalidAttributeValueException, MBeanException, + ReflectionException + { + if (attribute == null || name == null) + { + RuntimeException e = + new IllegalArgumentException("One of the supplied arguments was null."); + throw new RuntimeOperationsException(e); + } + Object bean = getBean(name); + checkSecurity(name, attribute.getName(), "setAttribute"); + if (bean instanceof DynamicMBean) + ((DynamicMBean) bean).setAttribute(attribute); + else + try + { + new StandardMBean(bean, null).setAttribute(attribute); + } + catch (NotCompliantMBeanException e) + { + throw (Error) + (new InternalError("Failed to create dynamic bean.").initCause(e)); + } + } + + /** + * Sets the value of each of the specified attributes + * of the supplied management bean to that specified by + * the {@link Attribute} object. The returned list contains + * the attributes that were set and their new values. + * + * @param name the name of the management bean. + * @param attributes the attributes to set. + * @return a list of the changed attributes. + * @throws InstanceNotFoundException if the bean can not be found. + * @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. + * @throws RuntimeOperationsException if an {@link IllegalArgumentException} + * is thrown by the server due to a + * <code>null</code> bean or attribute + * list. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * <code>MBeanPermission(className, null, bean, + * "setAttribute")</code>}. Additionally, + * for an attribute name, <code>n</code>, the + * caller's permission must imply {@link + * MBeanPermission(String,String,ObjectName,String) + * <code>MBeanPermission(className, n, bean, + * "setAttribute")</code>} or that attribute will + * not be included. + * @see #getAttributes(ObjectName, String[]) + * @see DynamicMBean#setAttributes(AttributeList) + */ + public AttributeList setAttributes(ObjectName name, AttributeList attributes) + throws InstanceNotFoundException, ReflectionException + { + if (name == null || attributes == null) + { + RuntimeException e = + new IllegalArgumentException("One of the supplied arguments was null."); + throw new RuntimeOperationsException(e); + } + Object abean = getBean(name); + checkSecurity(name, null, "setAttribute"); + AttributeList list = new AttributeList(attributes.size()); + Iterator<Object> it = attributes.iterator(); + while (it.hasNext()) + { + try + { + Attribute attrib = (Attribute) it.next(); + if (attrib == null) + { + RuntimeException e = + new IllegalArgumentException("An attribute was null."); + throw new RuntimeOperationsException(e); + } + checkSecurity(name, attrib.getName(), "setAttribute"); + if (abean instanceof DynamicMBean) + ((DynamicMBean) abean).setAttribute(attrib); + else + try + { + new StandardMBean(abean, null).setAttribute(attrib); + } + catch (NotCompliantMBeanException e) + { + throw (Error) + (new InternalError("Failed to create dynamic bean.").initCause(e)); + } + list.add(attrib); + } + catch (AttributeNotFoundException e) + { + /* Ignored */ + } + catch (InvalidAttributeValueException e) + { + /* Ignored */ + } + catch (MBeanException e) + { + /* Ignored */ + } + } + return list; + } + + /** + * Unregisters the specified management bean. Following this operation, + * the bean instance is no longer accessible from the server via this + * name. Prior to unregistering the bean, the + * {@link MBeanRegistration#preDeregister()} method will be called if + * the bean implements the {@link MBeanRegistration} interface. + * + * @param name the name of the management bean. + * @throws InstanceNotFoundException if the bean can not be found. + * @throws MBeanRegistrationException if an exception occurs in + * calling the preDeregister + * method. + * @throws RuntimeOperationsException if an {@link IllegalArgumentException} + * is thrown by the server due to a + * <code>null</code> bean name or a + * request being made to unregister the + * {@link MBeanServerDelegate} bean. + * @throws SecurityException if a security manager exists and the + * caller's permissions don't imply {@link + * MBeanPermission(String,String,ObjectName,String) + * <code>MBeanPermission(className, null, name, + * "unregisterMBean")</code>}. + */ + public void unregisterMBean(ObjectName name) + throws InstanceNotFoundException, MBeanRegistrationException + { + if (name == null) + { + RuntimeException e = + new IllegalArgumentException("The name was null."); + throw new RuntimeOperationsException(e); + } + if (name.equals(DELEGATE_NAME)) + { + RuntimeException e = + new IllegalArgumentException("The delegate can not be unregistered."); + throw new RuntimeOperationsException(e); + } + Object bean = getBean(name); + checkSecurity(name, null, "unregisterMBean"); + MBeanRegistration register = null; + if (bean instanceof MBeanRegistration) + { + register = (MBeanRegistration) bean; + try + { + register.preDeregister(); + } + catch (Exception e) + { + throw new MBeanRegistrationException(e, "Pre-deregistration failed."); + } + } + beans.remove(name); + notify(name, MBeanServerNotification.UNREGISTRATION_NOTIFICATION); + if (register != null) + register.postDeregister(); + } + + /** + * Notifies the delegate of beans being registered + * and unregistered. + * + * @param name the bean being registered. + * @param type the type of notification; + * {@code REGISTRATION_NOTIFICATION} or + * {@code UNREGISTRATION_NOTIFICATION}. + */ + private void notify(ObjectName name, String type) + { + delegate.sendNotification + (new MBeanServerNotification + (type, DELEGATE_NAME, sequenceNumber.getAndIncrement(), name)); + } + + /** + * Input stream which deserializes using the given classloader. + */ + private class ServerInputStream + extends ObjectInputStream + { + + private ClassLoader cl; + + public ServerInputStream(InputStream is, ClassLoader cl) + throws IOException, StreamCorruptedException + { + super(is); + this.cl = cl; + } + + protected Class<?> resolveClass(ObjectStreamClass osc) + throws ClassNotFoundException, IOException + { + try + { + return Class.forName(osc.getName(), true, cl); + } + catch (ClassNotFoundException e) + { + return super.resolveClass(osc); + } + } + + } + + /** + * Holder for information on registered beans. + */ + private class ServerInfo + { + private ObjectInstance instance; + + private Object object; + + public ServerInfo(ObjectInstance instance, Object object) + { + this.instance = instance; + this.object = object; + } + + public Object getObject() + { + return object; + } + + public ObjectInstance getInstance() + { + return instance; + } + } + + /** + * Notification listener which removes direct references + * to beans. + */ + private class ServerNotificationListener + implements NotificationListener + { + + /** + * The bean from which notifications are emitted. + */ + Object bean; + + /** + * The {@link ObjectName} of the emitting bean. + */ + ObjectName name; + + /** + * The real {@link NotificationListener}. + */ + NotificationListener listener; + + /** + * Constructs a new {@link ServerNotificationListener} replacing + * occurrences of <code>bean</code> with its name. + * + * @param bean the bean emitting notifications. + * @param name the object name of the emitting bean. + * @param listener the listener events eventually reach. + */ + public ServerNotificationListener(Object bean, ObjectName name, + NotificationListener listener) + { + this.bean = bean; + this.name = name; + this.listener = listener; + } + + /** + * Replace a direct reference to <code>bean</code> with its + * object reference, if necessary, before calling the listener. + * + * @param notif the notification being emitted. + * @param handback an object that will be returned to the notification + * listener when an event occurs. + */ + public void handleNotification(Notification notif, Object handback) + { + if (notif.getSource() == bean) + notif.setSource(name); + listener.handleNotification(notif, handback); + } + + } + +} diff --git a/libjava/classpath/gnu/javax/management/Translator.java b/libjava/classpath/gnu/javax/management/Translator.java new file mode 100644 index 000000000..38d575aca --- /dev/null +++ b/libjava/classpath/gnu/javax/management/Translator.java @@ -0,0 +1,550 @@ +/* Translator.java -- Performs MXBean data type translation. + 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 gnu.javax.management; + +import java.lang.reflect.Array; +import java.lang.reflect.Method; +import java.lang.reflect.Modifier; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Proxy; +import java.lang.reflect.Type; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.SortedMap; +import java.util.SortedSet; + +import javax.management.JMX; +import javax.management.MBeanServerInvocationHandler; + +import javax.management.openmbean.ArrayType; +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.CompositeDataSupport; +import javax.management.openmbean.CompositeType; +import javax.management.openmbean.OpenDataException; +import javax.management.openmbean.OpenMBeanParameterInfo; +import javax.management.openmbean.OpenMBeanParameterInfoSupport; +import javax.management.openmbean.OpenType; +import javax.management.openmbean.SimpleType; +import javax.management.openmbean.TabularData; +import javax.management.openmbean.TabularDataSupport; +import javax.management.openmbean.TabularType; + +/** + * Translates Java data types to their equivalent + * open data type, and vice versa, according to the + * {@link javax.management.MXBean} rules. + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + */ +public final class Translator +{ + + /** + * Translates the input Java data types to the equivalent + * open data types. + * + * @param jtypes the Java types supplied as parameters. + * @param method the method that was called. + * @return the equivalent open types required by the {@link MXBean}. + * @throws Throwable if an exception is thrown in performing the + * conversion. + */ + public static final Object[] fromJava(Object[] jtypes, Method method) + throws Throwable + { + Type[] gtypes = method.getGenericParameterTypes(); + Object[] otypes = new Object[jtypes.length]; + for (int a = 0; a < jtypes.length; ++a) + otypes[a] = fromJava(jtypes[a], gtypes[a]); + return otypes; + } + + /** + * Translates the input Java data type to the equivalent + * open data type. + * + * @param jtype the Java type supplied as a parameter. + * @param type the type of the parameter. + * @return the equivalent open type required by the {@link MXBean}. + * @throws Throwable if an exception is thrown in performing the + * conversion. + */ + public static final Object fromJava(Object jtype, Type type) + throws Throwable + { + if (jtype == null) + return null; + Class<?> jclass = jtype.getClass(); + if (OpenType.ALLOWED_CLASSNAMES_LIST.contains(jclass.getName())) + return jtype; + if (jclass.isArray()) + { + Class<?> ctype = jclass.getComponentType(); + if (ctype.isPrimitive()) + return jtype; + if (OpenType.ALLOWED_CLASSNAMES_LIST.contains(ctype.getName())) + return jtype; + Object[] elems = (Object[]) jtype; + Object[] celems = new Object[elems.length]; + for (int a = 0; a < elems.length; ++a) + celems[a] = fromJava(elems[a], elems[a].getClass()); + return makeArraySpecific(celems); + } + String tName = getTypeName(type); + if (jtype instanceof List || jtype instanceof Set || + jtype instanceof SortedSet) + { + if (jtype instanceof SortedSet) + { + ParameterizedType ptype = (ParameterizedType) type; + Class<?> elemClass = (Class<?>) ptype.getActualTypeArguments()[0]; + if (!Comparable.class.isAssignableFrom(elemClass)) + throw new IllegalArgumentException(jtype + " has a " + + "non-comparable element " + + "type, " + elemClass); + if (((SortedSet<?>) jtype).comparator() != null) + throw new IllegalArgumentException(jtype + " does not " + + "use natural ordering."); + } + Collection<?> elems = (Collection<?>) jtype; + int numElems = elems.size(); + Object[] celems = new Object[numElems]; + Iterator<?> i = elems.iterator(); + for (int a = 0; a < numElems; ++a) + { + Object elem = i.next(); + celems[a] = fromJava(elem, elem.getClass()); + } + return makeArraySpecific(celems); + } + if (jtype instanceof Enum) + return ((Enum<?>) jtype).name(); + if (jtype instanceof Map || jtype instanceof SortedMap) + { + int lparam = tName.indexOf("<"); + int comma = tName.indexOf(",", lparam); + int rparam = tName.indexOf(">", comma); + String key = tName.substring(lparam + 1, comma).trim(); + String value = tName.substring(comma + 1, rparam).trim(); + String typeName = null; + if (jtype instanceof Map) + typeName = "java.util.Map" + tName.substring(lparam); + else + { + Class<?> keyClass = Class.forName(key); + if (!Comparable.class.isAssignableFrom(keyClass)) + throw new IllegalArgumentException(jtype + " has a " + + "non-comparable element " + + "type, " + keyClass); + if (((SortedMap<?,?>) jtype).comparator() != null) + throw new IllegalArgumentException(jtype + " does not " + + "use natural ordering."); + typeName = "java.util.SortedMap" + tName.substring(lparam); + } + OpenType<?> k = translate(key).getOpenType(); + OpenType<?> v = translate(value).getOpenType(); + CompositeType rowType = new CompositeType(typeName, typeName, + new String[] { "key", "value" }, + new String[] { "Map key", "Map value"}, + new OpenType[] {k,v}); + TabularType tabType = new TabularType(typeName, typeName, rowType, + new String[]{"key"}); + TabularData data = new TabularDataSupport(tabType); + for (Map.Entry<?,?> entry : ((Map<?,?>) jtype).entrySet()) + { + try + { + data.put(new CompositeDataSupport(rowType, + new String[] { + "key", + "value" + }, + new Object[] { + entry.getKey(), + entry.getValue() + })); + } + catch (OpenDataException e) + { + throw (InternalError) (new InternalError("A problem occurred " + + "converting the map " + + "to a composite data " + + "structure.").initCause(e)); + } + } + return data; + } + if (JMX.isMXBeanInterface(jclass)) + { + try + { + MBeanServerInvocationHandler ih = (MBeanServerInvocationHandler) + Proxy.getInvocationHandler(jtype); + return ih.getObjectName(); + } + catch (IllegalArgumentException e) + { + throw new IllegalArgumentException("For a MXBean to be translated " + + "to an open type, it must be a " + + "proxy.", e); + } + catch (ClassCastException e) + { + throw new IllegalArgumentException("For a MXBean to be translated " + + "to an open type, it must have a " + + "MBeanServerInvocationHandler.", e); + } + } + /* FIXME: Handle other types */ + throw new IllegalArgumentException("The type, " + jtype + + ", is not convertible."); + } + + /** + * Translates the returned open data type to the value + * required by the interface. + * + * @param otype the open type returned by the method call. + * @param method the method that was called. + * @return the equivalent return type required by the interface. + * @throws Throwable if an exception is thrown in performing the + * conversion. + */ + public static final Object toJava(Object otype, Method method) + throws Throwable + { + Class<?> returnType = method.getReturnType(); + if (returnType.isEnum()) + { + String ename = (String) otype; + Enum<?>[] constants = (Enum[]) returnType.getEnumConstants(); + for (Enum<?> c : constants) + if (c.name().equals(ename)) + return c; + } + if (List.class.isAssignableFrom(returnType)) + { + Object[] elems = (Object[]) otype; + List<Object> l = new ArrayList<Object>(elems.length); + for (Object elem : elems) + l.add(elem); + return l; + } + if (Map.class.isAssignableFrom(returnType)) + { + TabularData data = (TabularData) otype; + Map<Object,Object> m = new HashMap<Object,Object>(data.size()); + for (Object val : data.values()) + { + CompositeData vals = (CompositeData) val; + m.put(vals.get("key"), vals.get("value")); + } + return m; + } + try + { + Method m = returnType.getMethod("from", + new Class[] + { CompositeData.class }); + return m.invoke(null, (CompositeData) otype); + } + catch (NoSuchMethodException e) + { + /* Ignored; we expect this if this + isn't a from(CompositeData) class */ + } + return otype; + } + + /** + * Creates a new array which has the specific type + * used by the elements of the original {@link Object} + * array supplied. + * + * @param arr a series of elements in an {@link Object} + * array. + * @return the same elements in a new array of the specific + * type. + */ + private static final Object[] makeArraySpecific(Object[] arr) + { + Object[] rcelems = (Object[]) Array.newInstance(arr[0].getClass(), + arr.length); + System.arraycopy(arr, 0, rcelems, 0, arr.length); + return rcelems; + } + + /** + * Translates the name of a type into an equivalent + * {@link javax.management.openmbean.OpenMBeanParameterInfo} + * that describes it. + * + * @param type the type to describe. + * @return an instance of + * {@link javax.management.openmbean.OpenMBeanParameterInfo}, + * describing the translated type and limits of the given type. + * @throws OpenDataException if a type is not open. + */ + public static final OpenMBeanParameterInfo translate(String type) + throws OpenDataException + { + if (type.equals("boolean") || type.equals(Boolean.class.getName())) + return new OpenMBeanParameterInfoSupport("TransParam", + "Translated parameter", + SimpleType.BOOLEAN, + null, + new Boolean[] { + Boolean.TRUE, + Boolean.FALSE + }); + if (type.equals("byte") || type.equals(Byte.class.getName())) + return new OpenMBeanParameterInfoSupport("TransParam", + "Translated parameter", + SimpleType.BYTE, + null, + Byte.valueOf(Byte.MIN_VALUE), + Byte.valueOf(Byte.MAX_VALUE)); + if (type.equals("char") || type.equals(Character.class.getName())) + return new OpenMBeanParameterInfoSupport("TransParam", + "Translated parameter", + SimpleType.CHARACTER, + null, + Character.valueOf(Character.MIN_VALUE), + Character.valueOf(Character.MAX_VALUE)); + if (type.equals("double") || type.equals(Double.class.getName())) + return new OpenMBeanParameterInfoSupport("TransParam", + "Translated parameter", + SimpleType.DOUBLE, + null, + Double.valueOf(Double.MIN_VALUE), + Double.valueOf(Double.MAX_VALUE)); + if (type.equals("float") || type.equals(Float.class.getName())) + return new OpenMBeanParameterInfoSupport("TransParam", + "Translated parameter", + SimpleType.FLOAT, + null, + Float.valueOf(Float.MIN_VALUE), + Float.valueOf(Float.MAX_VALUE)); + if (type.equals("int") || type.equals(Integer.class.getName())) + return new OpenMBeanParameterInfoSupport("TransParam", + "Translated parameter", + SimpleType.INTEGER, + null, + Integer.valueOf(Integer.MIN_VALUE), + Integer.valueOf(Integer.MAX_VALUE)); + if (type.equals("long") || type.equals(Long.class.getName())) + return new OpenMBeanParameterInfoSupport("TransParam", + "Translated parameter", + SimpleType.LONG, + null, + Long.valueOf(Long.MIN_VALUE), + Long.valueOf(Long.MAX_VALUE)); + if (type.equals("short") || type.equals(Short.class.getName())) + return new OpenMBeanParameterInfoSupport("TransParam", + "Translated parameter", + SimpleType.SHORT, + null, + Short.valueOf(Short.MIN_VALUE), + Short.valueOf(Short.MAX_VALUE)); + if (type.equals(String.class.getName())) + return new OpenMBeanParameterInfoSupport("TransParam", + "Translated parameter", + SimpleType.STRING); + if (type.equals("void")) + return new OpenMBeanParameterInfoSupport("TransParam", + "Translated parameter", + SimpleType.VOID); + if (type.startsWith("java.util.Map")) + { + int lparam = type.indexOf("<"); + int comma = type.indexOf(",", lparam); + int rparam = type.indexOf(">", comma); + String key = type.substring(lparam + 1, comma).trim(); + OpenType<?> k = translate(key).getOpenType(); + OpenType<?> v = translate(type.substring(comma + 1, rparam).trim()).getOpenType(); + CompositeType ctype = new CompositeType(Map.class.getName(), Map.class.getName(), + new String[] { "key", "value" }, + new String[] { "Map key", "Map value"}, + new OpenType[] { k, v}); + TabularType ttype = new TabularType(key, key, ctype, + new String[] { "key" }); + return new OpenMBeanParameterInfoSupport("TransParam", + "Translated parameter", + ttype); + } + if (type.startsWith("java.util.List")) + { + int lparam = type.indexOf("<"); + int rparam = type.indexOf(">"); + OpenType<?> e = translate(type.substring(lparam + 1, rparam).trim()).getOpenType(); + return new OpenMBeanParameterInfoSupport("TransParam", + "Translated parameter", + new ArrayType<OpenType<?>>(1, e) + ); + } + Class<?> c; + try + { + c = Class.forName(type); + } + catch (ClassNotFoundException e) + { + throw (InternalError) + (new InternalError("The class for a type used in a management bean " + + "could not be loaded.").initCause(e)); + } + if (c.isEnum()) + { + Object[] values = c.getEnumConstants(); + String[] names = new String[values.length]; + for (int a = 0; a < values.length; ++a) + names[a] = values[a].toString(); + return new OpenMBeanParameterInfoSupport("TransParam", + "Translated parameter", + SimpleType.STRING, + null, names); + } + if (c.isArray()) + { + int depth; + for (depth = 0; c.getName().charAt(depth) == '['; ++depth) + ; + OpenType<?> ot = getTypeFromClass(c.getComponentType()); + return new OpenMBeanParameterInfoSupport("TransParam", + "Translated parameter", + new ArrayType<OpenType<?>>(depth, ot) + ); + } + Method[] methods = c.getDeclaredMethods(); + List<String> names = new ArrayList<String>(); + List<OpenType<?>> types = new ArrayList<OpenType<?>>(); + for (int a = 0; a < methods.length; ++a) + { + String name = methods[a].getName(); + if (Modifier.isPublic(methods[a].getModifiers())) + { + if (name.startsWith("get")) + { + names.add(name.substring(3)); + types.add(getTypeFromClass(methods[a].getReturnType())); + } + else if (name.startsWith("is")) + { + names.add(name.substring(2)); + types.add(getTypeFromClass(methods[a].getReturnType())); + } + } + } + if (names.isEmpty()) + throw new OpenDataException("The type used does not have an open type translation."); + String[] fields = names.toArray(new String[names.size()]); + CompositeType ctype = new CompositeType(c.getName(), c.getName(), + fields, fields, + types.toArray(new OpenType[types.size()])); + return new OpenMBeanParameterInfoSupport("TransParam", + "Translated parameter", + ctype); + } + + /** + * Obtains the {@link javax.management.openmbean.OpenType} + * for a particular class. + * + * @param c the class to obtain the type for. + * @return the appropriate instance. + * @throws OpenDataException if the type is not open. + */ + private static final OpenType<?> getTypeFromClass(Class<?> c) + throws OpenDataException + { + return Translator.translate(c.getName()).getOpenType(); + } + + /** + * <p> + * Returns the type name according to the rules described + * in {@link javax.management.MXBean}. Namely, for a type, + * {@code T}, {@code typename(T)} is computed as follows: + * </p> + * <ul> + * <li>If T is non-generic and not an array, then the value + * of {@link java.lang.Class#getName()} is returned.</li> + * <li>If T is an array type, {@code{E[]}, then the type name + * is {@code typename(E)} followed by an occurrence + * of {@code '[]'} for each dimension.</li> + * <li>If T is a generic or parameterized type, the type name + * is composed of {@code typename(P)}, where {@code P} is the + * parameterized type name, followed by {@code '<'}, the resulting + * list of type names of the parameters after applying {@code typename} + * to each, separated by commas, and {@code '>'}.</li> + * </ul> + * + * @param type the type to return the type name of. + * @return the type name computed according to the rules above. + */ + private static final String getTypeName(Type type) + { + if (type instanceof Class) + { + Class<?> c = (Class<?>) type; + if (c.isArray()) + { + StringBuilder b = + new StringBuilder(c.getComponentType().getName()); + String normName = c.getName(); + for (int a = 0; a < normName.length(); ++a) + { + if (normName.charAt(a) == '[') + b.append("[]"); + else + break; + } + return b.toString(); + } + return c.getName(); + } + return type.toString(); + } + +} |