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 defaultSettings;
54
55 public JavacJavaCompiler() {
56 defaultSettings = new JavacJavaCompilerSettings();
57 }
58
59 public JavacJavaCompiler( final JavacJavaCompilerSettings pSettings ) {
60 defaultSettings = 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
75 final String[] compilerArguments = buildCompilerArguments(new JavacJavaCompilerSettings(pSettings), pSourcePaths, pClasspathClassLoader);
76
77 final Integer ok = (Integer) compile.invoke(null, new Object[] { compilerArguments, new PrintWriter(out) });
78
79 final CompilationResult result = parseModernStream(new BufferedReader(new StringReader(out.toString())));
80
81 if (result.getErrors().length == 0 && ok.intValue() != 0) {
82 return new CompilationResult(new CompilationProblem[] {
83 new JavacCompilationProblem("Failure executing javac, but could not parse the error: " + out.toString(), true) });
84 }
85
86 return result;
87
88 } catch(Exception e) {
89 return new CompilationResult(new CompilationProblem[] {
90 new JavacCompilationProblem("Error while executing the compiler: " + e.toString(), true) });
91 } finally {
92
93 FileInputStreamProxy.setResourceReader(null);
94 FileOutputStreamProxy.setResourceStore(null);
95 }
96 }
97
98 private CompilationResult parseModernStream( final BufferedReader pReader ) throws IOException {
99 final List problems = new ArrayList();
100 String line;
101
102 while (true) {
103
104 final StringBuffer buffer = new StringBuffer();
105
106
107 do {
108 line = pReader.readLine();
109 if (line == null) {
110 return new CompilationResult((CompilationProblem[]) problems.toArray(new CompilationProblem[problems.size()]));
111 }
112
113
114 if (buffer.length() == 0 && line.startsWith(ERROR_PREFIX)) {
115 problems.add(new JavacCompilationProblem(line, true));
116 }
117 else if (buffer.length() == 0 && line.startsWith(NOTE_PREFIX)) {
118
119
120 } else {
121 buffer.append(line);
122 buffer.append(EOL);
123 }
124 } while (!line.endsWith("^"));
125
126
127 problems.add(parseModernError(buffer.toString()));
128 }
129 }
130
131 private CompilationProblem parseModernError( final String pError ) {
132 final StringTokenizer tokens = new StringTokenizer(pError, ":");
133 boolean isError = true;
134 try {
135 String file = tokens.nextToken();
136
137 if (file.length() == 1) {
138 file = new StringBuffer(file).append(":").append(
139 tokens.nextToken()).toString();
140 }
141 final int line = Integer.parseInt(tokens.nextToken());
142 final StringBuffer msgBuffer = new StringBuffer();
143
144 String msg = tokens.nextToken(EOL).substring(2);
145 isError = !msg.startsWith(WARNING_PREFIX);
146
147
148 if (!isError) {
149 msg = msg.substring(WARNING_PREFIX.length());
150 }
151 msgBuffer.append(msg);
152
153 String context = tokens.nextToken(EOL);
154 String pointer = tokens.nextToken(EOL);
155
156 if (tokens.hasMoreTokens()) {
157 msgBuffer.append(EOL);
158 msgBuffer.append(context);
159 msgBuffer.append(EOL);
160 msgBuffer.append(pointer);
161 msgBuffer.append(EOL);
162
163 context = tokens.nextToken(EOL);
164
165 try {
166 pointer = tokens.nextToken(EOL);
167 } catch (NoSuchElementException e) {
168 pointer = context;
169 context = null;
170 }
171 }
172 final String message = msgBuffer.toString();
173 int startcolumn = pointer.indexOf("^");
174 int endcolumn = context == null ? startcolumn : context.indexOf(" ", startcolumn);
175 if (endcolumn == -1) {
176 endcolumn = context.length();
177 }
178 return new JavacCompilationProblem(file, isError, line, startcolumn, line, endcolumn, message);
179 }
180 catch (NoSuchElementException e) {
181 return new JavacCompilationProblem("no more tokens - could not parse error message: " + pError, isError);
182 }
183 catch (NumberFormatException e) {
184 return new JavacCompilationProblem("could not parse error message: " + pError, isError);
185 }
186 catch (Exception e) {
187 return new JavacCompilationProblem("could not parse error message: " + pError, isError);
188 }
189 }
190
191 public JavaCompilerSettings createDefaultSettings() {
192 return new JavacJavaCompilerSettings(defaultSettings);
193 }
194
195 private String[] buildCompilerArguments( final JavacJavaCompilerSettings pSettings, final String[] pResourcePaths, final ClassLoader pClassloader ) {
196
197
198 final String[] classpath = new String[0];
199 final String[] resources = pResourcePaths;
200 final String[] args = pSettings.toNativeSettings();
201
202 final String[] result = new String[classpath.length + resources.length + args.length];
203
204 System.arraycopy(classpath, 0, result, 0, classpath.length);
205 System.arraycopy(resources, 0, result, classpath.length, resources.length);
206 System.arraycopy(args, 0, result, classpath.length + resources.length, args.length);
207
208 return result;
209 }
210
211 }