001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.commons.jci.compilers;
018:
019: import java.io.ByteArrayOutputStream;
020: import java.io.IOException;
021: import java.io.InputStream;
022: import java.util.ArrayList;
023: import java.util.Collection;
024: import java.util.Locale;
025: import java.util.Map;
026: import java.util.StringTokenizer;
027:
028: import org.apache.commons.jci.problems.CompilationProblem;
029: import org.apache.commons.jci.readers.ResourceReader;
030: import org.apache.commons.jci.stores.ResourceStore;
031: import org.apache.commons.jci.utils.ConversionUtils;
032: import org.apache.commons.logging.Log;
033: import org.apache.commons.logging.LogFactory;
034: import org.eclipse.jdt.core.compiler.IProblem;
035: import org.eclipse.jdt.internal.compiler.ClassFile;
036: import org.eclipse.jdt.internal.compiler.CompilationResult;
037: import org.eclipse.jdt.internal.compiler.Compiler;
038: import org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies;
039: import org.eclipse.jdt.internal.compiler.ICompilerRequestor;
040: import org.eclipse.jdt.internal.compiler.IErrorHandlingPolicy;
041: import org.eclipse.jdt.internal.compiler.IProblemFactory;
042: import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader;
043: import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException;
044: import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
045: import org.eclipse.jdt.internal.compiler.env.INameEnvironment;
046: import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer;
047: import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory;
048:
049: /**
050: * Eclipse compiler implemenation
051: *
052: * @author tcurdt
053: */
054: public final class EclipseJavaCompiler extends AbstractJavaCompiler {
055:
056: private final Log log = LogFactory
057: .getLog(EclipseJavaCompiler.class);
058: private final EclipseJavaCompilerSettings defaultSettings;
059:
060: public EclipseJavaCompiler() {
061: this (new EclipseJavaCompilerSettings());
062: }
063:
064: public EclipseJavaCompiler(final Map pSettings) {
065: defaultSettings = new EclipseJavaCompilerSettings(pSettings);
066: }
067:
068: public EclipseJavaCompiler(
069: final EclipseJavaCompilerSettings pSettings) {
070: defaultSettings = pSettings;
071: }
072:
073: final class CompilationUnit implements ICompilationUnit {
074:
075: final private String clazzName;
076: final private String fileName;
077: final private char[] typeName;
078: final private char[][] packageName;
079: final private ResourceReader reader;
080:
081: CompilationUnit(final ResourceReader pReader,
082: final String pSourceFile) {
083: reader = pReader;
084: clazzName = ConversionUtils
085: .convertResourceToClassName(pSourceFile);
086: fileName = pSourceFile;
087: int dot = clazzName.lastIndexOf('.');
088: if (dot > 0) {
089: typeName = clazzName.substring(dot + 1).toCharArray();
090: } else {
091: typeName = clazzName.toCharArray();
092: }
093:
094: log.debug("className=" + clazzName);
095: log.debug("fileName=" + fileName);
096: log.debug("typeName=" + new String(typeName));
097:
098: final StringTokenizer izer = new StringTokenizer(clazzName,
099: ".");
100: packageName = new char[izer.countTokens() - 1][];
101: for (int i = 0; i < packageName.length; i++) {
102: packageName[i] = izer.nextToken().toCharArray();
103: log.debug("package[" + i + "]="
104: + new String(packageName[i]));
105: }
106: }
107:
108: public char[] getFileName() {
109: return fileName.toCharArray();
110: }
111:
112: public char[] getContents() {
113: final byte[] content = reader.getBytes(fileName);
114:
115: if (content == null) {
116: return null;
117: //throw new RuntimeException("resource " + fileName + " could not be found");
118: }
119:
120: return new String(content).toCharArray();
121: }
122:
123: public char[] getMainTypeName() {
124: return typeName;
125: }
126:
127: public char[][] getPackageName() {
128: return packageName;
129: }
130: }
131:
132: public org.apache.commons.jci.compilers.CompilationResult compile(
133: final String[] pSourceFiles, final ResourceReader pReader,
134: final ResourceStore pStore, final ClassLoader pClassLoader,
135: final JavaCompilerSettings pSettings) {
136:
137: final Map settingsMap = ((EclipseJavaCompilerSettings) defaultSettings)
138: .getMap();
139:
140: final Collection problems = new ArrayList();
141:
142: final ICompilationUnit[] compilationUnits = new ICompilationUnit[pSourceFiles.length];
143: for (int i = 0; i < compilationUnits.length; i++) {
144: final String sourceFile = pSourceFiles[i];
145:
146: if (pReader.isAvailable(sourceFile)) {
147: compilationUnits[i] = new CompilationUnit(pReader,
148: sourceFile);
149: log.debug("compiling " + sourceFile);
150: } else {
151: // log.error("source not found " + sourceFile);
152:
153: final CompilationProblem problem = new CompilationProblem() {
154:
155: public int getEndColumn() {
156: return 0;
157: }
158:
159: public int getEndLine() {
160: return 0;
161: }
162:
163: public String getFileName() {
164: return sourceFile;
165: }
166:
167: public String getMessage() {
168: return "Source " + sourceFile
169: + " could not be found";
170: }
171:
172: public int getStartColumn() {
173: return 0;
174: }
175:
176: public int getStartLine() {
177: return 0;
178: }
179:
180: public boolean isError() {
181: return true;
182: }
183:
184: public String toString() {
185: return getMessage();
186: }
187: };
188:
189: if (problemHandler != null) {
190: problemHandler.handle(problem);
191: }
192:
193: problems.add(problem);
194: }
195: }
196:
197: if (problems.size() > 0) {
198: final CompilationProblem[] result = new CompilationProblem[problems
199: .size()];
200: problems.toArray(result);
201: return new org.apache.commons.jci.compilers.CompilationResult(
202: result);
203: }
204:
205: final IErrorHandlingPolicy policy = DefaultErrorHandlingPolicies
206: .proceedWithAllProblems();
207: final IProblemFactory problemFactory = new DefaultProblemFactory(
208: Locale.getDefault());
209: final INameEnvironment nameEnvironment = new INameEnvironment() {
210:
211: public NameEnvironmentAnswer findType(
212: final char[][] pCompoundTypeName) {
213: final StringBuffer result = new StringBuffer();
214: for (int i = 0; i < pCompoundTypeName.length; i++) {
215: if (i != 0) {
216: result.append('.');
217: }
218: result.append(pCompoundTypeName[i]);
219: }
220:
221: //log.debug("finding compoundTypeName=" + result.toString());
222:
223: return findType(result.toString());
224: }
225:
226: public NameEnvironmentAnswer findType(
227: final char[] pTypeName, final char[][] pPackageName) {
228: final StringBuffer result = new StringBuffer();
229: for (int i = 0; i < pPackageName.length; i++) {
230: result.append(pPackageName[i]);
231: result.append('.');
232: }
233:
234: // log.debug("finding typeName=" + new String(typeName) + " packageName=" + result.toString());
235:
236: result.append(pTypeName);
237: return findType(result.toString());
238: }
239:
240: private NameEnvironmentAnswer findType(
241: final String pClazzName) {
242:
243: if (isPackage(pClazzName)) {
244: return null;
245: }
246:
247: log.debug("finding " + pClazzName);
248:
249: final String resourceName = ConversionUtils
250: .convertClassToResourcePath(pClazzName);
251:
252: final byte[] clazzBytes = pStore.read(pClazzName);
253: if (clazzBytes != null) {
254: log.debug("loading from store " + pClazzName);
255:
256: final char[] fileName = pClazzName.toCharArray();
257: try {
258: final ClassFileReader classFileReader = new ClassFileReader(
259: clazzBytes, fileName, true);
260: return new NameEnvironmentAnswer(
261: classFileReader, null);
262: } catch (final ClassFormatException e) {
263: log.error("wrong class format", e);
264: return null;
265: }
266: }
267:
268: log.debug("not in store " + pClazzName);
269:
270: final InputStream is = pClassLoader
271: .getResourceAsStream(resourceName);
272: if (is == null) {
273: log.debug("class " + pClazzName + " not found");
274: return null;
275: }
276:
277: final byte[] buffer = new byte[8192];
278: final ByteArrayOutputStream baos = new ByteArrayOutputStream(
279: buffer.length);
280: int count;
281: try {
282: while ((count = is.read(buffer, 0, buffer.length)) > 0) {
283: baos.write(buffer, 0, count);
284: }
285: baos.flush();
286: final char[] fileName = pClazzName.toCharArray();
287: final ClassFileReader classFileReader = new ClassFileReader(
288: baos.toByteArray(), fileName, true);
289: return new NameEnvironmentAnswer(classFileReader,
290: null);
291: } catch (final IOException e) {
292: log.error("could not read class", e);
293: return null;
294: } catch (final ClassFormatException e) {
295: log.error("wrong class format", e);
296: return null;
297: } finally {
298: try {
299: baos.close();
300: } catch (final IOException oe) {
301: log.error("could not close output stream", oe);
302: }
303: try {
304: is.close();
305: } catch (final IOException ie) {
306: log.error("could not close input stream", ie);
307: }
308: }
309: }
310:
311: private boolean isPackage(final String pClazzName) {
312:
313: final InputStream is = pClassLoader
314: .getResourceAsStream(ConversionUtils
315: .convertClassToResourcePath(pClazzName));
316: if (is != null) {
317: log.debug("found the class for " + pClazzName
318: + "- no package");
319: return false;
320: }
321:
322: // FIXME: this should not be tied to the extension
323: final String source = pClazzName.replace('.', '/')
324: + ".java";
325: if (pReader.isAvailable(source)) {
326: log.debug("found the source " + source + " for "
327: + pClazzName + " - no package ");
328: return false;
329: }
330:
331: return true;
332: }
333:
334: public boolean isPackage(char[][] parentPackageName,
335: char[] pPackageName) {
336: final StringBuffer result = new StringBuffer();
337: if (parentPackageName != null) {
338: for (int i = 0; i < parentPackageName.length; i++) {
339: if (i != 0) {
340: result.append('.');
341: }
342: result.append(parentPackageName[i]);
343: }
344: }
345:
346: // log.debug("isPackage parentPackageName=" + result.toString() + " packageName=" + new String(packageName));
347:
348: if (parentPackageName != null
349: && parentPackageName.length > 0) {
350: result.append('.');
351: }
352: result.append(pPackageName);
353: return isPackage(result.toString());
354: }
355:
356: public void cleanup() {
357: log.debug("cleanup");
358: }
359: };
360:
361: final ICompilerRequestor compilerRequestor = new ICompilerRequestor() {
362: public void acceptResult(final CompilationResult pResult) {
363: if (pResult.hasProblems()) {
364: final IProblem[] iproblems = pResult.getProblems();
365: for (int i = 0; i < iproblems.length; i++) {
366: final IProblem iproblem = iproblems[i];
367: final CompilationProblem problem = new EclipseCompilationProblem(
368: iproblem);
369: if (problemHandler != null) {
370: problemHandler.handle(problem);
371: }
372: problems.add(problem);
373: }
374: }
375: if (!pResult.hasErrors()) {
376: final ClassFile[] clazzFiles = pResult
377: .getClassFiles();
378: for (int i = 0; i < clazzFiles.length; i++) {
379: final ClassFile clazzFile = clazzFiles[i];
380: final char[][] compoundName = clazzFile
381: .getCompoundName();
382: final StringBuffer clazzName = new StringBuffer();
383: for (int j = 0; j < compoundName.length; j++) {
384: if (j != 0) {
385: clazzName.append('.');
386: }
387: clazzName.append(compoundName[j]);
388: }
389: pStore.write(clazzName.toString().replace('.',
390: '/')
391: + ".class", clazzFile.getBytes());
392: }
393: }
394: }
395: };
396:
397: final Compiler compiler = new Compiler(nameEnvironment, policy,
398: settingsMap, compilerRequestor, problemFactory, false);
399:
400: compiler.compile(compilationUnits);
401:
402: final CompilationProblem[] result = new CompilationProblem[problems
403: .size()];
404: problems.toArray(result);
405: return new org.apache.commons.jci.compilers.CompilationResult(
406: result);
407: }
408:
409: public JavaCompilerSettings createDefaultSettings() {
410: return defaultSettings;
411: }
412: }
|