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&trade;
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