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