JavacTool.java revision 2571:10fc81ac75b4
1/*
2 * Copyright (c) 2005, 2014, 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
26package com.sun.tools.javac.api;
27
28import java.io.InputStream;
29import java.io.OutputStream;
30import java.io.OutputStreamWriter;
31import java.io.PrintWriter;
32import java.io.Writer;
33import java.nio.charset.Charset;
34import java.util.Collections;
35import java.util.EnumSet;
36import java.util.Iterator;
37import java.util.Locale;
38import java.util.Set;
39import javax.lang.model.SourceVersion;
40import javax.tools.*;
41
42import com.sun.source.util.JavacTask;
43import com.sun.tools.javac.file.JavacFileManager;
44import com.sun.tools.javac.main.Main;
45import com.sun.tools.javac.main.Option;
46import com.sun.tools.javac.main.OptionHelper;
47import com.sun.tools.javac.main.OptionHelper.GrumpyHelper;
48import com.sun.tools.javac.util.ClientCodeException;
49import com.sun.tools.javac.util.Context;
50import com.sun.tools.javac.util.Log;
51import com.sun.tools.javac.util.Log.PrefixKind;
52import com.sun.tools.javac.util.Options;
53
54/**
55 * TODO: describe com.sun.tools.javac.api.Tool
56 *
57 * <p><b>This is NOT part of any supported API.
58 * If you write code that depends on this, you do so at your own
59 * risk.  This code and its internal interfaces are subject to change
60 * or deletion without notice.</b></p>
61 *
62 * @author Peter von der Ah\u00e9
63 */
64public final class JavacTool implements JavaCompiler {
65    /**
66     * Constructor used by service provider mechanism.  The recommended way to
67     * obtain an instance of this class is by using {@link #create} or the
68     * service provider mechanism.
69     * @see javax.tools.JavaCompiler
70     * @see javax.tools.ToolProvider
71     * @see #create
72     */
73    @Deprecated
74    public JavacTool() {}
75
76    /**
77     * Static factory method for creating new instances of this tool.
78     * @return new instance of this tool
79     */
80    public static JavacTool create() {
81        return new JavacTool();
82    }
83
84    public JavacFileManager getStandardFileManager(
85        DiagnosticListener<? super JavaFileObject> diagnosticListener,
86        Locale locale,
87        Charset charset) {
88        Context context = new Context();
89        context.put(Locale.class, locale);
90        if (diagnosticListener != null)
91            context.put(DiagnosticListener.class, diagnosticListener);
92        PrintWriter pw = (charset == null)
93                ? new PrintWriter(System.err, true)
94                : new PrintWriter(new OutputStreamWriter(System.err, charset), true);
95        context.put(Log.outKey, pw);
96        return new JavacFileManager(context, true, charset);
97    }
98
99    @Override
100    public JavacTask getTask(Writer out,
101                             JavaFileManager fileManager,
102                             DiagnosticListener<? super JavaFileObject> diagnosticListener,
103                             Iterable<String> options,
104                             Iterable<String> classes,
105                             Iterable<? extends JavaFileObject> compilationUnits) {
106        Context context = new Context();
107        return getTask(out, fileManager, diagnosticListener,
108                options, classes, compilationUnits,
109                context);
110    }
111
112    public JavacTask getTask(Writer out,
113                             JavaFileManager fileManager,
114                             DiagnosticListener<? super JavaFileObject> diagnosticListener,
115                             Iterable<String> options,
116                             Iterable<String> classes,
117                             Iterable<? extends JavaFileObject> compilationUnits,
118                             Context context)
119    {
120        try {
121            ClientCodeWrapper ccw = ClientCodeWrapper.instance(context);
122
123            if (options != null)
124                for (String option : options)
125                    option.getClass(); // null check
126            if (classes != null) {
127                for (String cls : classes)
128                    if (!SourceVersion.isName(cls)) // implicit null check
129                        throw new IllegalArgumentException("Not a valid class name: " + cls);
130            }
131            if (compilationUnits != null) {
132                compilationUnits = ccw.wrapJavaFileObjects(compilationUnits); // implicit null check
133                for (JavaFileObject cu : compilationUnits) {
134                    if (cu.getKind() != JavaFileObject.Kind.SOURCE) {
135                        String kindMsg = "Compilation unit is not of SOURCE kind: "
136                                + "\"" + cu.getName() + "\"";
137                        throw new IllegalArgumentException(kindMsg);
138                    }
139                }
140            }
141
142            if (diagnosticListener != null)
143                context.put(DiagnosticListener.class, ccw.wrap(diagnosticListener));
144
145            if (out == null)
146                context.put(Log.outKey, new PrintWriter(System.err, true));
147            else
148                context.put(Log.outKey, new PrintWriter(out, true));
149
150            if (fileManager == null)
151                fileManager = getStandardFileManager(diagnosticListener, null, null);
152            fileManager = ccw.wrap(fileManager);
153
154            context.put(JavaFileManager.class, fileManager);
155
156            processOptions(context, fileManager, options);
157            Main compiler = new Main("javacTask", context.get(Log.outKey));
158            return new JavacTaskImpl(compiler, options, context, classes, compilationUnits);
159        } catch (ClientCodeException ex) {
160            throw new RuntimeException(ex.getCause());
161        }
162    }
163
164    private void processOptions(Context context,
165                                       JavaFileManager fileManager,
166                                       Iterable<String> options)
167    {
168        if (options == null)
169            return;
170
171        final Options optionTable = Options.instance(context);
172        Log log = Log.instance(context);
173
174        Option[] recognizedOptions =
175                Option.getJavacToolOptions().toArray(new Option[0]);
176        OptionHelper optionHelper = new GrumpyHelper(log) {
177            @Override
178            public String get(Option option) {
179                return optionTable.get(option.getText());
180            }
181
182            @Override
183            public void put(String name, String value) {
184                optionTable.put(name, value);
185            }
186
187            @Override
188            public void remove(String name) {
189                optionTable.remove(name);
190            }
191        };
192
193        Iterator<String> flags = options.iterator();
194        while (flags.hasNext()) {
195            String flag = flags.next();
196            int j;
197            for (j=0; j<recognizedOptions.length; j++)
198                if (recognizedOptions[j].matches(flag))
199                    break;
200
201            if (j == recognizedOptions.length) {
202                if (fileManager.handleOption(flag, flags)) {
203                    continue;
204                } else {
205                    String msg = log.localize(PrefixKind.JAVAC, "err.invalid.flag", flag);
206                    throw new IllegalArgumentException(msg);
207                }
208            }
209
210            Option option = recognizedOptions[j];
211            if (option.hasArg()) {
212                if (!flags.hasNext()) {
213                    String msg = log.localize(PrefixKind.JAVAC, "err.req.arg", flag);
214                    throw new IllegalArgumentException(msg);
215                }
216                String operand = flags.next();
217                if (option.process(optionHelper, flag, operand))
218                    // should not happen as the GrumpyHelper will throw exceptions
219                    // in case of errors
220                    throw new IllegalArgumentException(flag + " " + operand);
221            } else {
222                if (option.process(optionHelper, flag))
223                    // should not happen as the GrumpyHelper will throw exceptions
224                    // in case of errors
225                    throw new IllegalArgumentException(flag);
226            }
227        }
228
229        optionTable.notifyListeners();
230    }
231
232    public int run(InputStream in, OutputStream out, OutputStream err, String... arguments) {
233        if (err == null)
234            err = System.err;
235        for (String argument : arguments)
236            argument.getClass(); // null check
237        return com.sun.tools.javac.Main.compile(arguments, new PrintWriter(err, true));
238    }
239
240    public Set<SourceVersion> getSourceVersions() {
241        return Collections.unmodifiableSet(EnumSet.range(SourceVersion.RELEASE_3,
242                                                         SourceVersion.latest()));
243    }
244
245    public int isSupportedOption(String option) {
246        Set<Option> recognizedOptions = Option.getJavacToolOptions();
247        for (Option o : recognizedOptions) {
248            if (o.matches(option))
249                return o.hasArg() ? 1 : 0;
250        }
251        return -1;
252    }
253
254}
255