ModuleBuilder.java revision 3792:d516975e8110
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. 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.File; 27import java.io.IOException; 28import java.nio.file.Files; 29import java.nio.file.Path; 30import java.nio.file.Paths; 31import java.util.ArrayList; 32import java.util.Arrays; 33import java.util.LinkedHashSet; 34import java.util.List; 35import java.util.Set; 36import java.util.stream.Collectors; 37 38/** 39 * Builder for module declarations. 40 */ 41public class ModuleBuilder { 42 43 private final ToolBox tb; 44 private final String name; 45 private String comment = ""; 46 private List<String> requires = new ArrayList<>(); 47 private List<String> exports = new ArrayList<>(); 48 private List<String> uses = new ArrayList<>(); 49 private List<String> provides = new ArrayList<>(); 50 private List<String> content = new ArrayList<>(); 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 */ 58 public ModuleBuilder(ToolBox tb, String name) { 59 this.tb = tb; 60 this.name = name; 61 } 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" directive to the declaration. 76 * @param module the name of the module that is required 77 * @param modulePath a path in while to locate the modules 78 * if the declaration is compiled 79 * @return this builder 80 */ 81 public ModuleBuilder requires(String module, Path... modulePath) { 82 addDirective(requires, "requires " + module + ";"); 83 this.modulePath.addAll(Arrays.asList(modulePath)); 84 return this; 85 86 } 87 88 /** 89 * Adds a "requires static" directive to the declaration. 90 * @param module the name of the module that is required 91 * @param modulePath a path in which to locate the modules 92 * if the declaration is compiled 93 * @return this builder 94 */ 95 public ModuleBuilder requiresStatic(String module, Path... modulePath) { 96 addDirective(requires, "requires static " + module + ";"); 97 this.modulePath.addAll(Arrays.asList(modulePath)); 98 return this; 99 } 100 101 /** 102 * Adds a "requires transitive" directive to the declaration. 103 * @param module the name of the module that is required 104 * @param modulePath a path in which to locate the modules 105 * if the declaration is compiled 106 * @return this builder 107 */ 108 public ModuleBuilder requiresTransitive(String module, Path... modulePath) { 109 addDirective(requires, "requires transitive " + module + ";"); 110 this.modulePath.addAll(Arrays.asList(modulePath)); 111 return this; 112 } 113 114 /** 115 * Adds a "requires static transitive" directive to the declaration. 116 * @param module the name of the module that is required 117 * @param modulePath a path in which to locate the modules 118 * if the declaration is compiled 119 * @return this builder 120 */ 121 public ModuleBuilder requiresStaticTransitive(String module, Path... modulePath) { 122 addDirective(requires, "requires static transitive " + module + ";"); 123 this.modulePath.addAll(Arrays.asList(modulePath)); 124 return this; 125 } 126 127 /** 128 * Adds an unqualified "exports" directive to the declaration. 129 * @param pkg the name of the package to be exported 130 * @return this builder 131 */ 132 public ModuleBuilder exports(String pkg) { 133 return addDirective(exports, "exports " + pkg + ";"); 134 } 135 136 /** 137 * Adds an unqualified "exports dynamic" directive to the declaration. 138 * @param pkg the name of the package to be exported 139 * @return this builder 140 */ 141 public ModuleBuilder exportsDynamic(String pkg) { 142 return addDirective(exports, "exports dynamic " + pkg + ";"); 143 } 144 145 /** 146 * Adds an unqualified "exports private" directive to the declaration. 147 * @param pkg the name of the package to be exported 148 * @return this builder 149 */ 150 public ModuleBuilder exportsPrivate(String pkg) { 151 return addDirective(exports, "exports private " + pkg + ";"); 152 } 153 154 /** 155 * Adds an unqualified "exports dynamic private" directive to the declaration. 156 * @param pkg the name of the package to be exported 157 * @return this builder 158 */ 159 public ModuleBuilder exportsDynamicPrivate(String pkg) { 160 return addDirective(exports, "exports dynamic private " + pkg + ";"); 161 } 162 163 /** 164 * Adds a qualified "exports" directive to the declaration. 165 * @param pkg the name of the package to be exported 166 * @param module the name of the module to which it is to be exported 167 * @return this builder 168 */ 169 public ModuleBuilder exportsTo(String pkg, String module) { 170 return addDirective(exports, "exports " + pkg + " to " + module + ";"); 171 } 172 173 /** 174 * Adds a qualified "exports dynamic" directive to the declaration. 175 * @param pkg the name of the package to be exported 176 * @param module the name of the module to which it is to be exported 177 * @return this builder 178 */ 179 public ModuleBuilder exportsDynamicTo(String pkg, String module) { 180 return addDirective(exports, "exports dynamic " + pkg + " to " + module + ";"); 181 } 182 183 /** 184 * Adds a qualified "exports private" directive to the declaration. 185 * @param pkg the name of the package to be exported 186 * @param module the name of the module to which it is to be exported 187 * @return this builder 188 */ 189 public ModuleBuilder exportsPrivateTo(String pkg, String module) { 190 return addDirective(exports, "exports private " + pkg + " to " + module + ";"); 191 } 192 193 /** 194 * Adds a qualified "exports dynamic private" directive to the declaration. 195 * @param pkg the name of the package to be exported 196 * @param module the name of the module to which it is to be exported 197 * @return this builder 198 */ 199 public ModuleBuilder exportsDynamicPrivateTo(String pkg, String module) { 200 return addDirective(exports, "exports dynamic private " + pkg + " to " + module + ";"); 201 } 202 203 /** 204 * Adds a "uses" directive to the declaration. 205 * @param service the name of the service type 206 * @return this builder 207 */ 208 public ModuleBuilder uses(String service) { 209 return addDirective(uses, "uses " + service + ";"); 210 } 211 212 /** 213 * Adds a "provides" directive to the declaration. 214 * @param service the name of the service type 215 * @param implementation the name of the implementation type 216 * @return this builder 217 */ 218 public ModuleBuilder provides(String service, String implementation) { 219 return addDirective(provides, "provides " + service + " with " + implementation + ";"); 220 } 221 222 private ModuleBuilder addDirective(List<String> directives, String directive) { 223 directives.add(directive); 224 return this; 225 } 226 227 /** 228 * Adds type definitions to the module. 229 * @param content a series of strings, each representing the content of 230 * a compilation unit to be included with the module 231 * @return this builder 232 */ 233 public ModuleBuilder classes(String... content) { 234 this.content.addAll(Arrays.asList(content)); 235 return this; 236 } 237 238 /** 239 * Writes the module declaration and associated additional compilation 240 * units to a module directory within a given directory. 241 * @param srcDir the directory in which a directory will be created 242 * to contain the source files for the module 243 * @return the directory containing the source files for the module 244 */ 245 public Path write(Path srcDir) throws IOException { 246 Files.createDirectories(srcDir); 247 List<String> sources = new ArrayList<>(); 248 StringBuilder sb = new StringBuilder(); 249 if (!comment.isEmpty()) { 250 sb.append("/**\n").append(comment.replace("\n", " *")).append(" */\n"); 251 } 252 sb.append("module ").append(name).append(" {\n"); 253 requires.forEach(r -> sb.append(" " + r + "\n")); 254 exports.forEach(e -> sb.append(" " + e + "\n")); 255 uses.forEach(u -> sb.append(" " + u + "\n")); 256 provides.forEach(p -> sb.append(" " + p + "\n")); 257 sb.append("}"); 258 sources.add(sb.toString()); 259 sources.addAll(content); 260 Path moduleSrc = srcDir.resolve(name); 261 tb.writeJavaFiles(moduleSrc, sources.toArray(new String[]{})); 262 return moduleSrc; 263 } 264 265 /** 266 * Writes the source files for the module to an interim directory, 267 * and then compiles them to a given directory. 268 * @param modules the directory in which a directory will be created 269 * to contain the compiled class files for the module 270 * @throws IOException if an error occurs while compiling the files 271 */ 272 public void build(Path modules) throws IOException { 273 build(Paths.get(modules + "Src"), modules); 274 } 275 276 /** 277 * Writes the source files for the module to a specified directory, 278 * and then compiles them to a given directory. 279 * @param srcDir the directory in which a directory will be created 280 * to contain the source files for the module 281 * @param modules the directory in which a directory will be created 282 * to contain the compiled class files for the module 283 * @throws IOException if an error occurs while compiling the files 284 */ 285 public void build(Path src, Path modules) throws IOException { 286 Path moduleSrc = write(src); 287 String mp = modulePath.stream() 288 .map(Path::toString) 289 .collect(Collectors.joining(File.pathSeparator)); 290 new JavacTask(tb) 291 .outdir(Files.createDirectories(modules.resolve(name))) 292 .options("--module-path", mp) 293 .files(tb.findJavaFiles(moduleSrc)) 294 .run() 295 .writeAll(); 296 } 297} 298