1 | /* |
2 | * Copyright 2005-2006 Sun Microsystems, Inc. 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. Sun designates this |
8 | * particular file as subject to the "Classpath" exception as provided |
9 | * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, |
22 | * CA 95054 USA or visit www.sun.com if you need additional information or |
23 | * have any questions. |
24 | */ |
25 | |
26 | package com.sun.tools.javac.api; |
27 | |
28 | import java.io.File; |
29 | import java.io.InputStream; |
30 | import java.io.OutputStream; |
31 | import java.io.PrintWriter; |
32 | import java.io.Writer; |
33 | import java.util.ArrayList; |
34 | import java.util.Arrays; |
35 | import java.util.Collections; |
36 | import java.util.EnumSet; |
37 | import java.util.Iterator; |
38 | import java.util.List; |
39 | import java.util.Locale; |
40 | import java.util.Set; |
41 | import javax.lang.model.SourceVersion; |
42 | import javax.tools.*; |
43 | |
44 | import com.sun.source.util.JavacTask; |
45 | import com.sun.tools.javac.main.JavacOption.OptionKind; |
46 | import com.sun.tools.javac.main.JavacOption; |
47 | import com.sun.tools.javac.main.Main; |
48 | import com.sun.tools.javac.main.RecognizedOptions.GrumpyHelper; |
49 | import com.sun.tools.javac.main.RecognizedOptions; |
50 | import com.sun.tools.javac.util.Context; |
51 | import com.sun.tools.javac.util.JavacFileManager; |
52 | import com.sun.tools.javac.util.Log; |
53 | import com.sun.tools.javac.util.Options; |
54 | import com.sun.tools.javac.util.Pair; |
55 | import java.nio.charset.Charset; |
56 | |
57 | /** |
58 | * TODO: describe com.sun.tools.javac.api.Tool |
59 | * |
60 | * <p><b>This is NOT part of any API supported by Sun Microsystems. |
61 | * If you write code that depends on this, you do so at your own |
62 | * risk. This code and its internal interfaces are subject to change |
63 | * or deletion without notice.</b></p> |
64 | * |
65 | * @author Peter von der Ah\u00e9 |
66 | */ |
67 | public final class JavacTool implements JavaCompiler { |
68 | private final List<Pair<String,String>> options |
69 | = new ArrayList<Pair<String,String>>(); |
70 | private final Context dummyContext = new Context(); |
71 | |
72 | private final PrintWriter silent = new PrintWriter(new OutputStream(){ |
73 | public void write(int b) {} |
74 | }); |
75 | |
76 | private final Main sharedCompiler = new Main("javac", silent); |
77 | { |
78 | sharedCompiler.setOptions(Options.instance(dummyContext)); |
79 | } |
80 | |
81 | /** |
82 | * Constructor used by service provider mechanism. The correct way to |
83 | * obtain an instance of this class is using create or the service provider |
84 | * mechanism. |
85 | * @see javax.tools.JavaCompilerTool |
86 | * @see javax.tools.ToolProvider |
87 | * @see #create |
88 | */ |
89 | @Deprecated |
90 | public JavacTool() {} |
91 | |
92 | /** |
93 | * Static factory method for creating new instances of this tool. |
94 | * @return new instance of this tool |
95 | */ |
96 | public static JavacTool create() { |
97 | return new JavacTool(); |
98 | } |
99 | |
100 | private String argsToString(Object... args) { |
101 | String newArgs = null; |
102 | if (args.length > 0) { |
103 | StringBuilder sb = new StringBuilder(); |
104 | String separator = ""; |
105 | for (Object arg : args) { |
106 | sb.append(separator).append(arg.toString()); |
107 | separator = File.pathSeparator; |
108 | } |
109 | newArgs = sb.toString(); |
110 | } |
111 | return newArgs; |
112 | } |
113 | |
114 | private void setOption1(String name, OptionKind kind, Object... args) { |
115 | String arg = argsToString(args); |
116 | JavacOption option = sharedCompiler.getOption(name); |
117 | if (option == null || !match(kind, option.getKind())) |
118 | throw new IllegalArgumentException(name); |
119 | if ((args.length != 0) != option.hasArg()) |
120 | throw new IllegalArgumentException(name); |
121 | if (option.hasArg()) { |
122 | if (option.process(null, name, arg)) // FIXME |
123 | throw new IllegalArgumentException(name); |
124 | } else { |
125 | if (option.process(null, name)) // FIXME |
126 | throw new IllegalArgumentException(name); |
127 | } |
128 | options.add(new Pair<String,String>(name,arg)); |
129 | } |
130 | |
131 | public void setOption(String name, Object... args) { |
132 | setOption1(name, OptionKind.NORMAL, args); |
133 | } |
134 | |
135 | public void setExtendedOption(String name, Object... args) { |
136 | setOption1(name, OptionKind.EXTENDED, args); |
137 | } |
138 | |
139 | private static boolean match(OptionKind clientKind, OptionKind optionKind) { |
140 | return (clientKind == (optionKind == OptionKind.HIDDEN ? optionKind.EXTENDED : optionKind)); |
141 | } |
142 | |
143 | public JavacFileManager getStandardFileManager( |
144 | DiagnosticListener<? super JavaFileObject> diagnosticListener, |
145 | Locale locale, |
146 | Charset charset) { |
147 | Context context = new Context(); |
148 | if (diagnosticListener != null) |
149 | context.put(DiagnosticListener.class, diagnosticListener); |
150 | context.put(Log.outKey, new PrintWriter(System.err, true)); // FIXME |
151 | return new JavacFileManager(context, true, charset); |
152 | } |
153 | |
154 | private boolean compilationInProgress = false; |
155 | |
156 | /** |
157 | * Register that a compilation is about to start. |
158 | */ |
159 | void beginContext(final Context context) { |
160 | if (compilationInProgress) |
161 | throw new IllegalStateException("Compilation in progress"); |
162 | compilationInProgress = true; |
163 | final JavaFileManager givenFileManager = context.get(JavaFileManager.class); |
164 | context.put(JavaFileManager.class, (JavaFileManager)null); |
165 | context.put(JavaFileManager.class, new Context.Factory<JavaFileManager>() { |
166 | public JavaFileManager make() { |
167 | if (givenFileManager != null) { |
168 | context.put(JavaFileManager.class, givenFileManager); |
169 | return givenFileManager; |
170 | } else { |
171 | return new JavacFileManager(context, true, null); |
172 | } |
173 | } |
174 | }); |
175 | } |
176 | |
177 | /** |
178 | * Register that a compilation is completed. |
179 | */ |
180 | void endContext() { |
181 | compilationInProgress = false; |
182 | } |
183 | |
184 | public JavacTask getTask(Writer out, |
185 | JavaFileManager fileManager, |
186 | DiagnosticListener<? super JavaFileObject> diagnosticListener, |
187 | Iterable<String> options, |
188 | Iterable<String> classes, |
189 | Iterable<? extends JavaFileObject> compilationUnits) |
190 | { |
191 | final String kindMsg = "All compilation units must be of SOURCE kind"; |
192 | if (options != null) |
193 | for (String option : options) |
194 | option.getClass(); // null check |
195 | if (classes != null) { |
196 | for (String cls : classes) |
197 | if (!SourceVersion.isName(cls)) // implicit null check |
198 | throw new IllegalArgumentException("Not a valid class name: " + cls); |
199 | } |
200 | if (compilationUnits != null) { |
201 | for (JavaFileObject cu : compilationUnits) { |
202 | if (cu.getKind() != JavaFileObject.Kind.SOURCE) // implicit null check |
203 | throw new IllegalArgumentException(kindMsg); |
204 | } |
205 | } |
206 | |
207 | Context context = new Context(); |
208 | |
209 | if (diagnosticListener != null) |
210 | context.put(DiagnosticListener.class, diagnosticListener); |
211 | |
212 | if (out == null) |
213 | context.put(Log.outKey, new PrintWriter(System.err, true)); |
214 | else |
215 | context.put(Log.outKey, new PrintWriter(out, true)); |
216 | |
217 | if (fileManager == null) |
218 | fileManager = getStandardFileManager(diagnosticListener, null, null); |
219 | context.put(JavaFileManager.class, fileManager); |
220 | processOptions(context, fileManager, options); |
221 | Main compiler = new Main("javacTask", context.get(Log.outKey)); |
222 | return new JavacTaskImpl(this, compiler, options, context, classes, compilationUnits); |
223 | } |
224 | |
225 | private static void processOptions(Context context, |
226 | JavaFileManager fileManager, |
227 | Iterable<String> options) |
228 | { |
229 | if (options == null) |
230 | return; |
231 | |
232 | Options optionTable = Options.instance(context); |
233 | |
234 | JavacOption[] recognizedOptions = |
235 | RecognizedOptions.getJavacToolOptions(new GrumpyHelper()); |
236 | Iterator<String> flags = options.iterator(); |
237 | while (flags.hasNext()) { |
238 | String flag = flags.next(); |
239 | int j; |
240 | for (j=0; j<recognizedOptions.length; j++) |
241 | if (recognizedOptions[j].matches(flag)) |
242 | break; |
243 | |
244 | if (j == recognizedOptions.length) { |
245 | if (fileManager.handleOption(flag, flags)) { |
246 | continue; |
247 | } else { |
248 | String msg = Main.getLocalizedString("err.invalid.flag", flag); |
249 | throw new IllegalArgumentException(msg); |
250 | } |
251 | } |
252 | |
253 | JavacOption option = recognizedOptions[j]; |
254 | if (option.hasArg()) { |
255 | if (!flags.hasNext()) { |
256 | String msg = Main.getLocalizedString("err.req.arg", flag); |
257 | throw new IllegalArgumentException(msg); |
258 | } |
259 | String operand = flags.next(); |
260 | if (option.process(optionTable, flag, operand)) |
261 | // should not happen as the GrumpyHelper will throw exceptions |
262 | // in case of errors |
263 | throw new IllegalArgumentException(flag + " " + operand); |
264 | } else { |
265 | if (option.process(optionTable, flag)) |
266 | // should not happen as the GrumpyHelper will throw exceptions |
267 | // in case of errors |
268 | throw new IllegalArgumentException(flag); |
269 | } |
270 | } |
271 | } |
272 | |
273 | public int run(InputStream in, OutputStream out, OutputStream err, String... arguments) { |
274 | if (err == null) |
275 | err = System.err; |
276 | for (String argument : arguments) |
277 | argument.getClass(); // null check |
278 | return com.sun.tools.javac.Main.compile(arguments, new PrintWriter(err, true)); |
279 | } |
280 | |
281 | public Set<SourceVersion> getSourceVersions() { |
282 | return Collections.unmodifiableSet(EnumSet.range(SourceVersion.RELEASE_3, |
283 | SourceVersion.latest())); |
284 | } |
285 | |
286 | public int isSupportedOption(String option) { |
287 | JavacOption[] recognizedOptions = |
288 | RecognizedOptions.getJavacToolOptions(new GrumpyHelper()); |
289 | for (JavacOption o : recognizedOptions) { |
290 | if (o.matches(option)) |
291 | return o.hasArg() ? 1 : 0; |
292 | } |
293 | return -1; |
294 | } |
295 | |
296 | } |