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