OpenJDK / jdk / jdk
changeset 1702:50e12093123c
6287328: Add methods to StandardMBean to retrieve a method based on MBean{Attribute|Operation}Info
Reviewed-by: emcmanus
author | jfdenise |
---|---|
date | Tue, 09 Dec 2008 16:26:30 +0100 |
parents | f5cedaa459bf |
children | d2b5c71d8771 |
files | jdk/src/share/classes/com/sun/jmx/mbeanserver/MBeanInstantiator.java jdk/src/share/classes/com/sun/jmx/mbeanserver/MBeanIntrospector.java jdk/src/share/classes/javax/management/StandardMBean.java jdk/test/javax/management/standardmbean/FindMethodTest.java |
diffstat | 4 files changed, 540 insertions(+), 1 deletions(-) [+] |
line wrap: on
line diff
--- a/jdk/src/share/classes/com/sun/jmx/mbeanserver/MBeanInstantiator.java Tue Dec 09 16:14:53 2008 +0100 +++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/MBeanInstantiator.java Tue Dec 09 16:26:30 2008 +0100 @@ -614,6 +614,15 @@ } /** + * Returns the class of a primitive type. + * @param name The type for which we the associated class. + * @return the class, or null if name is not primitive. + */ + public static Class<?> primitiveType(String name) { + return primitiveClasses.get(name); + } + + /** * Load a class with the specified loader, or with this object * class loader if the specified loader is null. **/
--- a/jdk/src/share/classes/com/sun/jmx/mbeanserver/MBeanIntrospector.java Tue Dec 09 16:14:53 2008 +0100 +++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/MBeanIntrospector.java Tue Dec 09 16:26:30 2008 +0100 @@ -518,7 +518,7 @@ * see the version of the @ManagedAttribute (or ...Operation) annotation * from that method, which might have a different description or whatever. */ - private static void getAnnotatedMethods(Class<?> c, List<Method> methods) + public static void getAnnotatedMethods(Class<?> c, List<Method> methods) throws Exception { Class<?> sup = c.getSuperclass(); if (sup != null)
--- a/jdk/src/share/classes/javax/management/StandardMBean.java Tue Dec 09 16:14:53 2008 +0100 +++ b/jdk/src/share/classes/javax/management/StandardMBean.java Tue Dec 09 16:26:30 2008 +0100 @@ -28,14 +28,21 @@ import com.sun.jmx.mbeanserver.DescriptorCache; import com.sun.jmx.mbeanserver.Introspector; import com.sun.jmx.mbeanserver.MBeanInjector; +import com.sun.jmx.mbeanserver.MBeanInstantiator; +import com.sun.jmx.mbeanserver.MBeanIntrospector; import com.sun.jmx.mbeanserver.MBeanSupport; import com.sun.jmx.mbeanserver.MXBeanSupport; import com.sun.jmx.mbeanserver.StandardMBeanSupport; import com.sun.jmx.mbeanserver.Util; +import java.lang.reflect.Method; import java.security.AccessController; import java.security.PrivilegedAction; +import java.util.ArrayList; import java.util.HashMap; +import java.util.HashSet; +import java.util.List; import java.util.Map; +import java.util.Set; import java.util.WeakHashMap; import java.util.logging.Level; import javax.management.openmbean.MXBeanMappingFactory; @@ -1316,6 +1323,145 @@ return natts; } + // ------------------------------------------------------------------ + // Resolve from a type name to a Class. + // ------------------------------------------------------------------ + private static Class<?> resolveClass(MBeanFeatureInfo info, String type, + Class<?> mbeanItf) + throws ClassNotFoundException { + String t = (String) info.getDescriptor(). + getFieldValue(JMX.ORIGINAL_TYPE_FIELD); + if (t == null) { + t = type; + } + Class<?> clazz = MBeanInstantiator.primitiveType(t); + if(clazz == null) + clazz = Class.forName(t, false, mbeanItf.getClassLoader()); + return clazz; + } + + // ------------------------------------------------------------------ + // Return the subset of valid Management methods + // ------------------------------------------------------------------ + private static Method getManagementMethod(final Class<?> mbeanType, + String opName, Class<?>... parameters) throws NoSuchMethodException, + SecurityException { + Method m = mbeanType.getMethod(opName, parameters); + if (mbeanType.isInterface()) { + return m; + } + final List<Method> methods = new ArrayList<Method>(); + try { + MBeanIntrospector.getAnnotatedMethods(mbeanType, methods); + }catch (SecurityException ex) { + throw ex; + }catch (NoSuchMethodException ex) { + throw ex; + }catch (Exception ex) { + NoSuchMethodException nsme = + new NoSuchMethodException(ex.toString()); + nsme.initCause(ex); + throw nsme; + } + + if(methods.contains(m)) return m; + + throw new NoSuchMethodException("Operation " + opName + + " not found in management interface " + mbeanType.getName()); + } + /** + * Retrieve the set of MBean attribute accessor <code>Method</code>s + * located in the <code>mbeanInterface</code> MBean interface that + * correspond to the <code>attr</code> <code>MBeanAttributeInfo</code> + * parameter. + * @param mbeanInterface the management interface. + * Can be a standard MBean or MXBean interface, or a Java class + * annotated with {@link MBean @MBean} or {@link MXBean @MXBean}. + * @param attr The attribute we want the accessors for. + * @return The set of accessors. + * @throws java.lang.NoSuchMethodException if no accessor exists + * for the given {@link MBeanAttributeInfo MBeanAttributeInfo}. + * @throws java.lang.IllegalArgumentException if at least one + * of the two parameters is null. + * @throws java.lang.ClassNotFoundException if the class named in the + * attribute type is not found. + * @throws java.lang.SecurityException if this exception is + * encountered while introspecting the MBean interface. + */ + public static Set<Method> findAttributeAccessors(Class<?> mbeanInterface, + MBeanAttributeInfo attr) + throws NoSuchMethodException, + ClassNotFoundException { + if (mbeanInterface == null || attr == null) { + throw new IllegalArgumentException("mbeanInterface or attr " + + "parameter is null"); + } + String attributeName = attr.getName(); + Set<Method> methods = new HashSet<Method>(); + Class<?> clazz = resolveClass(attr, attr.getType(), mbeanInterface); + if (attr.isReadable()) { + String radical = "get"; + if(attr.isIs()) radical = "is"; + Method getter = getManagementMethod(mbeanInterface, radical + + attributeName); + if (getter.getReturnType().equals(clazz)) { + methods.add(getter); + } else { + throw new NoSuchMethodException("Invalid getter return type, " + + "should be " + clazz + ", found " + + getter.getReturnType()); + } + } + if (attr.isWritable()) { + Method setter = getManagementMethod(mbeanInterface, "set" + + attributeName, + clazz); + if (setter.getReturnType().equals(Void.TYPE)) { + methods.add(setter); + } else { + throw new NoSuchMethodException("Invalid setter return type, " + + "should be void, found " + setter.getReturnType()); + } + } + return methods; + } + + /** + * Retrieve the MBean operation <code>Method</code> + * located in the <code>mbeanInterface</code> MBean interface that + * corresponds to the provided <code>op</code> + * <code>MBeanOperationInfo</code> parameter. + * @param mbeanInterface the management interface. + * Can be a standard MBean or MXBean interface, or a Java class + * annotated with {@link MBean @MBean} or {@link MXBean @MXBean}. + * @param op The operation we want the method for. + * @return the method corresponding to the provided MBeanOperationInfo. + * @throws java.lang.NoSuchMethodException if no method exists + * for the given {@link MBeanOperationInfo MBeanOperationInfo}. + * @throws java.lang.IllegalArgumentException if at least one + * of the two parameters is null. + * @throws java.lang.ClassNotFoundException if one of the + * classes named in the operation signature array is not found. + * @throws java.lang.SecurityException if this exception is + * encountered while introspecting the MBean interface. + */ + public static Method findOperationMethod(Class<?> mbeanInterface, + MBeanOperationInfo op) + throws ClassNotFoundException, NoSuchMethodException { + if (mbeanInterface == null || op == null) { + throw new IllegalArgumentException("mbeanInterface or op " + + "parameter is null"); + } + List<Class<?>> classes = new ArrayList<Class<?>>(); + for (MBeanParameterInfo info : op.getSignature()) { + Class<?> clazz = resolveClass(info, info.getType(), mbeanInterface); + classes.add(clazz); + } + Class<?>[] signature = new Class<?>[classes.size()]; + classes.toArray(signature); + return getManagementMethod(mbeanInterface, op.getName(), signature); + } + /** * <p>Allows the MBean to perform any operations it needs before * being registered in the MBean server. If the name of the MBean
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/jdk/test/javax/management/standardmbean/FindMethodTest.java Tue Dec 09 16:26:30 2008 +0100 @@ -0,0 +1,384 @@ +/* + * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code 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 + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, + * CA 95054 USA or visit www.sun.com if you need additional information or + * have any questions. + */ + +/* + * @test + * @bug 6287328 + * @summary Add methods to StandardMBean to retrieve a method based on + * MBean{Attribute|Operation}Info + * @author Jean-Francois Denise + * @run main FindMethodTest + */ + +import java.lang.management.ManagementFactory; +import java.lang.management.MemoryMXBean; +import java.lang.management.ThreadMXBean; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import javax.management.MBean; +import javax.management.MBeanAttributeInfo; +import javax.management.MBeanInfo; +import javax.management.MBeanOperationInfo; +import javax.management.MBeanParameterInfo; +import javax.management.MBeanServer; +import javax.management.ManagedAttribute; +import javax.management.ManagedOperation; +import javax.management.ObjectName; +import javax.management.StandardMBean; + +public class FindMethodTest { + + private static MBeanServer server = + ManagementFactory.getPlatformMBeanServer(); + + private static Map<String, Set<Method>> expectedMapping = + new HashMap<String, Set<Method>>(); + private static Set<Method> STATE_SET = new HashSet<Method>(); + private static Set<Method> ENABLED_SET = new HashSet<Method>(); + private static Set<Method> DOIT_SET = new HashSet<Method>(); + private static Set<Method> STATUS_SET = new HashSet<Method>(); + private static Set<Method> HEAPMEMORYUSAGE_SET = new HashSet<Method>(); + private static Set<Method> THREADINFO_SET = new HashSet<Method>(); + private static Set<Method> DOIT_ANNOTATED_SET = new HashSet<Method>(); + private static Set<Method> IT_ANNOTATED_SET = new HashSet<Method>(); + private static HashSet<Set<Method>> TEST_MBEAN_SET = + new HashSet<Set<Method>>(); + private static HashSet<Set<Method>> ANNOTATED_MBEAN_SET = + new HashSet<Set<Method>>(); + private static HashSet<Set<Method>> MEMORY_MBEAN_SET = + new HashSet<Set<Method>>(); + private static HashSet<Set<Method>> THREAD_MBEAN_SET = + new HashSet<Set<Method>>(); + + public interface TestMBean { + + public void doIt(); + + public void setState(String str); + + public String getState(); + + public boolean isEnabled(); + + public void setStatus(int i); + } + + public interface FaultyTestMBean { + + public void doIt(String doIt); + + public long getState(); + + public void setEnabled(boolean b); + + public int getStatus(); + + public String setWrong(int i); + } + + @MBean + public static class AnnotatedTest { + @ManagedOperation + public void doItAnnotated() { + + } + + public void dontDoIt() { + + } + + @ManagedAttribute + public String getItAnnotated() { + return null; + } + @ManagedAttribute + public void setItAnnotated(String str) { + + } + + public String getItNot() { + return null; + } + + } + + static class Test implements TestMBean { + + public void doIt() { + throw new UnsupportedOperationException("Not supported yet."); + } + + public void setState(String str) { + throw new UnsupportedOperationException("Not supported yet."); + } + + public String getState() { + throw new UnsupportedOperationException("Not supported yet."); + } + + public boolean isEnabled() { + throw new UnsupportedOperationException("Not supported yet."); + } + + public void setStatus(int i) { + throw new UnsupportedOperationException("Not supported yet."); + } + } + + + static { + try { + ENABLED_SET.add(TestMBean.class.getDeclaredMethod("isEnabled")); + + STATE_SET.add(TestMBean.class.getDeclaredMethod("getState")); + STATE_SET.add(TestMBean.class.getDeclaredMethod("setState", + String.class)); + STATUS_SET.add(TestMBean.class.getDeclaredMethod("setStatus", + int.class)); + + DOIT_SET.add(TestMBean.class.getDeclaredMethod("doIt")); + + DOIT_ANNOTATED_SET.add(AnnotatedTest.class.getDeclaredMethod("doItAnnotated")); + + IT_ANNOTATED_SET.add(AnnotatedTest.class.getDeclaredMethod("getItAnnotated")); + IT_ANNOTATED_SET.add(AnnotatedTest.class.getDeclaredMethod("setItAnnotated", String.class)); + + THREADINFO_SET.add(ThreadMXBean.class.getDeclaredMethod("dumpAllThreads", boolean.class, + boolean.class)); + + HEAPMEMORYUSAGE_SET.add(MemoryMXBean.class.getDeclaredMethod("getHeapMemoryUsage")); + + TEST_MBEAN_SET.add(ENABLED_SET); + TEST_MBEAN_SET.add(STATE_SET); + TEST_MBEAN_SET.add(STATUS_SET); + TEST_MBEAN_SET.add(DOIT_SET); + + ANNOTATED_MBEAN_SET.add(DOIT_ANNOTATED_SET); + ANNOTATED_MBEAN_SET.add(IT_ANNOTATED_SET); + + MEMORY_MBEAN_SET.add(HEAPMEMORYUSAGE_SET); + + THREAD_MBEAN_SET.add(THREADINFO_SET); + + expectedMapping.put("State", STATE_SET); + expectedMapping.put("Enabled", ENABLED_SET); + expectedMapping.put("Status", STATUS_SET); + expectedMapping.put("doIt", DOIT_SET); + expectedMapping.put("HeapMemoryUsage", HEAPMEMORYUSAGE_SET); + expectedMapping.put("dumpAllThreads", THREADINFO_SET); + expectedMapping.put("doItAnnotated", DOIT_ANNOTATED_SET); + expectedMapping.put("ItAnnotated", IT_ANNOTATED_SET); + + } catch (Exception ex) { + ex.printStackTrace(); + throw new RuntimeException("Initialization failed"); + } + } + + private static void testMBean(ObjectName name, Class<?> itf, + HashSet<Set<Method>> expectMappings) + throws Exception { + + Set<Set<Method>> expectedMappings = + (Set<Set<Method>>) expectMappings.clone(); + + MBeanInfo info = server.getMBeanInfo(name); + for (MBeanAttributeInfo attr : info.getAttributes()) { + Set<Method> expected = expectedMapping.get(attr.getName()); + if (expected == null) { + continue; + } + if (!expectedMappings.remove(expected)) { + throw new Exception("The mapping to use is not the expected " + + "one for " + attr); + } + System.out.println("Expected : " + expected); + Set<Method> found = + StandardMBean.findAttributeAccessors(itf, attr); + System.out.println("Found : " + found); + if (!found.equals(expected)) { + throw new Exception("Mapping error."); + } + } + for (MBeanOperationInfo op : info.getOperations()) { + Set<Method> expected = expectedMapping.get(op.getName()); + if (expected == null) { + continue; + } + if (!expectedMappings.remove(expected)) { + throw new Exception("The mapping to use is not the expected " + + "one for " + op); + } + System.out.println("Expected : " + expected); + Method method = + StandardMBean.findOperationMethod(itf, op); + Set<Method> found = new HashSet<Method>(); + found.add(method); + System.out.println("Found : " + found); + if (!found.equals(expected)) { + throw new Exception("Mapping error."); + } + } + + if (expectedMappings.size() != 0) { + throw new Exception("Some mapping have not been found " + + expectedMappings); + } else { + System.out.println("All mappings have been found"); + } + } + + public static void main(String[] args) throws Exception { + // Positive tests + Test t = new Test(); + ObjectName name = ObjectName.valueOf(":type=Test"); + server.registerMBean(t, name); + AnnotatedTest at = new AnnotatedTest(); + ObjectName annotatedName = ObjectName.valueOf(":type=AnnotatedTest"); + server.registerMBean(at, annotatedName); + + testMBean(name, TestMBean.class, TEST_MBEAN_SET); + + testMBean(annotatedName, AnnotatedTest.class, ANNOTATED_MBEAN_SET); + + ObjectName memoryName = + ObjectName.valueOf(ManagementFactory.MEMORY_MXBEAN_NAME); + testMBean(memoryName, MemoryMXBean.class, MEMORY_MBEAN_SET); + + ObjectName threadName = + ObjectName.valueOf(ManagementFactory.THREAD_MXBEAN_NAME); + testMBean(threadName, ThreadMXBean.class, THREAD_MBEAN_SET); + + // Negative tests + try { + StandardMBean.findOperationMethod(null, + new MBeanOperationInfo("Test", + TestMBean.class.getDeclaredMethod("doIt"))); + throw new Exception("Expected exception not found"); + } catch (IllegalArgumentException ex) { + System.out.println("OK received expected exception " + ex); + } + try { + StandardMBean.findOperationMethod(TestMBean.class, null); + throw new Exception("Expected exception not found"); + } catch (IllegalArgumentException ex) { + System.out.println("OK received expected exception " + ex); + } + try { + StandardMBean.findAttributeAccessors(null, + new MBeanAttributeInfo("Test", "Test", + TestMBean.class.getDeclaredMethod("getState"), + TestMBean.class.getDeclaredMethod("setState", + String.class))); + throw new Exception("Expected exception not found"); + } catch (IllegalArgumentException ex) { + System.out.println("OK received expected exception " + ex); + } + try { + StandardMBean.findAttributeAccessors(TestMBean.class, null); + throw new Exception("Expected exception not found"); + } catch (IllegalArgumentException ex) { + System.out.println("OK received expected exception " + ex); + } + //Wrong operation signature + try { + StandardMBean.findOperationMethod(TestMBean.class, + new MBeanOperationInfo("FaultyTest", + FaultyTestMBean.class.getDeclaredMethod("doIt", + String.class))); + throw new Exception("Expected exception not found"); + } catch (NoSuchMethodException ex) { + System.out.println("OK received expected exception " + ex); + } + //Wrong attribute accessor + try { + StandardMBean.findAttributeAccessors(TestMBean.class, + new MBeanAttributeInfo("FaultyTest", "FaultyTest", null, + FaultyTestMBean.class.getDeclaredMethod("setEnabled", + String.class))); + throw new Exception("Expected exception not found"); + } catch (NoSuchMethodException ex) { + System.out.println("OK received expected exception " + ex); + } + //Wrong attribute type + try { + StandardMBean.findAttributeAccessors(TestMBean.class, + new MBeanAttributeInfo("State", "toto.FaultType", + "FaultyTest", true, true, false)); + throw new Exception("Expected exception not found"); + } catch (ClassNotFoundException ex) { + System.out.println("OK received expected exception " + ex); + } + //Wrong operation parameter type + try { + MBeanParameterInfo[] p = {new MBeanParameterInfo("p1", + "toto.FaultType2", "FaultyParameter") + }; + StandardMBean.findOperationMethod(TestMBean.class, + new MBeanOperationInfo("doIt", "FaultyMethod", p, "void", + 0)); + throw new Exception("Expected exception not found"); + } catch (ClassNotFoundException ex) { + System.out.println("OK received expected exception " + ex); + } + // Check that not annotated attributes are not found + try { + StandardMBean.findAttributeAccessors(AnnotatedTest.class, + new MBeanAttributeInfo("ItNot", String.class.getName(), + "FaultyTest", true, false, false)); + throw new Exception("Expected exception not found"); + } catch (NoSuchMethodException ex) { + System.out.println("OK received expected exception " + ex); + } + // Check that not annotated operations are not found + try { + StandardMBean.findOperationMethod(AnnotatedTest.class, + new MBeanOperationInfo("dontDoIt","dontDoIt",null, + Void.TYPE.getName(),0)); + throw new Exception("Expected exception not found"); + } catch (NoSuchMethodException ex) { + System.out.println("OK received expected exception " + ex); + } + // Check that wrong getter return type throws Exception + try { + StandardMBean.findAttributeAccessors(AnnotatedTest.class, + new MBeanAttributeInfo("ItAnnotated", Long.class.getName(), + "FaultyTest", true, false, false)); + throw new Exception("Expected exception not found"); + } catch (NoSuchMethodException ex) { + System.out.println("OK received expected exception " + ex); + } + // Check that wrong setter return type throws Exception + try { + StandardMBean.findAttributeAccessors(FaultyTestMBean.class, + new MBeanAttributeInfo("Wrong", String.class.getName(), + "FaultyTest", true, true, false)); + throw new Exception("Expected exception not found"); + } catch (NoSuchMethodException ex) { + System.out.println("OK received expected exception " + ex); + } + } +}