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