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
24 package toolbox;
25
26 import java.io.File;
27 import java.io.IOException;
28 import java.io.PrintWriter;
29 import java.nio.file.Path;
30 import java.nio.file.Paths;
31 import java.util.ArrayList;
32 import java.util.Arrays;
33 import java.util.Collections;
34 import java.util.HashMap;
35 import java.util.List;
36 import java.util.Map;
37 import java.util.stream.Collectors;
38 import java.util.stream.Stream;
39 import javax.tools.JavaCompiler;
40 import javax.tools.JavaFileManager;
41 import javax.tools.JavaFileObject;
42 import javax.tools.StandardJavaFileManager;
43 import javax.tools.StandardLocation;
44
45 import com.sun.tools.javac.api.JavacTaskImpl;
46 import com.sun.tools.javac.api.JavacTool;
47
48 /**
49 * A task to configure and run the Java compiler, javac.
50 */
51 public class JavacTask extends AbstractTask<JavacTask> {
52 private boolean includeStandardOptions;
53 private List<Path> classpath;
54 private List<Path> sourcepath;
55 private Path outdir;
56 private List<String> options;
57 private List<String> classes;
58 private List<String> files;
59 private List<JavaFileObject> fileObjects;
60 private JavaFileManager fileManager;
61
62 private JavaCompiler compiler;
63 private StandardJavaFileManager internalFileManager;
64
65 /**
66 * Creates a task to execute {@code javac} using API mode.
67 * @param toolBox the {@code ToolBox} to use
68 */
69 public JavacTask(ToolBox toolBox) {
70 super(toolBox, Task.Mode.API);
71 }
72
73 /**
74 * Creates a task to execute {@code javac} in a specified mode.
75 * @param toolBox the {@code ToolBox} to use
76 * @param mode the mode to be used
77 */
78 public JavacTask(ToolBox toolBox, Task.Mode mode) {
79 super(toolBox, mode);
80 }
237 * @return this task object
238 */
239 public JavacTask sources(String... sources) {
240 fileObjects = Stream.of(sources)
241 .map(s -> new ToolBox.JavaSource(s))
242 .collect(Collectors.toList());
243 return this;
244 }
245
246 /**
247 * Sets the file manager to be used by this task.
248 * @param fileManager the file manager
249 * @return this task object
250 */
251 public JavacTask fileManager(JavaFileManager fileManager) {
252 this.fileManager = fileManager;
253 return this;
254 }
255
256 /**
257 * {@inheritDoc}
258 * @return the name "javac"
259 */
260 @Override
261 public String name() {
262 return "javac";
263 }
264
265 /**
266 * Calls the compiler with the arguments as currently configured.
267 * @return a Result object indicating the outcome of the compilation
268 * and the content of any output written to stdout, stderr, or the
269 * main stream by the compiler.
270 * @throws TaskError if the outcome of the task is not as expected.
271 */
272 @Override
273 public Task.Result run() {
274 if (mode == Task.Mode.EXEC)
275 return runExec();
276
277 AbstractTask.WriterOutput direct = new AbstractTask.WriterOutput();
278 // The following are to catch output to System.out and System.err,
279 // in case these are used instead of the primary (main) stream
280 AbstractTask.StreamOutput sysOut = new AbstractTask.StreamOutput(System.out, System::setOut);
281 AbstractTask.StreamOutput sysErr = new AbstractTask.StreamOutput(System.err, System::setErr);
282 int rc;
283 Map<Task.OutputKind, String> outputMap = new HashMap<>();
284 try {
285 switch (mode == null ? Task.Mode.API : mode) {
286 case API:
287 rc = runAPI(direct.pw);
288 break;
289 case CMDLINE:
290 if (fileManager != null) {
291 throw new IllegalStateException("file manager set in CMDLINE mode");
292 }
293 rc = runCommand(direct.pw);
294 break;
295 default:
296 throw new IllegalStateException("unknown mode " + mode);
297 }
298 } catch (IOException e) {
299 toolBox.out.println("Exception occurred: " + e);
300 rc = 99;
301 } finally {
302 outputMap.put(Task.OutputKind.STDOUT, sysOut.close());
303 outputMap.put(Task.OutputKind.STDERR, sysErr.close());
304 outputMap.put(Task.OutputKind.DIRECT, direct.close());
305 }
306 return checkExit(new Task.Result(toolBox, this, rc, outputMap));
307 }
308
309 private int runAPI(PrintWriter pw) throws IOException {
310 try {
311 // if (compiler == null) {
312 // TODO: allow this to be set externally
316
317 if (fileManager == null)
318 fileManager = internalFileManager = compiler.getStandardFileManager(null, null, null);
319 if (outdir != null)
320 setLocationFromPaths(StandardLocation.CLASS_OUTPUT, Collections.singletonList(outdir));
321 if (classpath != null)
322 setLocationFromPaths(StandardLocation.CLASS_PATH, classpath);
323 if (sourcepath != null)
324 setLocationFromPaths(StandardLocation.SOURCE_PATH, sourcepath);
325 List<String> allOpts = new ArrayList<>();
326 if (options != null)
327 allOpts.addAll(options);
328
329 Iterable<? extends JavaFileObject> allFiles = joinFiles(files, fileObjects);
330 JavaCompiler.CompilationTask task = compiler.getTask(pw,
331 fileManager,
332 null, // diagnostic listener; should optionally collect diags
333 allOpts,
334 classes,
335 allFiles);
336 return ((JavacTaskImpl) task).doCall().exitCode;
337 } finally {
338 if (internalFileManager != null)
339 internalFileManager.close();
340 }
341 }
342
343 private void setLocationFromPaths(StandardLocation location, List<Path> files) throws IOException {
344 if (!(fileManager instanceof StandardJavaFileManager))
345 throw new IllegalStateException("not a StandardJavaFileManager");
346 ((StandardJavaFileManager) fileManager).setLocationFromPaths(location, files);
347 }
348
349 private int runCommand(PrintWriter pw) {
350 List<String> args = getAllArgs();
351 String[] argsArray = args.toArray(new String[args.size()]);
352 return com.sun.tools.javac.Main.compile(argsArray, pw);
353 }
354
355 private Task.Result runExec() {
356 List<String> args = new ArrayList<>();
|
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
24 package toolbox;
25
26 import java.io.File;
27 import java.io.IOException;
28 import java.io.PrintWriter;
29 import java.nio.file.Path;
30 import java.nio.file.Paths;
31 import java.util.ArrayList;
32 import java.util.Arrays;
33 import java.util.Collections;
34 import java.util.HashMap;
35 import java.util.List;
36 import java.util.Map;
37 import java.util.function.Consumer;
38 import java.util.stream.Collectors;
39 import java.util.stream.Stream;
40 import javax.tools.JavaCompiler;
41 import javax.tools.JavaFileManager;
42 import javax.tools.JavaFileObject;
43 import javax.tools.StandardJavaFileManager;
44 import javax.tools.StandardLocation;
45
46 import com.sun.tools.javac.api.JavacTaskImpl;
47 import com.sun.tools.javac.api.JavacTool;
48
49 /**
50 * A task to configure and run the Java compiler, javac.
51 */
52 public class JavacTask extends AbstractTask<JavacTask> {
53 private boolean includeStandardOptions;
54 private List<Path> classpath;
55 private List<Path> sourcepath;
56 private Path outdir;
57 private List<String> options;
58 private List<String> classes;
59 private List<String> files;
60 private List<JavaFileObject> fileObjects;
61 private JavaFileManager fileManager;
62 private Consumer<com.sun.source.util.JavacTask> callback;
63
64 private JavaCompiler compiler;
65 private StandardJavaFileManager internalFileManager;
66
67 /**
68 * Creates a task to execute {@code javac} using API mode.
69 * @param toolBox the {@code ToolBox} to use
70 */
71 public JavacTask(ToolBox toolBox) {
72 super(toolBox, Task.Mode.API);
73 }
74
75 /**
76 * Creates a task to execute {@code javac} in a specified mode.
77 * @param toolBox the {@code ToolBox} to use
78 * @param mode the mode to be used
79 */
80 public JavacTask(ToolBox toolBox, Task.Mode mode) {
81 super(toolBox, mode);
82 }
239 * @return this task object
240 */
241 public JavacTask sources(String... sources) {
242 fileObjects = Stream.of(sources)
243 .map(s -> new ToolBox.JavaSource(s))
244 .collect(Collectors.toList());
245 return this;
246 }
247
248 /**
249 * Sets the file manager to be used by this task.
250 * @param fileManager the file manager
251 * @return this task object
252 */
253 public JavacTask fileManager(JavaFileManager fileManager) {
254 this.fileManager = fileManager;
255 return this;
256 }
257
258 /**
259 * Set a callback to be used by this task.
260 * @param callback the callback
261 * @return this task object
262 */
263 public JavacTask callback(Consumer<com.sun.source.util.JavacTask> callback) {
264 this.callback = callback;
265 return this;
266 }
267
268 /**
269 * {@inheritDoc}
270 * @return the name "javac"
271 */
272 @Override
273 public String name() {
274 return "javac";
275 }
276
277 /**
278 * Calls the compiler with the arguments as currently configured.
279 * @return a Result object indicating the outcome of the compilation
280 * and the content of any output written to stdout, stderr, or the
281 * main stream by the compiler.
282 * @throws TaskError if the outcome of the task is not as expected.
283 */
284 @Override
285 public Task.Result run() {
286 if (mode == Task.Mode.EXEC)
287 return runExec();
288
289 AbstractTask.WriterOutput direct = new AbstractTask.WriterOutput();
290 // The following are to catch output to System.out and System.err,
291 // in case these are used instead of the primary (main) stream
292 AbstractTask.StreamOutput sysOut = new AbstractTask.StreamOutput(System.out, System::setOut);
293 AbstractTask.StreamOutput sysErr = new AbstractTask.StreamOutput(System.err, System::setErr);
294 int rc;
295 Map<Task.OutputKind, String> outputMap = new HashMap<>();
296 try {
297 switch (mode == null ? Task.Mode.API : mode) {
298 case API:
299 rc = runAPI(direct.pw);
300 break;
301 case CMDLINE:
302 if (fileManager != null) {
303 throw new IllegalStateException("file manager set in CMDLINE mode");
304 }
305 if (callback != null) {
306 throw new IllegalStateException("callback set in CMDLINE mode");
307 }
308 rc = runCommand(direct.pw);
309 break;
310 default:
311 throw new IllegalStateException("unknown mode " + mode);
312 }
313 } catch (IOException e) {
314 toolBox.out.println("Exception occurred: " + e);
315 rc = 99;
316 } finally {
317 outputMap.put(Task.OutputKind.STDOUT, sysOut.close());
318 outputMap.put(Task.OutputKind.STDERR, sysErr.close());
319 outputMap.put(Task.OutputKind.DIRECT, direct.close());
320 }
321 return checkExit(new Task.Result(toolBox, this, rc, outputMap));
322 }
323
324 private int runAPI(PrintWriter pw) throws IOException {
325 try {
326 // if (compiler == null) {
327 // TODO: allow this to be set externally
331
332 if (fileManager == null)
333 fileManager = internalFileManager = compiler.getStandardFileManager(null, null, null);
334 if (outdir != null)
335 setLocationFromPaths(StandardLocation.CLASS_OUTPUT, Collections.singletonList(outdir));
336 if (classpath != null)
337 setLocationFromPaths(StandardLocation.CLASS_PATH, classpath);
338 if (sourcepath != null)
339 setLocationFromPaths(StandardLocation.SOURCE_PATH, sourcepath);
340 List<String> allOpts = new ArrayList<>();
341 if (options != null)
342 allOpts.addAll(options);
343
344 Iterable<? extends JavaFileObject> allFiles = joinFiles(files, fileObjects);
345 JavaCompiler.CompilationTask task = compiler.getTask(pw,
346 fileManager,
347 null, // diagnostic listener; should optionally collect diags
348 allOpts,
349 classes,
350 allFiles);
351 JavacTaskImpl taskImpl = (JavacTaskImpl) task;
352 if (callback != null) {
353 callback.accept(taskImpl);
354 }
355 return taskImpl.doCall().exitCode;
356 } finally {
357 if (internalFileManager != null)
358 internalFileManager.close();
359 }
360 }
361
362 private void setLocationFromPaths(StandardLocation location, List<Path> files) throws IOException {
363 if (!(fileManager instanceof StandardJavaFileManager))
364 throw new IllegalStateException("not a StandardJavaFileManager");
365 ((StandardJavaFileManager) fileManager).setLocationFromPaths(location, files);
366 }
367
368 private int runCommand(PrintWriter pw) {
369 List<String> args = getAllArgs();
370 String[] argsArray = args.toArray(new String[args.size()]);
371 return com.sun.tools.javac.Main.compile(argsArray, pw);
372 }
373
374 private Task.Result runExec() {
375 List<String> args = new ArrayList<>();
|