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 */
25package jdk.internal.module;
26
27import java.lang.module.ModuleDescriptor;
28import java.lang.module.ModuleDescriptor.Exports;
29import java.lang.module.ModuleDescriptor.Opens;
30import java.lang.module.ModuleDescriptor.Provides;
31import java.lang.module.ModuleDescriptor.Requires;
32import java.lang.module.ModuleDescriptor.Version;
33import java.util.Collections;
34import java.util.List;
35import java.util.Set;
36
37import jdk.internal.misc.JavaLangModuleAccess;
38import jdk.internal.misc.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 */
51final 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}
284