6456269: Add a GenericMBeanException so clients don't have to have server's exception classes present
Reviewed-by: jfdenise, dfuchs
This commit is contained in:
parent
0a521a9457
commit
871bbff9ce
@ -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>
|
||||
*
|
||||
|
@ -0,0 +1,276 @@
|
||||
/*
|
||||
* 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 @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 @DescriptorKey} facility
|
||||
* to define annotations that allow you to specify the error codes. If you
|
||||
* define...</p>
|
||||
*
|
||||
* <pre>
|
||||
* {@link java.lang.annotation.Documented @Documented}
|
||||
* {@link java.lang.annotation.Target @Target}(ElementType.METHOD)
|
||||
* {@link java.lang.annotation.Retention @Retention}(RetentionPolicy.RUNTIME)
|
||||
* public @interface ErrorCodes {
|
||||
* @DescriptorKey("exceptionErrorCodes")
|
||||
* String[] value();
|
||||
* }
|
||||
* </pre>
|
||||
*
|
||||
* <p>...then you can write MBean interfaces like this...</p>
|
||||
*
|
||||
* <pre>
|
||||
* public interface FooMBean { // or FooMXBean
|
||||
* @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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
166
jdk/test/javax/management/interop/MBeanExceptionInteropTest.java
Normal file
166
jdk/test/javax/management/interop/MBeanExceptionInteropTest.java
Normal file
@ -0,0 +1,166 @@
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
}
|
@ -0,0 +1,278 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user