| /* ManagementFactory.java - Factory for obtaining system beans. |
| 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 java.lang.management; |
| |
| import gnu.classpath.SystemProperties; |
| |
| import gnu.java.lang.management.ClassLoadingMXBeanImpl; |
| import gnu.java.lang.management.CompilationMXBeanImpl; |
| import gnu.java.lang.management.GarbageCollectorMXBeanImpl; |
| import gnu.java.lang.management.OperatingSystemMXBeanImpl; |
| import gnu.java.lang.management.MemoryMXBeanImpl; |
| import gnu.java.lang.management.MemoryManagerMXBeanImpl; |
| import gnu.java.lang.management.MemoryPoolMXBeanImpl; |
| import gnu.java.lang.management.RuntimeMXBeanImpl; |
| import gnu.java.lang.management.ThreadMXBeanImpl; |
| |
| import java.io.IOException; |
| |
| import java.lang.reflect.InvocationHandler; |
| import java.lang.reflect.Method; |
| import java.lang.reflect.Proxy; |
| |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| |
| import java.util.logging.LogManager; |
| |
| import javax.management.Attribute; |
| import javax.management.InstanceAlreadyExistsException; |
| import javax.management.MBeanRegistrationException; |
| import javax.management.MBeanServer; |
| import javax.management.MBeanServerConnection; |
| import javax.management.MBeanServerFactory; |
| import javax.management.MalformedObjectNameException; |
| import javax.management.NotCompliantMBeanException; |
| import javax.management.NotificationEmitter; |
| import javax.management.NotificationFilter; |
| import javax.management.NotificationListener; |
| import javax.management.ObjectName; |
| |
| import javax.management.openmbean.CompositeData; |
| import javax.management.openmbean.TabularData; |
| |
| /** |
| * <p> |
| * Provides access to the system's management beans via a series |
| * of static methods. |
| * </p> |
| * <p> |
| * An instance of a system management bean can be obtained by |
| * using one of the following methods: |
| * </p> |
| * <ol> |
| * <li>Calling the appropriate static method of this factory. |
| * </li> |
| * <li>Using the platform {@link javax.management.MBeanServer} |
| * to access the beans locally, or an |
| * {@link javax.management.MBeanServerConnection} for remote |
| * access. The attributes and operations use the limited |
| * range of data types specified below.</li> |
| * </ol> |
| * <h2>Open Data Types</h2> |
| * <p> |
| * The data types used by the management beans are restricted |
| * to <emph>open</emph> data types to aid interoperability. This |
| * allows the beans to be accessed remotely, including from non-Java |
| * clients. Below is a table which lists the types used by the beans |
| * on the left, and the types they are converted to when returned via |
| * a bean server on the right. Type information is provided for each |
| * bean by obtaining its instance of {@link javax.management.MBeanInfo}. |
| * </p> |
| * <table> |
| * <th><td>Data Type Used</td><td>Data Type Returned</td></th> |
| * <tr> |
| * <td>Primitive types (<code>int</code>, <code>char</code>, etc.)</td> |
| * <td>Same</td> |
| * </tr><tr> |
| * <td>Wrapper classes ({@link{java.lang.Integer}, |
| * @link{java.lang.Character}, etc.)</td> |
| * <td>Same</td> |
| * </tr><tr> |
| * <td>An {@link java.lang.Enum}</td> |
| * <td>The <code>name</code> of the enumeration constant</td> |
| * </tr><tr> |
| * <td>An array of type <code>E</code></td> |
| * <td>An array of the same dimensions with this mapping applied |
| * to <code>E</code>.</td> |
| * </tr><tr> |
| * <td>A class with `getter' methods and a |
| * <code>from({@link javax.management.openmbean.CompositeData})</code> |
| * method.</td> |
| * <td>The equivalent {@link javax.management.openmbean.CompositeData} |
| * instance, specified by the <code>from</code> method.</td> |
| * </tr><tr> |
| * <td>A map with keys of type <code>K</code> and values of |
| * type <code>V</code>.</td> |
| * <td>A {@link javax.management.openmbean.TabularData} instance, |
| * with the row type containing two items, <code>"key"</code> and |
| * <code>"value"</code> with the types <code>K</code> and <code>V</code> |
| * respectively (with translation applied).</td> |
| * </tr><tr> |
| * <td>A list of type <code>E</code>.</td> |
| * <td>An array with this mapping applied to <code>E</code>.</td> |
| * </tr></table> |
| * |
| * @author Andrew John Hughes (gnu_andrew@member.fsf.org) |
| * @since 1.5 |
| */ |
| public class ManagementFactory |
| { |
| |
| /** |
| * The object name for the class loading bean. |
| */ |
| public static final String CLASS_LOADING_MXBEAN_NAME = |
| "java.lang:type=ClassLoading"; |
| |
| /** |
| * The object name for the compilation bean. |
| */ |
| public static final String COMPILATION_MXBEAN_NAME = |
| "java.lang:type=Compilation"; |
| |
| /** |
| * The domain for the garbage collecting beans. |
| */ |
| public static final String GARBAGE_COLLECTOR_MXBEAN_DOMAIN_TYPE = |
| "java.lang:type=GarbageCollector"; |
| |
| /** |
| * The domain for the memory manager beans. |
| */ |
| public static final String MEMORY_MANAGER_MXBEAN_DOMAIN_TYPE = |
| "java.lang:type=MemoryManager"; |
| |
| /** |
| * The object name for the memory bean. |
| */ |
| public static final String MEMORY_MXBEAN_NAME = |
| "java.lang:type=Memory"; |
| |
| /** |
| * The domain for the memory pool beans. |
| */ |
| public static final String MEMORY_POOL_MXBEAN_DOMAIN_TYPE = |
| "java.lang:type=MemoryPool"; |
| |
| /** |
| * The object name for the operating system bean. |
| */ |
| public static final String OPERATING_SYSTEM_MXBEAN_NAME = |
| "java.lang:type=OperatingSystem"; |
| |
| /** |
| * The object name for the runtime bean. |
| */ |
| public static final String RUNTIME_MXBEAN_NAME = |
| "java.lang:type=Runtime"; |
| |
| /** |
| * The object name for the threading bean. |
| */ |
| public static final String THREAD_MXBEAN_NAME = |
| "java.lang:type=Threading"; |
| |
| /** |
| * The operating system management bean. |
| */ |
| private static OperatingSystemMXBean osBean; |
| |
| /** |
| * The runtime management bean. |
| */ |
| private static RuntimeMXBean runtimeBean; |
| |
| /** |
| * The class loading management bean. |
| */ |
| private static ClassLoadingMXBean classLoadingBean; |
| |
| /** |
| * The thread bean. |
| */ |
| private static ThreadMXBean threadBean; |
| |
| /** |
| * The memory bean. |
| */ |
| private static MemoryMXBean memoryBean; |
| |
| /** |
| * The compilation bean (may remain null). |
| */ |
| private static CompilationMXBean compilationBean; |
| |
| /** |
| * The platform server. |
| */ |
| private static MBeanServer platformServer; |
| |
| /** |
| * Private constructor to prevent instance creation. |
| */ |
| private ManagementFactory() {} |
| |
| /** |
| * Returns the operating system management bean for the |
| * operating system on which the virtual machine is running. |
| * |
| * @return an instance of {@link OperatingSystemMXBean} for |
| * the underlying operating system. |
| */ |
| public static OperatingSystemMXBean getOperatingSystemMXBean() |
| { |
| if (osBean == null) |
| try |
| { |
| osBean = new OperatingSystemMXBeanImpl(); |
| } |
| catch (NotCompliantMBeanException e) |
| { |
| throw new InternalError("The GNU implementation of the " + |
| "operating system bean is not a " + |
| "compliant management bean."); |
| } |
| return osBean; |
| } |
| |
| /** |
| * Returns the runtime management bean for the |
| * running virtual machine. |
| * |
| * @return an instance of {@link RuntimeMXBean} for |
| * this virtual machine. |
| */ |
| public static RuntimeMXBean getRuntimeMXBean() |
| { |
| if (runtimeBean == null) |
| try |
| { |
| runtimeBean = new RuntimeMXBeanImpl(); |
| } |
| catch (NotCompliantMBeanException e) |
| { |
| throw new InternalError("The GNU implementation of the " + |
| "runtime bean is not a compliant " + |
| "management bean."); |
| } |
| return runtimeBean; |
| } |
| |
| /** |
| * Returns the class loading management bean for the |
| * running virtual machine. |
| * |
| * @return an instance of {@link ClassLoadingMXBean} for |
| * this virtual machine. |
| */ |
| public static ClassLoadingMXBean getClassLoadingMXBean() |
| { |
| if (classLoadingBean == null) |
| try |
| { |
| classLoadingBean = new ClassLoadingMXBeanImpl(); |
| } |
| catch (NotCompliantMBeanException e) |
| { |
| throw new InternalError("The GNU implementation of the " + |
| "class loading bean is not a " + |
| "compliant management bean."); |
| } |
| return classLoadingBean; |
| } |
| |
| /** |
| * Returns the thread management bean for the running |
| * virtual machine. |
| * |
| * @return an instance of {@link ThreadMXBean} for |
| * this virtual machine. |
| */ |
| public static ThreadMXBean getThreadMXBean() |
| { |
| if (threadBean == null) |
| try |
| { |
| threadBean = new ThreadMXBeanImpl(); |
| } |
| catch (NotCompliantMBeanException e) |
| { |
| throw new InternalError("The GNU implementation of the " + |
| "thread bean is not a compliant " + |
| "management bean."); |
| } |
| return threadBean; |
| } |
| |
| /** |
| * Returns the memory management bean for the running |
| * virtual machine. |
| * |
| * @return an instance of {@link MemoryMXBean} for |
| * this virtual machine. |
| */ |
| public static MemoryMXBean getMemoryMXBean() |
| { |
| if (memoryBean == null) |
| try |
| { |
| memoryBean = new MemoryMXBeanImpl(); |
| } |
| catch (NotCompliantMBeanException e) |
| { |
| throw new InternalError("The GNU implementation of the " + |
| "memory bean is not a compliant " + |
| "management bean."); |
| } |
| return memoryBean; |
| } |
| |
| /** |
| * Returns the compilation bean for the running |
| * virtual machine, if supported. Otherwise, |
| * it returns <code>null</code>. |
| * |
| * @return an instance of {@link CompilationMXBean} for |
| * this virtual machine, or <code>null</code> |
| * if the virtual machine doesn't include |
| * a Just-In-Time (JIT) compiler. |
| */ |
| public static CompilationMXBean getCompilationMXBean() |
| { |
| if (compilationBean == null && |
| SystemProperties.getProperty("gnu.java.compiler.name") != null) |
| try |
| { |
| compilationBean = new CompilationMXBeanImpl(); |
| } |
| catch (NotCompliantMBeanException e) |
| { |
| throw new InternalError("The GNU implementation of the " + |
| "compilation bean is not a compliant " + |
| "management bean."); |
| } |
| return compilationBean; |
| } |
| |
| /** |
| * Returns the memory pool beans for the running |
| * virtual machine. These may change during the course |
| * of execution. |
| * |
| * @return a list of memory pool beans, one for each pool. |
| */ |
| public static List<MemoryPoolMXBean> getMemoryPoolMXBeans() |
| { |
| List<MemoryPoolMXBean> poolBeans = |
| new ArrayList<MemoryPoolMXBean>(); |
| String[] names = VMManagementFactory.getMemoryPoolNames(); |
| for (int a = 0; a < names.length; ++a) |
| try |
| { |
| poolBeans.add(new MemoryPoolMXBeanImpl(names[a])); |
| } |
| catch (NotCompliantMBeanException e) |
| { |
| throw new InternalError("The GNU implementation of the " + |
| "memory pool bean, " + a + ", is " + |
| "not a compliant management bean."); |
| } |
| return poolBeans; |
| } |
| |
| /** |
| * Returns the memory manager beans for the running |
| * virtual machine. These may change during the course |
| * of execution. |
| * |
| * @return a list of memory manager beans, one for each manager. |
| */ |
| public static List<MemoryManagerMXBean> getMemoryManagerMXBeans() |
| { |
| List<MemoryManagerMXBean> managerBeans = |
| new ArrayList<MemoryManagerMXBean>(); |
| String[] names = VMManagementFactory.getMemoryManagerNames(); |
| for (int a = 0; a < names.length; ++a) |
| try |
| { |
| managerBeans.add(new MemoryManagerMXBeanImpl(names[a])); |
| } |
| catch (NotCompliantMBeanException e) |
| { |
| throw new InternalError("The GNU implementation of the " + |
| "memory manager bean, " + a + ", is " + |
| "not a compliant management bean."); |
| } |
| managerBeans.addAll(getGarbageCollectorMXBeans()); |
| return managerBeans; |
| } |
| |
| /** |
| * Returns the garbage collector beans for the running |
| * virtual machine. These may change during the course |
| * of execution. |
| * |
| * @return a list of garbage collector beans, one for each pool. |
| */ |
| public static List<GarbageCollectorMXBean> getGarbageCollectorMXBeans() |
| { |
| List<GarbageCollectorMXBean> gcBeans = |
| new ArrayList<GarbageCollectorMXBean>(); |
| String[] names = VMManagementFactory.getGarbageCollectorNames(); |
| for (int a = 0; a < names.length; ++a) |
| try |
| { |
| gcBeans.add(new GarbageCollectorMXBeanImpl(names[a])); |
| } |
| catch (NotCompliantMBeanException e) |
| { |
| throw new InternalError("The GNU implementation of the " + |
| "garbage collector bean, " + a + |
| ", is not a compliant management " + |
| "bean."); |
| } |
| return gcBeans; |
| } |
| |
| /** |
| * <p> |
| * Returns the platform {@link javax.management.MBeanServer}. On the |
| * first call to this method, a server instance is retrieved from |
| * the {@link javax.management.MBeanServerFactory} and each of the |
| * beans are registered with it. Subsequent calls return the existing |
| * instance. If the property <code>javax.management.builder.initial</code> |
| * is set, its value will be used as the name of the class which is used |
| * to provide the server instance. |
| * </p> |
| * <p> |
| * It is recommended that the platform server is used for other beans as |
| * well, in order to simplify their discovery and publication. Name conflicts |
| * should be avoided. |
| * </p> |
| * |
| * @return the platform {@link javax.management.MBeanServer} |
| * @throws SecurityException if a security manager exists and the |
| * caller's permissions don't imply {@link |
| * MBeanServerPermission(String)}("createMBeanServer") |
| * @see javax.management.MBeanServerFactory |
| * @see javax.management.MBeanServerFactory#createMBeanServer() |
| */ |
| public static MBeanServer getPlatformMBeanServer() |
| { |
| if (platformServer == null) |
| { |
| platformServer = MBeanServerFactory.createMBeanServer(); |
| try |
| { |
| platformServer.registerMBean(getOperatingSystemMXBean(), |
| new ObjectName(OPERATING_SYSTEM_MXBEAN_NAME)); |
| platformServer.registerMBean(getRuntimeMXBean(), |
| new ObjectName(RUNTIME_MXBEAN_NAME)); |
| platformServer.registerMBean(getClassLoadingMXBean(), |
| new ObjectName(CLASS_LOADING_MXBEAN_NAME)); |
| platformServer.registerMBean(getThreadMXBean(), |
| new ObjectName(THREAD_MXBEAN_NAME)); |
| platformServer.registerMBean(getMemoryMXBean(), |
| new ObjectName(MEMORY_MXBEAN_NAME)); |
| CompilationMXBean compBean = getCompilationMXBean(); |
| if (compBean != null) |
| platformServer.registerMBean(compBean, |
| new ObjectName(COMPILATION_MXBEAN_NAME)); |
| Iterator beans = getMemoryPoolMXBeans().iterator(); |
| while (beans.hasNext()) |
| { |
| MemoryPoolMXBean bean = (MemoryPoolMXBean) beans.next(); |
| platformServer.registerMBean(bean, |
| new ObjectName(MEMORY_POOL_MXBEAN_DOMAIN_TYPE + |
| ",name=" + |
| bean.getName())); |
| } |
| beans = getMemoryManagerMXBeans().iterator(); |
| while (beans.hasNext()) |
| { |
| MemoryManagerMXBean bean = (MemoryManagerMXBean) beans.next(); |
| platformServer.registerMBean(bean, |
| new ObjectName(MEMORY_MANAGER_MXBEAN_DOMAIN_TYPE + |
| ",name=" + |
| bean.getName())); |
| } |
| beans = getGarbageCollectorMXBeans().iterator(); |
| while (beans.hasNext()) |
| { |
| GarbageCollectorMXBean bean = (GarbageCollectorMXBean) beans.next(); |
| platformServer.registerMBean(bean, |
| new ObjectName(GARBAGE_COLLECTOR_MXBEAN_DOMAIN_TYPE + |
| ",name=" + |
| bean.getName())); |
| } |
| platformServer.registerMBean(LogManager.getLoggingMXBean(), |
| new ObjectName(LogManager.LOGGING_MXBEAN_NAME)); |
| } |
| catch (InstanceAlreadyExistsException e) |
| { |
| throw (Error) |
| (new InternalError("One of the management beans is " + |
| "already registered.").initCause(e)); |
| } |
| catch (MBeanRegistrationException e) |
| { |
| throw (Error) |
| (new InternalError("One of the management beans' preRegister " + |
| "methods threw an exception.").initCause(e)); |
| } |
| catch (NotCompliantMBeanException e) |
| { |
| throw (Error) |
| (new InternalError("One of the management beans is " + |
| "not compliant.").initCause(e)); |
| } |
| catch (MalformedObjectNameException e) |
| { |
| throw (Error) |
| (new InternalError("The object name of a management bean is " + |
| "not compliant.").initCause(e)); |
| } |
| } |
| return platformServer; |
| } |
| |
| /** |
| * <p> |
| * Returns a proxy for the specified platform bean. A proxy object is created |
| * using <code>Proxy.newProxyInstance(mxbeanInterface.getClassLoader(), |
| * new Class[] { mxbeanInterface }, handler)</code>. The |
| * {@link javax.management.NotificationEmitter} class is also added to the |
| * array if the bean provides notifications. <code>handler</code> refers |
| * to the invocation handler which forwards calls to the connection, and |
| * also provides translation between the Java data types used in the |
| * bean interfaces and the open data types, as specified in the description |
| * of this class. It is this translation that makes the |
| * usual {@link javax.management.MBeanServerInvocationHandler} inappropriate |
| * for providing such a proxy. |
| * </p> |
| * <p> |
| * <strong>Note</strong>: use of the proxy may result in |
| * {@link java.io.IOException}s from the underlying {@link MBeanServerConnection} |
| * and a {@link java.io.InvalidObjectException} if enum constants |
| * used on the client and the server don't match. |
| * </p> |
| * |
| * @param connection the server connection to use to access the bean. |
| * @param mxbeanName the {@link javax.management.ObjectName} of the |
| * bean to provide a proxy for. |
| * @param mxbeanInterface the interface for the bean being proxied. |
| * @return a proxy for the specified bean. |
| * @throws IllegalArgumentException if <code>mxbeanName</code> is not a valid |
| * {@link javax.management.ObjectName}, |
| * the interface and name do not match the |
| * same bean, the name does not refer to a |
| * platform bean or the bean is not registered |
| * with the server accessed by <code>connection</code>. |
| * @throws IOException if the connection throws one. |
| */ |
| public static <T> T newPlatformMXBeanProxy(MBeanServerConnection connection, |
| String mxbeanName, |
| Class<T> mxbeanInterface) |
| throws IOException |
| { |
| if (!(mxbeanName.equals(CLASS_LOADING_MXBEAN_NAME) || |
| mxbeanName.equals(COMPILATION_MXBEAN_NAME) || |
| mxbeanName.startsWith(GARBAGE_COLLECTOR_MXBEAN_DOMAIN_TYPE) || |
| mxbeanName.startsWith(MEMORY_MANAGER_MXBEAN_DOMAIN_TYPE) || |
| mxbeanName.equals(MEMORY_MXBEAN_NAME) || |
| mxbeanName.startsWith(MEMORY_POOL_MXBEAN_DOMAIN_TYPE) || |
| mxbeanName.equals(OPERATING_SYSTEM_MXBEAN_NAME) || |
| mxbeanName.equals(RUNTIME_MXBEAN_NAME) || |
| mxbeanName.equals(THREAD_MXBEAN_NAME))) |
| { |
| throw new IllegalArgumentException("The named bean, " + mxbeanName + |
| ", is not a platform name."); |
| } |
| if ((mxbeanName.equals(CLASS_LOADING_MXBEAN_NAME) && |
| mxbeanInterface != ClassLoadingMXBean.class) || |
| (mxbeanName.equals(COMPILATION_MXBEAN_NAME) && |
| mxbeanInterface != CompilationMXBean.class) || |
| (mxbeanName.startsWith(GARBAGE_COLLECTOR_MXBEAN_DOMAIN_TYPE) && |
| mxbeanInterface != GarbageCollectorMXBean.class) || |
| (mxbeanName.startsWith(MEMORY_MANAGER_MXBEAN_DOMAIN_TYPE) && |
| mxbeanInterface != MemoryManagerMXBean.class) || |
| (mxbeanName.equals(MEMORY_MXBEAN_NAME) && |
| mxbeanInterface != MemoryMXBean.class) || |
| (mxbeanName.startsWith(MEMORY_POOL_MXBEAN_DOMAIN_TYPE) && |
| mxbeanInterface != MemoryPoolMXBean.class) || |
| (mxbeanName.equals(OPERATING_SYSTEM_MXBEAN_NAME) && |
| mxbeanInterface != OperatingSystemMXBean.class) || |
| (mxbeanName.equals(RUNTIME_MXBEAN_NAME) && |
| mxbeanInterface != RuntimeMXBean.class) || |
| (mxbeanName.equals(THREAD_MXBEAN_NAME) && |
| mxbeanInterface != ThreadMXBean.class)) |
| throw new IllegalArgumentException("The interface, " + mxbeanInterface + |
| ", does not match the bean, " + mxbeanName); |
| ObjectName bean; |
| try |
| { |
| bean = new ObjectName(mxbeanName); |
| } |
| catch (MalformedObjectNameException e) |
| { |
| throw new IllegalArgumentException("The named bean is invalid."); |
| } |
| if (!(connection.isRegistered(bean))) |
| throw new IllegalArgumentException("The bean is not registered on this connection."); |
| Class[] interfaces; |
| if (mxbeanName.equals(MEMORY_MXBEAN_NAME)) |
| interfaces = new Class[] { mxbeanInterface, NotificationEmitter.class }; |
| else |
| interfaces = new Class[] { mxbeanInterface }; |
| return (T) Proxy.newProxyInstance(mxbeanInterface.getClassLoader(), |
| interfaces, |
| new ManagementInvocationHandler(connection, bean)); |
| } |
| |
| /** |
| * This invocation handler provides method calls for a platform bean |
| * by forwarding them to a {@link MBeanServerConnection}. Translation from |
| * Java data types to open data types is performed as specified above. |
| * |
| * @author Andrew John Hughes (gnu_andrew@member.fsf.org) |
| * @since 1.5 |
| */ |
| private static class ManagementInvocationHandler |
| implements InvocationHandler |
| { |
| |
| /** |
| * The encapsulated connection. |
| */ |
| private MBeanServerConnection conn; |
| |
| /** |
| * The bean being proxied. |
| */ |
| private ObjectName bean; |
| |
| /** |
| * Constructs a new {@link InvocationHandler} which proxies |
| * for the specified bean using the supplied connection. |
| * |
| * @param conn the connection on which to forward method calls. |
| * @param bean the bean to proxy. |
| */ |
| public ManagementInvocationHandler(MBeanServerConnection conn, |
| ObjectName bean) |
| throws IOException |
| { |
| this.conn = conn; |
| this.bean = bean; |
| } |
| |
| /** |
| * Called by the proxy class whenever a method is called. The method |
| * is emulated by retrieving an attribute from, setting an attribute on |
| * or invoking a method on the server connection as required. Translation |
| * between the Java data types supplied as arguments to the open types used |
| * by the bean is provided, as well as translation of the return value back |
| * in to the appropriate Java type. |
| * |
| * @param proxy the proxy on which the method was called. |
| * @param method the method which was called. |
| * @param args the arguments supplied to the method. |
| * @return the return value from the method. |
| * @throws Throwable if an exception is thrown in performing the |
| * method emulation. |
| */ |
| public Object invoke(Object proxy, Method method, Object[] args) |
| throws Throwable |
| { |
| String name = method.getName(); |
| if (name.equals("toString")) |
| return "Proxy for " + bean + " using " + conn; |
| if (name.equals("addNotificationListener")) |
| { |
| conn.addNotificationListener(bean, |
| (NotificationListener) args[0], |
| (NotificationFilter) args[1], |
| args[2]); |
| return null; |
| } |
| if (name.equals("getNotificationInfo")) |
| return conn.getMBeanInfo(bean).getNotifications(); |
| if (name.equals("removeNotificationListener")) |
| { |
| if (args.length == 1) |
| conn.removeNotificationListener(bean, |
| (NotificationListener) |
| args[0]); |
| else |
| conn.removeNotificationListener(bean, |
| (NotificationListener) |
| args[0], |
| (NotificationFilter) |
| args[1], args[2]); |
| return null; |
| } |
| String attrib = null; |
| if (name.startsWith("get")) |
| attrib = name.substring(3); |
| else if (name.startsWith("is")) |
| attrib = name.substring(2); |
| if (attrib != null) |
| return translate(conn.getAttribute(bean, attrib), method); |
| else if (name.startsWith("set")) |
| { |
| conn.setAttribute(bean, new Attribute(name.substring(3), |
| args[0])); |
| return null; |
| } |
| else |
| return translate(conn.invoke(bean, name, args, null), method); |
| } |
| |
| /** |
| * 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. |
| */ |
| private final Object translate(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 l = new ArrayList(elems.length); |
| for (Object elem : elems) |
| l.add(elem); |
| return l; |
| } |
| if (Map.class.isAssignableFrom(returnType)) |
| { |
| TabularData data = (TabularData) otype; |
| Map m = new HashMap(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; |
| } |
| |
| } |
| } |