25 |
25 |
26 import java.io.File; |
26 import java.io.File; |
27 import java.io.IOException; |
27 import java.io.IOException; |
28 import java.nio.file.Files; |
28 import java.nio.file.Files; |
29 import java.nio.file.Path; |
29 import java.nio.file.Path; |
|
30 import java.nio.file.Paths; |
30 import java.util.ArrayList; |
31 import java.util.ArrayList; |
31 import java.util.Arrays; |
32 import java.util.Arrays; |
|
33 import java.util.LinkedHashSet; |
32 import java.util.List; |
34 import java.util.List; |
|
35 import java.util.Set; |
33 import java.util.stream.Collectors; |
36 import java.util.stream.Collectors; |
34 |
37 |
|
38 /** |
|
39 * Builder for module declarations. |
|
40 */ |
35 public class ModuleBuilder { |
41 public class ModuleBuilder { |
36 |
42 |
37 private final ToolBox tb; |
43 private final ToolBox tb; |
38 private final String name; |
44 private final String name; |
39 private String requires = ""; |
45 private String comment = ""; |
40 private String exports = ""; |
46 private List<String> requires = new ArrayList<>(); |
41 private String uses = ""; |
47 private List<String> exports = new ArrayList<>(); |
42 private String provides = ""; |
48 private List<String> uses = new ArrayList<>(); |
43 private String modulePath = ""; |
49 private List<String> provides = new ArrayList<>(); |
44 private List<String> content = new ArrayList<>(); |
50 private List<String> content = new ArrayList<>(); |
45 |
51 private Set<Path> modulePath = new LinkedHashSet<>(); |
|
52 |
|
53 /** |
|
54 * Creates a builder for a module. |
|
55 * @param tb a Toolbox that can be used to compile the module declaration. |
|
56 * @param name the name of the module to be built |
|
57 */ |
46 public ModuleBuilder(ToolBox tb, String name) { |
58 public ModuleBuilder(ToolBox tb, String name) { |
47 this.tb = tb; |
59 this.tb = tb; |
48 this.name = name; |
60 this.name = name; |
49 } |
61 } |
50 |
62 |
|
63 /** |
|
64 * Sets the doc comment for the declaration. |
|
65 * @param comment the content of the comment, excluding the initial |
|
66 * '/**', leading whitespace and asterisks, and the final trailing 'a;/'. |
|
67 * @return this builder |
|
68 */ |
|
69 public ModuleBuilder comment(String comment) { |
|
70 this.comment = comment; |
|
71 return this; |
|
72 } |
|
73 |
|
74 /** |
|
75 * Adds a "requires public" directive to the declaration. |
|
76 * @param requires the name of the module that is required |
|
77 * @param modulePath a path in which to locate the modules |
|
78 * if the declaration is compiled |
|
79 * @return this builder |
|
80 */ |
51 public ModuleBuilder requiresPublic(String requires, Path... modulePath) { |
81 public ModuleBuilder requiresPublic(String requires, Path... modulePath) { |
52 return requires("public " + requires, modulePath); |
82 this.requires.add("requires public " + requires + ";"); |
53 } |
83 this.modulePath.addAll(Arrays.asList(modulePath)); |
54 |
84 return this; |
|
85 } |
|
86 |
|
87 /** |
|
88 * Adds a "requires" directive to the declaration. |
|
89 * @param requires the name of the module that is required |
|
90 * @param modulePath a path in while to locate the modules |
|
91 * if the declaration is compiled |
|
92 * @return this builder |
|
93 */ |
55 public ModuleBuilder requires(String requires, Path... modulePath) { |
94 public ModuleBuilder requires(String requires, Path... modulePath) { |
56 this.requires += " requires " + requires + ";\n"; |
95 this.requires.add("requires " + requires + ";"); |
57 this.modulePath += Arrays.stream(modulePath) |
96 this.modulePath.addAll(Arrays.asList(modulePath)); |
|
97 return this; |
|
98 } |
|
99 |
|
100 /** |
|
101 * Adds a qualified "exports" directive to the declaration. |
|
102 * @param pkg the name of the package to be exported |
|
103 * @param module the name of the module to which it is to be exported |
|
104 * @return this builder |
|
105 */ |
|
106 public ModuleBuilder exportsTo(String pkg, String module) { |
|
107 this.exports.add("exports " + pkg + " to " + module + ";"); |
|
108 return this; |
|
109 } |
|
110 |
|
111 /** |
|
112 * Adds an unqualified "exports" directive to the declaration. |
|
113 * @param pkg the name of the package to be exported |
|
114 * @param module the name of the module to which it is to be exported |
|
115 * @return this builder |
|
116 */ |
|
117 public ModuleBuilder exports(String pkg) { |
|
118 this.exports.add("exports " + pkg + ";"); |
|
119 return this; |
|
120 } |
|
121 |
|
122 /** |
|
123 * Adds a "uses" directive to the declaration. |
|
124 * @param service the name of the service type |
|
125 * @return this builder |
|
126 */ |
|
127 public ModuleBuilder uses(String service) { |
|
128 this.uses.add("uses " + service + ";"); |
|
129 return this; |
|
130 } |
|
131 |
|
132 /** |
|
133 * Adds a "provides" directive to the declaration. |
|
134 * @param service the name of the service type |
|
135 * @param implementation the name of the implementation type |
|
136 * @return this builder |
|
137 */ |
|
138 public ModuleBuilder provides(String service, String implementation) { |
|
139 this.provides.add("provides " + service + " with " + implementation + ";"); |
|
140 return this; |
|
141 } |
|
142 |
|
143 /** |
|
144 * Adds type definitions to the module. |
|
145 * @param content a series of strings, each representing the content of |
|
146 * a compilation unit to be included with the module |
|
147 * @return this builder |
|
148 */ |
|
149 public ModuleBuilder classes(String... content) { |
|
150 this.content.addAll(Arrays.asList(content)); |
|
151 return this; |
|
152 } |
|
153 |
|
154 /** |
|
155 * Writes the module declaration and associated additional compilation |
|
156 * units to a module directory within a given directory. |
|
157 * @param srcDir the directory in which a directory will be created |
|
158 * to contain the source files for the module |
|
159 * @return the directory containing the source files for the module |
|
160 */ |
|
161 public Path write(Path srcDir) throws IOException { |
|
162 Files.createDirectories(srcDir); |
|
163 List<String> sources = new ArrayList<>(); |
|
164 StringBuilder sb = new StringBuilder(); |
|
165 if (!comment.isEmpty()) { |
|
166 sb.append("/**\n").append(comment.replace("\n", " *")).append(" */\n"); |
|
167 } |
|
168 sb.append("module ").append(name).append(" {"); |
|
169 requires.forEach(r -> sb.append(" " + r + "\n")); |
|
170 exports.forEach(e -> sb.append(" " + e + "\n")); |
|
171 uses.forEach(u -> sb.append(" " + u + "\n")); |
|
172 provides.forEach(p -> sb.append(" " + p + "\n")); |
|
173 sb.append("}"); |
|
174 sources.add(sb.toString()); |
|
175 sources.addAll(content); |
|
176 Path moduleSrc = srcDir.resolve(name); |
|
177 tb.writeJavaFiles(moduleSrc, sources.toArray(new String[]{})); |
|
178 return moduleSrc; |
|
179 } |
|
180 |
|
181 /** |
|
182 * Writes the source files for the module to an interim directory, |
|
183 * and then compiles them to a given directory. |
|
184 * @param modules the directory in which a directory will be created |
|
185 * to contain the compiled class files for the module |
|
186 * @throws IOException if an error occurs while compiling the files |
|
187 */ |
|
188 public void build(Path modules) throws IOException { |
|
189 build(Paths.get(modules + "Src"), modules); |
|
190 } |
|
191 |
|
192 /** |
|
193 * Writes the source files for the module to a specified directory, |
|
194 * and then compiles them to a given directory. |
|
195 * @param srcDir the directory in which a directory will be created |
|
196 * to contain the source files for the module |
|
197 * @param modules the directory in which a directory will be created |
|
198 * to contain the compiled class files for the module |
|
199 * @throws IOException if an error occurs while compiling the files |
|
200 */ |
|
201 public void build(Path src, Path modules) throws IOException { |
|
202 Path moduleSrc = write(src); |
|
203 String mp = modulePath.stream() |
58 .map(Path::toString) |
204 .map(Path::toString) |
59 .collect(Collectors.joining(File.pathSeparator)); |
205 .collect(Collectors.joining(File.pathSeparator)); |
60 return this; |
|
61 } |
|
62 |
|
63 public ModuleBuilder exportsTo(String pkg, String module) { |
|
64 return exports(pkg + " to " + module); |
|
65 } |
|
66 |
|
67 public ModuleBuilder exports(String pkg) { |
|
68 this.exports += " exports " + pkg + ";\n"; |
|
69 return this; |
|
70 } |
|
71 |
|
72 public ModuleBuilder uses(String uses) { |
|
73 this.uses += " uses " + uses + ";\n"; |
|
74 return this; |
|
75 } |
|
76 |
|
77 public ModuleBuilder provides(String service, String implementation) { |
|
78 this.provides += " provides " + service + " with " + implementation + ";\n"; |
|
79 return this; |
|
80 } |
|
81 |
|
82 public ModuleBuilder classes(String... content) { |
|
83 this.content.addAll(Arrays.asList(content)); |
|
84 return this; |
|
85 } |
|
86 |
|
87 public Path write(Path where) throws IOException { |
|
88 Files.createDirectories(where); |
|
89 List<String> sources = new ArrayList<>(); |
|
90 sources.add("module " + name + "{" |
|
91 + requires |
|
92 + exports |
|
93 + uses |
|
94 + provides |
|
95 + "}"); |
|
96 sources.addAll(content); |
|
97 Path moduleSrc = where.resolve(name + "/src"); |
|
98 tb.writeJavaFiles(moduleSrc, sources.toArray(new String[]{})); |
|
99 return moduleSrc; |
|
100 } |
|
101 |
|
102 public void build(Path where) throws IOException { |
|
103 Path moduleSrc = write(where); |
|
104 new JavacTask(tb) |
206 new JavacTask(tb) |
105 .outdir(where.resolve(name)) |
207 .outdir(Files.createDirectories(modules.resolve(name))) |
106 .options("-mp", modulePath) |
208 .options("-mp", mp) |
107 .files(tb.findJavaFiles(moduleSrc)) |
209 .files(tb.findJavaFiles(moduleSrc)) |
108 .run() |
210 .run() |
109 .writeAll(); |
211 .writeAll(); |
110 } |
212 } |
111 } |
213 } |