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