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.HashSet;
  35 import java.util.List;
  36 import java.util.Set;
  37 
  38 import jdk.internal.misc.JavaLangModuleAccess;
  39 import jdk.internal.misc.SharedSecrets;
  40 
  41 /**
  42  * This builder is optimized for reconstituting ModuleDescriptor
  43  * for system modules.  The validation should be done at jlink time.
  44  *
  45  * 1. skip name validation
  46  * 2. ignores dependency hashes.
  47  * 3. ModuleDescriptor skips the defensive copy and directly uses the
  48  *    sets/maps created in this Builder.
  49  *
  50  * SystemModules should contain modules for the boot layer.
  51  */
  52 final class Builder {
  53     private static final JavaLangModuleAccess JLMA =
  54         SharedSecrets.getJavaLangModuleAccess();
  55 
  56     // Static cache of the most recently seen Version to cheaply deduplicate
  57     // most Version objects.  JDK modules have the same version.
  58     static Version cachedVersion;
  59 
  60     /**
  61      * Returns a {@link Requires} for a dependence on a module with the given
  62      * (and possibly empty) set of modifiers, and optionally the version
  63      * recorded at compile time.
  64      */
  65     public static Requires newRequires(Set<Requires.Modifier> mods,
  66                                        String mn,
  67                                        String compiledVersion)
  68     {
  69         Version version = null;
  70         if (compiledVersion != null) {
  71             // use the cached version if the same version string
  72             Version ver = cachedVersion;
  73             if (ver != null && compiledVersion.equals(ver.toString())) {
  74                 version = ver;
  75             } else {
  76                 version = Version.parse(compiledVersion);
  77             }
  78         }
  79         return JLMA.newRequires(mods, mn, version);
  80     }
  81 
  82     /**
  83      * Returns a {@link Requires} for a dependence on a module with the given
  84      * (and possibly empty) set of modifiers, and optionally the version
  85      * recorded at compile time.
  86      */
  87     public static Requires newRequires(Set<Requires.Modifier> mods,
  88                                        String mn)
  89     {
  90         return newRequires(mods, mn, null);
  91     }
  92 
  93     /**
  94      * Returns a {@link Exports} for a qualified export, with
  95      * the given (and possibly empty) set of modifiers,
  96      * to a set of target modules.
  97      */
  98     public static Exports newExports(Set<Exports.Modifier> ms,
  99                                      String pn,
 100                                      Set<String> targets) {
 101         return JLMA.newExports(ms, pn, targets);
 102     }
 103 
 104     /**
 105      * Returns an {@link Opens} for an unqualified open with a given set of
 106      * modifiers.
 107      */
 108     public static Opens newOpens(Set<Opens.Modifier> ms, String pn) {
 109         return JLMA.newOpens(ms, pn);
 110     }
 111 
 112     /**
 113      * Returns an {@link Opens} for a qualified opens, with
 114      * the given (and possibly empty) set of modifiers,
 115      * to a set of target modules.
 116      */
 117     public static Opens newOpens(Set<Opens.Modifier> ms,
 118                                  String pn,
 119                                  Set<String> targets) {
 120         return JLMA.newOpens(ms, pn, targets);
 121     }
 122 
 123     /**
 124      * Returns a {@link Exports} for an unqualified export with a given set
 125      * of modifiers.
 126      */
 127     public static Exports newExports(Set<Exports.Modifier> ms, String pn) {
 128         return JLMA.newExports(ms, pn);
 129     }
 130 
 131     /**
 132      * Returns a {@link Provides} for a service with a given list of
 133      * implementation classes.
 134      */
 135     public static Provides newProvides(String st, List<String> pcs) {
 136         return JLMA.newProvides(st, pcs);
 137     }
 138 
 139     final String name;
 140     boolean open;
 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 synthetic(boolean value) {
 169         this.synthetic = 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      * Sets the OS name.
 249      */
 250     public Builder osName(String name) {
 251         this.osName = name;
 252         return this;
 253     }
 254 
 255     /**
 256      * Sets the OS arch.
 257      */
 258     public Builder osArch(String arch) {
 259         this.osArch = arch;
 260         return this;
 261     }
 262 
 263     /**
 264      * Sets the OS version.
 265      *
 266      * @throws IllegalStateException if already set
 267      */
 268     public Builder osVersion(String version) {
 269         this.osVersion = version;
 270         return this;
 271     }
 272 
 273     /**
 274      * Builds a {@code ModuleDescriptor} from the components.
 275      */
 276     public ModuleDescriptor build(int hashCode) {
 277         assert name != null;
 278 
 279         Set<ModuleDescriptor.Modifier> modifiers;
 280         if (open || synthetic) {
 281             modifiers = new HashSet<>();
 282             if (open) modifiers.add(ModuleDescriptor.Modifier.OPEN);
 283             if (synthetic) modifiers.add(ModuleDescriptor.Modifier.SYNTHETIC);
 284             modifiers = Collections.unmodifiableSet(modifiers);
 285         } else {
 286             modifiers = Collections.emptySet();
 287         }
 288 
 289         return JLMA.newModuleDescriptor(name,
 290                                         version,
 291                                         modifiers,
 292                                         requires,
 293                                         exports,
 294                                         opens,
 295                                         uses,
 296                                         provides,
 297                                         packages,
 298                                         mainClass,
 299                                         osName,
 300                                         osArch,
 301                                         osVersion,
 302                                         hashCode);
 303     }
 304 }