| /* | |
| * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. | |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
| * | |
| * This code is free software; you can redistribute it and/or modify it | |
| * under the terms of the GNU General Public License version 2 only, as | |
| * published by the Free Software Foundation. | |
| * | |
| * This code is distributed in the hope that it will be useful, but WITHOUT | |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
| * version 2 for more details (a copy is included in the LICENSE file that | |
| * accompanied this code). | |
| * | |
| * You should have received a copy of the GNU General Public License version | |
| * 2 along with this work; if not, write to the Free Software Foundation, | |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
| * | |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
| * or visit www.oracle.com if you need additional information or have any | |
| * questions. | |
| */ | |
| package toolbox; | |
| import java.io.IOException; | |
| import java.io.PrintWriter; | |
| import java.nio.file.Path; | |
| import java.nio.file.Paths; | |
| import java.util.ArrayList; | |
| import java.util.Arrays; | |
| import java.util.Collections; | |
| import java.util.HashMap; | |
| import java.util.List; | |
| import java.util.Map; | |
| import java.util.stream.Collectors; | |
| import java.util.stream.Stream; | |
| import javax.tools.DocumentationTool.DocumentationTask; | |
| import javax.tools.DocumentationTool; | |
| import javax.tools.JavaFileManager; | |
| import javax.tools.JavaFileManager.Location; | |
| import javax.tools.JavaFileObject; | |
| import javax.tools.StandardJavaFileManager; | |
| import javax.tools.StandardLocation; | |
| import javax.tools.ToolProvider; | |
| import jdk.javadoc.internal.api.JavadocTool; | |
| /** | |
| * A task to configure and run the documentation tool, javadoc. | |
| */ | |
| public class JavadocTask extends AbstractTask<JavadocTask> { | |
| private boolean includeStandardOptions; | |
| private List<Path> classpath; | |
| private List<Path> sourcepath; | |
| private Path outdir; | |
| private List<String> options; | |
| private List<String> classes; | |
| private List<String> files; | |
| private List<JavaFileObject> fileObjects; | |
| private JavaFileManager fileManager; | |
| private JavadocTool jdtool; | |
| private StandardJavaFileManager internalFileManager; | |
| private Class<?> docletClass = null; // use the standard doclet by default | |
| /** | |
| * Creates a task to execute {@code javadoc} using API mode. | |
| * @param toolBox the {@code ToolBox} to use | |
| */ | |
| public JavadocTask(ToolBox toolBox) { | |
| super(toolBox, Task.Mode.API); | |
| } | |
| /** | |
| * Creates a task to execute {@code javadoc} in a specified mode. | |
| * @param toolBox the {@code ToolBox} to use | |
| * @param mode the mode to be used | |
| */ | |
| public JavadocTask(ToolBox toolBox, Task.Mode mode) { | |
| super(toolBox, mode); | |
| } | |
| /** | |
| * Sets the classpath. | |
| * @param classpath the classpath | |
| * @return this task object | |
| */ | |
| public JavadocTask classpath(String classpath) { | |
| this.classpath = Stream.of(classpath.split(ToolBox.pathSeparator)) | |
| .filter(s -> !s.isEmpty()) | |
| .map(s -> Paths.get(s)) | |
| .collect(Collectors.toList()); | |
| return this; | |
| } | |
| /** | |
| * Sets the classpath. | |
| * @param classpath the classpath | |
| * @return this task object | |
| */ | |
| public JavadocTask classpath(Path... classpath) { | |
| this.classpath = Arrays.asList(classpath); | |
| return this; | |
| } | |
| /** | |
| * Sets the classpath. | |
| * @param classpath the classpath | |
| * @return this task object | |
| */ | |
| public JavadocTask classpath(List<Path> classpath) { | |
| this.classpath = classpath; | |
| return this; | |
| } | |
| /** | |
| * Sets the sourcepath. | |
| * @param sourcepath the sourcepath | |
| * @return this task object | |
| */ | |
| public JavadocTask sourcepath(String sourcepath) { | |
| this.sourcepath = Stream.of(sourcepath.split(ToolBox.pathSeparator)) | |
| .filter(s -> !s.isEmpty()) | |
| .map(s -> Paths.get(s)) | |
| .collect(Collectors.toList()); | |
| return this; | |
| } | |
| /** | |
| * Sets the sourcepath. | |
| * @param sourcepath the sourcepath | |
| * @return this task object | |
| */ | |
| public JavadocTask sourcepath(Path... sourcepath) { | |
| this.sourcepath = Arrays.asList(sourcepath); | |
| return this; | |
| } | |
| /** | |
| * Sets the sourcepath. | |
| * @param sourcepath the sourcepath | |
| * @return this task object | |
| */ | |
| public JavadocTask sourcepath(List<Path> sourcepath) { | |
| this.sourcepath = sourcepath; | |
| return this; | |
| } | |
| /** | |
| * Sets the output directory. | |
| * @param outdir the output directory | |
| * @return this task object | |
| */ | |
| public JavadocTask outdir(String outdir) { | |
| this.outdir = Paths.get(outdir); | |
| return this; | |
| } | |
| /** | |
| * Sets the output directory. | |
| * @param outdir the output directory | |
| * @return this task object | |
| */ | |
| public JavadocTask outdir(Path outdir) { | |
| this.outdir = outdir; | |
| return this; | |
| } | |
| /** | |
| * Sets the options. | |
| * @param options the options | |
| * @return this task object | |
| */ | |
| public JavadocTask options(String... options) { | |
| this.options = Arrays.asList(options); | |
| return this; | |
| } | |
| /** | |
| * Sets the options. | |
| * @param options the options | |
| * @return this task object | |
| */ | |
| public JavadocTask options(List<String> options) { | |
| this.options = options; | |
| return this; | |
| } | |
| /** | |
| * Sets the files to be documented. | |
| * @param files the files | |
| * @return this task object | |
| */ | |
| public JavadocTask files(String... files) { | |
| this.files = Arrays.asList(files); | |
| return this; | |
| } | |
| /** | |
| * Sets the files to be documented. | |
| * @param files the files | |
| * @return this task object | |
| */ | |
| public JavadocTask files(Path... files) { | |
| this.files = Stream.of(files) | |
| .map(Path::toString) | |
| .collect(Collectors.toList()); | |
| return this; | |
| } | |
| /** | |
| * Sets the files to be documented. | |
| * @param files the files | |
| * @return this task object | |
| */ | |
| public JavadocTask files(List<Path> files) { | |
| this.files = files.stream() | |
| .map(Path::toString) | |
| .collect(Collectors.toList()); | |
| return this; | |
| } | |
| /** | |
| * Sets the sources to be documented. | |
| * Each source string is converted into an in-memory object that | |
| * can be passed directly to the tool. | |
| * @param sources the sources | |
| * @return this task object | |
| */ | |
| public JavadocTask sources(String... sources) { | |
| fileObjects = Stream.of(sources) | |
| .map(s -> new ToolBox.JavaSource(s)) | |
| .collect(Collectors.toList()); | |
| return this; | |
| } | |
| /** | |
| * Sets the file manager to be used by this task. | |
| * @param fileManager the file manager | |
| * @return this task object | |
| */ | |
| public JavadocTask fileManager(JavaFileManager fileManager) { | |
| this.fileManager = fileManager; | |
| return this; | |
| } | |
| /** | |
| * Sets the doclet class to be invoked by javadoc. | |
| * Note: this is applicable only in API mode. | |
| * @param docletClass the user specified doclet | |
| * @return this task object | |
| */ | |
| public JavadocTask docletClass(Class<?> docletClass) { | |
| this.docletClass = docletClass; | |
| return this; | |
| } | |
| /** | |
| * {@inheritDoc} | |
| * @return the name "javadoc" | |
| */ | |
| @Override | |
| public String name() { | |
| return "javadoc"; | |
| } | |
| /** | |
| * Calls the javadoc tool with the arguments as currently configured. | |
| * @return a Result object indicating the outcome of the execution | |
| * and the content of any output written to stdout, stderr, or the | |
| * main stream by the tool. | |
| */ | |
| @Override | |
| public Task.Result run() { | |
| if (mode == Task.Mode.EXEC) | |
| return runExec(); | |
| AbstractTask.WriterOutput direct = new AbstractTask.WriterOutput(); | |
| // The following are to catch output to System.out and System.err, | |
| // in case these are used instead of the primary (main) stream | |
| AbstractTask.StreamOutput sysOut = new AbstractTask.StreamOutput(System.out, System::setOut); | |
| AbstractTask.StreamOutput sysErr = new AbstractTask.StreamOutput(System.err, System::setErr); | |
| int rc; | |
| Map<Task.OutputKind, String> outputMap = new HashMap<>(); | |
| try { | |
| switch (mode == null ? Task.Mode.API : mode) { | |
| case API: | |
| rc = runAPI(direct.pw); | |
| break; | |
| case CMDLINE: | |
| rc = runCommand(direct.pw); | |
| break; | |
| default: | |
| throw new IllegalStateException(); | |
| } | |
| } catch (IOException e) { | |
| toolBox.out.println("Exception occurred: " + e); | |
| rc = 99; | |
| } finally { | |
| outputMap.put(Task.OutputKind.STDOUT, sysOut.close()); | |
| outputMap.put(Task.OutputKind.STDERR, sysErr.close()); | |
| outputMap.put(Task.OutputKind.DIRECT, direct.close()); | |
| } | |
| return checkExit(new Task.Result(toolBox, this, rc, outputMap)); | |
| } | |
| private int runAPI(PrintWriter pw) throws IOException { | |
| try { | |
| jdtool = (JavadocTool) ToolProvider.getSystemDocumentationTool(); | |
| jdtool = new JavadocTool(); | |
| if (fileManager == null) | |
| fileManager = internalFileManager = jdtool.getStandardFileManager(null, null, null); | |
| if (outdir != null) | |
| setLocationFromPaths(DocumentationTool.Location.DOCUMENTATION_OUTPUT, | |
| Collections.singletonList(outdir)); | |
| if (classpath != null) | |
| setLocationFromPaths(StandardLocation.CLASS_PATH, classpath); | |
| if (sourcepath != null) | |
| setLocationFromPaths(StandardLocation.SOURCE_PATH, sourcepath); | |
| List<String> allOpts = new ArrayList<>(); | |
| if (options != null) | |
| allOpts.addAll(options); | |
| Iterable<? extends JavaFileObject> allFiles = joinFiles(files, fileObjects); | |
| DocumentationTask task = jdtool.getTask(pw, | |
| fileManager, | |
| null, // diagnostic listener; should optionally collect diags | |
| docletClass, | |
| allOpts, | |
| allFiles); | |
| return ((DocumentationTask) task).call() ? 0 : 1; | |
| } finally { | |
| if (internalFileManager != null) | |
| internalFileManager.close(); | |
| } | |
| } | |
| private void setLocationFromPaths(Location location, List<Path> files) throws IOException { | |
| if (!(fileManager instanceof StandardJavaFileManager)) | |
| throw new IllegalStateException("not a StandardJavaFileManager"); | |
| ((StandardJavaFileManager) fileManager).setLocationFromPaths(location, files); | |
| } | |
| private int runCommand(PrintWriter pw) { | |
| List<String> args = getAllArgs(); | |
| String[] argsArray = args.toArray(new String[args.size()]); | |
| return jdk.javadoc.internal.tool.Main.execute(argsArray, pw); | |
| } | |
| private Task.Result runExec() { | |
| List<String> args = new ArrayList<>(); | |
| Path javadoc = toolBox.getJDKTool("javadoc"); | |
| args.add(javadoc.toString()); | |
| if (includeStandardOptions) { | |
| args.addAll(toolBox.split(System.getProperty("test.tool.vm.opts"), " +")); | |
| } | |
| args.addAll(getAllArgs()); | |
| String[] argsArray = args.toArray(new String[args.size()]); | |
| ProcessBuilder pb = getProcessBuilder(); | |
| pb.command(argsArray); | |
| try { | |
| return runProcess(toolBox, this, pb.start()); | |
| } catch (IOException | InterruptedException e) { | |
| throw new Error(e); | |
| } | |
| } | |
| private List<String> getAllArgs() { | |
| List<String> args = new ArrayList<>(); | |
| if (options != null) | |
| args.addAll(options); | |
| if (outdir != null) { | |
| args.add("-d"); | |
| args.add(outdir.toString()); | |
| } | |
| if (classpath != null) { | |
| args.add("-classpath"); | |
| args.add(toSearchPath(classpath)); | |
| } | |
| if (sourcepath != null) { | |
| args.add("-sourcepath"); | |
| args.add(toSearchPath(sourcepath)); | |
| } | |
| if (classes != null) | |
| args.addAll(classes); | |
| if (files != null) | |
| args.addAll(files); | |
| return args; | |
| } | |
| private String toSearchPath(List<Path> files) { | |
| return files.stream() | |
| .map(Path::toString) | |
| .collect(Collectors.joining(ToolBox.pathSeparator)); | |
| } | |
| private Iterable<? extends JavaFileObject> joinFiles( | |
| List<String> files, List<JavaFileObject> fileObjects) { | |
| if (files == null) | |
| return fileObjects; | |
| if (internalFileManager == null) | |
| internalFileManager = jdtool.getStandardFileManager(null, null, null); | |
| Iterable<? extends JavaFileObject> filesAsFileObjects = | |
| internalFileManager.getJavaFileObjectsFromStrings(files); | |
| if (fileObjects == null) | |
| return filesAsFileObjects; | |
| List<JavaFileObject> combinedList = new ArrayList<>(); | |
| for (JavaFileObject o : filesAsFileObjects) | |
| combinedList.add(o); | |
| combinedList.addAll(fileObjects); | |
| return combinedList; | |
| } | |
| } |