/*
 * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package jdk.internal.module;

import java.lang.module.Configuration;
import java.lang.module.ModuleDescriptor;
import java.lang.module.ModuleFinder;
import java.lang.module.ModuleReference;
import java.lang.module.ResolvedModule;
import java.net.URI;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;

import jdk.internal.loader.BootLoader;
import jdk.internal.loader.BuiltinClassLoader;
import jdk.internal.loader.ClassLoaders;
import jdk.internal.access.JavaLangAccess;
import jdk.internal.access.SharedSecrets;

A helper class for creating and updating modules. This class is intended to support command-line options, tests, and the instrumentation API. It is also used by the VM to load modules or add read edges when agents are instrumenting code that need to link to supporting classes. The parameters that are package names in this API are the fully-qualified names of the packages as defined in section 6.5.3 of The Java™ Language Specification , for example, "java.lang".
/** * A helper class for creating and updating modules. This class is intended to * support command-line options, tests, and the instrumentation API. It is also * used by the VM to load modules or add read edges when agents are instrumenting * code that need to link to supporting classes. * * The parameters that are package names in this API are the fully-qualified * names of the packages as defined in section 6.5.3 of <cite>The Java&trade; * Language Specification </cite>, for example, {@code "java.lang"}. */
public class Modules { private Modules() { } private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess();
Creates a new Module. The module has the given ModuleDescriptor and is defined to the given class loader. The resulting Module is in a larval state in that it does not read any other module and does not have any exports. The URI is for information purposes only.
/** * Creates a new Module. The module has the given ModuleDescriptor and * is defined to the given class loader. * * The resulting Module is in a larval state in that it does not read * any other module and does not have any exports. * * The URI is for information purposes only. */
public static Module defineModule(ClassLoader loader, ModuleDescriptor descriptor, URI uri) { return JLA.defineModule(loader, descriptor, uri); }
Updates m1 to read m2. Same as m1.addReads(m2) but without a caller check.
/** * Updates m1 to read m2. * Same as m1.addReads(m2) but without a caller check. */
public static void addReads(Module m1, Module m2) { JLA.addReads(m1, m2); }
Update module m to read all unnamed modules.
/** * Update module m to read all unnamed modules. */
public static void addReadsAllUnnamed(Module m) { JLA.addReadsAllUnnamed(m); }
Updates module m1 to export a package to module m2. Same as m1.addExports(pn, m2) but without a caller check
/** * Updates module m1 to export a package to module m2. * Same as m1.addExports(pn, m2) but without a caller check */
public static void addExports(Module m1, String pn, Module m2) { JLA.addExports(m1, pn, m2); }
Updates module m to export a package to all unnamed modules.
/** * Updates module m to export a package to all unnamed modules. */
public static void addExportsToAllUnnamed(Module m, String pn) { JLA.addExportsToAllUnnamed(m, pn); }
Updates module m1 to open a package to module m2. Same as m1.addOpens(pn, m2) but without a caller check.
/** * Updates module m1 to open a package to module m2. * Same as m1.addOpens(pn, m2) but without a caller check. */
public static void addOpens(Module m1, String pn, Module m2) { JLA.addOpens(m1, pn, m2); }
Updates module m to open a package to all unnamed modules.
/** * Updates module m to open a package to all unnamed modules. */
public static void addOpensToAllUnnamed(Module m, String pn) { JLA.addOpensToAllUnnamed(m, pn); }
Updates module m to use a service. Same as m2.addUses(service) but without a caller check.
/** * Updates module m to use a service. * Same as m2.addUses(service) but without a caller check. */
public static void addUses(Module m, Class<?> service) { JLA.addUses(m, service); }
Updates module m to provide a service
/** * Updates module m to provide a service */
public static void addProvides(Module m, Class<?> service, Class<?> impl) { ModuleLayer layer = m.getLayer(); PrivilegedAction<ClassLoader> pa = m::getClassLoader; ClassLoader loader = AccessController.doPrivileged(pa); ClassLoader platformClassLoader = ClassLoaders.platformClassLoader(); if (layer == null || loader == null || loader == platformClassLoader) { // update ClassLoader catalog ServicesCatalog catalog; if (loader == null) { catalog = BootLoader.getServicesCatalog(); } else { catalog = ServicesCatalog.getServicesCatalog(loader); } catalog.addProvider(m, service, impl); } if (layer != null) { // update Layer catalog JLA.getServicesCatalog(layer).addProvider(m, service, impl); } }
Called by the VM when code in the given Module has been transformed by an agent and so may have been instrumented to call into supporting classes on the boot class path or application class path.
/** * Called by the VM when code in the given Module has been transformed by * an agent and so may have been instrumented to call into supporting * classes on the boot class path or application class path. */
public static void transformedByAgent(Module m) { addReads(m, BootLoader.getUnnamedModule()); addReads(m, ClassLoaders.appClassLoader().getUnnamedModule()); }
Called by the VM to load a system module, typically "java.instrument" or "jdk.management.agent". If the module is not loaded then it is resolved and loaded (along with any dependences that weren't previously loaded) into a child layer.
/** * Called by the VM to load a system module, typically "java.instrument" or * "jdk.management.agent". If the module is not loaded then it is resolved * and loaded (along with any dependences that weren't previously loaded) * into a child layer. */
public static synchronized Module loadModule(String name) { ModuleLayer top = topLayer; if (top == null) top = ModuleLayer.boot(); Module module = top.findModule(name).orElse(null); if (module != null) { // module already loaded return module; } // resolve the module with the top-most layer as the parent ModuleFinder empty = ModuleFinder.of(); ModuleFinder finder = ModuleBootstrap.unlimitedFinder(); Set<String> roots = Set.of(name); Configuration cf = top.configuration().resolveAndBind(empty, finder, roots); // create the child layer Function<String, ClassLoader> clf = ModuleLoaderMap.mappingFunction(cf); ModuleLayer newLayer = top.defineModules(cf, clf); // add qualified exports/opens to give access to modules in child layer Map<String, Module> map = newLayer.modules().stream() .collect(Collectors.toMap(Module::getName, Function.identity())); ModuleLayer layer = top; while (layer != null) { for (Module m : layer.modules()) { // qualified exports m.getDescriptor().exports().stream() .filter(ModuleDescriptor.Exports::isQualified) .forEach(e -> e.targets().forEach(target -> { Module other = map.get(target); if (other != null) { addExports(m, e.source(), other); }})); // qualified opens m.getDescriptor().opens().stream() .filter(ModuleDescriptor.Opens::isQualified) .forEach(o -> o.targets().forEach(target -> { Module other = map.get(target); if (other != null) { addOpens(m, o.source(), other); }})); } List<ModuleLayer> parents = layer.parents(); assert parents.size() <= 1; layer = parents.isEmpty() ? null : parents.get(0); } // update security manager before making types visible JLA.addNonExportedPackages(newLayer); // update the built-in class loaders to make the types visible for (ResolvedModule resolvedModule : cf.modules()) { ModuleReference mref = resolvedModule.reference(); String mn = mref.descriptor().name(); ClassLoader cl = clf.apply(mn); if (cl == null) { BootLoader.loadModule(mref); } else { ((BuiltinClassLoader) cl).loadModule(mref); } } // new top layer topLayer = newLayer; // return module return newLayer.findModule(name) .orElseThrow(() -> new InternalError("module not loaded")); }
Finds the module with the given name in the boot layer or any child layers created to load the "java.instrument" or "jdk.management.agent" modules into a running VM.
/** * Finds the module with the given name in the boot layer or any child * layers created to load the "java.instrument" or "jdk.management.agent" * modules into a running VM. */
public static Optional<Module> findLoadedModule(String name) { ModuleLayer top = topLayer; if (top == null) top = ModuleLayer.boot(); return top.findModule(name); } // the top-most layer private static volatile ModuleLayer topLayer; }