1 /*
   2  * Copyright (c) 2015, 2016, 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.misc.JavaLangModuleAccess;
  38 import jdk.internal.misc.SharedSecrets;
  39 
  40 /**
  41  * This builder is optimized for reconstituting ModuleDescriptor
  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;
 140     boolean automatic;
 141     boolean synthetic;
 142     Set<Requires> requires;
 143     Set<Exports> exports;
 144     Set<Opens> opens;
 145     Set<String> packages;
 146     Set<String> uses;
 147     Set<Provides> provides;
 148     Version version;
 149     String mainClass;
 150     String osName;
 151     String osArch;
 152     String osVersion;
 153 
 154     Builder(String name) {
 155         this.name = name;
 156         this.requires = Collections.emptySet();
 157         this.exports = Collections.emptySet();
 158         this.opens = Collections.emptySet();
 159         this.provides = Collections.emptySet();
 160         this.uses = Collections.emptySet();
 161     }
 162 
 163     Builder open(boolean value) {
 164         this.open = value;
 165         return this;
 166     }
 167 
 168     Builder automatic(boolean value) {
 169         this.automatic = value;
 170         return this;
 171     }
 172 
 173     Builder synthetic(boolean value) {
 174         this.synthetic = value;
 175         return this;
 176     }
 177 
 178     /**
 179      * Sets module exports.
 180      */
 181     public Builder exports(Exports[] exports) {
 182         this.exports = Set.of(exports);
 183         return this;
 184     }
 185 
 186     /**
 187      * Sets module opens.
 188      */
 189     public Builder opens(Opens[] opens) {
 190         this.opens = Set.of(opens);
 191         return this;
 192     }
 193 
 194     /**
 195      * Sets module requires.
 196      */
 197     public Builder requires(Requires[] requires) {
 198         this.requires = Set.of(requires);
 199         return this;
 200     }
 201 
 202     /**
 203      * Adds a set of (possible empty) packages.
 204      */
 205     public Builder packages(Set<String> packages) {
 206         this.packages = packages;
 207         return this;
 208     }
 209 
 210     /**
 211      * Sets the set of service dependences.
 212      */
 213     public Builder uses(Set<String> uses) {
 214         this.uses = uses;
 215         return this;
 216     }
 217 
 218     /**
 219      * Sets module provides.
 220      */
 221     public Builder provides(Provides[] provides) {
 222         this.provides = Set.of(provides);
 223         return this;
 224     }
 225 
 226     /**
 227      * Sets the module version.
 228      *
 229      * @throws IllegalArgumentException if {@code v} is null or cannot be
 230      *         parsed as a version string
 231      * @throws IllegalStateException if the module version is already set
 232      *
 233      * @see Version#parse(String)
 234      */
 235     public Builder version(String v) {
 236         if (version != null)
 237             throw new IllegalStateException("module version already set");
 238         Version ver = cachedVersion;
 239         if (ver != null && v.equals(ver.toString())) {
 240             version = ver;
 241         } else {
 242             cachedVersion = version = Version.parse(v);
 243         }
 244         return this;
 245     }
 246 
 247     /**
 248      * Sets the module main class.
 249      *
 250      * @throws IllegalStateException if already set
 251      */
 252     public Builder mainClass(String mc) {
 253         if (mainClass != null)
 254             throw new IllegalStateException("main class already set");
 255         mainClass = mc;
 256         return this;
 257     }
 258 
 259     /**
 260      * Sets the OS name.
 261      *
 262      * @throws IllegalStateException if already set
 263      */
 264     public Builder osName(String name) {
 265         if (osName != null)
 266             throw new IllegalStateException("OS name already set");
 267         this.osName = name;
 268         return this;
 269     }
 270 
 271     /**
 272      * Sets the OS arch.
 273      *
 274      * @throws IllegalStateException if already set
 275      */
 276     public Builder osArch(String arch) {
 277         if (osArch != null)
 278             throw new IllegalStateException("OS arch already set");
 279         this.osArch = arch;
 280         return this;
 281     }
 282 
 283     /**
 284      * Sets the OS version.
 285      *
 286      * @throws IllegalStateException if already set
 287      */
 288     public Builder osVersion(String version) {
 289         if (osVersion != null)
 290             throw new IllegalStateException("OS version already set");
 291         this.osVersion = version;
 292         return this;
 293     }
 294 
 295     /**
 296      * Builds a {@code ModuleDescriptor} from the components.
 297      */
 298     public ModuleDescriptor build(int hashCode) {
 299         assert name != null;
 300 
 301         return JLMA.newModuleDescriptor(name,
 302                                         version,
 303                                         open,
 304                                         automatic,
 305                                         synthetic,
 306                                         requires,
 307                                         exports,
 308                                         opens,
 309                                         uses,
 310                                         provides,
 311                                         packages,
 312                                         mainClass,
 313                                         osName,
 314                                         osArch,
 315                                         osVersion,
 316                                         hashCode);
 317     }
 318 }