blob: 5fc77f9c11934f0efc921e21736bc54b7a79caac [file] [log] [blame]
/*
* Copyright 2007 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 6323980
* @summary Test @Description
* @author Eamonn McManus
*/
import java.lang.management.ManagementFactory;
import javax.management.Description;
import javax.management.IntrospectionException;
import javax.management.MBean;
import javax.management.MBeanAttributeInfo;
import javax.management.MBeanConstructorInfo;
import javax.management.MBeanFeatureInfo;
import javax.management.MBeanInfo;
import javax.management.MBeanOperationInfo;
import javax.management.MBeanParameterInfo;
import javax.management.MBeanServer;
import javax.management.MXBean;
import javax.management.ManagedAttribute;
import javax.management.ManagedOperation;
import javax.management.NotCompliantMBeanException;
import javax.management.ObjectName;
import javax.management.StandardMBean;
public class MBeanDescriptionTest {
private static String failure;
private static final MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
private static final ObjectName name;
static {
try {
name = new ObjectName("a:b=c");
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static interface Interface {
@Description("A description")
public String getA();
@Description("B description")
public int getB();
public void setB(int x);
public boolean isC();
@Description("C description")
public void setC(boolean x);
@Description("D description")
public void setD(float x);
@Description("H description")
public int getH();
@Description("H description")
public void setH(int x);
public String getE();
public int getF();
public void setF(int x);
public void setG(boolean x);
@Description("opA description")
public int opA(
@Description("p1 description")
int p1,
@Description("p2 description")
int p2);
public void opB(float x);
}
@Description("MBean description")
public static interface TestMBean extends Interface {}
public static class Test implements TestMBean {
@Description("0-arg constructor description")
public Test() {}
public Test(String why) {}
@Description("2-arg constructor description")
public Test(
@Description("p1 description")
int x,
@Description("p2 description")
String y) {
}
public String getA() {
return null;
}
public int getB() {
return 0;
}
public void setB(int x) {
}
public boolean isC() {
return false;
}
public void setC(boolean x) {
}
public void setD(float x) {
}
public String getE() {
return null;
}
public int getF() {
return 0;
}
public void setF(int x) {
}
public void setG(boolean x) {
}
public int getH() {
return 0;
}
public void setH(int x) {
}
public int opA(int p1, int p2) {
return 0;
}
public void opB(float x) {
}
}
public static class TestSub extends Test {
@Description("0-arg constructor description")
public TestSub() {}
public TestSub(String why) {}
@Description("2-arg constructor description")
public TestSub(
@Description("p1 description")
int x,
@Description("p2 description")
String y) {
}
}
public static class StandardSub extends StandardMBean implements TestMBean {
@Description("0-arg constructor description")
public StandardSub() {
super(TestMBean.class, false);
}
public StandardSub(String why) {
super(TestMBean.class, false);
}
@Description("2-arg constructor description")
public StandardSub(
@Description("p1 description")
int x,
@Description("p2 description")
String y) {
super(TestMBean.class, false);
}
public String getA() {
return null;
}
public int getB() {
return 0;
}
public void setB(int x) {
}
public boolean isC() {
return false;
}
public void setC(boolean x) {
}
public void setD(float x) {
}
public String getE() {
return null;
}
public int getF() {
return 0;
}
public void setF(int x) {
}
public void setG(boolean x) {
}
public int opA(int p1, int p2) {
return 0;
}
public void opB(float x) {
}
public int getH() {
return 0;
}
public void setH(int x) {
}
}
@Description("MBean description")
public static interface TestMXBean extends Interface {}
public static class TestMXBeanImpl implements TestMXBean {
@Description("0-arg constructor description")
public TestMXBeanImpl() {}
public TestMXBeanImpl(String why) {}
@Description("2-arg constructor description")
public TestMXBeanImpl(
@Description("p1 description")
int x,
@Description("p2 description")
String y) {
}
public String getA() {
return null;
}
public int getB() {
return 0;
}
public void setB(int x) {
}
public boolean isC() {
return false;
}
public void setC(boolean x) {
}
public void setD(float x) {
}
public String getE() {
return null;
}
public int getF() {
return 0;
}
public void setF(int x) {
}
public void setG(boolean x) {
}
public int opA(int p1, int p2) {
return 0;
}
public void opB(float x) {
}
public int getH() {
return 0;
}
public void setH(int x) {
}
}
public static class StandardMXSub extends StandardMBean implements TestMXBean {
@Description("0-arg constructor description")
public StandardMXSub() {
super(TestMXBean.class, true);
}
public StandardMXSub(String why) {
super(TestMXBean.class, true);
}
@Description("2-arg constructor description")
public StandardMXSub(
@Description("p1 description")
int x,
@Description("p2 description")
String y) {
super(TestMXBean.class, true);
}
public String getA() {
return null;
}
public int getB() {
return 0;
}
public void setB(int x) {
}
public boolean isC() {
return false;
}
public void setC(boolean x) {
}
public void setD(float x) {
}
public String getE() {
return null;
}
public int getF() {
return 0;
}
public void setF(int x) {
}
public void setG(boolean x) {
}
public int opA(int p1, int p2) {
return 0;
}
public void opB(float x) {
}
public int getH() {
return 0;
}
public void setH(int x) {
}
}
@MBean
@Description("MBean description")
public static class AnnotatedMBean {
@Description("0-arg constructor description")
public AnnotatedMBean() {}
public AnnotatedMBean(String why) {}
@Description("2-arg constructor description")
public AnnotatedMBean(
@Description("p1 description")
int x,
@Description("p2 description")
String y) {}
@ManagedAttribute
@Description("A description")
public String getA() {
return null;
}
@ManagedAttribute
@Description("B description")
public int getB() {
return 0;
}
@ManagedAttribute
public void setB(int x) {
}
@ManagedAttribute
public boolean isC() {
return false;
}
@ManagedAttribute
@Description("C description")
public void setC(boolean x) {
}
@ManagedAttribute
@Description("D description")
public void setD(float x) {
}
@ManagedAttribute
public String getE() {
return null;
}
@ManagedAttribute
public int getF() {
return 0;
}
@ManagedAttribute
public void setF(int x) {
}
@ManagedAttribute
public void setG(boolean x) {
}
@ManagedAttribute
@Description("H description")
public int getH() {
return 0;
}
@ManagedAttribute
@Description("H description")
public void setH(int x) {
}
@ManagedOperation
@Description("opA description")
public int opA(
@Description("p1 description") int p1,
@Description("p2 description") int p2) {
return 0;
}
@ManagedOperation
public void opB(float x) {
}
}
@MXBean
@Description("MBean description")
public static class AnnotatedMXBean {
@Description("0-arg constructor description")
public AnnotatedMXBean() {}
public AnnotatedMXBean(String why) {}
@Description("2-arg constructor description")
public AnnotatedMXBean(
@Description("p1 description")
int x,
@Description("p2 description")
String y) {}
@ManagedAttribute
@Description("A description")
public String getA() {
return null;
}
@ManagedAttribute
@Description("B description")
public int getB() {
return 0;
}
@ManagedAttribute
public void setB(int x) {
}
@ManagedAttribute
public boolean isC() {
return false;
}
@ManagedAttribute
@Description("C description")
public void setC(boolean x) {
}
@ManagedAttribute
@Description("D description")
public void setD(float x) {
}
@ManagedAttribute
public String getE() {
return null;
}
@ManagedAttribute
public int getF() {
return 0;
}
@ManagedAttribute
public void setF(int x) {
}
@ManagedAttribute
public void setG(boolean x) {
}
@ManagedAttribute
@Description("H description")
public int getH() {
return 0;
}
@ManagedAttribute
@Description("H description")
public void setH(int x) {
}
@ManagedOperation
@Description("opA description")
public int opA(
@Description("p1 description") int p1,
@Description("p2 description") int p2) {
return 0;
}
@ManagedOperation
public void opB(float x) {
}
}
// Negative tests follow.
// Inconsistent descriptions
public static interface BadInterface {
@Description("foo")
public String getFoo();
@Description("bar")
public void setFoo(String x);
}
public static interface BadMBean extends BadInterface {}
public static class Bad implements BadMBean {
public String getFoo() {
return null;
}
public void setFoo(String x) {
}
}
public static interface BadMXBean extends BadInterface {}
public static class BadMXBeanImpl implements BadMXBean {
public String getFoo() {
return null;
}
public void setFoo(String x) {
}
}
private static interface Defaults {
public String defaultAttributeDescription(String name);
public String defaultOperationDescription(String name);
public String defaultParameterDescription(int index);
}
private static class StandardDefaults implements Defaults {
public String defaultAttributeDescription(String name) {
return "Attribute exposed for management";
}
public String defaultOperationDescription(String name) {
return "Operation exposed for management";
}
public String defaultParameterDescription(int index) {
return "";
}
}
private static final Defaults standardDefaults = new StandardDefaults();
private static class MXBeanDefaults implements Defaults {
public String defaultAttributeDescription(String name) {
return name;
}
public String defaultOperationDescription(String name) {
return name;
}
public String defaultParameterDescription(int index) {
return "p" + index;
}
}
private static final Defaults mxbeanDefaults = new MXBeanDefaults();
private static class TestCase {
final String name;
final Object mbean;
final Defaults defaults;
TestCase(String name, Object mbean, Defaults defaults) {
this.name = name;
this.mbean = mbean;
this.defaults = defaults;
}
}
private static class ExceptionTest {
final String name;
final Object mbean;
ExceptionTest(String name, Object mbean) {
this.name = name;
this.mbean = mbean;
}
}
private static final TestCase[] tests = {
new TestCase("Standard MBean", new Test(), standardDefaults),
new TestCase("Standard MBean subclass", new TestSub(), standardDefaults),
new TestCase("StandardMBean delegating",
new StandardMBean(new Test(), TestMBean.class, false),
standardDefaults),
new TestCase("StandardMBean delegating to subclass",
new StandardMBean(new TestSub(), TestMBean.class, false),
standardDefaults),
new TestCase("StandardMBean subclass", new StandardSub(), standardDefaults),
new TestCase("MXBean", new TestMXBeanImpl(), mxbeanDefaults),
new TestCase("StandardMBean MXBean delegating",
new StandardMBean(new TestMXBeanImpl(), TestMXBean.class, true),
mxbeanDefaults),
new TestCase("StandardMBean MXBean subclass",
new StandardMXSub(), mxbeanDefaults),
new TestCase("@MBean", new AnnotatedMBean(), standardDefaults),
new TestCase("@MXBean", new AnnotatedMXBean(), mxbeanDefaults),
new TestCase("StandardMBean @MBean delegating",
new StandardMBean(new AnnotatedMBean(), null, false),
standardDefaults),
new TestCase("StandardMBean @MXBean delegating",
new StandardMBean(new AnnotatedMXBean(), null, true),
mxbeanDefaults),
};
private static final ExceptionTest[] exceptionTests = {
new ExceptionTest("Standard MBean with inconsistent get/set", new Bad()),
new ExceptionTest("MXBean with inconsistent get/set", new BadMXBeanImpl()),
};
public static void main(String[] args) throws Exception {
System.out.println("=== Testing correct MBeans ===");
for (TestCase test : tests) {
System.out.println("Testing " + test.name + "...");
mbs.registerMBean(test.mbean, name);
boolean expectConstructors =
(test.mbean.getClass() != StandardMBean.class);
check(mbs.getMBeanInfo(name), test.defaults, expectConstructors);
mbs.unregisterMBean(name);
}
System.out.println();
System.out.println("=== Testing incorrect MBeans ===");
for (ExceptionTest test : exceptionTests) {
System.out.println("Testing " + test.name);
try {
mbs.registerMBean(test.mbean, name);
fail("Registration succeeded but should not have");
mbs.unregisterMBean(name);
} catch (NotCompliantMBeanException e) {
// OK
} catch (Exception e) {
fail("Registration failed with wrong exception: " +
"expected NotCompliantMBeanException, got " +
e.getClass().getName());
}
}
System.out.println();
if (failure == null)
System.out.println("TEST PASSED");
else
throw new Exception("TEST FAILED: " + failure);
}
private static void check(
MBeanInfo mbi, Defaults defaults, boolean expectConstructors)
throws Exception {
assertEquals("MBean description", mbi.getDescription());
// These attributes have descriptions
for (String attr : new String[] {"A", "B", "C", "D", "H"}) {
MBeanAttributeInfo mbai = getAttributeInfo(mbi, attr);
assertEquals(attr + " description", mbai.getDescription());
}
// These attributes don't have descriptions
for (String attr : new String[] {"E", "F", "G"}) {
// If we ever change the default description, we'll need to change
// this test accordingly.
MBeanAttributeInfo mbai = getAttributeInfo(mbi, attr);
assertEquals(
defaults.defaultAttributeDescription(attr), mbai.getDescription());
}
// This operation has a description, as do its parameters
MBeanOperationInfo opA = getOperationInfo(mbi, "opA");
assertEquals("opA description", opA.getDescription());
checkSignature(opA.getSignature());
// This operation has the default description, as does its parameter
MBeanOperationInfo opB = getOperationInfo(mbi, "opB");
assertEquals(defaults.defaultOperationDescription("opB"), opB.getDescription());
MBeanParameterInfo opB0 = opB.getSignature()[0];
assertEquals(defaults.defaultParameterDescription(0), opB0.getDescription());
if (expectConstructors) {
// The 0-arg and 2-arg constructors have descriptions
MBeanConstructorInfo con0 = getConstructorInfo(mbi, 0);
assertEquals("0-arg constructor description", con0.getDescription());
MBeanConstructorInfo con2 = getConstructorInfo(mbi, 2);
assertEquals("2-arg constructor description", con2.getDescription());
checkSignature(con2.getSignature());
// The 1-arg constructor does not have a description.
// The default description for constructors and their
// parameters is the same for all types of MBean.
MBeanConstructorInfo con1 = getConstructorInfo(mbi, 1);
assertEquals("Public constructor of the MBean", con1.getDescription());
assertEquals("", con1.getSignature()[0].getDescription());
}
}
private static void checkSignature(MBeanParameterInfo[] params) {
for (int i = 0; i < params.length; i++) {
MBeanParameterInfo mbpi = params[i];
assertEquals("p" + (i+1) + " description", mbpi.getDescription());
}
}
private static MBeanAttributeInfo getAttributeInfo(MBeanInfo mbi, String attr)
throws Exception {
return getFeatureInfo(mbi.getAttributes(), attr);
}
private static MBeanOperationInfo getOperationInfo(MBeanInfo mbi, String op)
throws Exception {
return getFeatureInfo(mbi.getOperations(), op);
}
private static MBeanConstructorInfo getConstructorInfo(MBeanInfo mbi, int nparams)
throws Exception {
for (MBeanConstructorInfo mbci : mbi.getConstructors()) {
if (mbci.getSignature().length == nparams)
return mbci;
}
throw new Exception("Constructor not found: " + nparams);
}
private static <T extends MBeanFeatureInfo> T getFeatureInfo(
T[] features, String name) throws Exception {
for (T feature : features) {
if (feature.getName().equals(name))
return feature;
}
throw new Exception("Feature not found: " + name);
}
private static void assertEquals(Object expected, Object actual) {
if (!expected.equals(actual))
fail("Expected " + string(expected) + ", got " + string(actual));
}
private static String string(Object x) {
if (x instanceof String)
return quote((String) x);
else
return String.valueOf(x);
}
private static String quote(String s) {
return '"' + s.replace("\\", "\\\\").replace("\"", "\\\"") + '"';
}
private static void fail(String why) {
StackTraceElement[] stack = new Throwable().getStackTrace();
int n = 0;
for (StackTraceElement elmt : stack) {
String method = elmt.getMethodName();
if (method.equals("fail") || method.equals("assertEquals") ||
method.equals("checkSignature"))
continue;
n = elmt.getLineNumber();
break;
}
System.out.println("FAILED: " + why + " (line " + n + ")");
failure = why;
}
}