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