Path: blob/master/src/java.base/share/classes/jdk/internal/module/Modules.java
41159 views
/*1* Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package jdk.internal.module;2627import java.io.PrintStream;28import java.lang.module.Configuration;29import java.lang.module.ModuleDescriptor;30import java.lang.module.ModuleFinder;31import java.lang.module.ModuleReference;32import java.lang.module.ResolvedModule;33import java.net.URI;34import java.security.AccessController;35import java.security.PrivilegedAction;36import java.util.Collection;37import java.util.List;38import java.util.Map;39import java.util.Optional;40import java.util.Set;41import java.util.function.Function;42import java.util.stream.Collectors;4344import jdk.internal.access.JavaLangModuleAccess;45import jdk.internal.loader.BootLoader;46import jdk.internal.loader.BuiltinClassLoader;47import jdk.internal.loader.ClassLoaders;48import jdk.internal.access.JavaLangAccess;49import jdk.internal.access.SharedSecrets;5051/**52* A helper class for creating and updating modules. This class is intended to53* support command-line options, tests, and the instrumentation API. It is also54* used by the VM to load modules or add read edges when agents are instrumenting55* code that need to link to supporting classes.56*57* The parameters that are package names in this API are the fully-qualified58* names of the packages as defined in section 6.5.3 of <cite>The Java59* Language Specification </cite>, for example, {@code "java.lang"}.60*/6162public class Modules {63private Modules() { }6465private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess();66private static final JavaLangModuleAccess JLMA = SharedSecrets.getJavaLangModuleAccess();6768/**69* Creates a new Module. The module has the given ModuleDescriptor and70* is defined to the given class loader.71*72* The resulting Module is in a larval state in that it does not read73* any other module and does not have any exports.74*75* The URI is for information purposes only.76*/77public static Module defineModule(ClassLoader loader,78ModuleDescriptor descriptor,79URI uri)80{81return JLA.defineModule(loader, descriptor, uri);82}8384/**85* Updates m1 to read m2.86* Same as m1.addReads(m2) but without a caller check.87*/88public static void addReads(Module m1, Module m2) {89JLA.addReads(m1, m2);90}9192/**93* Update module m to read all unnamed modules.94*/95public static void addReadsAllUnnamed(Module m) {96JLA.addReadsAllUnnamed(m);97}9899/**100* Updates module m1 to export a package to module m2.101* Same as m1.addExports(pn, m2) but without a caller check102*/103public static void addExports(Module m1, String pn, Module m2) {104JLA.addExports(m1, pn, m2);105}106107/**108* Updates module m to export a package unconditionally.109*/110public static void addExports(Module m, String pn) {111JLA.addExports(m, pn);112}113114/**115* Updates module m to export a package to all unnamed modules.116*/117public static void addExportsToAllUnnamed(Module m, String pn) {118JLA.addExportsToAllUnnamed(m, pn);119}120121/**122* Updates module m1 to open a package to module m2.123* Same as m1.addOpens(pn, m2) but without a caller check.124*/125public static void addOpens(Module m1, String pn, Module m2) {126JLA.addOpens(m1, pn, m2);127}128129/**130* Updates module m to open a package to all unnamed modules.131*/132public static void addOpensToAllUnnamed(Module m, String pn) {133JLA.addOpensToAllUnnamed(m, pn);134}135136/**137* Updates module m to use a service.138* Same as m2.addUses(service) but without a caller check.139*/140public static void addUses(Module m, Class<?> service) {141JLA.addUses(m, service);142}143144/**145* Updates module m to provide a service146*/147public static void addProvides(Module m, Class<?> service, Class<?> impl) {148ModuleLayer layer = m.getLayer();149150PrivilegedAction<ClassLoader> pa = m::getClassLoader;151@SuppressWarnings("removal")152ClassLoader loader = AccessController.doPrivileged(pa);153154ClassLoader platformClassLoader = ClassLoaders.platformClassLoader();155if (layer == null || loader == null || loader == platformClassLoader) {156// update ClassLoader catalog157ServicesCatalog catalog;158if (loader == null) {159catalog = BootLoader.getServicesCatalog();160} else {161catalog = ServicesCatalog.getServicesCatalog(loader);162}163catalog.addProvider(m, service, impl);164}165166if (layer != null) {167// update Layer catalog168JLA.getServicesCatalog(layer).addProvider(m, service, impl);169}170}171172/**173* Resolves a collection of root modules, with service binding and the empty174* Configuration as the parent to create a Configuration for the boot layer.175*176* This method is intended to be used to create the Configuration for the177* boot layer during startup or at a link-time.178*/179public static Configuration newBootLayerConfiguration(ModuleFinder finder,180Collection<String> roots,181PrintStream traceOutput)182{183return JLMA.resolveAndBind(finder, roots, traceOutput);184}185186/**187* Called by the VM when code in the given Module has been transformed by188* an agent and so may have been instrumented to call into supporting189* classes on the boot class path or application class path.190*/191public static void transformedByAgent(Module m) {192addReads(m, BootLoader.getUnnamedModule());193addReads(m, ClassLoaders.appClassLoader().getUnnamedModule());194}195196/**197* Called by the VM to load a system module, typically "java.instrument" or198* "jdk.management.agent". If the module is not loaded then it is resolved199* and loaded (along with any dependences that weren't previously loaded)200* into a child layer.201*/202public static synchronized Module loadModule(String name) {203ModuleLayer top = topLayer;204if (top == null)205top = ModuleLayer.boot();206207Module module = top.findModule(name).orElse(null);208if (module != null) {209// module already loaded210return module;211}212213// resolve the module with the top-most layer as the parent214ModuleFinder empty = ModuleFinder.of();215ModuleFinder finder = ModuleBootstrap.unlimitedFinder();216Set<String> roots = Set.of(name);217Configuration cf = top.configuration().resolveAndBind(empty, finder, roots);218219// create the child layer220Function<String, ClassLoader> clf = ModuleLoaderMap.mappingFunction(cf);221ModuleLayer newLayer = top.defineModules(cf, clf);222223// add qualified exports/opens to give access to modules in child layer224Map<String, Module> map = newLayer.modules().stream()225.collect(Collectors.toMap(Module::getName,226Function.identity()));227ModuleLayer layer = top;228while (layer != null) {229for (Module m : layer.modules()) {230// qualified exports231m.getDescriptor().exports().stream()232.filter(ModuleDescriptor.Exports::isQualified)233.forEach(e -> e.targets().forEach(target -> {234Module other = map.get(target);235if (other != null) {236addExports(m, e.source(), other);237}}));238239// qualified opens240m.getDescriptor().opens().stream()241.filter(ModuleDescriptor.Opens::isQualified)242.forEach(o -> o.targets().forEach(target -> {243Module other = map.get(target);244if (other != null) {245addOpens(m, o.source(), other);246}}));247}248249List<ModuleLayer> parents = layer.parents();250assert parents.size() <= 1;251layer = parents.isEmpty() ? null : parents.get(0);252}253254// update security manager before making types visible255JLA.addNonExportedPackages(newLayer);256257// update the built-in class loaders to make the types visible258for (ResolvedModule resolvedModule : cf.modules()) {259ModuleReference mref = resolvedModule.reference();260String mn = mref.descriptor().name();261ClassLoader cl = clf.apply(mn);262if (cl == null) {263BootLoader.loadModule(mref);264} else {265((BuiltinClassLoader) cl).loadModule(mref);266}267}268269// new top layer270topLayer = newLayer;271272// return module273return newLayer.findModule(name)274.orElseThrow(() -> new InternalError("module not loaded"));275276}277278/**279* Finds the module with the given name in the boot layer or any child280* layers created to load the "java.instrument" or "jdk.management.agent"281* modules into a running VM.282*/283public static Optional<Module> findLoadedModule(String name) {284ModuleLayer top = topLayer;285if (top == null)286top = ModuleLayer.boot();287return top.findModule(name);288}289290// the top-most layer291private static volatile ModuleLayer topLayer;292293}294295296