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.cocoon.components.language.programming.java;
018:
019: import org.apache.avalon.excalibur.pool.Recyclable;
020: import org.apache.cocoon.components.language.programming.CompilerError;
021: import org.apache.cocoon.components.language.programming.LanguageCompiler;
022: import org.apache.cocoon.util.ClassUtils;
023: import org.apache.commons.lang.StringUtils;
024: import org.apache.commons.lang.SystemUtils;
025:
026: import org.eclipse.jdt.core.compiler.IProblem;
027: import org.eclipse.jdt.internal.compiler.ClassFile;
028: import org.eclipse.jdt.internal.compiler.CompilationResult;
029: import org.eclipse.jdt.internal.compiler.Compiler;
030: import org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies;
031: import org.eclipse.jdt.internal.compiler.ICompilerRequestor;
032: import org.eclipse.jdt.internal.compiler.IErrorHandlingPolicy;
033: import org.eclipse.jdt.internal.compiler.IProblemFactory;
034: import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader;
035: import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
036: import org.eclipse.jdt.internal.compiler.env.INameEnvironment;
037: import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer;
038: import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
039: import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory;
040:
041: import java.io.BufferedOutputStream;
042: import java.io.BufferedReader;
043: import java.io.ByteArrayOutputStream;
044: import java.io.File;
045: import java.io.FileOutputStream;
046: import java.io.FileReader;
047: import java.io.IOException;
048: import java.io.InputStream;
049: import java.io.Reader;
050: import java.util.HashMap;
051: import java.util.LinkedList;
052: import java.util.List;
053: import java.util.Locale;
054: import java.util.Map;
055: import java.util.StringTokenizer;
056:
057: /**
058: * Eclipse Java Compiler
059: *
060: * @version $Id: EclipseJavaCompiler.java 555089 2007-07-10 21:45:10Z anathaniel $
061: */
062: public class EclipseJavaCompiler implements LanguageCompiler,
063: Recyclable {
064:
065: boolean debug;
066:
067: String sourceDir;
068: String sourceFile;
069: String destDir;
070: String sourceEncoding;
071: int compilerComplianceLevel;
072:
073: List errors = new LinkedList();
074:
075: public EclipseJavaCompiler() {
076: this .debug = true;
077: }
078:
079: public void recycle() {
080: sourceFile = null;
081: sourceDir = null;
082: destDir = null;
083: sourceEncoding = null;
084: errors.clear();
085: }
086:
087: public void setFile(String file) {
088: // This is the absolute path to the file to be compiled
089: this .sourceFile = file;
090: }
091:
092: public void setSource(String srcDir) {
093: // This is the "sourcepath" of the file to be compiled
094: this .sourceDir = srcDir;
095: }
096:
097: public void setDestination(String destDir) {
098: // This is the output directory)
099: this .destDir = destDir;
100: }
101:
102: public void setEncoding(String encoding) {
103: this .sourceEncoding = encoding;
104: }
105:
106: /**
107: * Set the version of the java source code to be compiled
108: *
109: * @param compilerComplianceLevel The version of the JVM for wich the code was written.
110: * i.e: 130 = Java 1.3, 140 = Java 1.4 and 150 = Java 1.5
111: *
112: * @since 2.1.7
113: */
114: public void setCompilerComplianceLevel(int compilerComplianceLevel) {
115: this .compilerComplianceLevel = compilerComplianceLevel;
116: }
117:
118: /**
119: * Eclipse Java compiler ignores class path setting and uses current
120: * Java class loader
121: * @param cp classpath to be ignored
122: */
123: public void setClasspath(String cp) {
124: // Not used
125: }
126:
127: private String makeClassName(String fileName) throws IOException {
128: File origFile = new File(fileName);
129: String canonical = null;
130: if (origFile.exists()) {
131: canonical = origFile.getCanonicalPath().replace('\\', '/');
132: }
133: String str = fileName;
134: str = str.replace('\\', '/');
135: if (sourceDir != null) {
136: String prefix = new File(sourceDir).getCanonicalPath()
137: .replace('\\', '/');
138: if (canonical != null) {
139: if (canonical.startsWith(prefix)) {
140: String result = canonical
141: .substring(prefix.length() + 1, canonical
142: .length() - 5);
143: result = result.replace('/', '.');
144: return result;
145: }
146: } else {
147: File t = new File(sourceDir, fileName);
148: if (t.exists()) {
149: str = t.getCanonicalPath().replace('\\', '/');
150: String result = str.substring(prefix.length() + 1,
151: str.length() - 5).replace('/', '.');
152: return result;
153: }
154: }
155: }
156: if (fileName.endsWith(".java")) {
157: fileName = fileName.substring(0, fileName.length() - 5);
158: }
159: return StringUtils.replaceChars(fileName, "\\/", "..");
160: }
161:
162: public boolean compile() throws IOException {
163: final String targetClassName = makeClassName(sourceFile);
164: final ClassLoader classLoader = ClassUtils.getClassLoader();
165: String[] fileNames = new String[] { sourceFile };
166: String[] classNames = new String[] { targetClassName };
167: class CompilationUnit implements ICompilationUnit {
168:
169: String className;
170: String sourceFile;
171:
172: CompilationUnit(String sourceFile, String className) {
173: this .className = className;
174: this .sourceFile = sourceFile;
175: }
176:
177: public char[] getFileName() {
178: return className.toCharArray();
179: }
180:
181: public char[] getContents() {
182: char[] result = null;
183: FileReader fr = null;
184: try {
185: fr = new FileReader(sourceFile);
186: Reader reader = new BufferedReader(fr);
187: if (reader != null) {
188: char[] chars = new char[8192];
189: StringBuffer buf = new StringBuffer();
190: int count;
191: while ((count = reader.read(chars, 0,
192: chars.length)) > 0) {
193: buf.append(chars, 0, count);
194: }
195: result = new char[buf.length()];
196: buf.getChars(0, result.length, result, 0);
197: }
198: } catch (IOException e) {
199: handleError(className, -1, -1, e.getMessage());
200: }
201: return result;
202: }
203:
204: public char[] getMainTypeName() {
205: int dot = className.lastIndexOf('.');
206: if (dot > 0) {
207: return className.substring(dot + 1).toCharArray();
208: }
209: return className.toCharArray();
210: }
211:
212: public char[][] getPackageName() {
213: StringTokenizer izer = new StringTokenizer(className,
214: ".");
215: char[][] result = new char[izer.countTokens() - 1][];
216: for (int i = 0; i < result.length; i++) {
217: String tok = izer.nextToken();
218: result[i] = tok.toCharArray();
219: }
220: return result;
221: }
222: }
223:
224: final INameEnvironment env = new INameEnvironment() {
225:
226: public NameEnvironmentAnswer findType(
227: char[][] compoundTypeName) {
228: StringBuffer result = new StringBuffer();
229: for (int i = 0; i < compoundTypeName.length; i++) {
230: if (i > 0) {
231: result.append(".");
232: }
233: result.append(compoundTypeName[i]);
234: }
235: return findType(result.toString());
236: }
237:
238: public NameEnvironmentAnswer findType(char[] typeName,
239: char[][] packageName) {
240: StringBuffer result = new StringBuffer();
241: for (int i = 0; i < packageName.length; i++) {
242: if (i > 0) {
243: result.append(".");
244: }
245: result.append(packageName[i]);
246: }
247: result.append(".");
248: result.append(typeName);
249: return findType(result.toString());
250: }
251:
252: private NameEnvironmentAnswer findType(String className) {
253:
254: try {
255: if (className.equals(targetClassName)) {
256: ICompilationUnit compilationUnit = new CompilationUnit(
257: sourceFile, className);
258: return new NameEnvironmentAnswer(
259: compilationUnit, null);
260: }
261: String resourceName = className.replace('.', '/')
262: + ".class";
263: InputStream is = classLoader
264: .getResourceAsStream(resourceName);
265: if (is != null) {
266: byte[] classBytes;
267: byte[] buf = new byte[8192];
268: ByteArrayOutputStream baos = new ByteArrayOutputStream(
269: buf.length);
270: int count;
271: while ((count = is.read(buf, 0, buf.length)) > 0) {
272: baos.write(buf, 0, count);
273: }
274: baos.flush();
275: classBytes = baos.toByteArray();
276: char[] fileName = className.toCharArray();
277: ClassFileReader classFileReader = new ClassFileReader(
278: classBytes, fileName, true);
279: return new NameEnvironmentAnswer(
280: classFileReader, null);
281: }
282: } catch (IOException exc) {
283: handleError(className, -1, -1, exc.getMessage());
284: } catch (org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException exc) {
285: handleError(className, -1, -1, exc.getMessage());
286: }
287: return null;
288: }
289:
290: private boolean isPackage(String result) {
291: if (result.equals(targetClassName)) {
292: return false;
293: }
294: String resourceName = result.replace('.', '/')
295: + ".class";
296: InputStream is = classLoader
297: .getResourceAsStream(resourceName);
298: return is == null;
299: }
300:
301: public boolean isPackage(char[][] parentPackageName,
302: char[] packageName) {
303: StringBuffer result = new StringBuffer();
304: if (parentPackageName != null) {
305: for (int i = 0; i < parentPackageName.length; i++) {
306: if (i > 0) {
307: result.append(".");
308: }
309: result.append(parentPackageName[i]);
310: }
311: }
312: String str = new String(packageName);
313: if (Character.isUpperCase(str.charAt(0))
314: && !isPackage(result.toString())) {
315: return false;
316: }
317: result.append(".");
318: result.append(str);
319: return isPackage(result.toString());
320: }
321:
322: public void cleanup() {
323: // EMPTY
324: }
325: };
326: final IErrorHandlingPolicy policy = DefaultErrorHandlingPolicies
327: .proceedWithAllProblems();
328: final Map settings = new HashMap(9);
329: settings.put(CompilerOptions.OPTION_LineNumberAttribute,
330: CompilerOptions.GENERATE);
331: settings.put(CompilerOptions.OPTION_SourceFileAttribute,
332: CompilerOptions.GENERATE);
333: settings.put(CompilerOptions.OPTION_ReportDeprecation,
334: CompilerOptions.IGNORE);
335: settings.put(CompilerOptions.OPTION_ReportUnusedImport,
336: CompilerOptions.IGNORE);
337: if (sourceEncoding != null) {
338: settings.put(CompilerOptions.OPTION_Encoding,
339: sourceEncoding);
340: }
341: if (debug) {
342: settings.put(CompilerOptions.OPTION_LocalVariableAttribute,
343: CompilerOptions.GENERATE);
344: }
345: // Set the sourceCodeVersion
346: switch (this .compilerComplianceLevel) {
347: case 150:
348: settings.put(CompilerOptions.OPTION_Source,
349: CompilerOptions.VERSION_1_5);
350: settings.put(CompilerOptions.OPTION_Compliance,
351: CompilerOptions.VERSION_1_5);
352: break;
353: case 140:
354: settings.put(CompilerOptions.OPTION_Source,
355: CompilerOptions.VERSION_1_4);
356: break;
357: default:
358: settings.put(CompilerOptions.OPTION_Source,
359: CompilerOptions.VERSION_1_3);
360: }
361: // Set the target platform
362: switch (SystemUtils.JAVA_VERSION_INT) {
363: case 150:
364: settings.put(CompilerOptions.OPTION_TargetPlatform,
365: CompilerOptions.VERSION_1_5);
366: break;
367: case 140:
368: settings.put(CompilerOptions.OPTION_TargetPlatform,
369: CompilerOptions.VERSION_1_4);
370: break;
371: default:
372: settings.put(CompilerOptions.OPTION_TargetPlatform,
373: CompilerOptions.VERSION_1_3);
374: }
375: final IProblemFactory problemFactory = new DefaultProblemFactory(
376: Locale.getDefault());
377:
378: final ICompilerRequestor requestor = new ICompilerRequestor() {
379: public void acceptResult(CompilationResult result) {
380: try {
381: if (result.hasErrors()) {
382: IProblem[] errors = result.getErrors();
383: for (int i = 0; i < errors.length; i++) {
384: IProblem error = errors[i];
385: String name = new String(errors[i]
386: .getOriginatingFileName());
387: handleError(name, error
388: .getSourceLineNumber(), -1, error
389: .getMessage());
390: }
391: } else {
392: ClassFile[] classFiles = result.getClassFiles();
393: for (int i = 0; i < classFiles.length; i++) {
394: ClassFile classFile = classFiles[i];
395: char[][] compoundName = classFile
396: .getCompoundName();
397: StringBuffer className = new StringBuffer();
398: for (int j = 0; j < compoundName.length; j++) {
399: if (j > 0) {
400: className.append(".");
401: }
402: className.append(compoundName[j]);
403: }
404: byte[] bytes = classFile.getBytes();
405: String outFile = destDir
406: + "/"
407: + className.toString().replace('.',
408: '/') + ".class";
409: FileOutputStream fout = new FileOutputStream(
410: outFile);
411: BufferedOutputStream bos = new BufferedOutputStream(
412: fout);
413: bos.write(bytes);
414: bos.close();
415: }
416: }
417: } catch (IOException exc) {
418: exc.printStackTrace();
419: }
420: }
421: };
422: ICompilationUnit[] compilationUnits = new ICompilationUnit[classNames.length];
423: for (int i = 0; i < compilationUnits.length; i++) {
424: String className = classNames[i];
425: compilationUnits[i] = new CompilationUnit(fileNames[i],
426: className);
427: }
428: Compiler compiler = new Compiler(env, policy, settings,
429: requestor, problemFactory);
430: compiler.compile(compilationUnits);
431: return errors.size() == 0;
432: }
433:
434: void handleError(String className, int line, int column,
435: Object errorMessage) {
436: String fileName = className.replace('.', File.separatorChar)
437: + ".java";
438: if (column < 0)
439: column = 0;
440: errors.add(new CompilerError(fileName, true, line, column,
441: line, column, errorMessage.toString()));
442: }
443:
444: public List getErrors() throws IOException {
445: return errors;
446: }
447: }
|