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.drools.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.drools.commons.jci.problems.CompilationProblem;
029: import org.drools.commons.jci.readers.ResourceReader;
030: import org.drools.commons.jci.stores.ResourceStore;
031: import org.drools.util.ClassUtils;
032: import org.eclipse.jdt.core.compiler.IProblem;
033: import org.eclipse.jdt.internal.compiler.ClassFile;
034: import org.eclipse.jdt.internal.compiler.CompilationResult;
035: import org.eclipse.jdt.internal.compiler.Compiler;
036: import org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies;
037: import org.eclipse.jdt.internal.compiler.ICompilerRequestor;
038: import org.eclipse.jdt.internal.compiler.IErrorHandlingPolicy;
039: import org.eclipse.jdt.internal.compiler.IProblemFactory;
040: import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader;
041: import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException;
042: import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
043: import org.eclipse.jdt.internal.compiler.env.INameEnvironment;
044: import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer;
045: import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory;
046:
047: /**
048: * Eclipse compiler implemenation
049: *
050: * @author tcurdt
051: */
052: public final class EclipseJavaCompiler extends AbstractJavaCompiler {
053:
054: private final EclipseJavaCompilerSettings defaultSettings;
055:
056: public EclipseJavaCompiler() {
057: this (new EclipseJavaCompilerSettings());
058: }
059:
060: public EclipseJavaCompiler(final Map pSettings) {
061: this .defaultSettings = new EclipseJavaCompilerSettings(
062: pSettings);
063: }
064:
065: public EclipseJavaCompiler(
066: final EclipseJavaCompilerSettings pSettings) {
067: this .defaultSettings = pSettings;
068: }
069:
070: final class CompilationUnit implements ICompilationUnit {
071:
072: final private String clazzName;
073: final private String fileName;
074: final private char[] typeName;
075: final private char[][] packageName;
076: final private ResourceReader reader;
077:
078: CompilationUnit(final ResourceReader pReader,
079: final String pSourceFile) {
080: this .reader = pReader;
081: this .clazzName = ClassUtils
082: .convertResourceToClassName(pSourceFile);
083: this .fileName = pSourceFile;
084: final int dot = this .clazzName.lastIndexOf('.');
085: if (dot > 0) {
086: this .typeName = this .clazzName.substring(dot + 1)
087: .toCharArray();
088: } else {
089: this .typeName = this .clazzName.toCharArray();
090: }
091:
092: final StringTokenizer izer = new StringTokenizer(
093: this .clazzName, ".");
094: this .packageName = new char[izer.countTokens() - 1][];
095: for (int i = 0; i < this .packageName.length; i++) {
096: this .packageName[i] = izer.nextToken().toCharArray();
097: }
098: }
099:
100: public char[] getFileName() {
101: return this .fileName.toCharArray();
102: }
103:
104: public char[] getContents() {
105: final byte[] content = this .reader.getBytes(this .fileName);
106:
107: if (content == null) {
108: return null;
109: //throw new RuntimeException("resource " + fileName + " could not be found");
110: }
111:
112: return new String(content).toCharArray();
113: }
114:
115: public char[] getMainTypeName() {
116: return this .typeName;
117: }
118:
119: public char[][] getPackageName() {
120: return this .packageName;
121: }
122: }
123:
124: public org.drools.commons.jci.compilers.CompilationResult compile(
125: final String[] pSourceFiles, final ResourceReader pReader,
126: final ResourceStore pStore, final ClassLoader pClassLoader,
127: final JavaCompilerSettings pSettings) {
128:
129: final Map settingsMap = ((EclipseJavaCompilerSettings) pSettings)
130: .getMap();
131:
132: final Collection problems = new ArrayList();
133:
134: final ICompilationUnit[] compilationUnits = new ICompilationUnit[pSourceFiles.length];
135: for (int i = 0; i < compilationUnits.length; i++) {
136: final String sourceFile = pSourceFiles[i];
137:
138: if (pReader.isAvailable(sourceFile)) {
139: compilationUnits[i] = new CompilationUnit(pReader,
140: sourceFile);
141: } else {
142:
143: final CompilationProblem problem = new CompilationProblem() {
144:
145: public int getEndColumn() {
146: return 0;
147: }
148:
149: public int getEndLine() {
150: return 0;
151: }
152:
153: public String getFileName() {
154: return sourceFile;
155: }
156:
157: public String getMessage() {
158: return "Source " + sourceFile
159: + " could not be found";
160: }
161:
162: public int getStartColumn() {
163: return 0;
164: }
165:
166: public int getStartLine() {
167: return 0;
168: }
169:
170: public boolean isError() {
171: return true;
172: }
173:
174: public String toString() {
175: return getMessage();
176: }
177: };
178:
179: if (this .problemHandler != null) {
180: this .problemHandler.handle(problem);
181: }
182:
183: problems.add(problem);
184: }
185: }
186:
187: if (problems.size() > 0) {
188: final CompilationProblem[] result = new CompilationProblem[problems
189: .size()];
190: problems.toArray(result);
191: return new org.drools.commons.jci.compilers.CompilationResult(
192: result);
193: }
194:
195: final IErrorHandlingPolicy policy = DefaultErrorHandlingPolicies
196: .proceedWithAllProblems();
197: final IProblemFactory problemFactory = new DefaultProblemFactory(
198: Locale.getDefault());
199: final INameEnvironment nameEnvironment = new INameEnvironment() {
200:
201: public NameEnvironmentAnswer findType(
202: 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(
217: final char[] pTypeName, final char[][] pPackageName) {
218: final StringBuffer result = new StringBuffer();
219: for (int i = 0; i < pPackageName.length; i++) {
220: result.append(pPackageName[i]);
221: result.append('.');
222: }
223:
224: // log.debug("finding typeName=" + new String(typeName) + " packageName=" + result.toString());
225:
226: result.append(pTypeName);
227: return findType(result.toString());
228: }
229:
230: private NameEnvironmentAnswer findType(
231: final String pClazzName) {
232:
233: if (isPackage(pClazzName)) {
234: return null;
235: }
236:
237: final String resourceName = ClassUtils
238: .convertClassToResourcePath(pClazzName);
239:
240: final byte[] clazzBytes = pStore.read(pClazzName);
241: if (clazzBytes != null) {
242:
243: final char[] fileName = pClazzName.toCharArray();
244: try {
245: final ClassFileReader classFileReader = new ClassFileReader(
246: clazzBytes, fileName, true);
247: return new NameEnvironmentAnswer(
248: classFileReader, null);
249: } catch (final ClassFormatException e) {
250: throw new RuntimeException(
251: "ClassFormatException in loading class '"
252: + fileName + "' with JCI.");
253: }
254: }
255:
256: final InputStream is = pClassLoader
257: .getResourceAsStream(resourceName);
258: if (is == null) {
259: return null;
260: }
261:
262: final byte[] buffer = new byte[8192];
263: final ByteArrayOutputStream baos = new ByteArrayOutputStream(
264: buffer.length);
265: int count;
266: try {
267: while ((count = is.read(buffer, 0, buffer.length)) > 0) {
268: baos.write(buffer, 0, count);
269: }
270: baos.flush();
271: final char[] fileName = pClazzName.toCharArray();
272: final ClassFileReader classFileReader = new ClassFileReader(
273: baos.toByteArray(), fileName, true);
274: return new NameEnvironmentAnswer(classFileReader,
275: null);
276: } catch (final IOException e) {
277: throw new RuntimeException("could not read class",
278: e);
279: } catch (final ClassFormatException e) {
280: throw new RuntimeException("wrong class format", e);
281: } finally {
282: try {
283: baos.close();
284: } catch (final IOException oe) {
285: throw new RuntimeException(
286: "could not close output stream", oe);
287: }
288: try {
289: is.close();
290: } catch (final IOException ie) {
291: throw new RuntimeException(
292: "could not close input stream", ie);
293: }
294: }
295: }
296:
297: private boolean isPackage(final String pClazzName) {
298:
299: final InputStream is = pClassLoader
300: .getResourceAsStream(ClassUtils
301: .convertClassToResourcePath(pClazzName));
302: if (is != null) {
303: return false;
304: }
305:
306: // FIXME: this should not be tied to the extension
307: final String source = pClazzName.replace('.', '/')
308: + ".java";
309: if (pReader.isAvailable(source)) {
310: return false;
311: }
312:
313: return true;
314: }
315:
316: public boolean isPackage(char[][] parentPackageName,
317: char[] pPackageName) {
318: final StringBuffer result = new StringBuffer();
319: if (parentPackageName != null) {
320: for (int i = 0; i < parentPackageName.length; i++) {
321: if (i != 0) {
322: result.append('.');
323: }
324: result.append(parentPackageName[i]);
325: }
326: }
327:
328: // log.debug("isPackage parentPackageName=" + result.toString() + " packageName=" + new String(packageName));
329:
330: if (parentPackageName != null
331: && parentPackageName.length > 0) {
332: result.append('.');
333: }
334: result.append(pPackageName);
335: return isPackage(result.toString());
336: }
337:
338: public void cleanup() {
339: }
340: };
341:
342: final ICompilerRequestor compilerRequestor = new ICompilerRequestor() {
343: public void acceptResult(final CompilationResult pResult) {
344: if (pResult.hasProblems()) {
345: final IProblem[] iproblems = pResult.getProblems();
346: for (int i = 0; i < iproblems.length; i++) {
347: final IProblem iproblem = iproblems[i];
348: final CompilationProblem problem = new EclipseCompilationProblem(
349: iproblem);
350: if (EclipseJavaCompiler.this .problemHandler != null) {
351: EclipseJavaCompiler.this .problemHandler
352: .handle(problem);
353: }
354: problems.add(problem);
355: }
356: }
357: if (!pResult.hasErrors()) {
358: final ClassFile[] clazzFiles = pResult
359: .getClassFiles();
360: for (int i = 0; i < clazzFiles.length; i++) {
361: final ClassFile clazzFile = clazzFiles[i];
362: final char[][] compoundName = clazzFile
363: .getCompoundName();
364: final StringBuffer clazzName = new StringBuffer();
365: for (int j = 0; j < compoundName.length; j++) {
366: if (j != 0) {
367: clazzName.append('.');
368: }
369: clazzName.append(compoundName[j]);
370: }
371: pStore.write(clazzName.toString().replace('.',
372: '/')
373: + ".class", clazzFile.getBytes());
374: }
375: }
376: }
377: };
378:
379: final Compiler compiler = new Compiler(nameEnvironment, policy,
380: settingsMap, compilerRequestor, problemFactory, false);
381:
382: compiler.compile(compilationUnits);
383:
384: final CompilationProblem[] result = new CompilationProblem[problems
385: .size()];
386: problems.toArray(result);
387: return new org.drools.commons.jci.compilers.CompilationResult(
388: result);
389: }
390:
391: public JavaCompilerSettings createDefaultSettings() {
392: return this.defaultSettings;
393: }
394: }
|