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