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