jdk
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.
8*
9* This code is distributed in the hope that it will be useful, but WITHOUT
10* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12* version 2 for more details (a copy is included in the LICENSE file that
13* accompanied this code).
14*
15* You should have received a copy of the GNU General Public License version
16* 2 along with this work; if not, write to the Free Software Foundation,
17* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18*
19* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20* or visit www.oracle.com if you need additional information or have any
21* questions.
22*/
23
24package toolbox;25
26import java.io.IOException;27import java.nio.file.Files;28import java.nio.file.Path;29import java.nio.file.Paths;30import java.util.ArrayList;31import java.util.Arrays;32import java.util.LinkedHashSet;33import java.util.List;34import java.util.Set;35import java.util.stream.Collectors;36
37/**
38* Builder for module declarations.
39*/
40public class ModuleBuilder {41
42private final ToolBox tb;43private final String name;44private String comment = "";45private boolean open;46private List<String> requires = new ArrayList<>();47private List<String> exports = new ArrayList<>();48private List<String> opens = new ArrayList<>();49private List<String> uses = new ArrayList<>();50private List<String> provides = new ArrayList<>();51private List<String> content = new ArrayList<>();52private Set<Path> modulePath = new LinkedHashSet<>();53
54/**55* Creates a builder for a module.
56* @param tb a Toolbox that can be used to compile the module declaration
57* @param name the name of the module to be built
58*/
59public ModuleBuilder(ToolBox tb, String name) {60this(tb, false, name);61}62
63/**64* Creates a builder for a module.
65* @param tb a Toolbox that can be used to compile the module declaration
66* @param open whether or not this is an open module
67* @param name the name of the module to be built
68*/
69public ModuleBuilder(ToolBox tb, boolean open, String name) {70this.tb = tb;71this.open = open;72this.name = name;73}74
75/**76* Sets the doc comment for the declaration.
77* @param comment the content of the comment, excluding the initial
78* '/**', leading whitespace and asterisks, and the final trailing 'a;/'.
79* @return this builder
80*/
81public ModuleBuilder comment(String comment) {82this.comment = comment;83return this;84}85
86/**87* Adds a "requires" directive to the declaration.
88* @param module the name of the module that is required
89* @param modulePath a path in while to locate the modules
90* if the declaration is compiled
91* @return this builder
92*/
93public ModuleBuilder requires(String module, Path... modulePath) {94addDirective(requires, "requires " + module + ";");95this.modulePath.addAll(Arrays.asList(modulePath));96return this;97
98}99
100/**101* Adds a "requires static" directive to the declaration.
102* @param module the name of the module that is required
103* @param modulePath a path in which to locate the modules
104* if the declaration is compiled
105* @return this builder
106*/
107public ModuleBuilder requiresStatic(String module, Path... modulePath) {108addDirective(requires, "requires static " + module + ";");109this.modulePath.addAll(Arrays.asList(modulePath));110return this;111}112
113/**114* Adds a "requires transitive" directive to the declaration.
115* @param module the name of the module that is required
116* @param modulePath a path in which to locate the modules
117* if the declaration is compiled
118* @return this builder
119*/
120public ModuleBuilder requiresTransitive(String module, Path... modulePath) {121addDirective(requires, "requires transitive " + module + ";");122this.modulePath.addAll(Arrays.asList(modulePath));123return this;124}125
126/**127* Adds a "requires static transitive" directive to the declaration.
128* @param module the name of the module that is required
129* @param modulePath a path in which to locate the modules
130* if the declaration is compiled
131* @return this builder
132*/
133public ModuleBuilder requiresStaticTransitive(String module, Path... modulePath) {134addDirective(requires, "requires static transitive " + module + ";");135this.modulePath.addAll(Arrays.asList(modulePath));136return this;137}138
139/**140* Adds an unqualified "exports" directive to the declaration.
141* @param pkg the name of the package to be exported
142* @return this builder
143*/
144public ModuleBuilder exports(String pkg) {145return addDirective(exports, "exports " + pkg + ";");146}147
148/**149* Adds a qualified "exports" directive to the declaration.
150* @param pkg the name of the package to be exported
151* @param module the name of the module to which it is to be exported
152* @return this builder
153*/
154public ModuleBuilder exportsTo(String pkg, String module) {155return addDirective(exports, "exports " + pkg + " to " + module + ";");156}157
158/**159* Adds an unqualified "opens" directive to the declaration.
160* @param pkg the name of the package to be opened
161* @return this builder
162*/
163public ModuleBuilder opens(String pkg) {164return addDirective(opens, "opens " + pkg + ";");165}166
167/**168* Adds a qualified "opens" directive to the declaration.
169* @param pkg the name of the package to be opened
170* @param module the name of the module to which it is to be opened
171* @return this builder
172*/
173public ModuleBuilder opensTo(String pkg, String module) {174return addDirective(opens, "opens " + pkg + " to " + module + ";");175}176
177/**178* Adds a "uses" directive to the declaration.
179* @param service the name of the service type
180* @return this builder
181*/
182public ModuleBuilder uses(String service) {183return addDirective(uses, "uses " + service + ";");184}185
186/**187* Adds a "provides" directive to the declaration.
188* @param service the name of the service type
189* @param implementation the name of the implementation type
190* @return this builder
191*/
192public ModuleBuilder provides(String service, String implementation) {193return addDirective(provides, "provides " + service + " with " + implementation + ";");194}195
196private ModuleBuilder addDirective(List<String> directives, String directive) {197directives.add(directive);198return this;199}200
201/**202* Adds type definitions to the module.
203* @param content a series of strings, each representing the content of
204* a compilation unit to be included with the module
205* @return this builder
206*/
207public ModuleBuilder classes(String... content) {208this.content.addAll(Arrays.asList(content));209return this;210}211
212/**213* Writes the module declaration and associated additional compilation
214* units to a module directory within a given directory.
215* @param srcDir the directory in which a directory will be created
216* to contain the source files for the module
217* @return the directory containing the source files for the module
218*/
219public Path write(Path srcDir) throws IOException {220Files.createDirectories(srcDir);221List<String> sources = new ArrayList<>();222StringBuilder sb = new StringBuilder();223if (!comment.isEmpty()) {224sb.append("/**\n * ")225.append(comment.replace("\n", "\n * "))226.append("\n */\n");227}228if (open) {229sb.append("open ");230}231sb.append("module ").append(name).append(" {\n");232requires.forEach(r -> sb.append(" " + r + "\n"));233exports.forEach(e -> sb.append(" " + e + "\n"));234opens.forEach(o -> sb.append(" " + o + "\n"));235uses.forEach(u -> sb.append(" " + u + "\n"));236provides.forEach(p -> sb.append(" " + p + "\n"));237sb.append("}");238sources.add(sb.toString());239sources.addAll(content);240Path moduleSrc = srcDir.resolve(name);241tb.writeJavaFiles(moduleSrc, sources.toArray(new String[]{}));242return moduleSrc;243}244
245/**246* Writes the source files for the module to an interim directory,
247* and then compiles them to a given directory.
248* @param modules the directory in which a directory will be created
249* to contain the compiled class files for the module
250* @throws IOException if an error occurs while compiling the files
251*/
252public void build(Path modules) throws IOException {253build(Paths.get(modules + "Src"), modules);254}255
256/**257* Writes the source files for the module to a specified directory,
258* and then compiles them to a given directory.
259* @param src the directory in which a directory will be created
260* to contain the source files for the module
261* @param modules the directory in which a directory will be created
262* to contain the compiled class files for the module
263* @throws IOException if an error occurs while compiling the files
264*/
265public void build(Path src, Path modules) throws IOException {266Path moduleSrc = write(src);267String mp = modulePath.stream()268.map(Path::toString)269.collect(Collectors.joining(ToolBox.pathSeparator));270new JavacTask(tb)271.outdir(Files.createDirectories(modules.resolve(name)))272.options("--module-path", mp)273.files(tb.findJavaFiles(moduleSrc))274.run()275.writeAll();276}277}
278