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      * Updates module m to use a service.
139      * Same as m2.addUses(service) but without a caller check.
140      */
141     public static void addUses(Module m, Class<?> service) {
142         JLA.addUses(m, service);
143     }
144 
145     /**
146      * Updates module m to provide a service
147      */
148     public static void addProvides(Module m, Class<?> service, Class<?> impl) {
149         ModuleLayer layer = m.getLayer();
150 
151         PrivilegedAction<ClassLoader> pa = m::getClassLoader;
152         @SuppressWarnings("removal")
153         ClassLoader loader = AccessController.doPrivileged(pa);
154 
155         ClassLoader platformClassLoader = ClassLoaders.platformClassLoader();
156         if (layer == null || loader == null || loader == platformClassLoader) {
157             // update ClassLoader catalog
158             ServicesCatalog catalog;
159             if (loader == null) {
160                 catalog = BootLoader.getServicesCatalog();
161             } else {
162                 catalog = ServicesCatalog.getServicesCatalog(loader);
163             }
164             catalog.addProvider(m, service, impl);
165         }
166 
167         if (layer != null) {
168             // update Layer catalog
169             JLA.getServicesCatalog(layer).addProvider(m, service, impl);
170         }
171     }
172 
173     /**
174      * Resolves a collection of root modules, with service binding and the empty
175      * Configuration as the parent to create a Configuration for the boot layer.
176      *
177      * This method is intended to be used to create the Configuration for the
178      * boot layer during startup or at a link-time.
179      */
180     public static Configuration newBootLayerConfiguration(ModuleFinder finder,
181                                                           Collection<String> roots,
182                                                           PrintStream traceOutput)
183     {
184         return JLMA.resolveAndBind(finder, roots, traceOutput);
185     }
186 
187     /**
188      * Called by the VM when code in the given Module has been transformed by
189      * an agent and so may have been instrumented to call into supporting
190      * classes on the boot class path or application class path.
191      */
192     public static void transformedByAgent(Module m) {
193         addReads(m, BootLoader.getUnnamedModule());
194         addReads(m, ClassLoaders.appClassLoader().getUnnamedModule());
195     }
196 
197     /**
198      * Called by the VM to load a system module, typically "java.instrument" or
199      * "jdk.management.agent". If the module is not loaded then it is resolved
200      * and loaded (along with any dependences that weren't previously loaded)
201      * into a child layer.
202      */
203     public static synchronized Module loadModule(String name) {
204         ModuleLayer top = topLayer;
205         if (top == null)
206             top = ModuleLayer.boot();
207 
208         Module module = top.findModule(name).orElse(null);
209         if (module != null) {
210             // module already loaded
211             return module;
212         }
213 
214         // resolve the module with the top-most layer as the parent
215         ModuleFinder empty = ModuleFinder.of();
216         ModuleFinder finder = ModuleBootstrap.unlimitedFinder();
217         Set<String> roots = Set.of(name);
218         Configuration cf = top.configuration().resolveAndBind(empty, finder, roots);
219 
220         // create the child layer
221         Function<String, ClassLoader> clf = ModuleLoaderMap.mappingFunction(cf);
222         ModuleLayer newLayer = top.defineModules(cf, clf);
223 
224         // add qualified exports/opens to give access to modules in child layer
225         Map<String, Module> map = newLayer.modules().stream()
226                                           .collect(Collectors.toMap(Module::getName,
227                                                   Function.identity()));
228         ModuleLayer layer = top;
229         while (layer != null) {
230             for (Module m : layer.modules()) {
231                 // qualified exports
232                 m.getDescriptor().exports().stream()
233                     .filter(ModuleDescriptor.Exports::isQualified)
234                     .forEach(e -> e.targets().forEach(target -> {
235                         Module other = map.get(target);
236                         if (other != null) {
237                             addExports(m, e.source(), other);
238                         }}));
239 
240                 // qualified opens
241                 m.getDescriptor().opens().stream()
242                     .filter(ModuleDescriptor.Opens::isQualified)
243                     .forEach(o -> o.targets().forEach(target -> {
244                         Module other = map.get(target);
245                         if (other != null) {
246                             addOpens(m, o.source(), other);
247                         }}));
248             }
249 
250             List<ModuleLayer> parents = layer.parents();
251             assert parents.size() <= 1;
252             layer = parents.isEmpty() ? null : parents.get(0);
253         }
254 
255         // update security manager before making types visible
256         JLA.addNonExportedPackages(newLayer);
257 
258         // update the built-in class loaders to make the types visible
259         for (ResolvedModule resolvedModule : cf.modules()) {
260             ModuleReference mref = resolvedModule.reference();
261             String mn = mref.descriptor().name();
262             ClassLoader cl = clf.apply(mn);
263             if (cl == null) {
264                 BootLoader.loadModule(mref);
265             } else {
266                 ((BuiltinClassLoader) cl).loadModule(mref);
267             }
268         }
269 
270         // new top layer
271         topLayer = newLayer;
272 
273         // return module
274         return newLayer.findModule(name)
275                        .orElseThrow(() -> new InternalError("module not loaded"));
276 
277     }
278 
279     /**
280      * Finds the module with the given name in the boot layer or any child
281      * layers created to load the "java.instrument" or "jdk.management.agent"
282      * modules into a running VM.
283      */
284     public static Optional<Module> findLoadedModule(String name) {
285         ModuleLayer top = topLayer;
286         if (top == null)
287             top = ModuleLayer.boot();
288         return top.findModule(name);
289     }
290 
291     // the top-most layer
292     private static volatile ModuleLayer topLayer;
293 
294 }