1 /* 2 * Copyright (c) 2015, 2018, 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.module; 27 28 import java.lang.module.Configuration; 29 import java.lang.module.ModuleDescriptor; 30 import java.lang.module.ModuleFinder; 31 import java.lang.module.ModuleReference; 32 import java.lang.module.ResolvedModule; 33 import java.net.URI; 34 import java.security.AccessController; 35 import java.security.PrivilegedAction; 36 import java.util.List; 37 import java.util.Map; 38 import java.util.Optional; 39 import java.util.Set; 40 import java.util.function.Function; 41 import java.util.stream.Collectors; 42 43 import jdk.internal.loader.BootLoader; 44 import jdk.internal.loader.BuiltinClassLoader; 45 import jdk.internal.loader.ClassLoaders; 46 import jdk.internal.access.JavaLangAccess; 47 import jdk.internal.access.SharedSecrets; 48 49 /** 50 * A helper class for creating and updating modules. This class is intended to 51 * support command-line options, tests, and the instrumentation API. It is also 52 * used by the VM to load modules or add read edges when agents are instrumenting 53 * code that need to link to supporting classes. 54 * 55 * The parameters that are package names in this API are the fully-qualified 56 * names of the packages as defined in section 6.5.3 of <cite>The Java™ 57 * Language Specification </cite>, for example, {@code "java.lang"}. 58 */ 59 60 public class Modules { Modules()61 private Modules() { } 62 63 private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess(); 64 65 /** 66 * Creates a new Module. The module has the given ModuleDescriptor and 67 * is defined to the given class loader. 68 * 69 * The resulting Module is in a larval state in that it does not read 70 * any other module and does not have any exports. 71 * 72 * The URI is for information purposes only. 73 */ defineModule(ClassLoader loader, ModuleDescriptor descriptor, URI uri)74 public static Module defineModule(ClassLoader loader, 75 ModuleDescriptor descriptor, 76 URI uri) 77 { 78 return JLA.defineModule(loader, descriptor, uri); 79 } 80 81 /** 82 * Updates m1 to read m2. 83 * Same as m1.addReads(m2) but without a caller check. 84 */ addReads(Module m1, Module m2)85 public static void addReads(Module m1, Module m2) { 86 JLA.addReads(m1, m2); 87 } 88 89 /** 90 * Update module m to read all unnamed modules. 91 */ addReadsAllUnnamed(Module m)92 public static void addReadsAllUnnamed(Module m) { 93 JLA.addReadsAllUnnamed(m); 94 } 95 96 /** 97 * Updates module m1 to export a package to module m2. 98 * Same as m1.addExports(pn, m2) but without a caller check 99 */ addExports(Module m1, String pn, Module m2)100 public static void addExports(Module m1, String pn, Module m2) { 101 JLA.addExports(m1, pn, m2); 102 } 103 104 /** 105 * Updates module m to export a package to all unnamed modules. 106 */ addExportsToAllUnnamed(Module m, String pn)107 public static void addExportsToAllUnnamed(Module m, String pn) { 108 JLA.addExportsToAllUnnamed(m, pn); 109 } 110 111 /** 112 * Updates module m1 to open a package to module m2. 113 * Same as m1.addOpens(pn, m2) but without a caller check. 114 */ addOpens(Module m1, String pn, Module m2)115 public static void addOpens(Module m1, String pn, Module m2) { 116 JLA.addOpens(m1, pn, m2); 117 } 118 119 /** 120 * Updates module m to open a package to all unnamed modules. 121 */ addOpensToAllUnnamed(Module m, String pn)122 public static void addOpensToAllUnnamed(Module m, String pn) { 123 JLA.addOpensToAllUnnamed(m, pn); 124 } 125 126 /** 127 * Updates module m to use a service. 128 * Same as m2.addUses(service) but without a caller check. 129 */ addUses(Module m, Class<?> service)130 public static void addUses(Module m, Class<?> service) { 131 JLA.addUses(m, service); 132 } 133 134 /** 135 * Updates module m to provide a service 136 */ addProvides(Module m, Class<?> service, Class<?> impl)137 public static void addProvides(Module m, Class<?> service, Class<?> impl) { 138 ModuleLayer layer = m.getLayer(); 139 140 PrivilegedAction<ClassLoader> pa = m::getClassLoader; 141 ClassLoader loader = AccessController.doPrivileged(pa); 142 143 ClassLoader platformClassLoader = ClassLoaders.platformClassLoader(); 144 if (layer == null || loader == null || loader == platformClassLoader) { 145 // update ClassLoader catalog 146 ServicesCatalog catalog; 147 if (loader == null) { 148 catalog = BootLoader.getServicesCatalog(); 149 } else { 150 catalog = ServicesCatalog.getServicesCatalog(loader); 151 } 152 catalog.addProvider(m, service, impl); 153 } 154 155 if (layer != null) { 156 // update Layer catalog 157 JLA.getServicesCatalog(layer).addProvider(m, service, impl); 158 } 159 } 160 161 /** 162 * Called by the VM when code in the given Module has been transformed by 163 * an agent and so may have been instrumented to call into supporting 164 * classes on the boot class path or application class path. 165 */ transformedByAgent(Module m)166 public static void transformedByAgent(Module m) { 167 addReads(m, BootLoader.getUnnamedModule()); 168 addReads(m, ClassLoaders.appClassLoader().getUnnamedModule()); 169 } 170 171 /** 172 * Called by the VM to load a system module, typically "java.instrument" or 173 * "jdk.management.agent". If the module is not loaded then it is resolved 174 * and loaded (along with any dependences that weren't previously loaded) 175 * into a child layer. 176 */ loadModule(String name)177 public static synchronized Module loadModule(String name) { 178 ModuleLayer top = topLayer; 179 if (top == null) 180 top = ModuleLayer.boot(); 181 182 Module module = top.findModule(name).orElse(null); 183 if (module != null) { 184 // module already loaded 185 return module; 186 } 187 188 // resolve the module with the top-most layer as the parent 189 ModuleFinder empty = ModuleFinder.of(); 190 ModuleFinder finder = ModuleBootstrap.unlimitedFinder(); 191 Set<String> roots = Set.of(name); 192 Configuration cf = top.configuration().resolveAndBind(empty, finder, roots); 193 194 // create the child layer 195 Function<String, ClassLoader> clf = ModuleLoaderMap.mappingFunction(cf); 196 ModuleLayer newLayer = top.defineModules(cf, clf); 197 198 // add qualified exports/opens to give access to modules in child layer 199 Map<String, Module> map = newLayer.modules().stream() 200 .collect(Collectors.toMap(Module::getName, 201 Function.identity())); 202 ModuleLayer layer = top; 203 while (layer != null) { 204 for (Module m : layer.modules()) { 205 // qualified exports 206 m.getDescriptor().exports().stream() 207 .filter(ModuleDescriptor.Exports::isQualified) 208 .forEach(e -> e.targets().forEach(target -> { 209 Module other = map.get(target); 210 if (other != null) { 211 addExports(m, e.source(), other); 212 }})); 213 214 // qualified opens 215 m.getDescriptor().opens().stream() 216 .filter(ModuleDescriptor.Opens::isQualified) 217 .forEach(o -> o.targets().forEach(target -> { 218 Module other = map.get(target); 219 if (other != null) { 220 addOpens(m, o.source(), other); 221 }})); 222 } 223 224 List<ModuleLayer> parents = layer.parents(); 225 assert parents.size() <= 1; 226 layer = parents.isEmpty() ? null : parents.get(0); 227 } 228 229 // update security manager before making types visible 230 JLA.addNonExportedPackages(newLayer); 231 232 // update the built-in class loaders to make the types visible 233 for (ResolvedModule resolvedModule : cf.modules()) { 234 ModuleReference mref = resolvedModule.reference(); 235 String mn = mref.descriptor().name(); 236 ClassLoader cl = clf.apply(mn); 237 if (cl == null) { 238 BootLoader.loadModule(mref); 239 } else { 240 ((BuiltinClassLoader) cl).loadModule(mref); 241 } 242 } 243 244 // new top layer 245 topLayer = newLayer; 246 247 // return module 248 return newLayer.findModule(name) 249 .orElseThrow(() -> new InternalError("module not loaded")); 250 251 } 252 253 /** 254 * Finds the module with the given name in the boot layer or any child 255 * layers created to load the "java.instrument" or "jdk.management.agent" 256 * modules into a running VM. 257 */ findLoadedModule(String name)258 public static Optional<Module> findLoadedModule(String name) { 259 ModuleLayer top = topLayer; 260 if (top == null) 261 top = ModuleLayer.boot(); 262 return top.findModule(name); 263 } 264 265 // the top-most layer 266 private static volatile ModuleLayer topLayer; 267 268 } 269