Path: blob/master/test/jdk/javax/management/remote/mandatory/loading/MethodResultTest.java
41159 views
/*1* Copyright (c) 2003, 2018, 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 489847826* @summary Tests client default class loader used before JSR 160 loader27* @author Eamonn McManus28*29* @library /test/lib30*31* @run clean MethodResultTest32* @run build MethodResultTest33* @run main MethodResultTest34*/3536import java.io.*;37import java.nio.file.Paths;38import java.net.*;39import java.util.*;40import javax.management.*;41import javax.management.remote.*;42import jdk.test.lib.Utils;4344/*45This test checks that the class loader that is used to deserialize46the return values from remote MBean server operations is indeed the47one specified by the user. The only MBean server operations that48matter are those than can return an arbitrary Object. We don't49care about getMBeanCount or queryNames or whatever because their50return values are always of classes loaded by the bootstrap loader.51But for the operations getAttribute, getAttributes, setAttributes,52and invoke, the return value can include any Java class. This is53also true of getMBeanInfo, since the return value can be an exotic54subclass of MBeanInfo, or a ModelMBeanInfo that refers to an55arbitrary Object. The JMX Remote API spec requires that these56return values be deserialized using the class loader supplied by57the user (default is context class loader). In particular it must58not be deserialized using the system class loader, which it will be59with RMI unless special precautions are taken.60*/61public class MethodResultTest {62public static void main(String[] args) throws Exception {63Class<?> thisClass = MethodResultTest.class;64Class<?> exoticClass = Exotic.class;65String exoticClassName = Exotic.class.getName();6667String[] cpaths = System.getProperty("test.classes", ".")68.split(File.pathSeparator);69URL[] urls = new URL[cpaths.length];70for (int i=0; i < cpaths.length; i++) {71urls[i] = Paths.get(cpaths[i]).toUri().toURL();72}7374ClassLoader shadowLoader =75new ShadowLoader(urls, thisClass.getClassLoader(),76new String[] {exoticClassName,77ExoticMBeanInfo.class.getName(),78ExoticException.class.getName()});79Class<?> cl = shadowLoader.loadClass(exoticClassName);80if (cl == exoticClass) {81System.out.println("TEST INVALID: Shadow class loader loaded " +82"same class as test class loader");83System.exit(1);84}85Thread.currentThread().setContextClassLoader(shadowLoader);8687ObjectName on = new ObjectName("a:b=c");88MBeanServer mbs = MBeanServerFactory.newMBeanServer();89mbs.createMBean(Thing.class.getName(), on);9091final String[] protos = {"rmi", "iiop", "jmxmp"};9293boolean ok = true;94for (int i = 0; i < protos.length; i++) {95try {96ok &= test(protos[i], mbs, on);97System.out.println();98} catch (Exception e) {99System.out.println("TEST FAILED WITH EXCEPTION:");100e.printStackTrace(System.out);101ok = false;102}103}104105if (ok)106System.out.println("Test passed");107else {108System.out.println("TEST FAILED");109System.exit(1);110}111}112113private static boolean test(String proto, MBeanServer mbs, ObjectName on)114throws Exception {115System.out.println("Testing for protocol " + proto);116117JMXConnectorServer cs;118JMXServiceURL url = new JMXServiceURL(proto, null, 0);119try {120cs = JMXConnectorServerFactory.newJMXConnectorServer(url, null,121mbs);122} catch (MalformedURLException e) {123System.out.println("System does not recognize URL: " + url +124"; ignoring");125return true;126}127cs.start();128JMXServiceURL addr = cs.getAddress();129JMXConnector client = connect(addr);130MBeanServerConnection mbsc = client.getMBeanServerConnection();131Object getAttributeExotic = mbsc.getAttribute(on, "Exotic");132AttributeList getAttrs =133mbsc.getAttributes(on, new String[] {"Exotic"});134AttributeList setAttrs = new AttributeList();135setAttrs.add(new Attribute("Exotic", new Exotic()));136setAttrs = mbsc.setAttributes(on, setAttrs);137Object invokeExotic =138mbsc.invoke(on, "anExotic", new Object[] {}, new String[] {});139MBeanInfo exoticMBI = mbsc.getMBeanInfo(on);140141mbsc.setAttribute(on, new Attribute("Exception", Boolean.TRUE));142Exception143getAttributeException, setAttributeException, invokeException;144try {145try {146mbsc.getAttribute(on, "Exotic");147throw noException("getAttribute");148} catch (Exception e) {149getAttributeException = e;150}151try {152mbsc.setAttribute(on, new Attribute("Exotic", new Exotic()));153throw noException("setAttribute");154} catch (Exception e) {155setAttributeException = e;156}157try {158mbsc.invoke(on, "anExotic", new Object[] {}, new String[] {});159throw noException("invoke");160} catch (Exception e) {161invokeException = e;162}163} finally {164mbsc.setAttribute(on, new Attribute("Exception", Boolean.FALSE));165}166client.close();167cs.stop();168169boolean ok = true;170171ok &= checkAttrs("getAttributes", getAttrs);172ok &= checkAttrs("setAttributes", setAttrs);173174ok &= checkType("getAttribute", getAttributeExotic, Exotic.class);175ok &= checkType("getAttributes", attrValue(getAttrs), Exotic.class);176ok &= checkType("setAttributes", attrValue(setAttrs), Exotic.class);177ok &= checkType("invoke", invokeExotic, Exotic.class);178ok &= checkType("getMBeanInfo", exoticMBI, ExoticMBeanInfo.class);179180ok &= checkExceptionType("getAttribute", getAttributeException,181ExoticException.class);182ok &= checkExceptionType("setAttribute", setAttributeException,183ExoticException.class);184ok &= checkExceptionType("invoke", invokeException,185ExoticException.class);186187if (ok)188System.out.println("Test passes for protocol " + proto);189return ok;190}191192private static JMXConnector connect(JMXServiceURL addr) {193final long timeout = Utils.adjustTimeout(100);194195JMXConnector connector = null;196while (connector == null) {197try {198connector = JMXConnectorFactory.connect(addr);199} catch (IOException e) {200System.out.println("Connection error. Retrying after delay...");201delay(timeout);202} catch (Exception otherException) {203System.out.println("Unexpected exception while connecting " + otherException);204throw new RuntimeException(otherException);205}206}207return connector;208}209210private static void delay(long ms) {211try {212Thread.sleep(ms);213} catch (InterruptedException e) {214throw new RuntimeException(e);215}216}217218private static Exception noException(String what) {219final String msg =220"Operation " + what + " returned when exception expected";221return new IllegalStateException(msg);222}223224private static Object attrValue(AttributeList attrs) {225return ((Attribute) attrs.get(0)).getValue();226}227228private static boolean checkType(String what, Object object,229Class<?> wrongClass) {230return checkType(what, object, wrongClass, false);231}232233private static boolean checkType(String what, Object object,234Class<?> wrongClass, boolean isException) {235final String type = isException ? "exception" : "object";236final String rendered = isException ? "thrown" : "returned";237System.out.println("For " + type + " " + rendered + " by " + what +238":");239if (wrongClass.isInstance(object)) {240System.out.println("TEST FAILS: " + type + " loaded by test " +241"classloader");242return false;243}244String className = object.getClass().getName();245if (!className.equals(wrongClass.getName())) {246System.out.println("TEST FAILS: " + rendered + " " + type +247" has wrong class name: " + className);248return false;249}250System.out.println("Test passes: " + rendered + " " + type +251" has same class name but is not same class");252return true;253}254255private static boolean checkExceptionType(String what, Exception exception,256Class<?> wrongClass) {257if (!(exception instanceof MBeanException)) {258System.out.println("Exception thrown by " + what + " is not an " +259MBeanException.class.getName() +260":");261exception.printStackTrace(System.out);262return false;263}264265exception = ((MBeanException) exception).getTargetException();266267return checkType(what, exception, wrongClass, true);268}269270private static boolean checkAttrs(String what, AttributeList attrs) {271if (attrs.size() != 1) {272System.out.println("TEST FAILS: list returned by " + what +273" does not have size 1: " + attrs);274return false;275}276Attribute attr = (Attribute) attrs.get(0);277if (!"Exotic".equals(attr.getName())) {278System.out.println("TEST FAILS: " + what + " returned wrong " +279"attribute: " + attr);280return false;281}282283return true;284}285286public static class Thing287extends StandardMBean implements ThingMBean {288public Thing() throws NotCompliantMBeanException {289super(ThingMBean.class);290}291292public Exotic getExotic() throws ExoticException {293if (exception)294throw new ExoticException();295return new Exotic();296}297298public void setExotic(Exotic x) throws ExoticException {299if (exception)300throw new ExoticException();301}302303public Exotic anExotic() throws ExoticException {304if (exception)305throw new ExoticException();306return new Exotic();307}308309public void cacheMBeanInfo(MBeanInfo mbi) {310if (mbi != null)311mbi = new ExoticMBeanInfo(mbi);312super.cacheMBeanInfo(mbi);313}314315public void setException(boolean x) {316this.exception = x;317}318319private boolean exception;320}321322public static interface ThingMBean {323public Exotic getExotic() throws ExoticException;324public void setExotic(Exotic x) throws ExoticException;325public Exotic anExotic() throws ExoticException;326public void setException(boolean x);327}328329public static class Exotic implements Serializable {}330331public static class ExoticException extends Exception {}332333public static class ExoticMBeanInfo extends MBeanInfo {334public ExoticMBeanInfo(MBeanInfo mbi) {335super(mbi.getClassName(),336mbi.getDescription(),337mbi.getAttributes(),338mbi.getConstructors(),339mbi.getOperations(),340mbi.getNotifications());341}342}343344private static class ShadowLoader extends URLClassLoader {345ShadowLoader(URL[] urls, ClassLoader realLoader,346String[] shadowClassNames) {347super(urls, null);348this.realLoader = realLoader;349this.shadowClassNames = Arrays.asList(shadowClassNames);350}351352protected Class<?> findClass(String name) throws ClassNotFoundException {353if (shadowClassNames.contains(name))354return super.findClass(name);355else356return realLoader.loadClass(name);357}358359private final ClassLoader realLoader;360private final List shadowClassNames;361}362}363364365