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