1 /*
   2  * Copyright (c) 2015, 2017, 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.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package jdk.internal.loader;
  27 
  28 import java.io.IOException;
  29 import java.net.URL;
  30 import java.nio.file.InvalidPathException;
  31 import java.nio.file.Paths;
  32 import java.security.CodeSource;
  33 import java.security.PermissionCollection;
  34 import java.util.jar.Manifest;
  35 
  36 import jdk.internal.misc.JavaLangAccess;
  37 import jdk.internal.misc.SharedSecrets;
  38 import jdk.internal.misc.VM;
  39 
  40 /**
  41  * Creates and provides access to the built-in platform and application class
  42  * loaders. It also creates the class loader that is used to locate resources
  43  * in modules defined to the boot class loader.
  44  */
  45 
  46 public class ClassLoaders {
  47 
  48     private ClassLoaders() { }
  49 
  50     private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess();
  51 
  52     // the built-in class loaders
  53     private static final BootClassLoader BOOT_LOADER;
  54     private static final PlatformClassLoader PLATFORM_LOADER;
  55     private static final AppClassLoader APP_LOADER;
  56 
  57     /**
  58      * Creates the built-in class loaders
  59      */
  60     static {
  61 
  62         // -Xbootclasspath/a or -javaagent with Boot-Class-Path attribute
  63         URLClassPath bcp = null;
  64         String s = VM.getSavedProperty("jdk.boot.class.path.append");
  65         if (s != null && s.length() > 0)
  66             bcp = new URLClassPath(s, true);
  67 
  68         // we have a class path if -cp is specified or -m is not specified.
  69         // If neither is specified then default to -cp <working directory>
  70         // If -cp is not specified and -m is specified, the value of
  71         // java.class.path is an empty string, then no class path.
  72         String mainMid = System.getProperty("jdk.module.main");
  73         String cp = System.getProperty("java.class.path");
  74         if (mainMid == null) {
  75             // no main module specified so class path required
  76             if (cp == null) {
  77                 cp = "";
  78             }
  79         } else {
  80             // main module specified, ignore empty class path
  81             if (cp != null && cp.length() == 0) {
  82                 cp = null;
  83             }
  84         }
  85         URLClassPath ucp = new URLClassPath(cp, false);
  86 
  87         // create the class loaders
  88         BOOT_LOADER = new BootClassLoader(bcp);
  89         PLATFORM_LOADER = new PlatformClassLoader(BOOT_LOADER);
  90         APP_LOADER = new AppClassLoader(PLATFORM_LOADER, ucp);
  91     }
  92 
  93     /**
  94      * Returns the class loader that is used to find resources in modules
  95      * defined to the boot class loader.
  96      *
  97      * @apiNote This method is not public, it should instead be used via
  98      * the BootLoader class that provides a restricted API to this class
  99      * loader.
 100      */
 101     static BuiltinClassLoader bootLoader() {
 102         return BOOT_LOADER;
 103     }
 104 
 105     /**
 106      * Returns the platform class loader.
 107      */
 108     public static ClassLoader platformClassLoader() {
 109         return PLATFORM_LOADER;
 110     }
 111 
 112     /**
 113      * Returns the application class loader.
 114      */
 115     public static ClassLoader appClassLoader() {
 116         return APP_LOADER;
 117     }
 118 
 119     /**
 120      * The class loader that is used to find resources in modules defined to
 121      * the boot class loader. It is not used for class loading.
 122      */
 123     private static class BootClassLoader extends BuiltinClassLoader {
 124         BootClassLoader(URLClassPath bcp) {
 125             super(null, null, bcp);
 126         }
 127 
 128         @Override
 129         protected Class<?> loadClassOrNull(String cn) {
 130             return JLA.findBootstrapClassOrNull(this, cn);
 131         }
 132     };
 133 
 134     /**
 135      * The platform class loader, a unique type to make it easier to distinguish
 136      * from the application class loader.
 137      */
 138     private static class PlatformClassLoader extends BuiltinClassLoader {
 139         static {
 140             if (!ClassLoader.registerAsParallelCapable())
 141                 throw new InternalError();
 142         }
 143 
 144         PlatformClassLoader(BootClassLoader parent) {
 145             super("platform", parent, null);
 146         }
 147 
 148         /**
 149          * Called by the VM to support define package for AppCDS.
 150          *
 151          * Shared classes are returned in ClassLoader::findLoadedClass
 152          * that bypass the defineClass call.
 153          */
 154         private Package definePackage(String pn, Module module) {
 155             return JLA.definePackage(this, pn, module);
 156         }
 157     }
 158 
 159     /**
 160      * The application class loader that is a {@code BuiltinClassLoader} with
 161      * customizations to be compatible with long standing behavior.
 162      */
 163     private static class AppClassLoader extends BuiltinClassLoader {
 164         static {
 165             if (!ClassLoader.registerAsParallelCapable())
 166                 throw new InternalError();
 167         }
 168 
 169         final URLClassPath ucp;
 170 
 171         AppClassLoader(PlatformClassLoader parent, URLClassPath ucp) {
 172             super("app", parent, ucp);
 173             this.ucp = ucp;
 174         }
 175 
 176         @Override
 177         protected Class<?> loadClass(String cn, boolean resolve)
 178             throws ClassNotFoundException
 179         {
 180             // for compatibility reasons, say where restricted package list has
 181             // been updated to list API packages in the unnamed module.
 182             SecurityManager sm = System.getSecurityManager();
 183             if (sm != null) {
 184                 int i = cn.lastIndexOf('.');
 185                 if (i != -1) {
 186                     sm.checkPackageAccess(cn.substring(0, i));
 187                 }
 188             }
 189 
 190             return super.loadClass(cn, resolve);
 191         }
 192 
 193         @Override
 194         protected PermissionCollection getPermissions(CodeSource cs) {
 195             PermissionCollection perms = super.getPermissions(cs);
 196             perms.add(new RuntimePermission("exitVM"));
 197             return perms;
 198         }
 199 
 200         /**
 201          * Called by the VM to support dynamic additions to the class path
 202          *
 203          * @see java.lang.instrument.Instrumentation#appendToSystemClassLoaderSearch
 204          */
 205         void appendToClassPathForInstrumentation(String path) {
 206             ucp.addFile(path);
 207         }
 208 
 209         /**
 210          * Called by the VM to support define package for AppCDS
 211          *
 212          * Shared classes are returned in ClassLoader::findLoadedClass
 213          * that bypass the defineClass call.
 214          */
 215         private Package definePackage(String pn, Module module) {
 216             return JLA.definePackage(this, pn, module);
 217         }
 218 
 219         /**
 220          * Called by the VM to support define package for AppCDS
 221          */
 222         protected Package defineOrCheckPackage(String pn, Manifest man, URL url) {
 223             return super.defineOrCheckPackage(pn, man, url);
 224         }
 225     }
 226 
 227     /**
 228      * Attempts to convert the given string to a file URL.
 229      *
 230      * @apiNote This is called by the VM
 231      */
 232     @Deprecated
 233     private static URL toFileURL(String s) {
 234         try {
 235             // Use an intermediate File object to construct a URI/URL without
 236             // authority component as URLClassPath can't handle URLs with a UNC
 237             // server name in the authority component.
 238             return Paths.get(s).toRealPath().toFile().toURI().toURL();
 239         } catch (InvalidPathException | IOException ignore) {
 240             // malformed path string or class path element does not exist
 241             return null;
 242         }
 243     }
 244 }