1 /*
2 * Copyright (c) 2003, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24 /*
25 * @test
26 * @bug 4898478
27 * @summary Tests client default class loader used before JSR 160 loader
28 * @author Eamonn McManus
29 * @run clean MethodResultTest
30 * @run build MethodResultTest
31 * @run main MethodResultTest
32 */
33
34 import java.io.*;
35 import java.net.*;
36 import java.util.*;
37 import javax.management.*;
38 import javax.management.remote.*;
39
40 /*
41 This test checks that the class loader that is used to deserialize
42 the return values from remote MBean server operations is indeed the
43 one specified by the user. The only MBean server operations that
44 matter are those than can return an arbitrary Object. We don't
45 care about getMBeanCount or queryNames or whatever because their
46 return values are always of classes loaded by the bootstrap loader.
47 But for the operations getAttribute, getAttributes, setAttributes,
48 and invoke, the return value can include any Java class. This is
49 also true of getMBeanInfo, since the return value can be an exotic
50 subclass of MBeanInfo, or a ModelMBeanInfo that refers to an
51 arbitrary Object. The JMX Remote API spec requires that these
52 return values be deserialized using the class loader supplied by
53 the user (default is context class loader). In particular it must
54 not be deserialized using the system class loader, which it will be
55 with RMI unless special precautions are taken.
56 */
57 public class MethodResultTest {
58 public static void main(String[] args) throws Exception {
59 Class thisClass = MethodResultTest.class;
60 Class exoticClass = Exotic.class;
61 String exoticClassName = Exotic.class.getName();
62 ClassLoader testClassLoader = thisClass.getClassLoader();
63 if (!(testClassLoader instanceof URLClassLoader)) {
64 System.out.println("TEST INVALID: Not loaded by a " +
65 "URLClassLoader: " + testClassLoader);
66 System.exit(1);
67 }
68
69 URLClassLoader tcl = (URLClassLoader) testClassLoader;
70 URL[] urls = tcl.getURLs();
71 ClassLoader shadowLoader =
72 new ShadowLoader(urls, testClassLoader,
73 new String[] {exoticClassName,
74 ExoticMBeanInfo.class.getName(),
75 ExoticException.class.getName()});
76 Class cl = shadowLoader.loadClass(exoticClassName);
77 if (cl == exoticClass) {
78 System.out.println("TEST INVALID: Shadow class loader loaded " +
79 "same class as test class loader");
80 System.exit(1);
81 }
82 Thread.currentThread().setContextClassLoader(shadowLoader);
83
84 ObjectName on = new ObjectName("a:b=c");
85 MBeanServer mbs = MBeanServerFactory.newMBeanServer();
86 mbs.createMBean(Thing.class.getName(), on);
87
88 final String[] protos = {"rmi", "iiop", "jmxmp"};
89
90 boolean ok = true;
91 for (int i = 0; i < protos.length; i++) {
92 try {
93 ok &= test(protos[i], mbs, on);
94 System.out.println();
95 } catch (Exception e) {
96 System.out.println("TEST FAILED WITH EXCEPTION:");
180 ExoticException.class);
181 ok &= checkExceptionType("invoke", invokeException,
182 ExoticException.class);
183
184 if (ok)
185 System.out.println("Test passes for protocol " + proto);
186 return ok;
187 }
188
189 private static Exception noException(String what) {
190 final String msg =
191 "Operation " + what + " returned when exception expected";
192 return new IllegalStateException(msg);
193 }
194
195 private static Object attrValue(AttributeList attrs) {
196 return ((Attribute) attrs.get(0)).getValue();
197 }
198
199 private static boolean checkType(String what, Object object,
200 Class wrongClass) {
201 return checkType(what, object, wrongClass, false);
202 }
203
204 private static boolean checkType(String what, Object object,
205 Class wrongClass, boolean isException) {
206 final String type = isException ? "exception" : "object";
207 final String rendered = isException ? "thrown" : "returned";
208 System.out.println("For " + type + " " + rendered + " by " + what +
209 ":");
210 if (wrongClass.isInstance(object)) {
211 System.out.println("TEST FAILS: " + type + " loaded by test " +
212 "classloader");
213 return false;
214 }
215 String className = object.getClass().getName();
216 if (!className.equals(wrongClass.getName())) {
217 System.out.println("TEST FAILS: " + rendered + " " + type +
218 " has wrong class name: " + className);
219 return false;
220 }
221 System.out.println("Test passes: " + rendered + " " + type +
222 " has same class name but is not same class");
223 return true;
224 }
225
226 private static boolean checkExceptionType(String what, Exception exception,
227 Class wrongClass) {
228 if (!(exception instanceof MBeanException)) {
229 System.out.println("Exception thrown by " + what + " is not an " +
230 MBeanException.class.getName() +
231 ":");
232 exception.printStackTrace(System.out);
233 return false;
234 }
235
236 exception = ((MBeanException) exception).getTargetException();
237
238 return checkType(what, exception, wrongClass, true);
239 }
240
241 private static boolean checkAttrs(String what, AttributeList attrs) {
242 if (attrs.size() != 1) {
243 System.out.println("TEST FAILS: list returned by " + what +
244 " does not have size 1: " + attrs);
245 return false;
246 }
247 Attribute attr = (Attribute) attrs.get(0);
303
304 public static class ExoticMBeanInfo extends MBeanInfo {
305 public ExoticMBeanInfo(MBeanInfo mbi) {
306 super(mbi.getClassName(),
307 mbi.getDescription(),
308 mbi.getAttributes(),
309 mbi.getConstructors(),
310 mbi.getOperations(),
311 mbi.getNotifications());
312 }
313 }
314
315 private static class ShadowLoader extends URLClassLoader {
316 ShadowLoader(URL[] urls, ClassLoader realLoader,
317 String[] shadowClassNames) {
318 super(urls, null);
319 this.realLoader = realLoader;
320 this.shadowClassNames = Arrays.asList(shadowClassNames);
321 }
322
323 protected Class findClass(String name) throws ClassNotFoundException {
324 if (shadowClassNames.contains(name))
325 return super.findClass(name);
326 else
327 return realLoader.loadClass(name);
328 }
329
330 private final ClassLoader realLoader;
331 private final List shadowClassNames;
332 }
333 }
|
1 /*
2 * Copyright (c) 2003, 2015, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23
24 /*
25 * @test
26 * @bug 4898478
27 * @summary Tests client default class loader used before JSR 160 loader
28 * @author Eamonn McManus
29 * @modules java.management
30 * @run clean MethodResultTest
31 * @run build MethodResultTest
32 * @run main MethodResultTest
33 */
34
35 import java.io.*;
36 import java.nio.file.Paths;
37 import java.net.*;
38 import java.util.*;
39 import javax.management.*;
40 import javax.management.remote.*;
41
42 /*
43 This test checks that the class loader that is used to deserialize
44 the return values from remote MBean server operations is indeed the
45 one specified by the user. The only MBean server operations that
46 matter are those than can return an arbitrary Object. We don't
47 care about getMBeanCount or queryNames or whatever because their
48 return values are always of classes loaded by the bootstrap loader.
49 But for the operations getAttribute, getAttributes, setAttributes,
50 and invoke, the return value can include any Java class. This is
51 also true of getMBeanInfo, since the return value can be an exotic
52 subclass of MBeanInfo, or a ModelMBeanInfo that refers to an
53 arbitrary Object. The JMX Remote API spec requires that these
54 return values be deserialized using the class loader supplied by
55 the user (default is context class loader). In particular it must
56 not be deserialized using the system class loader, which it will be
57 with RMI unless special precautions are taken.
58 */
59 public class MethodResultTest {
60 public static void main(String[] args) throws Exception {
61 Class<?> thisClass = MethodResultTest.class;
62 Class<?> exoticClass = Exotic.class;
63 String exoticClassName = Exotic.class.getName();
64
65 String[] cpaths = System.getProperty("test.classes", ".")
66 .split(File.pathSeparator);
67 URL[] urls = new URL[cpaths.length];
68 for (int i=0; i < cpaths.length; i++) {
69 urls[i] = Paths.get(cpaths[i]).toUri().toURL();
70 }
71
72 ClassLoader shadowLoader =
73 new ShadowLoader(urls, thisClass.getClassLoader(),
74 new String[] {exoticClassName,
75 ExoticMBeanInfo.class.getName(),
76 ExoticException.class.getName()});
77 Class<?> cl = shadowLoader.loadClass(exoticClassName);
78 if (cl == exoticClass) {
79 System.out.println("TEST INVALID: Shadow class loader loaded " +
80 "same class as test class loader");
81 System.exit(1);
82 }
83 Thread.currentThread().setContextClassLoader(shadowLoader);
84
85 ObjectName on = new ObjectName("a:b=c");
86 MBeanServer mbs = MBeanServerFactory.newMBeanServer();
87 mbs.createMBean(Thing.class.getName(), on);
88
89 final String[] protos = {"rmi", "iiop", "jmxmp"};
90
91 boolean ok = true;
92 for (int i = 0; i < protos.length; i++) {
93 try {
94 ok &= test(protos[i], mbs, on);
95 System.out.println();
96 } catch (Exception e) {
97 System.out.println("TEST FAILED WITH EXCEPTION:");
181 ExoticException.class);
182 ok &= checkExceptionType("invoke", invokeException,
183 ExoticException.class);
184
185 if (ok)
186 System.out.println("Test passes for protocol " + proto);
187 return ok;
188 }
189
190 private static Exception noException(String what) {
191 final String msg =
192 "Operation " + what + " returned when exception expected";
193 return new IllegalStateException(msg);
194 }
195
196 private static Object attrValue(AttributeList attrs) {
197 return ((Attribute) attrs.get(0)).getValue();
198 }
199
200 private static boolean checkType(String what, Object object,
201 Class<?> wrongClass) {
202 return checkType(what, object, wrongClass, false);
203 }
204
205 private static boolean checkType(String what, Object object,
206 Class<?> wrongClass, boolean isException) {
207 final String type = isException ? "exception" : "object";
208 final String rendered = isException ? "thrown" : "returned";
209 System.out.println("For " + type + " " + rendered + " by " + what +
210 ":");
211 if (wrongClass.isInstance(object)) {
212 System.out.println("TEST FAILS: " + type + " loaded by test " +
213 "classloader");
214 return false;
215 }
216 String className = object.getClass().getName();
217 if (!className.equals(wrongClass.getName())) {
218 System.out.println("TEST FAILS: " + rendered + " " + type +
219 " has wrong class name: " + className);
220 return false;
221 }
222 System.out.println("Test passes: " + rendered + " " + type +
223 " has same class name but is not same class");
224 return true;
225 }
226
227 private static boolean checkExceptionType(String what, Exception exception,
228 Class<?> wrongClass) {
229 if (!(exception instanceof MBeanException)) {
230 System.out.println("Exception thrown by " + what + " is not an " +
231 MBeanException.class.getName() +
232 ":");
233 exception.printStackTrace(System.out);
234 return false;
235 }
236
237 exception = ((MBeanException) exception).getTargetException();
238
239 return checkType(what, exception, wrongClass, true);
240 }
241
242 private static boolean checkAttrs(String what, AttributeList attrs) {
243 if (attrs.size() != 1) {
244 System.out.println("TEST FAILS: list returned by " + what +
245 " does not have size 1: " + attrs);
246 return false;
247 }
248 Attribute attr = (Attribute) attrs.get(0);
304
305 public static class ExoticMBeanInfo extends MBeanInfo {
306 public ExoticMBeanInfo(MBeanInfo mbi) {
307 super(mbi.getClassName(),
308 mbi.getDescription(),
309 mbi.getAttributes(),
310 mbi.getConstructors(),
311 mbi.getOperations(),
312 mbi.getNotifications());
313 }
314 }
315
316 private static class ShadowLoader extends URLClassLoader {
317 ShadowLoader(URL[] urls, ClassLoader realLoader,
318 String[] shadowClassNames) {
319 super(urls, null);
320 this.realLoader = realLoader;
321 this.shadowClassNames = Arrays.asList(shadowClassNames);
322 }
323
324 protected Class<?> findClass(String name) throws ClassNotFoundException {
325 if (shadowClassNames.contains(name))
326 return super.findClass(name);
327 else
328 return realLoader.loadClass(name);
329 }
330
331 private final ClassLoader realLoader;
332 private final List shadowClassNames;
333 }
334 }
|