1 /*
   2  * Copyright (c) 2015, 2019, 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.access.JavaLangAccess;
  37 import jdk.internal.access.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.isEmpty())
  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.isEmpty()) {
  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, boolean resolve) {
 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     /**
 138      * The application class loader that is a {@code BuiltinClassLoader} with
 139      * customizations to be compatible with long standing behavior.
 140      */
 141     private static class AppClassLoader extends BuiltinClassLoader {
 142         static {
 143             if (!ClassLoader.registerAsParallelCapable())
 144                 throw new InternalError();
 145         }
 146 
 147         final URLClassPath ucp;
 148 
 149         AppClassLoader(PlatformClassLoader parent, URLClassPath ucp) {
 150             super("app", parent, ucp);
 151             this.ucp = ucp;
 152         }
 153 
 154         @Override
 155         protected Class<?> loadClass(String cn, boolean resolve)
 156             throws ClassNotFoundException
 157         {
 158             // for compatibility reasons, say where restricted package list has
 159             // been updated to list API packages in the unnamed module.
 160             SecurityManager sm = System.getSecurityManager();
 161             if (sm != null) {
 162                 int i = cn.lastIndexOf('.');
 163                 if (i != -1) {
 164                     sm.checkPackageAccess(cn.substring(0, i));
 165                 }
 166             }
 167 
 168             return super.loadClass(cn, resolve);
 169         }
 170 
 171         @Override
 172         protected PermissionCollection getPermissions(CodeSource cs) {
 173             PermissionCollection perms = super.getPermissions(cs);
 174             perms.add(new RuntimePermission("exitVM"));
 175             return perms;
 176         }
 177 
 178         /**
 179          * Called by the VM to support dynamic additions to the class path
 180          *
 181          * @see java.lang.instrument.Instrumentation#appendToSystemClassLoaderSearch
 182          */
 183         void appendToClassPathForInstrumentation(String path) {
 184             ucp.addFile(path);
 185         }
 186 
 187         /**
 188          * Called by the VM to support define package for AppCDS
 189          */
 190         protected Package defineOrCheckPackage(String pn, Manifest man, URL url) {
 191             return super.defineOrCheckPackage(pn, man, url);
 192         }
 193     }
 194 
 195     /**
 196      * Attempts to convert the given string to a file URL.
 197      *
 198      * @apiNote This is called by the VM
 199      */
 200     @Deprecated
 201     private static URL toFileURL(String s) {
 202         try {
 203             // Use an intermediate File object to construct a URI/URL without
 204             // authority component as URLClassPath can't handle URLs with a UNC
 205             // server name in the authority component.
 206             return Path.of(s).toRealPath().toFile().toURI().toURL();
 207         } catch (InvalidPathException | IOException ignore) {
 208             // malformed path string or class path element does not exist
 209             return null;
 210         }
 211     }
 212 }