1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.jci.compilers;
19
20 import java.io.BufferedReader;
21 import java.io.IOException;
22 import java.io.PrintWriter;
23 import java.io.StringReader;
24 import java.io.StringWriter;
25 import java.lang.reflect.Method;
26 import java.util.ArrayList;
27 import java.util.List;
28 import java.util.NoSuchElementException;
29 import java.util.StringTokenizer;
30
31 import org.apache.commons.jci.problems.CompilationProblem;
32 import org.apache.commons.jci.readers.ResourceReader;
33 import org.apache.commons.jci.stores.ResourceStore;
34
35
36
37
38
39
40
41
42
43
44
45
46 public final class JavacJavaCompiler extends AbstractJavaCompiler {
47
48 private static final String EOL = System.getProperty("line.separator");
49 private static final String WARNING_PREFIX = "warning: ";
50 private static final String NOTE_PREFIX = "Note: ";
51 private static final String ERROR_PREFIX = "error: ";
52
53 private final JavacJavaCompilerSettings settings;
54
55 public JavacJavaCompiler() {
56 settings = new JavacJavaCompilerSettings();
57 }
58
59 public JavacJavaCompiler( final JavacJavaCompilerSettings pSettings ) {
60 settings = pSettings;
61 }
62
63 public CompilationResult compile( final String[] pSourcePaths, final ResourceReader pReader, ResourceStore pStore, final ClassLoader pClasspathClassLoader, final JavaCompilerSettings pSettings ) {
64
65 try {
66 final ClassLoader cl = new JavacClassLoader(pClasspathClassLoader);
67 final Class renamedClass = cl.loadClass("com.sun.tools.javac.Main");
68
69 FileInputStreamProxy.setResourceReader(pReader);
70 FileOutputStreamProxy.setResourceStore(pStore);
71
72 final Method compile = renamedClass.getMethod("compile", new Class[] { String[].class, PrintWriter.class });
73 final StringWriter out = new StringWriter();
74 final Integer ok = (Integer) compile.invoke(null, new Object[] { buildCompilerArguments(pSourcePaths, pClasspathClassLoader), new PrintWriter(out) });
75
76 final CompilationResult result = parseModernStream(new BufferedReader(new StringReader(out.toString())));
77
78 if (result.getErrors().length == 0 && ok.intValue() != 0) {
79 return new CompilationResult(new CompilationProblem[] {
80 new JavacCompilationProblem("Failure executing javac, but could not parse the error: " + out.toString(), true) });
81 }
82
83 return result;
84
85 } catch(Exception e) {
86 return new CompilationResult(new CompilationProblem[] {
87 new JavacCompilationProblem("Error while executing the compiler: " + e.toString(), true) });
88 } finally {
89
90 FileInputStreamProxy.setResourceReader(null);
91 FileOutputStreamProxy.setResourceStore(null);
92 }
93 }
94
95 private CompilationResult parseModernStream( final BufferedReader pReader ) throws IOException {
96 final List problems = new ArrayList();
97 String line;
98
99 while (true) {
100
101 final StringBuffer buffer = new StringBuffer();
102
103
104 do {
105 line = pReader.readLine();
106 if (line == null) {
107 return new CompilationResult((CompilationProblem[]) problems.toArray(new CompilationProblem[problems.size()]));
108 }
109
110
111 if (buffer.length() == 0 && line.startsWith(ERROR_PREFIX)) {
112 problems.add(new JavacCompilationProblem(line, true));
113 }
114 else if (buffer.length() == 0 && line.startsWith(NOTE_PREFIX)) {
115
116
117 } else {
118 buffer.append(line);
119 buffer.append(EOL);
120 }
121 } while (!line.endsWith("^"));
122
123
124 problems.add(parseModernError(buffer.toString()));
125 }
126 }
127
128 private CompilationProblem parseModernError( final String pError ) {
129 final StringTokenizer tokens = new StringTokenizer(pError, ":");
130 boolean isError = true;
131 try {
132 String file = tokens.nextToken();
133
134 if (file.length() == 1) {
135 file = new StringBuffer(file).append(":").append(
136 tokens.nextToken()).toString();
137 }
138 final int line = Integer.parseInt(tokens.nextToken());
139 final StringBuffer msgBuffer = new StringBuffer();
140
141 String msg = tokens.nextToken(EOL).substring(2);
142 isError = !msg.startsWith(WARNING_PREFIX);
143
144
145 if (!isError) {
146 msg = msg.substring(WARNING_PREFIX.length());
147 }
148 msgBuffer.append(msg);
149
150 String context = tokens.nextToken(EOL);
151 String pointer = tokens.nextToken(EOL);
152
153 if (tokens.hasMoreTokens()) {
154 msgBuffer.append(EOL);
155 msgBuffer.append(context);
156 msgBuffer.append(EOL);
157 msgBuffer.append(pointer);
158 msgBuffer.append(EOL);
159
160 context = tokens.nextToken(EOL);
161
162 try {
163 pointer = tokens.nextToken(EOL);
164 } catch (NoSuchElementException e) {
165 pointer = context;
166 context = null;
167 }
168 }
169 final String message = msgBuffer.toString();
170 int startcolumn = pointer.indexOf("^");
171 int endcolumn = context == null ? startcolumn : context.indexOf(" ", startcolumn);
172 if (endcolumn == -1) {
173 endcolumn = context.length();
174 }
175 return new JavacCompilationProblem(file, isError, line, startcolumn, line, endcolumn, message);
176 }
177 catch (NoSuchElementException e) {
178 return new JavacCompilationProblem("no more tokens - could not parse error message: " + pError, isError);
179 }
180 catch (NumberFormatException e) {
181 return new JavacCompilationProblem("could not parse error message: " + pError, isError);
182 }
183 catch (Exception e) {
184 return new JavacCompilationProblem("could not parse error message: " + pError, isError);
185 }
186 }
187
188 public JavaCompilerSettings createDefaultSettings() {
189 return settings;
190 }
191
192 private String[] buildCompilerArguments( final String[] resourcePaths, final ClassLoader classloader ) {
193
194
195 return resourcePaths;
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264 }
265 }