blob: 699260777d1b55f932fbc78a6f5b84f9964751d6 [file] [log] [blame]
/*
* Copyright (c) 2005, 2015, Oracle and/or its affiliates. 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/*
* @test
* @bug 8058865
* @summary Checks correct collection of MXBean's class after unregistration
* @author Olivier Lagneau
* @modules java.management
* @library /lib/testlibrary
* @run main/othervm/timeout=300 MXBeanLoadingTest1
*/
import java.lang.ref.WeakReference;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Arrays;
import java.util.Map;
import javax.management.Attribute;
import javax.management.JMX;
import javax.management.MBeanAttributeInfo;
import javax.management.MBeanInfo;
import javax.management.MBeanOperationInfo;
import javax.management.MBeanServer;
import javax.management.MBeanServerFactory;
import javax.management.MXBean;
import javax.management.ObjectName;
import javax.management.loading.PrivateMLet;
import javax.management.openmbean.CompositeData;
import javax.management.openmbean.CompositeDataSupport;
import javax.management.openmbean.CompositeType;
import javax.management.openmbean.OpenType;
import javax.management.openmbean.SimpleType;
public class MXBeanLoadingTest1 {
public static void main(String[] args) throws Exception {
MXBeanLoadingTest1 test = new MXBeanLoadingTest1();
test.run((Map<String, Object>)null);
}
public void run(Map<String, Object> args) {
System.out.println("MXBeanLoadingTest1::run: Start") ;
try {
System.out.println("We ensure no reference is retained on MXBean class"
+ " after it is unregistered. We take time to perform"
+ " some little extra check of Descriptors, MBean*Info.");
ClassLoader myClassLoader = MXBeanLoadingTest1.class.getClassLoader();
if (!(myClassLoader instanceof URLClassLoader)) {
String message = "(ERROR) Test's class loader is not " +
"a URLClassLoader";
System.out.println(message);
throw new RuntimeException(message);
}
URLClassLoader myURLClassLoader = (URLClassLoader) myClassLoader;
URL[] urls = myURLClassLoader.getURLs();
PrivateMLet mlet = new PrivateMLet(urls, null, false);
Class<?> shadowClass = mlet.loadClass(TestMXBean.class.getName());
if (shadowClass == TestMXBean.class) {
String message = "(ERROR) MLet got original TestMXBean, not shadow";
System.out.println(message);
throw new RuntimeException(message);
}
shadowClass = null;
MBeanServer mbs = MBeanServerFactory.createMBeanServer();
ObjectName mletName = new ObjectName("x:type=mlet");
mbs.registerMBean(mlet, mletName);
ObjectName testName = new ObjectName("x:type=test");
mbs.createMBean(Test.class.getName(), testName, mletName);
// That test fails because the MXBean instance is accessed via
// a delegate OpenMBean which has
ClassLoader testLoader = mbs.getClassLoaderFor(testName);
if (testLoader != mlet) {
System.out.println("MLet " + mlet);
String message = "(ERROR) MXBean's class loader is not MLet: "
+ testLoader;
System.out.println(message);
throw new RuntimeException(message);
}
testLoader = null;
// Cycle get/set/get of the attribute of type Luis.
// We check the set is effective.
CompositeData cd_B = (CompositeData)mbs.getAttribute(testName, "B");
CompositeType compType_B = cd_B.getCompositeType();
CompositeDataSupport cds_B =
new CompositeDataSupport(compType_B,
new String[]{"something"},
new Object[]{Integer.valueOf(13)});
Attribute myAtt = new Attribute("B", cds_B);
mbs.setAttribute(testName, myAtt);
CompositeData cd_B2 = (CompositeData)mbs.getAttribute(testName, "B");
if ( ((Integer)cd_B2.get("something")).intValue() != 13 ) {
String message = "(ERROR) The setAttribute of att B did not work;"
+ " expect Luis.something = 13 but got "
+ cd_B2.get("something");
System.out.println(message);
throw new RuntimeException(message);
}
MBeanInfo info = mbs.getMBeanInfo(testName);
String mxbeanField =
(String)info.getDescriptor().getFieldValue(JMX.MXBEAN_FIELD);
if ( mxbeanField == null || ! mxbeanField.equals("true")) {
String message = "(ERROR) Improper mxbean field value "
+ mxbeanField;
System.out.println(message);
throw new RuntimeException(message);
}
// Check the 2 attributes.
MBeanAttributeInfo[] attrs = info.getAttributes();
if ( attrs.length == 2 ) {
for (MBeanAttributeInfo mbai : attrs) {
String originalTypeFieldValue =
(String)mbai.getDescriptor().getFieldValue(JMX.ORIGINAL_TYPE_FIELD);
OpenType<?> openTypeFieldValue =
(OpenType<?>)mbai.getDescriptor().getFieldValue(JMX.OPEN_TYPE_FIELD);
if ( mbai.getName().equals("A") ) {
if ( !mbai.isReadable() || !mbai.isWritable()
|| mbai.isIs()
|| !mbai.getType().equals("int") ) {
String message = "(ERROR) Unexpected MBeanAttributeInfo for A "
+ mbai;
System.out.println(message);
throw new RuntimeException(message);
}
if ( ! originalTypeFieldValue.equals("int") ) {
String message = "(ERROR) Unexpected originalType in Descriptor for A "
+ originalTypeFieldValue;
System.out.println(message);
throw new RuntimeException(message);
}
if ( ! openTypeFieldValue.equals(SimpleType.INTEGER) ) {
String message = "(ERROR) Unexpected openType in Descriptor for A "
+ originalTypeFieldValue;
System.out.println(message);
throw new RuntimeException(message);
}
} else if ( mbai.getName().equals("B") ) {
if ( !mbai.isReadable() || !mbai.isWritable()
|| mbai.isIs()
|| !mbai.getType().equals("javax.management.openmbean.CompositeData") ) {
String message = "(ERROR) Unexpected MBeanAttributeInfo for B "
+ mbai;
System.out.println(message);
throw new RuntimeException(message);
}
if ( ! originalTypeFieldValue.equals(Luis.class.getName()) ) {
String message = "(ERROR) Unexpected originalType in Descriptor for B "
+ originalTypeFieldValue;
System.out.println(message);
throw new RuntimeException(message);
}
if ( ! openTypeFieldValue.equals(compType_B) ) {
String message = "(ERROR) Unexpected openType in Descriptor for B "
+ compType_B;
System.out.println(message);
throw new RuntimeException(message);
}
} else {
String message = "(ERROR) Unknown attribute name";
System.out.println(message);
throw new RuntimeException(message);
}
}
} else {
String message = "(ERROR) Unexpected MBeanAttributeInfo array"
+ Arrays.deepToString(attrs);
System.out.println(message);
throw new RuntimeException(message);
}
// Check the MXBean operation.
MBeanOperationInfo[] ops = info.getOperations();
// The impact is ACTION_INFO as for a standard MBean it is UNKNOWN,
// logged 6320104.
if (ops.length != 1 || !ops[0].getName().equals("bogus")
|| ops[0].getSignature().length > 0
|| !ops[0].getReturnType().equals("void")) {
String message = "(ERROR) Unexpected MBeanOperationInfo array "
+ Arrays.deepToString(ops);
System.out.println(message);
throw new RuntimeException(message);
}
String originalTypeFieldValue =
(String)ops[0].getDescriptor().getFieldValue(JMX.ORIGINAL_TYPE_FIELD);
OpenType<?> openTypeFieldValue =
(OpenType<?>)ops[0].getDescriptor().getFieldValue(JMX.OPEN_TYPE_FIELD);
if ( ! originalTypeFieldValue.equals("void") ) {
String message = "(ERROR) Unexpected originalType in Descriptor for bogus "
+ originalTypeFieldValue;
System.out.println(message);
throw new RuntimeException(message);
}
if ( ! openTypeFieldValue.equals(SimpleType.VOID) ) {
String message = "(ERROR) Unexpected openType in Descriptor for bogus "
+ originalTypeFieldValue;
System.out.println(message);
throw new RuntimeException(message);
}
// Check there is 2 constructors.
if (info.getConstructors().length != 2) {
String message = "(ERROR) Wrong number of constructors " +
"in introspected bean: " +
Arrays.asList(info.getConstructors());
System.out.println(message);
throw new RuntimeException(message);
}
// Check MXBean class name.
if (!info.getClassName().endsWith("Test")) {
String message = "(ERROR) Wrong info class name: " +
info.getClassName();
System.out.println(message);
throw new RuntimeException(message);
}
mbs.unregisterMBean(testName);
mbs.unregisterMBean(mletName);
WeakReference<PrivateMLet> mletRef =
new WeakReference<PrivateMLet>(mlet);
mlet = null;
System.out.println("MXBean registered and unregistered, waiting for " +
"garbage collector to collect class loader");
for (int i = 0; i < 10000 && mletRef.get() != null; i++) {
System.gc();
Thread.sleep(1);
}
if (mletRef.get() == null)
System.out.println("(OK) class loader was GC'd");
else {
String message = "(ERROR) Class loader was not GC'd";
System.out.println(message);
throw new RuntimeException(message);
}
} catch(Exception e) {
Utils.printThrowable(e, true) ;
throw new RuntimeException(e);
}
System.out.println("MXBeanLoadingTest1::run: Done without any error") ;
}
// I agree the use of the MXBean annotation and the MXBean suffix for the
// interface name are redundant but however harmless.
//
@MXBean(true)
public static interface TestMXBean {
public void bogus();
public int getA();
public void setA(int a);
public Luis getB();
public void setB(Luis mi);
}
public static class Test implements TestMXBean {
private Luis luis = new Luis() ;
public Test() {}
public Test(int x) {}
public void bogus() {}
public int getA() {return 0;}
public void setA(int a) {}
public Luis getB() {return this.luis;}
public void setB(Luis luis) {this.luis = luis;}
}
public static class Luis {
private int something = 0;
public Luis() {}
public int getSomething() {return something;}
public void setSomething(int v) {something = v;}
public void doNothing() {}
}
}