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