001/*
002 * Copyright (c) 2012, 2022, Oracle and/or its affiliates. All rights reserved.
003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004 *
005 * This code is free software; you can redistribute it and/or modify it
006 * under the terms of the GNU General Public License version 2 only, as
007 * published by the Free Software Foundation.  Oracle designates this
008 * particular file as subject to the "Classpath" exception as provided
009 * by Oracle in the LICENSE file that accompanied this code.
010 *
011 * This code is distributed in the hope that it will be useful, but WITHOUT
012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
014 * version 2 for more details (a copy is included in the LICENSE file that
015 * accompanied this code).
016 *
017 * You should have received a copy of the GNU General Public License version
018 * 2 along with this work; if not, write to the Free Software Foundation,
019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020 *
021 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
022 * or visit www.oracle.com if you need additional information or have any
023 * questions.
024 */
025
026package org.jdrupes.mdoclet.internal.api;
027
028import java.io.InputStream;
029import java.io.OutputStream;
030import java.io.OutputStreamWriter;
031import java.io.PrintWriter;
032import java.io.Writer;
033import java.nio.charset.Charset;
034import java.util.Collections;
035import java.util.EnumSet;
036import java.util.Locale;
037import java.util.Objects;
038import java.util.Set;
039
040import javax.lang.model.SourceVersion;
041import javax.tools.DiagnosticListener;
042import javax.tools.DocumentationTool;
043import javax.tools.JavaFileManager;
044import javax.tools.JavaFileObject;
045import javax.tools.StandardJavaFileManager;
046
047import jdk.javadoc.internal.tool.ToolOptions;
048
049import com.sun.tools.javac.api.ClientCodeWrapper;
050import com.sun.tools.javac.file.JavacFileManager;
051import com.sun.tools.javac.file.BaseFileManager;
052import com.sun.tools.javac.util.ClientCodeException;
053import com.sun.tools.javac.util.Context;
054import com.sun.tools.javac.util.Log;
055
056import org.jdrupes.mdoclet.internal.api.JavadocTaskImpl;
057
058/**
059 * Provides access to functionality specific to the JDK documentation tool,
060 * javadoc.
061 */
062public class JavadocTool implements DocumentationTool {
063
064    @Override
065    public String name() {
066        return "javadoc";
067    }
068
069    @Override
070    public DocumentationTask getTask(
071            Writer out,
072            JavaFileManager fileManager,
073            DiagnosticListener<? super JavaFileObject> diagnosticListener,
074            Class<?> docletClass,
075            Iterable<String> options,
076            Iterable<? extends JavaFileObject> compilationUnits) {
077        Context context = new Context();
078        return getTask(out, fileManager, diagnosticListener,
079            docletClass, options, compilationUnits, context);
080    }
081
082    public DocumentationTask getTask(
083            Writer out,
084            JavaFileManager fileManager,
085            DiagnosticListener<? super JavaFileObject> diagnosticListener,
086            Class<?> docletClass,
087            Iterable<String> options,
088            Iterable<? extends JavaFileObject> compilationUnits,
089            Context context) {
090        try {
091            ClientCodeWrapper ccw = ClientCodeWrapper.instance(context);
092
093            if (options != null) {
094                for (String option : options)
095                    Objects.requireNonNull(option);
096            }
097
098            if (compilationUnits != null) {
099                compilationUnits = ccw.wrapJavaFileObjects(compilationUnits); // implicit
100                                                                              // null
101                                                                              // check
102                for (JavaFileObject cu : compilationUnits) {
103                    if (cu.getKind() != JavaFileObject.Kind.SOURCE) {
104                        final String kindMsg
105                            = "All compilation units must be of SOURCE kind";
106                        throw new IllegalArgumentException(kindMsg);
107                    }
108                }
109            }
110
111            if (diagnosticListener != null)
112                context.put(DiagnosticListener.class,
113                    ccw.wrap(diagnosticListener));
114
115            if (out == null)
116                context.put(Log.errKey, new PrintWriter(System.err, true));
117            else if (out instanceof PrintWriter pout)
118                context.put(Log.errKey, pout);
119            else
120                context.put(Log.errKey, new PrintWriter(out, true));
121
122            if (fileManager == null) {
123                fileManager
124                    = getStandardFileManager(diagnosticListener, null, null);
125                if (fileManager instanceof BaseFileManager bfm) {
126                    bfm.autoClose = true;
127                }
128            }
129            fileManager = ccw.wrap(fileManager);
130            context.put(JavaFileManager.class, fileManager);
131
132            return new JavadocTaskImpl(context, docletClass, options,
133                compilationUnits);
134        } catch (ClientCodeException ex) {
135            throw new RuntimeException(ex.getCause());
136        }
137    }
138
139    // TODO: used shared static method in JavacFileManager
140    @Override
141    public StandardJavaFileManager getStandardFileManager(
142            DiagnosticListener<? super JavaFileObject> diagnosticListener,
143            Locale locale,
144            Charset charset) {
145        Context context = new Context();
146        context.put(Locale.class, locale);
147        if (diagnosticListener != null)
148            context.put(DiagnosticListener.class, diagnosticListener);
149        PrintWriter pw = (charset == null)
150            ? new PrintWriter(System.err, true)
151            : new PrintWriter(new OutputStreamWriter(System.err, charset),
152                true);
153        context.put(Log.errKey, pw);
154        return new JavacFileManager(context, true, charset);
155    }
156
157    @Override
158    public int run(InputStream in, OutputStream out, OutputStream err,
159            String... arguments) {
160        PrintWriter err_pw
161            = new PrintWriter(err == null ? System.err : err, true);
162        PrintWriter out_pw = new PrintWriter(out == null ? System.out : out);
163        try {
164            return jdk.javadoc.internal.tool.Main.execute(arguments,
165                err_pw);
166        } finally {
167            err_pw.flush();
168            out_pw.flush();
169        }
170    }
171
172    @Override
173    public Set<SourceVersion> getSourceVersions() {
174        return Collections.unmodifiableSet(
175            EnumSet.range(SourceVersion.RELEASE_3, SourceVersion.latest()));
176    }
177
178    @Override
179    public int isSupportedOption(String option) {
180        if (option == null)
181            throw new NullPointerException();
182        return ToolOptions.isSupportedOption(option);
183    }
184
185}