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 
 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 {
 292         void checkLoad(Proxy proxy, ClassLoader expectedLoader);
 293     }
 294 
 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 {
 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 {
 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     {
 412         public Object invoke(Object proxy, Method method, Object[] args)
 413             throws Throwable {return null;}
 414     }
 415 }