Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/test/javax/management/mxbean/MXBeanTest.java
38841 views
/*1* Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223/*24* @test25* @bug 6175517 6278707 6318827 6305746 6392303 6600709 801028526* @summary General MXBean test.27* @author Eamonn McManus28* @author Jaroslav Bachorik29* @run clean MXBeanTest MerlinMXBean TigerMXBean30* @run build MXBeanTest MerlinMXBean TigerMXBean31* @run main MXBeanTest32*/3334import java.lang.reflect.Array;35import java.lang.reflect.Field;36import java.lang.reflect.InvocationHandler;37import java.lang.reflect.Method;38import java.lang.reflect.Proxy;39import java.util.Arrays;40import java.util.Collection;41import java.util.HashMap;42import java.util.Iterator;43import java.util.Map;44import java.util.SortedMap;45import javax.management.JMX;46import javax.management.MBeanAttributeInfo;47import javax.management.MBeanInfo;48import javax.management.MBeanOperationInfo;49import javax.management.MBeanParameterInfo;50import javax.management.MBeanServer;51import javax.management.MBeanServerConnection;52import javax.management.MBeanServerFactory;53import javax.management.MBeanServerInvocationHandler;54import javax.management.NotCompliantMBeanException;55import javax.management.ObjectName;56import javax.management.StandardMBean;57import javax.management.openmbean.ArrayType;58import javax.management.openmbean.CompositeData;59import javax.management.openmbean.CompositeDataInvocationHandler;60import javax.management.openmbean.OpenType;61import javax.management.openmbean.SimpleType;62import javax.management.openmbean.TabularData;63import javax.management.openmbean.TabularType;64import javax.management.remote.JMXConnector;65import javax.management.remote.JMXConnectorFactory;66import javax.management.remote.JMXConnectorServer;67import javax.management.remote.JMXConnectorServerFactory;68import javax.management.remote.JMXServiceURL;6970public class MXBeanTest {71public static void main(String[] args) throws Exception {72testInterface(MerlinMXBean.class, false);73testInterface(TigerMXBean.class, false);74testInterface(MerlinMXBean.class, true);75testInterface(TigerMXBean.class, true);76testExplicitMXBean();77testSubclassMXBean();78testIndirectMXBean();79testNonCompliantMXBean("Private", new Private());80testNonCompliantMXBean("NonCompliant", new NonCompliant());8182if (failures == 0)83System.out.println("Test passed");84else85throw new Exception("TEST FAILURES: " + failures);86}8788private static int failures = 0;8990private static interface PrivateMXBean {91public int[] getInts();92}9394public static class Private implements PrivateMXBean {95public int[] getInts() {96return new int[]{1,2,3};97}98}99100public static interface NonCompliantMXBean {101public boolean getInt();102public boolean isInt();103public void setInt(int a);104public void setInt(long b);105}106107public static class NonCompliant implements NonCompliantMXBean {108public boolean getInt() {109return false;110}111112public boolean isInt() {113return true;114}115116public void setInt(int a) {117}118119public void setInt(long b) {120}121}122123public static interface ExplicitMXBean {124public int[] getInts();125}126public static class Explicit implements ExplicitMXBean {127public int[] getInts() {128return new int[] {1, 2, 3};129}130}131public static class Subclass132extends StandardMBean133implements ExplicitMXBean {134public Subclass() {135super(ExplicitMXBean.class, true);136}137138public int[] getInts() {139return new int[] {1, 2, 3};140}141}142public static interface IndirectInterface extends ExplicitMXBean {}143public static class Indirect implements IndirectInterface {144public int[] getInts() {145return new int[] {1, 2, 3};146}147}148149private static void testNonCompliantMXBean(String type, Object bean) throws Exception {150System.out.println(type + " MXBean test...");151MBeanServer mbs = MBeanServerFactory.newMBeanServer();152ObjectName on = new ObjectName("test:type=" + type);153try {154mbs.registerMBean(bean, on);155failure(bean.getClass().getInterfaces()[0].getName() + " is not a compliant "156+ "MXBean interface");157} catch (NotCompliantMBeanException e) {158success("Non-compliant MXBean not registered");159}160}161162private static void testExplicitMXBean() throws Exception {163System.out.println("Explicit MXBean test...");164MBeanServer mbs = MBeanServerFactory.newMBeanServer();165ObjectName on = new ObjectName("test:type=Explicit");166Explicit explicit = new Explicit();167mbs.registerMBean(explicit, on);168testMXBean(mbs, on);169}170171private static void testSubclassMXBean() throws Exception {172System.out.println("Subclass MXBean test...");173MBeanServer mbs = MBeanServerFactory.newMBeanServer();174ObjectName on = new ObjectName("test:type=Subclass");175Subclass subclass = new Subclass();176mbs.registerMBean(subclass, on);177testMXBean(mbs, on);178}179180private static void testIndirectMXBean() throws Exception {181System.out.println("Indirect MXBean test...");182MBeanServer mbs = MBeanServerFactory.newMBeanServer();183ObjectName on = new ObjectName("test:type=Indirect");184Indirect indirect = new Indirect();185mbs.registerMBean(indirect, on);186testMXBean(mbs, on);187}188189private static void testMXBean(MBeanServer mbs, ObjectName on)190throws Exception {191MBeanInfo mbi = mbs.getMBeanInfo(on);192MBeanAttributeInfo[] attrs = mbi.getAttributes();193int nattrs = attrs.length;194if (mbi.getAttributes().length != 1)195failure("wrong number of attributes: " + attrs);196else {197MBeanAttributeInfo mbai = attrs[0];198if (mbai.getName().equals("Ints")199&& mbai.isReadable() && !mbai.isWritable()200&& mbai.getDescriptor().getFieldValue("openType")201.equals(new ArrayType<int[]>(SimpleType.INTEGER, true))202&& attrs[0].getType().equals("[I"))203success("MBeanAttributeInfo");204else205failure("MBeanAttributeInfo: " + mbai);206}207208int[] ints = (int[]) mbs.getAttribute(on, "Ints");209if (equal(ints, new int[] {1, 2, 3}, null))210success("getAttribute");211else212failure("getAttribute: " + Arrays.toString(ints));213214ExplicitMXBean proxy =215JMX.newMXBeanProxy(mbs, on, ExplicitMXBean.class);216int[] pints = proxy.getInts();217if (equal(pints, new int[] {1, 2, 3}, null))218success("getAttribute through proxy");219else220failure("getAttribute through proxy: " + Arrays.toString(pints));221}222223private static class NamedMXBeans extends HashMap<ObjectName, Object> {224private static final long serialVersionUID = 0;225226NamedMXBeans(MBeanServerConnection mbsc) {227this.mbsc = mbsc;228}229230MBeanServerConnection getMBeanServerConnection() {231return mbsc;232}233234private final MBeanServerConnection mbsc;235}236237/* This is the core of the test. Given the MXBean interface c, we238make an MXBean object that implements that interface by239constructing a dynamic proxy. If the interface defines an240attribute Foo (with getFoo and setFoo methods), then it must241also contain a field (constant) Foo of the same type, and a242field (constant) FooType that is an OpenType. The field Foo is243a reference value for this case. We check that the attribute244does indeed have the given OpenType. The dynamically-created245MXBean will return the reference value from the getFoo()246method, and we check that that value survives the mapping to247open values and back when the attribute is accessed through an248MXBean proxy. The MXBean will also check in its setFoo method249that the value being set is equal to the reference value, which250tests that the mapping and unmapping also works in the other251direction. The interface should define an operation opFoo with252two parameters and a return value all of the same type as the253attribute. The MXBean will check that the two parameters are254equal to the reference value, and will return that value. The255test checks that calling the operation through an MXBean proxy256returns the reference value, again after mapping to and back257from open values.258259If any field (constant) in the MXBean interface has a name that260ends with ObjectName, say FooObjectName, then its value must be261a String containing an ObjectName value. There must be a field262(constant) called Foo that is a valid MXBean, and that MXBean263will be registered in the MBean Server with the given name before264the test starts. This enables us to test that inter-MXBean265references are correctly converted to ObjectNames and back.266*/267private static <T> void testInterface(Class<T> c, boolean nullTest)268throws Exception {269270System.out.println("Testing " + c.getName() +271(nullTest ? " for null values" : "") + "...");272273MBeanServer mbs = MBeanServerFactory.newMBeanServer();274275JMXServiceURL url = new JMXServiceURL("rmi", null, 0);276JMXConnectorServer cs =277JMXConnectorServerFactory.newJMXConnectorServer(url, null, mbs);278cs.start();279JMXServiceURL addr = cs.getAddress();280JMXConnector cc = JMXConnectorFactory.connect(addr);281MBeanServerConnection mbsc = cc.getMBeanServerConnection();282283NamedMXBeans namedMXBeans = new NamedMXBeans(mbsc);284InvocationHandler ih =285nullTest ? new MXBeanNullImplInvocationHandler(c, namedMXBeans) :286new MXBeanImplInvocationHandler(c, namedMXBeans);287T impl = c.cast(Proxy.newProxyInstance(c.getClassLoader(),288new Class[] {c},289ih));290ObjectName on = new ObjectName("test:type=" + c.getName());291mbs.registerMBean(impl, on);292293System.out.println("Register any MXBeans...");294295Field[] fields = c.getFields();296for (Field field : fields) {297String n = field.getName();298if (n.endsWith("ObjectName")) {299String objectNameString = (String) field.get(null);300String base = n.substring(0, n.length() - 10);301Field f = c.getField(base);302Object mxbean = f.get(null);303ObjectName objectName =304ObjectName.getInstance(objectNameString);305mbs.registerMBean(mxbean, objectName);306namedMXBeans.put(objectName, mxbean);307}308}309310try {311testInterface(c, mbsc, on, namedMXBeans, nullTest);312} finally {313try {314cc.close();315} finally {316cs.stop();317}318}319}320321private static <T> void testInterface(Class<T> c,322MBeanServerConnection mbsc,323ObjectName on,324NamedMXBeans namedMXBeans,325boolean nullTest)326throws Exception {327328System.out.println("Type check...");329330MBeanInfo mbi = mbsc.getMBeanInfo(on);331MBeanAttributeInfo[] mbais = mbi.getAttributes();332for (int i = 0; i < mbais.length; i++) {333MBeanAttributeInfo mbai = mbais[i];334String name = mbai.getName();335Field typeField = c.getField(name + "Type");336OpenType typeValue = (OpenType) typeField.get(null);337OpenType openType =338(OpenType) mbai.getDescriptor().getFieldValue("openType");339if (typeValue.equals(openType))340success("attribute " + name);341else {342final String msg =343"Wrong type attribute " + name + ": " +344openType + " should be " + typeValue;345failure(msg);346}347}348349MBeanOperationInfo[] mbois = mbi.getOperations();350for (int i = 0; i < mbois.length; i++) {351MBeanOperationInfo mboi = mbois[i];352String oname = mboi.getName();353if (!oname.startsWith("op"))354throw new Error();355OpenType retType =356(OpenType) mboi.getDescriptor().getFieldValue("openType");357MBeanParameterInfo[] params = mboi.getSignature();358MBeanParameterInfo p1i = params[0];359MBeanParameterInfo p2i = params[1];360OpenType p1Type =361(OpenType) p1i.getDescriptor().getFieldValue("openType");362OpenType p2Type =363(OpenType) p2i.getDescriptor().getFieldValue("openType");364if (!retType.equals(p1Type) || !p1Type.equals(p2Type)) {365final String msg =366"Parameter and return open types should all be same " +367"but are not: " + retType + " " + oname + "(" + p1Type +368", " + p2Type + ")";369failure(msg);370continue;371}372String name = oname.substring(2);373Field typeField = c.getField(name + "Type");374OpenType typeValue = (OpenType) typeField.get(null);375if (typeValue.equals(retType))376success("operation " + oname);377else {378final String msg =379"Wrong type operation " + oname + ": " +380retType + " should be " + typeValue;381failure(msg);382}383}384385386System.out.println("Mapping check...");387388Object proxy =389JMX.newMXBeanProxy(mbsc, on, c);390391Method[] methods = c.getMethods();392for (int i = 0; i < methods.length; i++) {393final Method method = methods[i];394if (method.getDeclaringClass() != c)395continue; // skip hashCode() etc inherited from Object396final String mname = method.getName();397final int what = getType(method);398final String name = getName(method);399final Field refField = c.getField(name);400if (nullTest && refField.getType().isPrimitive())401continue;402final Field openTypeField = c.getField(name + "Type");403final OpenType openType = (OpenType) openTypeField.get(null);404final Object refValue = nullTest ? null : refField.get(null);405Object setValue = refValue;406try {407Field onField = c.getField(name + "ObjectName");408String refName = (String) onField.get(null);409ObjectName refObjName = ObjectName.getInstance(refName);410Class<?> mxbeanInterface = refField.getType();411setValue = nullTest ? null :412JMX.newMXBeanProxy(mbsc, refObjName, mxbeanInterface);413} catch (Exception e) {414// no xObjectName field, setValue == refValue415}416boolean ok = true;417try {418switch (what) {419case GET:420final Object gotOpen = mbsc.getAttribute(on, name);421if (nullTest) {422if (gotOpen != null) {423failure(mname + " got non-null value " +424gotOpen);425ok = false;426}427} else if (!openType.isValue(gotOpen)) {428if (gotOpen instanceof TabularData) {429// detail the mismatch430TabularData gotTabular = (TabularData) gotOpen;431compareTabularType((TabularType) openType,432gotTabular.getTabularType());433}434failure(mname + " got open data " + gotOpen +435" not valid for open type " + openType);436ok = false;437}438final Object got = method.invoke(proxy, (Object[]) null);439if (!equal(refValue, got, namedMXBeans)) {440failure(mname + " got " + string(got) +441", should be " + string(refValue));442ok = false;443}444break;445446case SET:447method.invoke(proxy, new Object[] {setValue});448break;449450case OP:451final Object opped =452method.invoke(proxy, new Object[] {setValue, setValue});453if (!equal(refValue, opped, namedMXBeans)) {454failure(455mname + " got " + string(opped) +456", should be " + string(refValue)457);458ok = false;459}460break;461462default:463throw new Error();464}465466if (ok)467success(mname);468469} catch (Exception e) {470failure(mname, e);471}472}473}474475476private static void success(String what) {477System.out.println("OK: " + what);478}479480private static void failure(String what) {481System.out.println("FAILED: " + what);482failures++;483}484485private static void failure(String what, Exception e) {486System.out.println("FAILED WITH EXCEPTION: " + what);487e.printStackTrace(System.out);488failures++;489}490491private static class MXBeanImplInvocationHandler492implements InvocationHandler {493MXBeanImplInvocationHandler(Class intf, NamedMXBeans namedMXBeans) {494this.intf = intf;495this.namedMXBeans = namedMXBeans;496}497498public Object invoke(Object proxy, Method method, Object[] args)499throws Throwable {500final String mname = method.getName();501final int what = getType(method);502final String name = getName(method);503final Field refField = intf.getField(name);504final Object refValue = getRefValue(refField);505506switch (what) {507case GET:508assert args == null;509return refValue;510511case SET:512assert args.length == 1;513Object setValue = args[0];514if (!equal(refValue, setValue, namedMXBeans)) {515final String msg =516mname + "(" + string(setValue) +517") does not match ref: " + string(refValue);518throw new IllegalArgumentException(msg);519}520return null;521522case OP:523assert args.length == 2;524Object arg1 = args[0];525Object arg2 = args[1];526if (!equal(arg1, arg2, namedMXBeans)) {527final String msg =528mname + "(" + string(arg1) + ", " + string(arg2) +529"): args not equal";530throw new IllegalArgumentException(msg);531}532if (!equal(refValue, arg1, namedMXBeans)) {533final String msg =534mname + "(" + string(arg1) + ", " + string(arg2) +535"): args do not match ref: " + string(refValue);536throw new IllegalArgumentException(msg);537}538return refValue;539default:540throw new Error();541}542}543544Object getRefValue(Field refField) throws Exception {545return refField.get(null);546}547548private final Class intf;549private final NamedMXBeans namedMXBeans;550}551552private static class MXBeanNullImplInvocationHandler553extends MXBeanImplInvocationHandler {554MXBeanNullImplInvocationHandler(Class intf, NamedMXBeans namedMXBeans) {555super(intf, namedMXBeans);556}557558@Override559Object getRefValue(Field refField) throws Exception {560Class<?> type = refField.getType();561if (type.isPrimitive())562return super.getRefValue(refField);563else564return null;565}566}567568569private static final String[] prefixes = {570"get", "set", "op",571};572private static final int GET = 0, SET = 1, OP = 2;573574private static String getName(Method m) {575return getName(m.getName());576}577578private static String getName(String n) {579for (int i = 0; i < prefixes.length; i++) {580if (n.startsWith(prefixes[i]))581return n.substring(prefixes[i].length());582}583throw new Error();584}585586private static int getType(Method m) {587return getType(m.getName());588}589590private static int getType(String n) {591for (int i = 0; i < prefixes.length; i++) {592if (n.startsWith(prefixes[i]))593return i;594}595throw new Error();596}597598static boolean equal(Object o1, Object o2, NamedMXBeans namedMXBeans) {599if (o1 == o2)600return true;601if (o1 == null || o2 == null)602return false;603if (o1.getClass().isArray()) {604if (!o2.getClass().isArray())605return false;606return deepEqual(o1, o2, namedMXBeans);607}608if (o1 instanceof Map) {609if (!(o2 instanceof Map))610return false;611return equalMap((Map) o1, (Map) o2, namedMXBeans);612}613if (o1 instanceof CompositeData && o2 instanceof CompositeData) {614return compositeDataEqual((CompositeData) o1, (CompositeData) o2,615namedMXBeans);616}617if (Proxy.isProxyClass(o1.getClass())) {618if (Proxy.isProxyClass(o2.getClass()))619return proxyEqual(o1, o2, namedMXBeans);620InvocationHandler ih = Proxy.getInvocationHandler(o1);621// if (ih instanceof MXBeanInvocationHandler) {622// return proxyEqualsObject((MXBeanInvocationHandler) ih,623// o2, namedMXBeans);624if (ih instanceof MBeanServerInvocationHandler) {625return true;626} else if (ih instanceof CompositeDataInvocationHandler) {627return o2.equals(o1);628// We assume the other object has a reasonable equals method629}630} else if (Proxy.isProxyClass(o2.getClass()))631return equal(o2, o1, namedMXBeans);632return o1.equals(o2);633}634635// We'd use Arrays.deepEquals except we want the test to work on 1.4636// Note this code assumes no selfreferential arrays637// (as does Arrays.deepEquals)638private static boolean deepEqual(Object a1, Object a2,639NamedMXBeans namedMXBeans) {640int len = Array.getLength(a1);641if (len != Array.getLength(a2))642return false;643for (int i = 0; i < len; i++) {644Object e1 = Array.get(a1, i);645Object e2 = Array.get(a2, i);646if (!equal(e1, e2, namedMXBeans))647return false;648}649return true;650}651652private static boolean equalMap(Map<?,?> m1, Map<?,?> m2,653NamedMXBeans namedMXBeans) {654if (m1.size() != m2.size())655return false;656if ((m1 instanceof SortedMap) != (m2 instanceof SortedMap))657return false;658for (Object k1 : m1.keySet()) {659if (!m2.containsKey(k1))660return false;661if (!equal(m1.get(k1), m2.get(k1), namedMXBeans))662return false;663}664return true;665}666667// This is needed to work around a bug (5095277)668// in CompositeDataSupport.equals669private static boolean compositeDataEqual(CompositeData cd1,670CompositeData cd2,671NamedMXBeans namedMXBeans) {672if (cd1 == cd2)673return true;674if (!cd1.getCompositeType().equals(cd2.getCompositeType()))675return false;676Collection v1 = cd1.values();677Collection v2 = cd2.values();678if (v1.size() != v2.size())679return false; // should not happen680for (Iterator i1 = v1.iterator(), i2 = v2.iterator();681i1.hasNext(); ) {682if (!equal(i1.next(), i2.next(), namedMXBeans))683return false;684}685return true;686}687688// Also needed for 5095277689private static boolean proxyEqual(Object proxy1, Object proxy2,690NamedMXBeans namedMXBeans) {691if (proxy1.getClass() != proxy2.getClass())692return proxy1.equals(proxy2);693InvocationHandler ih1 = Proxy.getInvocationHandler(proxy1);694InvocationHandler ih2 = Proxy.getInvocationHandler(proxy2);695if (!(ih1 instanceof CompositeDataInvocationHandler)696|| !(ih2 instanceof CompositeDataInvocationHandler))697return proxy1.equals(proxy2);698CompositeData cd1 =699((CompositeDataInvocationHandler) ih1).getCompositeData();700CompositeData cd2 =701((CompositeDataInvocationHandler) ih2).getCompositeData();702return compositeDataEqual(cd1, cd2, namedMXBeans);703}704705// private static boolean proxyEqualsObject(MXBeanInvocationHandler ih,706// Object o,707// NamedMXBeans namedMXBeans) {708// if (namedMXBeans.getMBeanServerConnection() !=709// ih.getMBeanServerConnection())710// return false;711//712// ObjectName on = ih.getObjectName();713// Object named = namedMXBeans.get(on);714// if (named == null)715// return false;716// return (o == named && ih.getMXBeanInterface().isInstance(named));717// }718719/* I wanted to call this method toString(Object), but oddly enough720this meant that I couldn't call it from the inner class721MXBeanImplInvocationHandler, because the inherited Object.toString()722prevented that. */723static String string(Object o) {724if (o == null)725return "null";726if (o instanceof String)727return '"' + (String) o + '"';728if (o instanceof Collection)729return deepToString((Collection) o);730if (o.getClass().isArray())731return deepToString(o);732return o.toString();733}734735private static String deepToString(Object o) {736StringBuffer buf = new StringBuffer();737buf.append("[");738int len = Array.getLength(o);739for (int i = 0; i < len; i++) {740if (i > 0)741buf.append(", ");742Object e = Array.get(o, i);743buf.append(string(e));744}745buf.append("]");746return buf.toString();747}748749private static String deepToString(Collection c) {750return deepToString(c.toArray());751}752753private static void compareTabularType(TabularType t1, TabularType t2) {754if (t1.equals(t2)) {755System.out.println("same tabular type");756return;757}758if (t1.getClassName().equals(t2.getClassName()))759System.out.println("same class name");760if (t1.getDescription().equals(t2.getDescription()))761System.out.println("same description");762else {763System.out.println("t1 description: " + t1.getDescription());764System.out.println("t2 description: " + t2.getDescription());765}766if (t1.getIndexNames().equals(t2.getIndexNames()))767System.out.println("same index names");768if (t1.getRowType().equals(t2.getRowType()))769System.out.println("same row type");770}771}772773774