From 04950cd8463f130e211e26ddd573ce9d11565263 Mon Sep 17 00:00:00 2001 From: Jean-Francois Denise Date: Tue, 9 Dec 2008 15:36:14 +0100 Subject: [PATCH] 6250014: MBeanOperationInfo Descriptor field for exceptions Reviewed-by: emcmanus --- .../sun/jmx/mbeanserver/ConvertingMethod.java | 2 +- .../com/sun/jmx/mbeanserver/Introspector.java | 41 ++- .../jmx/mbeanserver/MBeanIntrospector.java | 2 +- .../jmx/mbeanserver/MXBeanIntrospector.java | 2 +- .../classes/javax/management/Descriptor.java | 15 ++ .../share/classes/javax/management/JMX.java | 12 + .../javax/management/MBeanAttributeInfo.java | 6 +- .../management/MBeanConstructorInfo.java | 2 +- .../javax/management/MBeanOperationInfo.java | 2 +- .../ExceptionsDescriptorTest.java | 245 ++++++++++++++++++ 10 files changed, 320 insertions(+), 9 deletions(-) create mode 100644 jdk/test/javax/management/Introspector/ExceptionsDescriptorTest.java diff --git a/jdk/src/share/classes/com/sun/jmx/mbeanserver/ConvertingMethod.java b/jdk/src/share/classes/com/sun/jmx/mbeanserver/ConvertingMethod.java index 1f802ca76d0..62239b5a984 100644 --- a/jdk/src/share/classes/com/sun/jmx/mbeanserver/ConvertingMethod.java +++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/ConvertingMethod.java @@ -53,7 +53,7 @@ final class ConvertingMethod { } Descriptor getDescriptor() { - return Introspector.descriptorForElement(method); + return Introspector.descriptorForElement(method, false); } Type getGenericReturnType() { diff --git a/jdk/src/share/classes/com/sun/jmx/mbeanserver/Introspector.java b/jdk/src/share/classes/com/sun/jmx/mbeanserver/Introspector.java index da4209cd2b3..dbf45b9997a 100644 --- a/jdk/src/share/classes/com/sun/jmx/mbeanserver/Introspector.java +++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/Introspector.java @@ -63,7 +63,10 @@ import java.beans.BeanInfo; import java.beans.PropertyDescriptor; import java.lang.reflect.Array; import java.lang.reflect.InvocationTargetException; +import java.util.LinkedHashSet; +import java.util.Set; import javax.management.AttributeNotFoundException; +import javax.management.JMX; import javax.management.openmbean.CompositeData; import javax.management.openmbean.MXBeanMappingFactory; @@ -462,11 +465,31 @@ public class Introspector { return null; } - public static Descriptor descriptorForElement(final AnnotatedElement elmt) { + public static Descriptor descriptorForElement(final AnnotatedElement elmt, + boolean isSetter) { if (elmt == null) return ImmutableDescriptor.EMPTY_DESCRIPTOR; final Annotation[] annots = elmt.getAnnotations(); - return descriptorForAnnotations(annots); + Descriptor descr = descriptorForAnnotations(annots); + String[] exceptions = {}; + if(elmt instanceof Method) + exceptions = getAllExceptions(((Method) elmt).getExceptionTypes()); + else + if(elmt instanceof Constructor) + exceptions = getAllExceptions(((Constructor) elmt). + getExceptionTypes()); + + if(exceptions.length > 0 ) { + String fieldName = isSetter ? JMX.SET_EXCEPTIONS_FIELD : + JMX.EXCEPTIONS_FIELD; + + String[] fieldNames = {fieldName}; + Object[] fieldValues = {exceptions}; + descr = ImmutableDescriptor.union(descr, + new ImmutableDescriptor(fieldNames, fieldValues)); + } + + return descr; } public static Descriptor descriptorForAnnotation(Annotation annot) { @@ -489,6 +512,20 @@ public class Introspector { return new ImmutableDescriptor(descriptorMap); } + /** + * Array of thrown excepions. + * @param exceptions can be null; + * @return An Array of Exception class names. Size is 0 if method is null. + */ + private static String[] getAllExceptions(Class[] exceptions) { + Set set = new LinkedHashSet(); + for(Classex : exceptions) + set.add(ex.getName()); + + String[] arr = new String[set.size()]; + return set.toArray(arr); + } + private static void addDescriptorFieldsToMap( Map descriptorMap, DescriptorFields df) { for (String field : df.value()) { diff --git a/jdk/src/share/classes/com/sun/jmx/mbeanserver/MBeanIntrospector.java b/jdk/src/share/classes/com/sun/jmx/mbeanserver/MBeanIntrospector.java index d1968b514ee..50ce702e871 100644 --- a/jdk/src/share/classes/com/sun/jmx/mbeanserver/MBeanIntrospector.java +++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/MBeanIntrospector.java @@ -403,7 +403,7 @@ public abstract class MBeanIntrospector { new ImmutableDescriptor(interfaceClassName); final Descriptor mbeanDescriptor = getBasicMBeanDescriptor(); final Descriptor annotatedDescriptor = - Introspector.descriptorForElement(mbeanInterface); + Introspector.descriptorForElement(mbeanInterface, false); final Descriptor descriptor = DescriptorCache.getInstance().union( classNameDescriptor, diff --git a/jdk/src/share/classes/com/sun/jmx/mbeanserver/MXBeanIntrospector.java b/jdk/src/share/classes/com/sun/jmx/mbeanserver/MXBeanIntrospector.java index af5420c38f3..fb9b3ccb093 100644 --- a/jdk/src/share/classes/com/sun/jmx/mbeanserver/MXBeanIntrospector.java +++ b/jdk/src/share/classes/com/sun/jmx/mbeanserver/MXBeanIntrospector.java @@ -292,7 +292,7 @@ class MXBeanIntrospector extends MBeanIntrospector { Descriptor descriptor = typeDescriptor(returnType, originalReturnType); descriptor = ImmutableDescriptor.union(descriptor, - Introspector.descriptorForElement(method)); + Introspector.descriptorForElement(method, false)); final MBeanOperationInfo oi; if (openReturnType && openParameterTypes) { /* If the return value and all the parameters can be faithfully diff --git a/jdk/src/share/classes/javax/management/Descriptor.java b/jdk/src/share/classes/javax/management/Descriptor.java index b9c98f4068b..a9161903c64 100644 --- a/jdk/src/share/classes/javax/management/Descriptor.java +++ b/jdk/src/share/classes/javax/management/Descriptor.java @@ -147,6 +147,14 @@ import javax.management.openmbean.OpenType; * might be disabled if it cannot currently be emitted but could be in * other circumstances. * + * exceptionsString[] + * MBeanAttributeInfo, MBeanConstructorInfo, MBeanOperationInfo + * + * The class names of the exceptions that can be thrown when invoking a + * constructor or operation, or getting an attribute. Exceptions thrown when + * setting an attribute are specified by the field + * {@code setExceptions}. + * * immutableInfoString * MBeanInfo * @@ -270,6 +278,13 @@ import javax.management.openmbean.OpenType; * href="MXBean.html#type-names">Type Names of the MXBean * specification.

* + * setExceptionsString[] + * MBeanAttributeInfo + * + * The class names of the exceptions that can be thrown when setting + * an attribute. Exceptions thrown when getting an attribute are specified + * by the field {@code exceptions}. + * * severityString
Integer * MBeanNotificationInfo * diff --git a/jdk/src/share/classes/javax/management/JMX.java b/jdk/src/share/classes/javax/management/JMX.java index d9329e0c3d4..3e551f3902f 100644 --- a/jdk/src/share/classes/javax/management/JMX.java +++ b/jdk/src/share/classes/javax/management/JMX.java @@ -75,6 +75,12 @@ public class JMX { public static final String DESCRIPTION_RESOURCE_KEY_FIELD = "descriptionResourceKey"; + /** + * The name of the {@code + * exceptions} field. + */ + public static final String EXCEPTIONS_FIELD = "exceptions"; + /** * The name of the {@code * immutableInfo} field. @@ -137,6 +143,12 @@ public class JMX { */ public static final String ORIGINAL_TYPE_FIELD = "originalType"; + /** + * The name of the {@code + * setExceptions} field. + */ + public static final String SET_EXCEPTIONS_FIELD = "setExceptions"; + /** *

Options to apply to an MBean proxy or to an instance of {@link * StandardMBean}.

diff --git a/jdk/src/share/classes/javax/management/MBeanAttributeInfo.java b/jdk/src/share/classes/javax/management/MBeanAttributeInfo.java index 2566c3e48a2..b4bcfaf4585 100644 --- a/jdk/src/share/classes/javax/management/MBeanAttributeInfo.java +++ b/jdk/src/share/classes/javax/management/MBeanAttributeInfo.java @@ -186,8 +186,10 @@ public class MBeanAttributeInfo extends MBeanFeatureInfo implements Cloneable { (getter != null), (setter != null), isIs(getter), - ImmutableDescriptor.union(Introspector.descriptorForElement(getter), - Introspector.descriptorForElement(setter))); + ImmutableDescriptor.union(Introspector. + descriptorForElement(getter, false), + Introspector.descriptorForElement(setter, + true))); } /** diff --git a/jdk/src/share/classes/javax/management/MBeanConstructorInfo.java b/jdk/src/share/classes/javax/management/MBeanConstructorInfo.java index 872c723e3af..e3e210318d8 100644 --- a/jdk/src/share/classes/javax/management/MBeanConstructorInfo.java +++ b/jdk/src/share/classes/javax/management/MBeanConstructorInfo.java @@ -67,7 +67,7 @@ public class MBeanConstructorInfo extends MBeanFeatureInfo implements Cloneable public MBeanConstructorInfo(String description, Constructor constructor) { this(constructor.getName(), description, constructorSignature(constructor), - Introspector.descriptorForElement(constructor)); + Introspector.descriptorForElement(constructor, false)); } /** diff --git a/jdk/src/share/classes/javax/management/MBeanOperationInfo.java b/jdk/src/share/classes/javax/management/MBeanOperationInfo.java index 006fc345d93..c3ee5382612 100644 --- a/jdk/src/share/classes/javax/management/MBeanOperationInfo.java +++ b/jdk/src/share/classes/javax/management/MBeanOperationInfo.java @@ -113,7 +113,7 @@ public class MBeanOperationInfo extends MBeanFeatureInfo implements Cloneable { methodSignature(method), method.getReturnType().getName(), UNKNOWN, - Introspector.descriptorForElement(method)); + Introspector.descriptorForElement(method, false)); } /** diff --git a/jdk/test/javax/management/Introspector/ExceptionsDescriptorTest.java b/jdk/test/javax/management/Introspector/ExceptionsDescriptorTest.java new file mode 100644 index 00000000000..5b931ba7294 --- /dev/null +++ b/jdk/test/javax/management/Introspector/ExceptionsDescriptorTest.java @@ -0,0 +1,245 @@ +/* + * 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 %M% %I% + * @bug 6250014 + * @summary Test that Exceptions are added to the MbeanInfo + * @author Jean-Francois Denise + * @run main/othervm ExceptionsDescriptorTest + */ +import java.lang.management.ManagementFactory; +import java.util.HashSet; +import java.util.Set; +import javax.management.Descriptor; +import javax.management.JMX; +import javax.management.MBeanAttributeInfo; +import javax.management.MBeanConstructorInfo; +import javax.management.MBeanInfo; +import javax.management.MBeanOperationInfo; +import javax.management.ObjectName; + +public class ExceptionsDescriptorTest { + + private static final ObjectName OBJECT_NAME = ObjectName.valueOf(":type=Foo"); + final static String EXCEPTION_NAME = Exception.class.getName(); + final static String ILLEGAL_ARGUMENT_EXCEPTION_NAME = + IllegalArgumentException.class.getName(); + final static Set ONE_EXCEPTION = new HashSet(); + final static Set TWO_EXCEPTION = new HashSet(); + static { + ONE_EXCEPTION.add(EXCEPTION_NAME); + TWO_EXCEPTION.add(EXCEPTION_NAME); + TWO_EXCEPTION.add(ILLEGAL_ARGUMENT_EXCEPTION_NAME); + } + public interface TestMBean { + + public void doIt(); + + public void doIt(String str) throws Exception; + + public void doIt(String str, boolean b) throws Exception, + IllegalArgumentException; + + public String getThat(); + + public void setThat(String that); + + public String getThe() throws Exception; + + public void setThe(String the); + + public String getThese(); + + public void setThese(String the) throws Exception; + + public String getIt() throws Exception; + + public void setIt(String str) throws Exception; + + public String getThis() throws Exception, IllegalArgumentException; + + public void setThose(String str) throws Exception, + IllegalArgumentException; + } + + public static class Test implements TestMBean { + + public Test() { + } + + public Test(int i) throws Exception { + } + + public Test(int i, int j) throws Exception, IllegalArgumentException { + } + + public void doIt() { + throw new UnsupportedOperationException("Not supported yet."); + } + + public void doIt(String str) throws Exception { + throw new UnsupportedOperationException("Not supported yet."); + } + + public void doIt(String str, boolean b) throws Exception, IllegalArgumentException { + throw new UnsupportedOperationException("Not supported yet."); + } + + public String getThat() { + throw new UnsupportedOperationException("Not supported yet."); + } + + public void setThat(String that) { + throw new UnsupportedOperationException("Not supported yet."); + } + + public String getThe() throws Exception { + throw new UnsupportedOperationException("Not supported yet."); + } + + public void setThe(String the) { + throw new UnsupportedOperationException("Not supported yet."); + } + + public String getThese() { + throw new UnsupportedOperationException("Not supported yet."); + } + + public void setThese(String the) throws Exception { + throw new UnsupportedOperationException("Not supported yet."); + } + + public String getIt() throws Exception { + throw new UnsupportedOperationException("Not supported yet."); + } + + public void setIt(String str) throws Exception { + throw new UnsupportedOperationException("Not supported yet."); + } + + public String getThis() throws Exception, IllegalArgumentException { + throw new UnsupportedOperationException("Not supported yet."); + } + + public void setThose(String str) throws Exception, IllegalArgumentException { + throw new UnsupportedOperationException("Not supported yet."); + } + } + + private static void check(Descriptor d, + Set exceptionsExpectedValue, + boolean exceptionsExpected, + Set setExceptionsExpectedValue, + boolean setExceptionsExpected) throws Exception { + String[] exceptionsValues = (String[]) d.getFieldValue(JMX.EXCEPTIONS_FIELD); + String[] setExceptionsValues = (String[]) d.getFieldValue(JMX.SET_EXCEPTIONS_FIELD); + + if (exceptionsExpected && exceptionsValues == null) { + throw new Exception("exceptions is expected but null value"); + } + if (!exceptionsExpected && exceptionsValues != null) { + throw new Exception("exceptions is not expected but non null value"); + } + if (setExceptionsExpected && setExceptionsValues == null) { + throw new Exception("setExceptions is expected but null value"); + } + if (!setExceptionsExpected && setExceptionsValues != null) { + throw new Exception("setExceptions is not expected but non null value"); + } + + if (exceptionsExpected) { + checkValues(exceptionsExpectedValue, exceptionsValues); + } + if (setExceptionsExpected) { + checkValues(setExceptionsExpectedValue, setExceptionsValues); + } + } + + private static void checkValues(Set expectedValuesSet, + String[] realValues) throws Exception { + + Set realValuesSet = new HashSet(); + for (String ex : realValues) { + realValuesSet.add(ex); + } + if (!realValuesSet.equals(expectedValuesSet)) { + throw new Exception("Invalid content for exceptions. Was expecting " + + expectedValuesSet + ". Found " + realValuesSet); + } + } + + public static void main(String[] args) throws Exception { + Test t = new Test(); + ManagementFactory.getPlatformMBeanServer().registerMBean(t, OBJECT_NAME); + MBeanInfo info = ManagementFactory.getPlatformMBeanServer(). + getMBeanInfo(OBJECT_NAME); + //Constructors + for (MBeanConstructorInfo ctr : info.getConstructors()) { + if (ctr.getSignature().length == 0) { + check(ctr.getDescriptor(), null, false, null, false); + } + if (ctr.getSignature().length == 1) { + check(ctr.getDescriptor(), ONE_EXCEPTION, true, null, false); + } + if (ctr.getSignature().length == 2) { + check(ctr.getDescriptor(),TWO_EXCEPTION,true, null, false); + } + } + //Attributes + for (MBeanAttributeInfo attr : info.getAttributes()) { + if (attr.getName().equals("That")) { + check(attr.getDescriptor(), null, false, null, false); + } + if (attr.getName().equals("The")) { + check(attr.getDescriptor(), ONE_EXCEPTION,true,null, false); + } + if (attr.getName().equals("These")) { + check(attr.getDescriptor(), null, false, ONE_EXCEPTION,true); + } + if (attr.getName().equals("It")) { + check(attr.getDescriptor(), ONE_EXCEPTION,true,ONE_EXCEPTION, + true); + } + if (attr.getName().equals("This")) { + check(attr.getDescriptor(), TWO_EXCEPTION,true,null,false); + } + if (attr.getName().equals("Those")) { + check(attr.getDescriptor(), null,false,TWO_EXCEPTION,true); + } + } + //Operations + for (MBeanOperationInfo oper : info.getOperations()) { + if (oper.getSignature().length == 0) { + check(oper.getDescriptor(), null, false, null, false); + } + if (oper.getSignature().length == 1) { + check(oper.getDescriptor(), ONE_EXCEPTION, true, null, false); + } + if (oper.getSignature().length == 2) { + check(oper.getDescriptor(), TWO_EXCEPTION,true, null, false); + } + } + System.out.println("Test passed"); + } +}