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.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      */
newRequires(Set<Requires.Modifier> mods, String mn, String compiledVersion)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      */
newRequires(Set<Requires.Modifier> mods, String mn)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      */
newExports(Set<Exports.Modifier> ms, String pn, Set<String> targets)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      */
newOpens(Set<Opens.Modifier> ms, String pn)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      */
newOpens(Set<Opens.Modifier> ms, String pn, Set<String> targets)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      */
newExports(Set<Exports.Modifier> ms, String pn)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      */
newProvides(String st, List<String> pcs)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 
Builder(String name)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 
open(boolean value)157     Builder open(boolean value) {
158         this.open = value;
159         return this;
160     }
161 
synthetic(boolean value)162     Builder synthetic(boolean value) {
163         this.synthetic = value;
164         return this;
165     }
166 
mandated(boolean value)167     Builder mandated(boolean value) {
168         this.mandated = value;
169         return this;
170     }
171 
172     /**
173      * Sets module exports.
174      */
exports(Exports[] exports)175     public Builder exports(Exports[] exports) {
176         this.exports = Set.of(exports);
177         return this;
178     }
179 
180     /**
181      * Sets module opens.
182      */
opens(Opens[] opens)183     public Builder opens(Opens[] opens) {
184         this.opens = Set.of(opens);
185         return this;
186     }
187 
188     /**
189      * Sets module requires.
190      */
requires(Requires[] requires)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      */
packages(Set<String> packages)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      */
uses(Set<String> uses)207     public Builder uses(Set<String> uses) {
208         this.uses = uses;
209         return this;
210     }
211 
212     /**
213      * Sets module provides.
214      */
provides(Provides[] provides)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      */
version(String v)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      */
mainClass(String mc)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      */
modifiers()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      */
build(int hashCode)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 }
283