View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.jci.compilers;
18  
19  import java.io.ByteArrayOutputStream;
20  import java.io.IOException;
21  import java.io.InputStream;
22  import java.util.ArrayList;
23  import java.util.Collection;
24  import java.util.Locale;
25  import java.util.Map;
26  import java.util.StringTokenizer;
27  
28  import org.apache.commons.jci.problems.CompilationProblem;
29  import org.apache.commons.jci.readers.ResourceReader;
30  import org.apache.commons.jci.stores.ResourceStore;
31  import org.apache.commons.jci.utils.ConversionUtils;
32  import org.apache.commons.logging.Log;
33  import org.apache.commons.logging.LogFactory;
34  import org.eclipse.jdt.core.compiler.IProblem;
35  import org.eclipse.jdt.internal.compiler.ClassFile;
36  import org.eclipse.jdt.internal.compiler.CompilationResult;
37  import org.eclipse.jdt.internal.compiler.Compiler;
38  import org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies;
39  import org.eclipse.jdt.internal.compiler.ICompilerRequestor;
40  import org.eclipse.jdt.internal.compiler.IErrorHandlingPolicy;
41  import org.eclipse.jdt.internal.compiler.IProblemFactory;
42  import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader;
43  import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException;
44  import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
45  import org.eclipse.jdt.internal.compiler.env.INameEnvironment;
46  import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer;
47  import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory;
48  
49  /**
50   * Eclipse compiler implemenation
51   * 
52   * @author tcurdt
53   */
54  public final class EclipseJavaCompiler extends AbstractJavaCompiler {
55  
56      private final Log log = LogFactory.getLog(EclipseJavaCompiler.class);
57      private final EclipseJavaCompilerSettings defaultSettings;
58  
59      public EclipseJavaCompiler() {
60          this(new EclipseJavaCompilerSettings());
61      }
62  
63      public EclipseJavaCompiler(final Map pSettings) {
64          defaultSettings = new EclipseJavaCompilerSettings(pSettings);
65      }
66  
67      public EclipseJavaCompiler(final EclipseJavaCompilerSettings pSettings) {
68          defaultSettings = pSettings;
69      }
70  
71      final class CompilationUnit implements ICompilationUnit {
72  
73          final private String clazzName;
74          final private String fileName;
75          final private char[] typeName;
76          final private char[][] packageName;
77          final private ResourceReader reader;
78  
79          CompilationUnit( final ResourceReader pReader, final String pSourceFile ) {
80              reader = pReader;
81              clazzName = ConversionUtils.convertResourceToClassName(pSourceFile);
82              fileName = pSourceFile;
83              int dot = clazzName.lastIndexOf('.');
84              if (dot > 0) {
85                  typeName = clazzName.substring(dot + 1).toCharArray();
86              } else {
87                  typeName = clazzName.toCharArray();
88              }
89              
90              log.debug("className=" + clazzName);
91              log.debug("fileName=" + fileName);
92              log.debug("typeName=" + new String(typeName)); 
93              
94              final StringTokenizer izer = new StringTokenizer(clazzName, ".");
95              packageName = new char[izer.countTokens() - 1][];
96              for (int i = 0; i < packageName.length; i++) {
97                  packageName[i] = izer.nextToken().toCharArray();
98                  log.debug("package[" + i + "]=" + new String(packageName[i]));
99              }
100         }
101 
102         public char[] getFileName() {
103             return fileName.toCharArray();
104         }
105 
106         public char[] getContents() {
107             final byte[] content = reader.getBytes(fileName);
108 
109             if (content == null) {
110                 return null;
111                 //throw new RuntimeException("resource " + fileName + " could not be found");
112             }
113 
114             return new String(content).toCharArray();
115         }
116 
117         public char[] getMainTypeName() {
118             return typeName;
119         }
120 
121         public char[][] getPackageName() {
122             return packageName;
123         }
124     }
125 
126     
127     public org.apache.commons.jci.compilers.CompilationResult compile(
128             final String[] pSourceFiles,
129             final ResourceReader pReader,
130             final ResourceStore pStore,
131             final ClassLoader pClassLoader,
132             final JavaCompilerSettings pSettings
133             ) {
134 
135         final Map settingsMap = ((EclipseJavaCompilerSettings) defaultSettings).getMap();
136         
137         final Collection problems = new ArrayList();
138         
139         final ICompilationUnit[] compilationUnits = new ICompilationUnit[pSourceFiles.length];
140         for (int i = 0; i < compilationUnits.length; i++) {
141             final String sourceFile = pSourceFiles[i];
142             
143             if (pReader.isAvailable(sourceFile)) {            
144                 compilationUnits[i] = new CompilationUnit(pReader, sourceFile);
145                 log.debug("compiling " + sourceFile);
146             } else {
147                 // log.error("source not found " + sourceFile);
148 
149                 final CompilationProblem problem = new CompilationProblem() {
150 
151                     public int getEndColumn() {
152                         return 0;
153                     }
154 
155                     public int getEndLine() {
156                         return 0;
157                     }
158 
159                     public String getFileName() {
160                         return sourceFile;
161                     }
162 
163                     public String getMessage() {
164                         return "Source " + sourceFile + " could not be found";
165                     }
166 
167                     public int getStartColumn() {
168                         return 0;
169                     }
170 
171                     public int getStartLine() {
172                         return 0;
173                     }
174 
175                     public boolean isError() {
176                         return true;
177                     }
178                     
179                     public String toString() {
180                         return getMessage();
181                     }
182                 };
183 
184                 if (problemHandler != null) {
185                     problemHandler.handle(problem);
186                 }
187                 
188                 problems.add(problem);
189             }
190         }
191 
192         if (problems.size() > 0) {
193             final CompilationProblem[] result = new CompilationProblem[problems.size()];
194             problems.toArray(result);
195             return new org.apache.commons.jci.compilers.CompilationResult(result);
196         }
197         
198         final IErrorHandlingPolicy policy = DefaultErrorHandlingPolicies.proceedWithAllProblems();
199         final IProblemFactory problemFactory = new DefaultProblemFactory(Locale.getDefault());
200         final INameEnvironment nameEnvironment = new INameEnvironment() {
201 
202             public NameEnvironmentAnswer findType( final char[][] pCompoundTypeName ) {
203                 final StringBuffer result = new StringBuffer();
204                 for (int i = 0; i < pCompoundTypeName.length; i++) {
205                     if (i != 0) {
206                         result.append('.');
207                     }
208                     result.append(pCompoundTypeName[i]);
209                 }
210 
211                 //log.debug("finding compoundTypeName=" + result.toString());
212 
213                 return findType(result.toString());
214             }
215 
216             public NameEnvironmentAnswer findType( final char[] pTypeName, final char[][] pPackageName ) {
217                 final StringBuffer result = new StringBuffer();
218                 for (int i = 0; i < pPackageName.length; i++) {
219                     result.append(pPackageName[i]);
220                     result.append('.');
221                 }
222                 
223 //                log.debug("finding typeName=" + new String(typeName) + " packageName=" + result.toString());
224 
225                 result.append(pTypeName);
226                 return findType(result.toString());
227             }
228 
229             private NameEnvironmentAnswer findType( final String pClazzName ) {
230                 
231                 if (isPackage(pClazzName)) {
232                     return null;
233                 }
234                 
235                 log.debug("finding " + pClazzName);
236                 
237                 final String resourceName = ConversionUtils.convertClassToResourcePath(pClazzName);
238                 
239                 final byte[] clazzBytes = pStore.read(pClazzName);
240                 if (clazzBytes != null) {
241                     log.debug("loading from store " + pClazzName);
242 
243                     final char[] fileName = pClazzName.toCharArray();
244                     try {
245                         final ClassFileReader classFileReader = new ClassFileReader(clazzBytes, fileName, true);
246                         return new NameEnvironmentAnswer(classFileReader, null);
247                     } catch (final ClassFormatException e) {
248                         log.error("wrong class format", e);
249                         return null;
250                     }
251                 }
252                 
253                 log.debug("not in store " + pClazzName);
254                 
255                 final InputStream is = pClassLoader.getResourceAsStream(resourceName);
256                 if (is == null) {
257                     log.debug("class " + pClazzName + " not found");
258                     return null;
259                 }
260 
261                 final byte[] buffer = new byte[8192];
262                 final ByteArrayOutputStream baos = new ByteArrayOutputStream(buffer.length);
263                 int count;
264                 try {
265                     while ((count = is.read(buffer, 0, buffer.length)) > 0) {
266                         baos.write(buffer, 0, count);
267                     }
268                     baos.flush();
269                     final char[] fileName = pClazzName.toCharArray();
270                     final ClassFileReader classFileReader = new ClassFileReader(baos.toByteArray(), fileName, true);
271                     return new NameEnvironmentAnswer(classFileReader, null);
272                 } catch (final IOException e) {
273                     log.error("could not read class", e);
274                     return null;
275                 } catch (final ClassFormatException e) {
276                     log.error("wrong class format", e);
277                     return null;
278                 } finally {
279                     try {
280                         baos.close();
281                     } catch (final IOException oe) {
282                         log.error("could not close output stream", oe);
283                     }
284                     try {
285                         is.close();
286                     } catch (final IOException ie) {
287                         log.error("could not close input stream", ie);
288                     }
289                 }
290             }
291 
292             private boolean isPackage( final String pClazzName ) {
293                 
294                 final InputStream is = pClassLoader.getResourceAsStream(ConversionUtils.convertClassToResourcePath(pClazzName));
295                 if (is != null) {
296                     log.debug("found the class for " + pClazzName + "- no package");
297                     return false;
298                 }
299                 
300                 // FIXME: this should not be tied to the extension
301                 final String source = pClazzName.replace('.', '/') + ".java";
302                 if (pReader.isAvailable(source)) {
303                     log.debug("found the source " + source + " for " + pClazzName + " - no package ");
304                     return false;
305                 }
306                 
307                 return true;
308             }
309 
310             public boolean isPackage( char[][] parentPackageName, char[] pPackageName ) {
311                 final StringBuffer result = new StringBuffer();
312                 if (parentPackageName != null) {
313                     for (int i = 0; i < parentPackageName.length; i++) {
314                         if (i != 0) {
315                             result.append('.');
316                         }
317                         result.append(parentPackageName[i]);
318                     }
319                 }
320                 
321 //                log.debug("isPackage parentPackageName=" + result.toString() + " packageName=" + new String(packageName));
322                 
323                 if (parentPackageName != null && parentPackageName.length > 0) {
324                     result.append('.');
325                 }
326                 result.append(pPackageName);
327                 return isPackage(result.toString());
328             }
329 
330             public void cleanup() {
331                 log.debug("cleanup");
332             }
333         };
334 
335         final ICompilerRequestor compilerRequestor = new ICompilerRequestor() {
336             public void acceptResult( final CompilationResult pResult ) {
337                 if (pResult.hasProblems()) {
338                     final IProblem[] iproblems = pResult.getProblems();
339                     for (int i = 0; i < iproblems.length; i++) {
340                         final IProblem iproblem = iproblems[i];
341                         final CompilationProblem problem = new EclipseCompilationProblem(iproblem); 
342                         if (problemHandler != null) {
343                             problemHandler.handle(problem);
344                         }
345                         problems.add(problem);
346                     }
347                 }
348                 if (!pResult.hasErrors()) {
349                     final ClassFile[] clazzFiles = pResult.getClassFiles();
350                     for (int i = 0; i < clazzFiles.length; i++) {
351                         final ClassFile clazzFile = clazzFiles[i];
352                         final char[][] compoundName = clazzFile.getCompoundName();
353                         final StringBuffer clazzName = new StringBuffer();
354                         for (int j = 0; j < compoundName.length; j++) {
355                             if (j != 0) {
356                                 clazzName.append('.');
357                             }
358                             clazzName.append(compoundName[j]);
359                         }
360                         pStore.write(clazzName.toString().replace('.', '/') + ".class", clazzFile.getBytes());
361                     }
362                 }
363             }
364         };
365 
366         final Compiler compiler = new Compiler(nameEnvironment, policy, settingsMap, compilerRequestor, problemFactory, false);
367 
368         compiler.compile(compilationUnits);
369 
370         final CompilationProblem[] result = new CompilationProblem[problems.size()];
371         problems.toArray(result);
372         return new org.apache.commons.jci.compilers.CompilationResult(result);
373     }
374 
375     public JavaCompilerSettings createDefaultSettings() {
376         return defaultSettings;
377     }
378 }