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.Path;
  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     // Creates the built-in class loaders.
  58     static {
  59         // -Xbootclasspath/a or -javaagent with Boot-Class-Path attribute
  60         String append = VM.getSavedProperty("jdk.boot.class.path.append");
  61         BOOT_LOADER =
  62             new BootClassLoader((append != null && append.length() > 0)
  63                 ? new URLClassPath(append, true)
  64                 : null);
  65         PLATFORM_LOADER = new PlatformClassLoader(BOOT_LOADER);
  66 
  67         // A class path is required when no initial module is specified.
  68         // In this case the class path defaults to "", meaning the current
  69         // working directory.  When an initial module is specified, on the
  70         // contrary, we drop this historic interpretation of the empty
  71         // string and instead treat it as unspecified.
  72         String cp = System.getProperty("java.class.path");
  73         if (cp == null || cp.length() == 0) {
  74             String initialModuleName = System.getProperty("jdk.module.main");
  75             cp = (initialModuleName == null) ? "" : null;
  76         }
  77         URLClassPath ucp = new URLClassPath(cp, false);
  78         APP_LOADER = new AppClassLoader(PLATFORM_LOADER, ucp);
  79     }
  80 
  81     /**
  82      * Returns the class loader that is used to find resources in modules
  83      * defined to the boot class loader.
  84      *
  85      * @apiNote This method is not public, it should instead be used via
  86      * the BootLoader class that provides a restricted API to this class
  87      * loader.
  88      */
  89     static BuiltinClassLoader bootLoader() {
  90         return BOOT_LOADER;
  91     }
  92 
  93     /**
  94      * Returns the platform class loader.
  95      */
  96     public static ClassLoader platformClassLoader() {
  97         return PLATFORM_LOADER;
  98     }
  99 
 100     /**
 101      * Returns the application class loader.
 102      */
 103     public static ClassLoader appClassLoader() {
 104         return APP_LOADER;
 105     }
 106 
 107     /**
 108      * The class loader that is used to find resources in modules defined to
 109      * the boot class loader. It is not used for class loading.
 110      */
 111     private static class BootClassLoader extends BuiltinClassLoader {
 112         BootClassLoader(URLClassPath bcp) {
 113             super(null, null, bcp);
 114         }
 115 
 116         @Override
 117         protected Class<?> loadClassOrNull(String cn) {
 118             return JLA.findBootstrapClassOrNull(this, cn);
 119         }
 120     };
 121 
 122     /**
 123      * The platform class loader, a unique type to make it easier to distinguish
 124      * from the application class loader.
 125      */
 126     private static class PlatformClassLoader extends BuiltinClassLoader {
 127         static {
 128             if (!ClassLoader.registerAsParallelCapable())
 129                 throw new InternalError();
 130         }
 131 
 132         PlatformClassLoader(BootClassLoader parent) {
 133             super("platform", parent, null);
 134         }
 135 
 136         /**
 137          * Called by the VM to support define package for AppCDS.
 138          *
 139          * Shared classes are returned in ClassLoader::findLoadedClass
 140          * that bypass the defineClass call.
 141          */
 142         private Package definePackage(String pn, Module module) {
 143             return JLA.definePackage(this, pn, module);
 144         }
 145     }
 146 
 147     /**
 148      * The application class loader that is a {@code BuiltinClassLoader} with
 149      * customizations to be compatible with long standing behavior.
 150      */
 151     private static class AppClassLoader extends BuiltinClassLoader {
 152         static {
 153             if (!ClassLoader.registerAsParallelCapable())
 154                 throw new InternalError();
 155         }
 156 
 157         final URLClassPath ucp;
 158 
 159         AppClassLoader(PlatformClassLoader parent, URLClassPath ucp) {
 160             super("app", parent, ucp);
 161             this.ucp = ucp;
 162         }
 163 
 164         @Override
 165         protected Class<?> loadClass(String cn, boolean resolve)
 166             throws ClassNotFoundException
 167         {
 168             // for compatibility reasons, say where restricted package list has
 169             // been updated to list API packages in the unnamed module.
 170             SecurityManager sm = System.getSecurityManager();
 171             if (sm != null) {
 172                 int i = cn.lastIndexOf('.');
 173                 if (i != -1) {
 174                     sm.checkPackageAccess(cn.substring(0, i));
 175                 }
 176             }
 177 
 178             return super.loadClass(cn, resolve);
 179         }
 180 
 181         @Override
 182         protected PermissionCollection getPermissions(CodeSource cs) {
 183             PermissionCollection perms = super.getPermissions(cs);
 184             perms.add(new RuntimePermission("exitVM"));
 185             return perms;
 186         }
 187 
 188         /**
 189          * Called by the VM to support dynamic additions to the class path
 190          *
 191          * @see java.lang.instrument.Instrumentation#appendToSystemClassLoaderSearch
 192          */
 193         void appendToClassPathForInstrumentation(String path) {
 194             ucp.addFile(path);
 195         }
 196 
 197         /**
 198          * Called by the VM to support define package for AppCDS
 199          *
 200          * Shared classes are returned in ClassLoader::findLoadedClass
 201          * that bypass the defineClass call.
 202          */
 203         private Package definePackage(String pn, Module module) {
 204             return JLA.definePackage(this, pn, module);
 205         }
 206 
 207         /**
 208          * Called by the VM to support define package for AppCDS
 209          */
 210         protected Package defineOrCheckPackage(String pn, Manifest man, URL url) {
 211             return super.defineOrCheckPackage(pn, man, url);
 212         }
 213     }
 214 
 215     /**
 216      * Attempts to convert the given string to a file URL.
 217      *
 218      * @apiNote This is called by the VM
 219      */
 220     @Deprecated
 221     private static URL toFileURL(String s) {
 222         try {
 223             // Use an intermediate File object to construct a URI/URL without
 224             // authority component as URLClassPath can't handle URLs with a UNC
 225             // server name in the authority component.
 226             return Path.get(s).toRealPath().toFile().toURI().toURL();
 227         } catch (InvalidPathException | IOException ignore) {
 228             // malformed path string or class path element does not exist
 229             return null;
 230         }
 231     }
 232 }