1 /*
   2  * Copyright (c) 2012, 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.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package jdk.javadoc.internal.api;
  27 
  28 import java.io.InputStream;
  29 import java.io.OutputStream;
  30 import java.io.OutputStreamWriter;
  31 import java.io.PrintWriter;
  32 import java.io.Writer;
  33 import java.nio.charset.Charset;
  34 import java.util.Collections;
  35 import java.util.EnumSet;
  36 import java.util.Locale;
  37 import java.util.Objects;
  38 import java.util.Set;
  39 
  40 import javax.lang.model.SourceVersion;
  41 import javax.tools.DiagnosticListener;
  42 import javax.tools.DocumentationTool;
  43 import javax.tools.JavaFileManager;
  44 import javax.tools.JavaFileObject;
  45 import javax.tools.StandardJavaFileManager;
  46 
  47 import com.sun.tools.javac.api.ClientCodeWrapper;
  48 import com.sun.tools.javac.file.JavacFileManager;
  49 import com.sun.tools.javac.file.BaseFileManager;
  50 import com.sun.tools.javac.util.ClientCodeException;
  51 import com.sun.tools.javac.util.Context;
  52 import com.sun.tools.javac.util.Log;
  53 import jdk.javadoc.internal.tool.ToolOptions;
  54 
  55 /**
  56  * Provides access to functionality specific to the JDK documentation tool,
  57  * javadoc.
  58  *
  59  * <p><b>This is NOT part of any supported API.
  60  * If you write code that depends on this, you do so at your own
  61  * risk.  This code and its internal interfaces are subject to change
  62  * or deletion without notice.</b></p>
  63  */
  64 public class JavadocTool implements DocumentationTool {
  65     // @Override // can't add @Override until bootstrap JDK provides Tool.name()
  66     public String name() {
  67         return "javadoc";
  68     }
  69 
  70     @Override
  71     public DocumentationTask getTask(
  72             Writer out,
  73             JavaFileManager fileManager,
  74             DiagnosticListener<? super JavaFileObject> diagnosticListener,
  75             Class<?> docletClass,
  76             Iterable<String> options,
  77             Iterable<? extends JavaFileObject> compilationUnits) {
  78         Context context = new Context();
  79         return getTask(out, fileManager, diagnosticListener,
  80                 docletClass, options, compilationUnits, context);
  81     }
  82 
  83     public DocumentationTask getTask(
  84             Writer out,
  85             JavaFileManager fileManager,
  86             DiagnosticListener<? super JavaFileObject> diagnosticListener,
  87             Class<?> docletClass,
  88             Iterable<String> options,
  89             Iterable<? extends JavaFileObject> compilationUnits,
  90             Context context) {
  91         try {
  92             ClientCodeWrapper ccw = ClientCodeWrapper.instance(context);
  93 
  94             if (options != null) {
  95                 for (String option : options)
  96                     Objects.requireNonNull(option);
  97             }
  98 
  99             if (compilationUnits != null) {
 100                 compilationUnits = ccw.wrapJavaFileObjects(compilationUnits); // implicit null check
 101                 for (JavaFileObject cu : compilationUnits) {
 102                     if (cu.getKind() != JavaFileObject.Kind.SOURCE) {
 103                         final String kindMsg = "All compilation units must be of SOURCE kind";
 104                         throw new IllegalArgumentException(kindMsg);
 105                     }
 106                 }
 107             }
 108 
 109             if (diagnosticListener != null)
 110                 context.put(DiagnosticListener.class, ccw.wrap(diagnosticListener));
 111 
 112             if (out == null)
 113                 context.put(Log.errKey, new PrintWriter(System.err, true));
 114             else if (out instanceof PrintWriter)
 115                 context.put(Log.errKey, ((PrintWriter) out));
 116             else
 117                 context.put(Log.errKey, new PrintWriter(out, true));
 118 
 119             if (fileManager == null) {
 120                 fileManager = getStandardFileManager(diagnosticListener, null, null);
 121                 if (fileManager instanceof BaseFileManager) {
 122                     ((BaseFileManager) fileManager).autoClose = true;
 123                 }
 124             }
 125             fileManager = ccw.wrap(fileManager);
 126             context.put(JavaFileManager.class, fileManager);
 127 
 128             return new JavadocTaskImpl(context, docletClass, options, compilationUnits);
 129         } catch (ClientCodeException ex) {
 130             throw new RuntimeException(ex.getCause());
 131         }
 132     }
 133 
 134     // TODO: used shared static method in JavacFileManager
 135     @Override
 136     public StandardJavaFileManager getStandardFileManager(
 137             DiagnosticListener<? super JavaFileObject> diagnosticListener,
 138             Locale locale,
 139             Charset charset) {
 140         Context context = new Context();
 141         context.put(Locale.class, locale);
 142         if (diagnosticListener != null)
 143             context.put(DiagnosticListener.class, diagnosticListener);
 144         PrintWriter pw = (charset == null)
 145                 ? new PrintWriter(System.err, true)
 146                 : new PrintWriter(new OutputStreamWriter(System.err, charset), true);
 147         context.put(Log.errKey, pw);
 148         return new JavacFileManager(context, true, charset);
 149     }
 150 
 151     @Override
 152     public int run(InputStream in, OutputStream out, OutputStream err, String... arguments) {
 153         PrintWriter err_pw = new PrintWriter(err == null ? System.err : err, true);
 154         PrintWriter out_pw = new PrintWriter(out == null ? System.out : out);
 155         try {
 156             return jdk.javadoc.internal.tool.Main.execute(arguments, err_pw);
 157         } finally {
 158             err_pw.flush();
 159             out_pw.flush();
 160         }
 161     }
 162 
 163     @Override
 164     public Set<SourceVersion> getSourceVersions() {
 165         return Collections.unmodifiableSet(
 166                 EnumSet.range(SourceVersion.RELEASE_3, SourceVersion.latest()));
 167     }
 168 
 169     @Override
 170     public int isSupportedOption(String option) {
 171         if (option == null)
 172             throw new NullPointerException();
 173         return ToolOptions.isSupportedOption(option);
 174     }
 175 
 176 }