1 /*
   2  * Copyright (c) 2015, 2017, 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 package jdk.internal.module;
  26 
  27 import java.lang.module.ModuleDescriptor;
  28 import java.lang.module.ModuleDescriptor.Exports;
  29 import java.lang.module.ModuleDescriptor.Opens;
  30 import java.lang.module.ModuleDescriptor.Provides;
  31 import java.lang.module.ModuleDescriptor.Requires;
  32 import java.lang.module.ModuleDescriptor.Version;
  33 import java.util.List;
  34 import java.util.Set;
  35 
  36 import jdk.internal.access.JavaLangModuleAccess;
  37 import jdk.internal.access.SharedSecrets;
  38 
  39 /**
  40  * This builder is optimized for reconstituting the {@code ModuleDescriptor}s
  41  * for system modules.  The validation should be done at jlink time.
  42  *
  43  * 1. skip name validation
  44  * 2. ignores dependency hashes.
  45  * 3. ModuleDescriptor skips the defensive copy and directly uses the
  46  *    sets/maps created in this Builder.
  47  *
  48  * SystemModules should contain modules for the boot layer.
  49  */
  50 final class Builder {
  51     private static final JavaLangModuleAccess JLMA =
  52         SharedSecrets.getJavaLangModuleAccess();
  53 
  54     // Static cache of the most recently seen Version to cheaply deduplicate
  55     // most Version objects.  JDK modules have the same version.
  56     static Version cachedVersion;
  57 
  58     /**
  59      * Returns a {@link Requires} for a dependence on a module with the given
  60      * (and possibly empty) set of modifiers, and optionally the version
  61      * recorded at compile time.
  62      */
  63     public static Requires newRequires(Set<Requires.Modifier> mods,
  64                                        String mn,
  65                                        String compiledVersion)
  66     {
  67         Version version = null;
  68         if (compiledVersion != null) {
  69             // use the cached version if the same version string
  70             Version ver = cachedVersion;
  71             if (ver != null && compiledVersion.equals(ver.toString())) {
  72                 version = ver;
  73             } else {
  74                 version = Version.parse(compiledVersion);
  75             }
  76         }
  77         return JLMA.newRequires(mods, mn, version);
  78     }
  79 
  80     /**
  81      * Returns a {@link Requires} for a dependence on a module with the given
  82      * (and possibly empty) set of modifiers, and optionally the version
  83      * recorded at compile time.
  84      */
  85     public static Requires newRequires(Set<Requires.Modifier> mods,
  86                                        String mn)
  87     {
  88         return newRequires(mods, mn, null);
  89     }
  90 
  91     /**
  92      * Returns a {@link Exports} for a qualified export, with
  93      * the given (and possibly empty) set of modifiers,
  94      * to a set of target modules.
  95      */
  96     public static Exports newExports(Set<Exports.Modifier> ms,
  97                                      String pn,
  98                                      Set<String> targets) {
  99         return JLMA.newExports(ms, pn, targets);
 100     }
 101 
 102     /**
 103      * Returns an {@link Opens} for an unqualified open with a given set of
 104      * modifiers.
 105      */
 106     public static Opens newOpens(Set<Opens.Modifier> ms, String pn) {
 107         return JLMA.newOpens(ms, pn);
 108     }
 109 
 110     /**
 111      * Returns an {@link Opens} for a qualified opens, with
 112      * the given (and possibly empty) set of modifiers,
 113      * to a set of target modules.
 114      */
 115     public static Opens newOpens(Set<Opens.Modifier> ms,
 116                                  String pn,
 117                                  Set<String> targets) {
 118         return JLMA.newOpens(ms, pn, targets);
 119     }
 120 
 121     /**
 122      * Returns a {@link Exports} for an unqualified export with a given set
 123      * of modifiers.
 124      */
 125     public static Exports newExports(Set<Exports.Modifier> ms, String pn) {
 126         return JLMA.newExports(ms, pn);
 127     }
 128 
 129     /**
 130      * Returns a {@link Provides} for a service with a given list of
 131      * implementation classes.
 132      */
 133     public static Provides newProvides(String st, List<String> pcs) {
 134         return JLMA.newProvides(st, pcs);
 135     }
 136 
 137     final String name;
 138     boolean open, synthetic, mandated;
 139     Set<Requires> requires;
 140     Set<Exports> exports;
 141     Set<Opens> opens;
 142     Set<String> packages;
 143     Set<String> uses;
 144     Set<Provides> provides;
 145     Version version;
 146     String mainClass;
 147 
 148     Builder(String name) {
 149         this.name = name;
 150         this.requires = Set.of();
 151         this.exports = Set.of();
 152         this.opens = Set.of();
 153         this.provides = Set.of();
 154         this.uses = Set.of();
 155     }
 156 
 157     Builder open(boolean value) {
 158         this.open = value;
 159         return this;
 160     }
 161 
 162     Builder synthetic(boolean value) {
 163         this.synthetic = value;
 164         return this;
 165     }
 166 
 167     Builder mandated(boolean value) {
 168         this.mandated = value;
 169         return this;
 170     }
 171 
 172     /**
 173      * Sets module exports.
 174      */
 175     public Builder exports(Exports[] exports) {
 176         this.exports = Set.of(exports);
 177         return this;
 178     }
 179 
 180     /**
 181      * Sets module opens.
 182      */
 183     public Builder opens(Opens[] opens) {
 184         this.opens = Set.of(opens);
 185         return this;
 186     }
 187 
 188     /**
 189      * Sets module requires.
 190      */
 191     public Builder requires(Requires[] requires) {
 192         this.requires = Set.of(requires);
 193         return this;
 194     }
 195 
 196     /**
 197      * Adds a set of (possible empty) packages.
 198      */
 199     public Builder packages(Set<String> packages) {
 200         this.packages = packages;
 201         return this;
 202     }
 203 
 204     /**
 205      * Sets the set of service dependences.
 206      */
 207     public Builder uses(Set<String> uses) {
 208         this.uses = uses;
 209         return this;
 210     }
 211 
 212     /**
 213      * Sets module provides.
 214      */
 215     public Builder provides(Provides[] provides) {
 216         this.provides = Set.of(provides);
 217         return this;
 218     }
 219 
 220     /**
 221      * Sets the module version.
 222      *
 223      * @throws IllegalArgumentException if {@code v} is null or cannot be
 224      *         parsed as a version string
 225      *
 226      * @see Version#parse(String)
 227      */
 228     public Builder version(String v) {
 229         Version ver = cachedVersion;
 230         if (ver != null && v.equals(ver.toString())) {
 231             version = ver;
 232         } else {
 233             cachedVersion = version = Version.parse(v);
 234         }
 235         return this;
 236     }
 237 
 238     /**
 239      * Sets the module main class.
 240      */
 241     public Builder mainClass(String mc) {
 242         mainClass = mc;
 243         return this;
 244     }
 245 
 246     /**
 247      * Returns an immutable set of the module modifiers derived from the flags.
 248      */
 249     private Set<ModuleDescriptor.Modifier> modifiers() {
 250         int n = 0;
 251         if (open) n++;
 252         if (synthetic) n++;
 253         if (mandated) n++;
 254         if (n == 0) {
 255             return Set.of();
 256         } else {
 257             ModuleDescriptor.Modifier[] mods = new ModuleDescriptor.Modifier[n];
 258             if (open) mods[--n] = ModuleDescriptor.Modifier.OPEN;
 259             if (synthetic) mods[--n] = ModuleDescriptor.Modifier.SYNTHETIC;
 260             if (mandated) mods[--n] = ModuleDescriptor.Modifier.MANDATED;
 261             return Set.of(mods);
 262         }
 263     }
 264 
 265     /**
 266      * Builds a {@code ModuleDescriptor} from the components.
 267      */
 268     public ModuleDescriptor build(int hashCode) {
 269         assert name != null;
 270         return JLMA.newModuleDescriptor(name,
 271                                         version,
 272                                         modifiers(),
 273                                         requires,
 274                                         exports,
 275                                         opens,
 276                                         uses,
 277                                         provides,
 278                                         packages,
 279                                         mainClass,
 280                                         hashCode);
 281     }
 282 }