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