提交 b5cf2485 编写于 作者: E emcmanus

6456269: Add a GenericMBeanException so clients don't have to have server's...

6456269: Add a GenericMBeanException so clients don't have to have server's exception classes present
Reviewed-by: jfdenise, dfuchs
上级 3ec89633
......@@ -155,6 +155,23 @@ import javax.management.openmbean.OpenType;
* setting an attribute are specified by the field
* <a href="#setExceptions">{@code setExceptions}</a>.
*
* <tr id="exceptionErrorCodes"><td>exceptionErrorCodes</td><td>String[]</td>
* <td>MBeanAttributeInfo<br>MBeanConstructorInfo<br>MBeanOperationInfo</td>
*
* <td>The {@linkplain GenericMBeanException#getErrorCode() error codes}
* that can appear in a {@link GenericMBeanException} thrown when getting
* this attribute or invoking this operation or constructor. See also
* <a href="#setExceptionErrorCodes">{@code setExceptionErrorCodes}</a>.
*
* <tr id="exceptionUserDataTypes"><td>exceptionUserDataTypes</td>
* <td>{@link javax.management.openmbean.CompositeType}[]</td>
* <td>MBeanAttributeInfo<br>MBeanConstructorInfo<br>MBeanOperationInfo</td>
*
* <td>The types of {@linkplain GenericMBeanException#getUserData() userData}
* that can appear in a {@link GenericMBeanException} thrown when getting
* this attribute or invoking this operation or constructor. See also
* <a href="#setExceptionUserDataTypes">{@code setExceptionUserDataTypes}</a>.
*
* <tr id="immutableInfo"><td><i>immutableInfo</i><td>String</td>
* <td>MBeanInfo</td>
*
......@@ -292,6 +309,23 @@ import javax.management.openmbean.OpenType;
* an attribute. Exceptions thrown when getting an attribute are specified
* by the field <a href="#exceptions">{@code exceptions}</a>.
*
* <tr id="setExceptionErrorCodes"><td>setExceptionErrorCodes</td>
* <td>String[]</td><td>MBeanAttributeInfo</td>
*
* <td>The {@linkplain GenericMBeanException#getErrorCode() error codes}
* that can appear in a {@link GenericMBeanException} thrown when setting
* this attribute. See also
* <a href="#exceptionErrorCodes">{@code exceptionErrorCodes}</a>.
*
* <tr id="setExceptionUserDataTypes"><td>setExceptionUserDataTypes</td>
* <td>{@link javax.management.openmbean.CompositeType}[]</td>
* <td>MBeanAttributeInfo</td>
*
* <td>The types of {@linkplain GenericMBeanException#getUserData() userData}
* that can appear in a {@link GenericMBeanException} thrown when setting
* this attribute. See also
* <a href="#exceptionUserDataTypes">{@code exceptionUserDataTypes}</a>.
*
* <tr><td>severity</td><td>String<br>Integer</td>
* <td>MBeanNotificationInfo</td>
*
......
/*
* 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. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the LICENSE file that accompanied this code.
*
* 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.
*/
package javax.management;
import javax.management.openmbean.CompositeData;
/**
* <p>A customizable exception that has an optional error code string and
* payload. By using this exception in an MBean, you can avoid requiring
* clients of the MBean to have custom exception classes.</p>
*
* <p>An instance of this class has an optional {@linkplain #getErrorCode()
* error code}, and an optional {@linkplain #getUserData() payload} known as
* {@code userData}. This allows you to distinguish between different
* sorts of exception while still using this class for all of them.</p>
*
* <p>To produce a suitable {@code userData}, it is often simplest to use
* the MXBean framework. For example, suppose you want to convey a severity
* and a subsystem with your exception, which are respectively an int and a
* String. You could define a class like this:</p>
*
* <pre>
* public class ExceptionDetails {
* private final int severity;
* private final String subsystem;
*
* {@link java.beans.ConstructorProperties &#64;ConstructorProperties}(<!--
* -->{"severity", "subsystem"})
* public ExceptionDetails(int severity, String subsystem) {
* this.severity = severity;
* this.subsystem = subsystem;
* }
*
* public int getSeverity() {
* return severity;
* }
*
* public String getSubsystem() {
* return subsystem;
* }
* }
* </pre>
*
* <p>Then you can get the MXBean framework to transform {@code ExceptionDetails}
* into {@link CompositeData} like this:</p>
*
* <pre>
* static final <!--
* -->{@link javax.management.openmbean.MXBeanMapping MXBeanMapping} <!--
* -->exceptionDetailsMapping = <!--
* -->{@link javax.management.openmbean.MXBeanMappingFactory#DEFAULT
* MXBeanMappingFactory.DEFAULT}.mappingForType(
* ExceptionDetails.class, MXBeanMappingFactory.DEFAULT);
*
* public static GenericMBeanException newGenericMBeanException(
* String message, String errorCode, int severity, String subsystem) {
* ExceptionDetails details = new ExceptionDetails(severity, subsystem);
* CompositeData userData = (CompositeData)
* exceptionDetailsMapping.toOpenValue(details);
* return new GenericMBeanException(
* message, errorCode, userData, (Throwable) null);
* }
*
* ...
* throw newGenericMBeanException(message, errorCode, 25, "foosystem");
* </pre>
*
* <p>A client that knows the {@code ExceptionDetails} class can convert
* back from the {@code userData} of a {@code GenericMBeanException}
* that was generated as above:</p>
*
* <pre>
* ...
* try {
* mbeanProxy.foo();
* } catch (GenericMBeanException e) {
* CompositeData userData = e.getUserData();
* ExceptionDetails details = (ExceptionDetails)
* exceptionDetailsMapping.fromOpenValue(userData);
* System.out.println("Exception Severity: " + details.getSeverity());
* }
* ...
* </pre>
*
* <p>The Descriptor field <a href="Descriptor.html#exceptionErrorCodes"><!--
* -->exceptionErrorCodes</a> can be used to specify in the
* {@link MBeanOperationInfo} for an operation what the possible
* {@linkplain #getErrorCode() error codes} are when that operation throws
* {@code GenericMBeanException}. It can also be used in an {@link
* MBeanConstructorInfo} or {@link MBeanAttributeInfo} to specify what the
* possible error codes are for {@code GenericMBeanException} when invoking
* that constructor or getting that attribute, respectively. The field
* <a href="Descriptor.html#setExceptionErrorCodes"><!--
* -->setExceptionErrorCodes</a> can be used to specify what the possible
* error codes are when setting an attribute.</p>
*
* <p>You may want to use the {@link DescriptorKey &#64;DescriptorKey} facility
* to define annotations that allow you to specify the error codes. If you
* define...</p>
*
* <pre>
* {@link java.lang.annotation.Documented &#64;Documented}
* {@link java.lang.annotation.Target &#64;Target}(ElementType.METHOD)
* {@link java.lang.annotation.Retention &#64;Retention}(RetentionPolicy.RUNTIME)
* public &#64;interface ErrorCodes {
* &#64;DescriptorKey("exceptionErrorCodes")
* String[] value();
* }
* </pre>
*
* <p>...then you can write MBean interfaces like this...</p>
*
* <pre>
* public interface FooMBean { // or FooMXBean
* &#64;ErrorCodes({"com.example.bad", "com.example.worse"})
* public void foo() throws GenericMBeanException;
* }
* </pre>
*
* <p>The Descriptor field <a href="Descriptor.html#exceptionUserDataTypes"><!--
* -->exceptionUserDataTypes</a> can be used to specify in the
* {@link MBeanOperationInfo} for an operation what the possible types of
* {@linkplain #getUserData() userData} are when that operation throws
* {@code GenericMBeanException}. It is an array of
* {@link javax.management.openmbean.CompositeType CompositeType} values
* describing the possible {@link CompositeData} formats. This field can also be used
* in an {@link MBeanConstructorInfo} or {@link MBeanAttributeInfo} to specify
* the possible types of user data for {@code GenericMBeanException} when
* invoking that constructor or getting that attribute, respectively. The
* field
* <a href="Descriptor.html#setExceptionUserDataTypes">setExceptionUserDataTypes</a>
* can be used to specify the possible types of user data for exceptions when
* setting an attribute. If a Descriptor has both {@code exceptionErrorCodes}
* and {@code exceptionUserDataTypes} then the two arrays should be the
* same size; each pair of corresponding elements describes one kind
* of exception. Similarly for {@code setExceptionErrorCodes} and {@code
* setExceptionUserDataTypes}.
*
*
* <h4>Serialization</h4>
*
* <p>For compatibility reasons, instances of this class are serialized as
* instances of {@link MBeanException}. Special logic in that class converts
* them back to instances of this class at deserialization time. If the
* serialized object is deserialized in an earlier version of the JMX API
* that does not include this class, then it will appear as just an {@code
* MBeanException} and the error code or userData will not be available.</p>
*
* @since 1.7
*/
public class GenericMBeanException extends MBeanException {
private static final long serialVersionUID = -1560202003985932823L;
/**
* <p>Constructs a new {@code GenericMBeanException} with the given
* detail message. This constructor is
* equivalent to {@link #GenericMBeanException(String, String,
* CompositeData, Throwable) GenericMBeanException(message, "",
* null, null)}.</p>
*
* @param message the exception detail message.
*/
public GenericMBeanException(String message) {
this(message, "", null, null);
}
/**
* <p>Constructs a new {@code GenericMBeanException} with the given
* detail message and cause. This constructor is
* equivalent to {@link #GenericMBeanException(String, String,
* CompositeData, Throwable) GenericMBeanException(message, "",
* null, cause)}.</p>
*
* @param message the exception detail message.
* @param cause the cause of this exception. Can be null.
*/
public GenericMBeanException(String message, Throwable cause) {
this(message, "", null, cause);
}
/**
* <p>Constructs a new {@code GenericMBeanException} with the given
* detail message, error code, and user data. This constructor is
* equivalent to {@link #GenericMBeanException(String, String,
* CompositeData, Throwable) GenericMBeanException(message, errorCode,
* userData, null)}.</p>
*
* @param message the exception detail message.
* @param errorCode the exception error code. Specifying a null value
* is equivalent to specifying an empty string. It is recommended to use
* the same reverse domain name convention as package names, for example
* "com.example.foo.UnexpectedFailure". There is no requirement that the
* error code be a syntactically valid Java identifier.
* @param userData extra information about the exception. Can be null.
*/
public GenericMBeanException(
String message, String errorCode, CompositeData userData) {
this(message, errorCode, userData, null);
}
/**
* <p>Constructs a new {@code GenericMBeanException} with the given
* detail message, error code, user data, and cause.</p>
*
* @param message the exception detail message.
* @param errorCode the exception error code. Specifying a null value
* is equivalent to specifying an empty string. It is recommended to use
* the same reverse domain name convention as package names, for example
* "com.example.foo.UnexpectedFailure". There is no requirement that the
* error code be a syntactically valid Java identifier.
* @param userData extra information about the exception. Can be null.
* @param cause the cause of this exception. Can be null.
*/
public GenericMBeanException(
String message, String errorCode, CompositeData userData,
Throwable cause) {
super(message, (errorCode == null) ? "" : errorCode, userData, cause);
}
/**
* <p>Returns the error code of this exception.</p>
*
* @return the error code. This value is never null.
*/
public String getErrorCode() {
return errorCode;
}
/**
* <p>Returns the userData of this exception.</p>
*
* @return the userData. Can be null.
*/
public CompositeData getUserData() {
return userData;
}
/**
* <p>Instances of this class are serialized as instances of
* {@link MBeanException}. {@code MBeanException} has private fields that can
* not be set by its public constructors. They can only be set in objects
* returned by this method. When an {@code MBeanException} instance is
* deserialized, if those fields are present then its {@code readResolve}
* method will substitute a {@code GenericMBeanException} equivalent to
* this one.</p>
*/
Object writeReplace() {
MBeanException x = new MBeanException(
getMessage(), errorCode, userData, getCause());
x.setStackTrace(this.getStackTrace());
return x;
}
}
......@@ -25,6 +25,8 @@
package javax.management;
import javax.management.openmbean.CompositeData;
/**
* Represents "user defined" exceptions thrown by MBean methods
......@@ -40,6 +42,26 @@ public class MBeanException extends JMException {
/* Serial version */
private static final long serialVersionUID = 4066342430588744142L;
/**
* @serial This field is null for instances of this class that were
* produced by its public constructors. It is non-null for instances
* of this class that represent serialized instances of {@link
* GenericMBeanException}.
*
* @see GenericMBeanException#getErrorCode()
*/
final String errorCode;
/**
* @serial This field is null for instances of this class that were
* produced by its public constructors. It may be non-null for instances
* of this class that represent serialized instances of {@link
* GenericMBeanException}.
*
* @see GenericMBeanException#getUserData()
*/
final CompositeData userData;
/**
* @serial Encapsulated {@link Exception}
*/
......@@ -51,9 +73,8 @@ public class MBeanException extends JMException {
*
* @param e the wrapped exception.
*/
public MBeanException(java.lang.Exception e) {
super() ;
exception = e ;
public MBeanException(Exception e) {
this(null, null, null, e);
}
/**
......@@ -63,11 +84,19 @@ public class MBeanException extends JMException {
* @param e the wrapped exception.
* @param message the detail message.
*/
public MBeanException(java.lang.Exception e, String message) {
super(message) ;
exception = e ;
public MBeanException(Exception e, String message) {
this(message, null, null, e);
}
MBeanException(
String message, String errorCode, CompositeData userData, Throwable cause) {
super(message);
initCause(cause);
if (cause instanceof Exception)
this.exception = (Exception) cause;
this.errorCode = errorCode;
this.userData = userData;
}
/**
* Return the actual {@link Exception} thrown.
......@@ -79,11 +108,24 @@ public class MBeanException extends JMException {
}
/**
* Return the actual {@link Exception} thrown.
*
* @return the wrapped exception.
* This method is invoked when deserializing instances of this class.
* If the {@code errorCode} field of the deserialized instance is not
* null, this method returns an instance of {@link GenericMBeanException}
* instead. Otherwise it returns {@code this}.
* @return {@code this}, or a {@code GenericMBeanException}.
*/
public Throwable getCause() {
return exception;
Object readResolve() {
if (errorCode == null) {
// serial compatibility: earlier versions did not set
// Throwable.cause because they overrode getCause().
if (getCause() == null && exception != null)
initCause(exception);
return this;
} else {
Throwable t = new GenericMBeanException(
getMessage(), errorCode, userData, getCause());
t.setStackTrace(this.getStackTrace());
return t;
}
}
}
/*
* 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 6456269
* @summary Test that an MBeanException serialized on JDK 6 deserializes
* correctly on JDK 7.
* @author Eamonn McManus
*/
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import javax.management.MBeanException;
// In JDK 6, the Throwable.cause field was always null for an MBeanException,
// but it didn't matter because we overrode getCause() to return
// MBeanException.exception instead. In JDK 7, we no longer override getCause()
// because MBeanException doubles as the serial form of GenericMBeanException.
// So we need some care to make sure that objects deserialized from JDK 6
// have the right getCause() behaviour.
public class MBeanExceptionInteropTest {
private static final byte[] SERIALIZED_MBEAN_EXCEPTION = {
-84,-19,0,5,115,114,0,31,106,97,118,97,120,46,109,97,
110,97,103,101,109,101,110,116,46,77,66,101,97,110,69,120,
99,101,112,116,105,111,110,56,110,-116,-27,110,87,49,-50,2,
0,1,76,0,9,101,120,99,101,112,116,105,111,110,116,0,
21,76,106,97,118,97,47,108,97,110,103,47,69,120,99,101,
112,116,105,111,110,59,120,114,0,28,106,97,118,97,120,46,
109,97,110,97,103,101,109,101,110,116,46,74,77,69,120,99,
101,112,116,105,111,110,4,-35,76,-20,-109,-99,126,113,2,0,
0,120,114,0,19,106,97,118,97,46,108,97,110,103,46,69,
120,99,101,112,116,105,111,110,-48,-3,31,62,26,59,28,-60,
2,0,0,120,114,0,19,106,97,118,97,46,108,97,110,103,
46,84,104,114,111,119,97,98,108,101,-43,-58,53,39,57,119,
-72,-53,3,0,3,76,0,5,99,97,117,115,101,116,0,21,
76,106,97,118,97,47,108,97,110,103,47,84,104,114,111,119,
97,98,108,101,59,76,0,13,100,101,116,97,105,108,77,101,
115,115,97,103,101,116,0,18,76,106,97,118,97,47,108,97,
110,103,47,83,116,114,105,110,103,59,91,0,10,115,116,97,
99,107,84,114,97,99,101,116,0,30,91,76,106,97,118,97,
47,108,97,110,103,47,83,116,97,99,107,84,114,97,99,101,
69,108,101,109,101,110,116,59,120,112,113,0,126,0,8,116,
0,7,79,104,32,100,101,97,114,117,114,0,30,91,76,106,
97,118,97,46,108,97,110,103,46,83,116,97,99,107,84,114,
97,99,101,69,108,101,109,101,110,116,59,2,70,42,60,60,
-3,34,57,2,0,0,120,112,0,0,0,2,115,114,0,27,
106,97,118,97,46,108,97,110,103,46,83,116,97,99,107,84,
114,97,99,101,69,108,101,109,101,110,116,97,9,-59,-102,38,
54,-35,-123,2,0,4,73,0,10,108,105,110,101,78,117,109,
98,101,114,76,0,14,100,101,99,108,97,114,105,110,103,67,
108,97,115,115,113,0,126,0,6,76,0,8,102,105,108,101,
78,97,109,101,113,0,126,0,6,76,0,10,109,101,116,104,
111,100,78,97,109,101,113,0,126,0,6,120,112,0,0,0,
63,116,0,25,77,66,101,97,110,69,120,99,101,112,116,105,
111,110,73,110,116,101,114,111,112,84,101,115,116,116,0,30,
77,66,101,97,110,69,120,99,101,112,116,105,111,110,73,110,
116,101,114,111,112,84,101,115,116,46,106,97,118,97,116,0,
5,119,114,105,116,101,115,113,0,126,0,12,0,0,0,46,
113,0,126,0,14,113,0,126,0,15,116,0,4,109,97,105,
110,120,115,114,0,34,106,97,118,97,46,108,97,110,103,46,
73,108,108,101,103,97,108,65,114,103,117,109,101,110,116,69,
120,99,101,112,116,105,111,110,-75,-119,115,-45,125,102,-113,-68,
2,0,0,120,114,0,26,106,97,118,97,46,108,97,110,103,
46,82,117,110,116,105,109,101,69,120,99,101,112,116,105,111,
110,-98,95,6,71,10,52,-125,-27,2,0,0,120,113,0,126,
0,3,113,0,126,0,21,116,0,3,66,97,100,117,113,0,
126,0,10,0,0,0,2,115,113,0,126,0,12,0,0,0,
62,113,0,126,0,14,113,0,126,0,15,113,0,126,0,16,
115,113,0,126,0,12,0,0,0,46,113,0,126,0,14,113,
0,126,0,15,113,0,126,0,18,120,
};
private static volatile String failure;
public static void main(String[] args) throws Exception {
if (args.length > 0) {
if (args[0].equals("write") && args.length == 1) {
write();
return;
} else {
System.err.println(
"Usage: java MBeanExceptionInteropTest");
System.err.println(
"or: java MBeanExceptionInteropTest write");
System.exit(1);
}
}
// Read the serialized object and check it is correct.
ByteArrayInputStream bin =
new ByteArrayInputStream(SERIALIZED_MBEAN_EXCEPTION);
ObjectInputStream oin = new ObjectInputStream(bin);
MBeanException mbeanEx = (MBeanException) oin.readObject();
assertEquals("MBeanException message", "Oh dear", mbeanEx.getMessage());
System.out.println("getCause(): " + mbeanEx.getCause() + "; " +
"getTargetException(): " + mbeanEx.getTargetException());
for (Throwable t :
new Throwable[] {mbeanEx.getCause(), mbeanEx.getTargetException()}) {
if (!(t instanceof IllegalArgumentException))
fail("Nested exception not an IllegalArgumentException: " + t);
else
assertEquals("Nested exception message", "Bad", t.getMessage());
}
if (failure == null)
System.out.println("TEST PASSED");
else
throw new Exception("TEST FAILED: " + failure);
}
// Write a file that can be inserted into this source file as the
// contents of the SERIALIZED_MBEAN_EXCEPTION array. Run this program
// on JDK 6 to generate the array, then test on JDK 7.
private static void write() throws Exception {
Exception wrapped = new IllegalArgumentException("Bad");
MBeanException mbeanEx = new MBeanException(wrapped, "Oh dear");
ByteArrayOutputStream bout = new ByteArrayOutputStream();
ObjectOutputStream oout = new ObjectOutputStream(bout);
oout.writeObject(mbeanEx);
oout.close();
byte[] bytes = bout.toByteArray();
for (int i = 0; i < bytes.length; i++) {
System.out.printf("%d,", bytes[i]);
if (i % 16 == 15)
System.out.println();
}
if (bytes.length % 16 != 0)
System.out.println();
}
private static void assertEquals(String what, Object expect, Object actual) {
boolean equal = (expect == null) ? (actual == null) : expect.equals(actual);
if (equal)
System.out.println("OK: " + what + ": " + expect);
else
fail(what + ": expected " + expect + ", got " + actual);
}
private static void fail(String why) {
System.out.println("FAIL: " + why);
failure = why;
}
}
/*
* 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 6456269
* @summary Test GenericMBeanException
* @author Eamonn McManus
*/
import java.beans.ConstructorProperties;
import java.lang.management.ManagementFactory;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import javax.management.GenericMBeanException;
import javax.management.JMX;
import javax.management.MBeanServer;
import javax.management.MBeanServerConnection;
import javax.management.ObjectName;
import javax.management.openmbean.CompositeData;
import javax.management.openmbean.CompositeType;
import javax.management.openmbean.MXBeanMapping;
import javax.management.openmbean.MXBeanMappingFactory;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXConnectorServer;
import javax.management.remote.JMXConnectorServerFactory;
import javax.management.remote.JMXServiceURL;
public class GenericMBeanExceptionTest {
private static volatile String failure = null;
public static interface ThrowerMBean {
public void throwGeneric() throws GenericMBeanException;
public void throwGeneric(Throwable cause) throws GenericMBeanException;
public void throwGeneric(String errorCode) throws GenericMBeanException;
public void throwGeneric(CompositeData userData) throws GenericMBeanException;
public void throwGeneric(String errorCode, CompositeData userData)
throws GenericMBeanException;
public void throwGeneric(String errorCode, CompositeData userData, Throwable cause)
throws GenericMBeanException;
}
public static class Thrower implements ThrowerMBean {
public void throwGeneric() throws GenericMBeanException {
throw new GenericMBeanException("Message");
}
public void throwGeneric(Throwable cause) throws GenericMBeanException {
throw new GenericMBeanException("Message", cause);
}
public void throwGeneric(String errorCode) throws GenericMBeanException {
throw new GenericMBeanException("Message", errorCode, null);
}
public void throwGeneric(CompositeData userData) throws GenericMBeanException {
throw new GenericMBeanException("Message", null, userData);
}
public void throwGeneric(String errorCode, CompositeData userData)
throws GenericMBeanException {
throw new GenericMBeanException("Message", errorCode, userData);
}
public void throwGeneric(String errorCode, CompositeData userData,
Throwable cause) throws GenericMBeanException {
throw new GenericMBeanException("Message", errorCode, userData, cause);
}
}
public static class Payload {
private final int severity;
private final String subsystem;
@ConstructorProperties({"severity", "subsystem"})
public Payload(int severity, String subsystem) {
this.severity = severity;
this.subsystem = subsystem;
}
public int getSeverity() {
return severity;
}
public String getSubsystem() {
return subsystem;
}
@Override
public boolean equals(Object x) {
if (!(x instanceof Payload))
return false;
Payload p = (Payload) x;
return (severity == p.severity &&
(subsystem == null) ?
p.subsystem == null : subsystem.equals(p.subsystem));
}
@Override
public int hashCode() {
return severity + subsystem.hashCode();
}
@Override
public String toString() {
return "Payload{severity: " + severity + ", subsystem: " + subsystem + "}";
}
}
public static void main(String[] args) throws Exception {
MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
ObjectName name = new ObjectName("test:type=Thrower");
Thrower thrower = new Thrower();
mbs.registerMBean(thrower, name);
if (args.length > 0) {
System.out.println("Attach client now, hit return to exit");
System.in.read();
return;
}
JMXServiceURL url = new JMXServiceURL("service:jmx:rmi://");
JMXConnectorServer cs = JMXConnectorServerFactory.newJMXConnectorServer(
url, null, mbs);
cs.start();
JMXServiceURL addr = cs.getAddress();
JMXConnector cc = JMXConnectorFactory.connect(addr);
MBeanServerConnection mbsc = cc.getMBeanServerConnection();
ThrowerMBean throwerProxy = JMX.newMBeanProxy(mbsc, name, ThrowerMBean.class);
Payload payload = new Payload(5, "modular modulizer");
MXBeanMapping payloadMapping = MXBeanMappingFactory.DEFAULT.mappingForType(
Payload.class, MXBeanMappingFactory.DEFAULT);
CompositeData userData = (CompositeData)
payloadMapping.toOpenValue(payload);
Throwable cause = new IllegalArgumentException("Badness");
Object[][] testCases = {
{},
{"code1"},
{userData},
{"code2", userData},
{(String) null, userData},
{"code99", userData, cause},
{(String) null, userData, cause},
};
for (Object[] testCase : testCases) {
System.out.println("Test case: " + testCaseString(testCase));
// Find which ThrowerMBean method it corresponds to
Method testMethod = null;
search:
for (Method m : ThrowerMBean.class.getMethods()) {
Class<?>[] paramTypes = m.getParameterTypes();
if (paramTypes.length != testCase.length)
continue;
for (int i = 0; i < paramTypes.length; i++) {
if (testCase[i] != null && !paramTypes[i].isInstance(testCase[i]))
continue search;
}
testMethod = m;
}
if (testMethod == null) {
throw new Exception("TEST ERROR: no method corresponds: " +
testCaseString(testCase));
}
try {
testMethod.invoke(throwerProxy, testCase);
fail("Did not throw exception", testCase);
continue;
} catch (InvocationTargetException e) {
Throwable iteCause = e.getCause();
if (!(iteCause instanceof GenericMBeanException)) {
iteCause.printStackTrace(System.out);
fail("Threw wrong exception " + iteCause, testCase);
continue;
}
GenericMBeanException ge = (GenericMBeanException) iteCause;
if (!ge.getMessage().equals("Message"))
fail("Wrong message: " + ge.getMessage(), testCase);
Class<?>[] paramTypes = testMethod.getParameterTypes();
for (int i = 0; i < paramTypes.length; i++) {
Class<?> paramType = paramTypes[i];
if (paramType == Throwable.class) { // cause
Throwable geCause = ge.getCause();
if (!(geCause instanceof IllegalArgumentException))
fail("Wrong cause: " + geCause, testCase);
else if (!geCause.getMessage().equals("Badness"))
fail("Wrong cause message: " + geCause.getMessage(), testCase);
} else if (paramType == String.class) { // errorCode
String errorCode = ge.getErrorCode();
String expectedErrorCode =
(testCase[i] == null) ? "" : (String) testCase[i];
if (!expectedErrorCode.equals(errorCode))
fail("Wrong error code: " + ge.getErrorCode(), testCase);
} else if (paramType == CompositeData.class) { // userData
CompositeData userData2 = ge.getUserData();
if (!userData.equals(userData2))
fail("Wrong userData: " + userData2, testCase);
Payload payload2 = (Payload) payloadMapping.fromOpenValue(userData2);
if (!payload.equals(payload2))
fail("Wrong payload: " + payload2, testCase);
} else
throw new Exception("TEST ERROR: unknown parameter type: " + paramType);
}
}
}
if (failure == null)
System.out.println("TEST PASSED");
else
throw new Exception("TEST FAILED: " + failure);
}
private static String testCaseString(Object[] testCase) {
StringBuilder sb = new StringBuilder("[");
String sep = "";
for (Object x : testCase) {
sb.append(sep);
String xs = (x instanceof CompositeData) ?
compositeDataString((CompositeData) x) : String.valueOf(x);
sb.append(xs);
sep = ", ";
}
sb.append("]");
return sb.toString();
}
private static String compositeDataString(CompositeData cd) {
StringBuilder sb = new StringBuilder("CompositeData{");
CompositeType ct = cd.getCompositeType();
String sep = "";
for (String key : ct.keySet()) {
sb.append(sep).append(key).append(": ").append(cd.get(key));
sep = ", ";
}
sb.append("}");
return sb.toString();
}
private static void fail(String why, Object[] testCase) {
fail(testCaseString(testCase) + ": " + why);
}
private static void fail(String why) {
failure = why;
System.out.println("FAIL: " + why);
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册