blob: 382a1219c68f09e597e4a3f37ce15a7e7d647f38 [file] [log] [blame]
/*
* Copyright 2007-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 6323980
* @summary Test MBeans defined with @MBean
* @author Eamonn McManus
* @run main/othervm -ea AnnotatedMBeanTest
*/
import java.io.File;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import javax.management.Attribute;
import javax.management.Descriptor;
import javax.management.DescriptorKey;
import javax.management.MBeanAttributeInfo;
import javax.management.MBeanInfo;
import javax.management.MBeanOperationInfo;
import javax.management.MBeanParameterInfo;
import javax.management.MBeanServer;
import javax.management.MBeanServerFactory;
import javax.management.MXBean;
import javax.management.MalformedObjectNameException;
import javax.management.ManagedAttribute;
import javax.management.ManagedOperation;
import javax.management.MBean;
import javax.management.ObjectName;
import javax.management.openmbean.CompositeData;
import javax.management.openmbean.CompositeType;
public class AnnotatedMBeanTest {
private static MBeanServer mbs;
private static final ObjectName objectName;
static {
try {
objectName = new ObjectName("test:type=Test");
} catch (MalformedObjectNameException e) {
throw new RuntimeException(e);
}
}
public static void main(String[] args) throws Exception {
if (!AnnotatedMBeanTest.class.desiredAssertionStatus())
throw new Exception("Test must be run with -ea");
File policyFile = File.createTempFile("jmxperms", ".policy");
policyFile.deleteOnExit();
PrintWriter pw = new PrintWriter(policyFile);
pw.println("grant {");
pw.println(" permission javax.management.MBeanPermission \"*\", \"*\";");
pw.println(" permission javax.management.MBeanServerPermission \"*\";");
pw.println(" permission javax.management.MBeanTrustPermission \"*\";");
pw.println("};");
pw.close();
System.setProperty("java.security.policy", policyFile.getAbsolutePath());
System.setSecurityManager(new SecurityManager());
String failure = null;
for (Method m : AnnotatedMBeanTest.class.getDeclaredMethods()) {
if (Modifier.isStatic(m.getModifiers()) &&
m.getName().startsWith("test") &&
m.getParameterTypes().length == 0) {
mbs = MBeanServerFactory.newMBeanServer();
try {
m.invoke(null);
System.out.println(m.getName() + " OK");
} catch (InvocationTargetException ite) {
System.out.println(m.getName() + " got exception:");
Throwable t = ite.getCause();
t.printStackTrace(System.out);
failure = m.getName() + ": " + t.toString();
}
}
}
if (failure == null)
System.out.println("TEST PASSED");
else
throw new Exception("TEST FAILED: " + failure);
}
public static class Stats {
private final int used;
private final int size;
private final boolean interesting;
public Stats(int used, int size, boolean interesting) {
this.used = used;
this.size = size;
this.interesting = interesting;
}
public int getUsed() {
return used;
}
public int getSize() {
return size;
}
public boolean isInteresting() {
return interesting;
}
}
@Retention(RetentionPolicy.RUNTIME)
public static @interface Units {
@DescriptorKey("units")
String value();
}
@MBean
public static class Cache {
private int used = 23;
private int size = 99;
@ManagedAttribute
@Units("bytes")
public int getUsed() {
return used;
}
@ManagedAttribute
public int getSize() {
return size;
}
@ManagedAttribute
public void setSize(int x) {
this.size = x;
}
@ManagedAttribute
public boolean isInteresting() {
return false;
}
@ManagedAttribute
public Stats getStats() {
return new Stats(used, size, false);
}
@ManagedOperation
public int dropOldest(int n) {
return 55;
}
private void irrelevantMethod() {}
private int getIrrelevant() {return 0;}
public int getIrrelevant2() {return 0;}
public int otherIrrelevantMethod() {return 5;}
}
public static class SubCache extends Cache {
// SubCache does not have the @MBean annotation
// but its parent does. It doesn't add any @ManagedAttribute or
// @ManagedOperation methods, so its management interface
// should be the same.
private void irrelevantMethod2() {}
public int otherIrrelevantMethod3() {return 0;}
public int getX() {return 0;}
public void setX(int x) {}
}
@MXBean
public static class CacheMX {
private int used = 23;
private int size = 99;
@ManagedAttribute
@Units("bytes")
public int getUsed() {
return used;
}
@ManagedAttribute
public int getSize() {
return size;
}
@ManagedAttribute
public void setSize(int x) {
this.size = x;
}
@ManagedAttribute
public boolean isInteresting() {
return false;
}
@ManagedAttribute
public Stats getStats() {
return new Stats(used, size, false);
}
@ManagedOperation
public int dropOldest(int n) {
return 55;
}
private void irrelevantMethod() {}
private int getIrrelevant() {return 0;}
public int getIrrelevant2() {return 0;}
public int otherIrrelevantMethod() {return 5;}
}
public static class SubCacheMX extends CacheMX {
private void irrelevantMethod2() {}
public int otherIrrelevantMethod3() {return 0;}
public int getX() {return 0;}
public void setX(int x) {}
}
private static void testSimpleManagedResource() throws Exception {
testResource(new Cache(), false);
}
private static void testSubclassManagedResource() throws Exception {
testResource(new SubCache(), false);
}
private static void testMXBeanResource() throws Exception {
testResource(new CacheMX(), true);
}
private static void testSubclassMXBeanResource() throws Exception {
testResource(new SubCacheMX(), true);
}
private static void testResource(Object resource, boolean mx) throws Exception {
mbs.registerMBean(resource, objectName);
MBeanInfo mbi = mbs.getMBeanInfo(objectName);
assert mbi.getDescriptor().getFieldValue("mxbean").equals(Boolean.toString(mx));
MBeanAttributeInfo[] mbais = mbi.getAttributes();
assert mbais.length == 4: mbais.length;
for (MBeanAttributeInfo mbai : mbais) {
String name = mbai.getName();
if (name.equals("Used")) {
assert mbai.isReadable();
assert !mbai.isWritable();
assert !mbai.isIs();
assert mbai.getType().equals("int");
assert "bytes".equals(mbai.getDescriptor().getFieldValue("units"));
} else if (name.equals("Size")) {
assert mbai.isReadable();
assert mbai.isWritable();
assert !mbai.isIs();
assert mbai.getType().equals("int");
} else if (name.equals("Interesting")) {
assert mbai.isReadable();
assert !mbai.isWritable();
assert mbai.isIs();
assert mbai.getType().equals("boolean");
} else if (name.equals("Stats")) {
assert mbai.isReadable();
assert !mbai.isWritable();
assert !mbai.isIs();
Descriptor d = mbai.getDescriptor();
if (mx) {
assert mbai.getType().equals(CompositeData.class.getName());
assert d.getFieldValue("originalType").equals(Stats.class.getName());
CompositeType ct = (CompositeType) d.getFieldValue("openType");
Set<String> names = new HashSet<String>(
Arrays.asList("used", "size", "interesting"));
assert ct.keySet().equals(names) : ct.keySet();
} else {
assert mbai.getType().equals(Stats.class.getName());
}
} else
assert false : name;
}
MBeanOperationInfo[] mbois = mbi.getOperations();
assert mbois.length == 1: mbois.length;
MBeanOperationInfo mboi = mbois[0];
assert mboi.getName().equals("dropOldest");
assert mboi.getReturnType().equals("int");
MBeanParameterInfo[] mbpis = mboi.getSignature();
assert mbpis.length == 1: mbpis.length;
assert mbpis[0].getType().equals("int");
assert mbs.getAttribute(objectName, "Used").equals(23);
assert mbs.getAttribute(objectName, "Size").equals(99);
mbs.setAttribute(objectName, new Attribute("Size", 55));
assert mbs.getAttribute(objectName, "Size").equals(55);
assert mbs.getAttribute(objectName, "Interesting").equals(false);
Object stats = mbs.getAttribute(objectName, "Stats");
assert (mx ? CompositeData.class : Stats.class).isInstance(stats) : stats.getClass();
int ret = (Integer) mbs.invoke(
objectName, "dropOldest", new Object[] {66}, new String[] {"int"});
assert ret == 55;
}
}