1 /*
2  * Copyright (c) 2000, 2013, 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 /* @test
25  *
26  * @summary functional test for RMIClassLoader.loadProxyClass; test
27  * ensures that the default RMI class loader provider implements
28  * RMIClassLoader.loadProxyClass correctly.
29  *
30  * @author Laird Dornin
31  *
32  * @library ../../../testlibrary
33  * @modules java.rmi/sun.rmi.registry
34  *          java.rmi/sun.rmi.server
35  *          java.rmi/sun.rmi.transport
36  *          java.rmi/sun.rmi.transport.tcp
37  * @build TestLibrary FnnClass FnnUnmarshal NonpublicInterface
38  *     NonpublicInterface1 PublicInterface PublicInterface1
39  * @run main/othervm/policy=security.policy
40  *     -Djava.rmi.server.useCodebaseOnly=false LoadProxyClasses
41  */
42 
43 import java.rmi.server.RMIClassLoader;
44 import java.lang.reflect.InvocationHandler;
45 import java.lang.reflect.Method;
46 import java.lang.reflect.Proxy;
47 import java.rmi.MarshalledObject;
48 import java.net.URL;
49 import java.net.URLClassLoader;
50 import java.io.Serializable;
51 import java.io.IOException;
52 
53 import java.util.Arrays;
54 import java.util.zip.Checksum;
55 
56 /**
57  *  Invokes RMIClassLoader.loadProxyClass() to load a proxy class with
58  *  multiple interfaces using using RMI class unmarshalling.  Test is
59  *  composed of cases which each unmarshal a proxy class in a
60  *  different environment.  All of the cases create needed class
61  *  loaders, load appropriate interfaces, create a proxy class that
62  *  implements those interfaces, create a marshalled object from that
63  *  proxy class, and finally call .get() on that object.  Get of the
64  *  object should pass in some cases and fail in others.
65  *
66  *  1. Nonpublic interface loaded from the parent of the First
67  *  Non-Null class Loader on the execution stack (FNNL).  Public
68  *  interface loaded from grandparent of FNNL parent. Proxy class must
69  *  be defined in non-null FNNL parent. Should succeed.
70  *
71  *  2. Nonpublic interface (java.util.zip.ZipConstants) and public
72  *  interface (java.util.zip.CheckSum) loaded from bootclasspath,
73  *  proxy class defined in null/boot class loader.  Should succeed.
74  *
75  *  3. Public interface classes loaded in FNNL are also available in
76  *  RMI loader parent.  FNNL is grandparent of RMI loader. Proxy class
77  *  must be defined in RMI class loader. Should succeed. public
78  *  interface must be defined in FNNL.
79  *
80  *  4. Non-public interfaces have multiple class loaders. Should fail
81  *  with a LinkageError.
82  *
83  *  5. Interface classes loaded from RMI class loader. Proxy class
84  *  defined in RMI class loader.
85  *
86  *  6. Not all interfaces classes can be loaded from a single class
87  *  loader; should fail with ClassNotFoundException.  All interface
88  *  classes will exist (but not all interfaces will be available from
89  *  one class loader).
90  *
91  *  7. prove that proxy loader has correct annotation.
92  *
93  *  8. REMIND: may want to add a case where the FNNL is null (This
94  *  would be for class unmarshalling in the implemntation of a remote
95  *  method invocation).
96  */
97 public class LoadProxyClasses {
98 
99     private static URL publicUrl = null;
100 
101     public static boolean boomerangSemantics = false;
102 
main(String[] args)103     public static void main(String[] args) {
104         try {
105             System.err.println("\nFunctional test to verify that RMI " +
106                                "loads proxy classes correctly\n");
107 
108             /* install proxy interfaces */
109             publicUrl =
110                 TestLibrary.installClassInCodebase("PublicInterface",
111                                                    "public");
112             URL publicUrl1 =
113                 TestLibrary.installClassInCodebase("PublicInterface1",
114                                                    "public1");
115             URL nonpublicUrl =
116                 TestLibrary.installClassInCodebase("NonpublicInterface",
117                                                    "nonpublic", false);
118             URL nonpublicUrl1 =
119                 TestLibrary.installClassInCodebase("NonpublicInterface1",
120                                                    "nonpublic1", false);
121             URL bothNonpublicUrl =
122                 TestLibrary.installClassInCodebase("NonpublicInterface",
123                                                    "bothNonpublic");
124             TestLibrary.installClassInCodebase("NonpublicInterface1",
125                                                "bothNonpublic");
126             URL fnnUrl =
127                 TestLibrary.installClassInCodebase("FnnClass", "fnn");
128 
129             TestLibrary.suggestSecurityManager(null);
130 
131 
132             /* Case 1 */
133             ClassLoader grandParentPublic =
134                 new URLClassLoader(new URL[] {publicUrl});
135             ClassLoader parentNonpublic =
136                 new URLClassLoader(new URL[] {nonpublicUrl},
137                                    grandParentPublic);
138             URLClassLoader fnnLoader1 =
139                 new URLClassLoader(new URL[] {fnnUrl}, parentNonpublic);
140 
141             Class nonpublicInterface =
142                 fnnLoader1.loadClass("NonpublicInterface");
143             Class publicInterface =
144                 fnnLoader1.loadClass("PublicInterface");
145 
146             Proxy proxy1 = (Proxy) Proxy.newProxyInstance(parentNonpublic,
147                 new Class[] {nonpublicInterface, publicInterface},
148                 new TestInvocationHandler());
149             unmarshalProxyClass(proxy1, fnnLoader1, parentNonpublic, 1, null);
150 
151 
152 
153             /* Case 2 */
154             Class zipConstantsClass =
155                 Class.forName("java.util.zip.ZipConstants");
156             URLClassLoader fnnLoader2 =
157                 new URLClassLoader(new URL[] {fnnUrl});
158             Proxy proxy2 = (Proxy) Proxy.newProxyInstance(null,
159                 new Class[] {zipConstantsClass, Checksum.class},
160                 new TestInvocationHandler());
161             unmarshalProxyClass(proxy2, fnnLoader2,
162                                 (ClassLoader) null, 2, null);
163 
164 
165 
166             /* Case 3 */
167             Thread currentThread = Thread.currentThread();
168             ClassLoader fnnLoader3 = new URLClassLoader(
169                 new URL[] {publicUrl, fnnUrl});
170             ClassLoader newCtxLoader =
171                 new URLClassLoader(new URL[] {publicUrl}, fnnLoader3);
172             Class publicInterface3 =
173                 fnnLoader3.loadClass("PublicInterface");
174             ClassLoader currentCtxLoader =
175                 currentThread.getContextClassLoader();
176             currentThread.setContextClassLoader(newCtxLoader);
177 
178             Proxy proxy3 = (Proxy) Proxy.newProxyInstance(newCtxLoader,
179                 new Class[] {publicInterface3},
180                 new TestInvocationHandler());
181 
182             unmarshalProxyClass(proxy3, fnnLoader3, fnnLoader3,
183                 3, new Case3Checker());
184 
185             currentThread.setContextClassLoader(currentCtxLoader);
186 
187 
188 
189             /* Case 4 */
190             ClassLoader bothNonpublicLoader =
191                 new URLClassLoader(new URL[] {bothNonpublicUrl});
192             Class nonpublicInterface4a =
193                 bothNonpublicLoader.loadClass("NonpublicInterface");
194             Class nonpublicInterface4b =
195                 bothNonpublicLoader.loadClass("NonpublicInterface1");
196             Proxy proxy4 = (Proxy) Proxy.newProxyInstance(bothNonpublicLoader,
197                 new Class[] {nonpublicInterface4a, nonpublicInterface4b},
198                 new TestInvocationHandler());
199 
200             ClassLoader nonpublicLoaderA =
201                 new URLClassLoader(new URL[] {nonpublicUrl});
202             ClassLoader nonpublicLoaderB =
203                 new URLClassLoader(new URL[] {nonpublicUrl1}, nonpublicLoaderA);
204             currentCtxLoader =
205                 currentThread.getContextClassLoader();
206             currentThread.setContextClassLoader(nonpublicLoaderB);
207 
208             IllegalAccessError illegal = null;
209             try {
210                 unmarshalProxyClass(proxy4, fnnLoader2, nonpublicLoaderB,
211                                     4, null);
212             } catch (IllegalAccessError e) {
213                 illegal = e;
214             }
215 
216             if (illegal == null) {
217                 TestLibrary.bomb("case4: IllegalAccessError not thrown " +
218                                  "when multiple nonpublic interfaces have \n" +
219                                  "different class loaders");
220             } else {
221                 System.err.println("\ncase4: IllegalAccessError correctly " +
222                                    "thrown \n when trying to load proxy " +
223                                    "with multiple nonpublic interfaces in \n" +
224                                    "  different class loaders");
225             }
226             currentThread.setContextClassLoader(currentCtxLoader);
227 
228 
229 
230             /* Case 5*/
231             ClassLoader publicLoader =
232                 new URLClassLoader(new URL[] {publicUrl});
233             Class publicInterface5 =
234                 publicLoader.loadClass("PublicInterface");
235             Proxy proxy5 = (Proxy) Proxy.newProxyInstance(publicLoader,
236                 new Class[] {publicInterface5},
237                 new TestInvocationHandler());
238 
239             currentCtxLoader =
240                 currentThread.getContextClassLoader();
241             currentThread.setContextClassLoader(publicLoader);
242             unmarshalProxyClass(proxy5, fnnLoader2, publicLoader, 5,
243                                 new Case5Checker());
244             currentThread.setContextClassLoader(currentCtxLoader);
245 
246 
247 
248             /* Case 6 */
249             ClassLoader fnnLoader6 =
250                 new URLClassLoader(new URL[] {fnnUrl, publicUrl});
251             ClassLoader publicLoader6 =
252                 new URLClassLoader(new URL[] {publicUrl1}, fnnLoader6);
253 
254             Class publicInterface6a =
255                 publicLoader6.loadClass("PublicInterface1");
256             Class publicInterface6b =
257                 fnnLoader6.loadClass("PublicInterface");
258             Proxy proxy6 = (Proxy) Proxy.newProxyInstance(publicLoader6,
259                 new Class[] {publicInterface6a, publicInterface6b},
260                 new TestInvocationHandler());
261             ClassNotFoundException cnfe = null;
262             try {
263                 unmarshalProxyClass(proxy6, fnnLoader6, publicLoader6, 6,
264                                     null);
265             } catch (ClassNotFoundException e) {
266                 cnfe = e;
267             }
268             if (cnfe == null) {
269                 TestLibrary.bomb("ClassNotFoundException not thrown " +
270                                  "when not all proxy interfaces could " +
271                                  " be found in a single class loader ");
272             } else {
273                 System.err.println("Case6: ClassNotFoundException " +
274                                    "correctly thrown when not all proxy" +
275                                    " interfaces could be found in a " +
276                                    "single class loader");
277                 cnfe.printStackTrace();
278             }
279 
280             System.err.println("TEST PASSED");
281 
282         } catch (Exception e) {
283             if (e instanceof RuntimeException) {
284                 throw (RuntimeException) e;
285             }
286             TestLibrary.bomb(e);
287         }
288     }
289 
290 
291     private interface LoadChecker {
checkLoad(Proxy proxy, ClassLoader expectedLoader)292         void checkLoad(Proxy proxy, ClassLoader expectedLoader);
293     }
294 
unmarshalProxyClass(Proxy proxy, ClassLoader fnnLoader, ClassLoader expectedLoader, int n, LoadChecker checker)295     private static Proxy unmarshalProxyClass(Proxy proxy,
296                                              ClassLoader fnnLoader,
297                                              ClassLoader expectedLoader,
298                                              int n,
299                                              LoadChecker checker)
300         throws ClassNotFoundException, IOException,
301                InstantiationException, IllegalAccessException
302     {
303         FnnUnmarshal fnnUnmarshal = (FnnUnmarshal)
304                 fnnLoader.loadClass("FnnClass").newInstance();
305         Proxy unmarshalled = (Proxy)
306             fnnUnmarshal.unmarshal(new MarshalledObject(proxy));
307         ClassLoader unmarshalledLoader =
308             unmarshalled.getClass().getClassLoader();
309 
310         if (checker != null) {
311             checker.checkLoad(unmarshalled, expectedLoader);
312         } else {
313             if (unmarshalledLoader != expectedLoader) {
314                 TestLibrary.bomb("case" + n + ": proxy class not " +
315                                  "placed into incorrect loader: " +
316                                  unmarshalledLoader);
317             } else {
318                 System.err.println("\ncase" + n + ": proxy class correctly" +
319                                    " placed into expected loader: " +
320                                    expectedLoader);
321             }
322         }
323         return proxy;
324     }
325 
326     private static class Case3Checker implements LoadChecker {
checkLoad(Proxy proxy, ClassLoader expectedLoader)327         public void checkLoad(Proxy proxy, ClassLoader expectedLoader) {
328             ClassLoader ifaceLoader =
329                 proxy.getClass().getInterfaces()[0].getClassLoader();
330             ClassLoader proxyLoader = proxy.getClass().getClassLoader();
331 
332             boolean proxyOk = false;
333 
334             if (boomerangSemantics) {
335                 ClassLoader ctxLoader =
336                     Thread.currentThread().getContextClassLoader();
337                 if (proxyLoader == ctxLoader) {
338                     proxyOk = true;
339                 }
340             } else if (proxyLoader.getClass().
341                        getName().indexOf("sun.rmi") >= 0)
342             {
343                 proxyOk = true;
344             }
345 
346             if (proxyOk) {
347                 System.err.println("\ncase3: proxy loaded in" +
348                                    " correct loader: " + proxyLoader +
349                                    Arrays.asList(((URLClassLoader)
350                                                  proxyLoader).getURLs()));
351             } else {
352                 TestLibrary.bomb("case3: proxy class loaded in " +
353                                  "incorrect loader: " + proxyLoader +
354                                    Arrays.asList(((URLClassLoader)
355                                                   proxyLoader).getURLs()));
356             }
357 
358             if (ifaceLoader == expectedLoader) {
359                 System.err.println("case3: proxy interface loaded in" +
360                                    " correct loader: " + ifaceLoader);
361             } else {
362                 TestLibrary.bomb("public proxy interface loaded in " +
363                                  "incorrect loader: " + ifaceLoader);
364             }
365         }
366     }
367 
368     private static class Case5Checker implements LoadChecker {
checkLoad(Proxy proxy, ClassLoader expectedLoader)369         public void checkLoad(Proxy proxy, ClassLoader expectedLoader) {
370             ClassLoader proxyLoader = proxy.getClass().getClassLoader();
371 
372             String proxyAnnotation =
373                 RMIClassLoader.getClassAnnotation(proxy.getClass());
374 
375             if ((proxyAnnotation == null) ||
376                 !proxyAnnotation.equals(publicUrl.toString()))
377             {
378                 TestLibrary.bomb("proxy class had incorrect annotation: " +
379                                  proxyAnnotation);
380             } else {
381                 System.err.println("proxy class had correct annotation: " +
382                                    proxyAnnotation);
383             }
384 
385             boolean proxyOk = false;
386 
387             if (boomerangSemantics) {
388                 ClassLoader ctxLoader =
389                     Thread.currentThread().getContextClassLoader();
390                 if (proxyLoader == ctxLoader) {
391                     proxyOk = true;
392                 }
393             } else if (proxyLoader.getClass().
394                        getName().indexOf("sun.rmi") >= 0)
395             {
396                 proxyOk = true;
397             }
398 
399             if (proxyOk) {
400                 System.err.println("\ncase5: proxy loaded from" +
401                                    " correct loader: " + proxyLoader);
402             } else {
403                 TestLibrary.bomb("case5: proxy interface loaded from " +
404                                  "incorrect loader: " + proxyLoader);
405             }
406         }
407     }
408 
409     private static class TestInvocationHandler
410         implements InvocationHandler, Serializable
411     {
invoke(Object proxy, Method method, Object[] args)412         public Object invoke(Object proxy, Method method, Object[] args)
413             throws Throwable {return null;}
414     }
415 }
416