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 }