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:
018: package org.apache.jasper.compiler;
019:
020: import java.io.BufferedOutputStream;
021: import java.io.BufferedReader;
022: import java.io.ByteArrayOutputStream;
023: import java.io.File;
024: import java.io.FileInputStream;
025: import java.io.FileNotFoundException;
026: import java.io.FileOutputStream;
027: import java.io.IOException;
028: import java.io.InputStream;
029: import java.io.InputStreamReader;
030: import java.io.Reader;
031: import java.util.ArrayList;
032: import java.util.HashMap;
033: import java.util.Locale;
034: import java.util.Map;
035: import java.util.StringTokenizer;
036:
037: import org.apache.jasper.JasperException;
038: import org.eclipse.jdt.core.compiler.IProblem;
039: import org.eclipse.jdt.internal.compiler.ClassFile;
040: import org.eclipse.jdt.internal.compiler.CompilationResult;
041: import org.eclipse.jdt.internal.compiler.Compiler;
042: import org.eclipse.jdt.internal.compiler.DefaultErrorHandlingPolicies;
043: import org.eclipse.jdt.internal.compiler.ICompilerRequestor;
044: import org.eclipse.jdt.internal.compiler.IErrorHandlingPolicy;
045: import org.eclipse.jdt.internal.compiler.IProblemFactory;
046: import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader;
047: import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
048: import org.eclipse.jdt.internal.compiler.env.INameEnvironment;
049: import org.eclipse.jdt.internal.compiler.env.NameEnvironmentAnswer;
050: import org.eclipse.jdt.internal.compiler.impl.CompilerOptions;
051: import org.eclipse.jdt.internal.compiler.problem.DefaultProblemFactory;
052:
053: /**
054: * JDT class compiler. This compiler will load source dependencies from the
055: * context classloader, reducing dramatically disk access during
056: * the compilation process.
057: *
058: * @author Cocoon2
059: * @author Remy Maucherat
060: */
061: public class JDTCompiler extends org.apache.jasper.compiler.Compiler {
062:
063: /**
064: * Compile the servlet from .java file to .class file
065: */
066: protected void generateClass(String[] smap)
067: throws FileNotFoundException, JasperException, Exception {
068:
069: long t1 = 0;
070: if (log.isDebugEnabled()) {
071: t1 = System.currentTimeMillis();
072: }
073:
074: final String sourceFile = ctxt.getServletJavaFileName();
075: final String outputDir = ctxt.getOptions().getScratchDir()
076: .getAbsolutePath();
077: String packageName = ctxt.getServletPackageName();
078: final String targetClassName = ((packageName.length() != 0) ? (packageName + ".")
079: : "")
080: + ctxt.getServletClassName();
081: final ClassLoader classLoader = ctxt.getJspLoader();
082: String[] fileNames = new String[] { sourceFile };
083: String[] classNames = new String[] { targetClassName };
084: final ArrayList problemList = new ArrayList();
085:
086: class CompilationUnit implements ICompilationUnit {
087:
088: String className;
089: String sourceFile;
090:
091: CompilationUnit(String sourceFile, String className) {
092: this .className = className;
093: this .sourceFile = sourceFile;
094: }
095:
096: public char[] getFileName() {
097: return sourceFile.toCharArray();
098: }
099:
100: public char[] getContents() {
101: char[] result = null;
102: FileInputStream is = null;
103: try {
104: is = new FileInputStream(sourceFile);
105: Reader reader = new BufferedReader(
106: new InputStreamReader(is, ctxt.getOptions()
107: .getJavaEncoding()));
108: if (reader != null) {
109: char[] chars = new char[8192];
110: StringBuffer buf = new StringBuffer();
111: int count;
112: while ((count = reader.read(chars, 0,
113: chars.length)) > 0) {
114: buf.append(chars, 0, count);
115: }
116: result = new char[buf.length()];
117: buf.getChars(0, result.length, result, 0);
118: }
119: } catch (IOException e) {
120: log.error("Compilation error", e);
121: } finally {
122: if (is != null) {
123: try {
124: is.close();
125: } catch (IOException exc) {
126: // Ignore
127: }
128: }
129: }
130: return result;
131: }
132:
133: public char[] getMainTypeName() {
134: int dot = className.lastIndexOf('.');
135: if (dot > 0) {
136: return className.substring(dot + 1).toCharArray();
137: }
138: return className.toCharArray();
139: }
140:
141: public char[][] getPackageName() {
142: StringTokenizer izer = new StringTokenizer(className,
143: ".");
144: char[][] result = new char[izer.countTokens() - 1][];
145: for (int i = 0; i < result.length; i++) {
146: String tok = izer.nextToken();
147: result[i] = tok.toCharArray();
148: }
149: return result;
150: }
151: }
152:
153: final INameEnvironment env = new INameEnvironment() {
154:
155: public NameEnvironmentAnswer findType(
156: char[][] compoundTypeName) {
157: String result = "";
158: String sep = "";
159: for (int i = 0; i < compoundTypeName.length; i++) {
160: result += sep;
161: result += new String(compoundTypeName[i]);
162: sep = ".";
163: }
164: return findType(result);
165: }
166:
167: public NameEnvironmentAnswer findType(char[] typeName,
168: char[][] packageName) {
169: String result = "";
170: String sep = "";
171: for (int i = 0; i < packageName.length; i++) {
172: result += sep;
173: result += new String(packageName[i]);
174: sep = ".";
175: }
176: result += sep;
177: result += new String(typeName);
178: return findType(result);
179: }
180:
181: private NameEnvironmentAnswer findType(String className) {
182:
183: InputStream is = null;
184: try {
185: if (className.equals(targetClassName)) {
186: ICompilationUnit compilationUnit = new CompilationUnit(
187: sourceFile, className);
188: return new NameEnvironmentAnswer(
189: compilationUnit, null);
190: }
191: String resourceName = className.replace('.', '/')
192: + ".class";
193: is = classLoader.getResourceAsStream(resourceName);
194: if (is != null) {
195: byte[] classBytes;
196: byte[] buf = new byte[8192];
197: ByteArrayOutputStream baos = new ByteArrayOutputStream(
198: buf.length);
199: int count;
200: while ((count = is.read(buf, 0, buf.length)) > 0) {
201: baos.write(buf, 0, count);
202: }
203: baos.flush();
204: classBytes = baos.toByteArray();
205: char[] fileName = className.toCharArray();
206: ClassFileReader classFileReader = new ClassFileReader(
207: classBytes, fileName, true);
208: return new NameEnvironmentAnswer(
209: classFileReader, null);
210: }
211: } catch (IOException exc) {
212: log.error("Compilation error", exc);
213: } catch (org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException exc) {
214: log.error("Compilation error", exc);
215: } finally {
216: if (is != null) {
217: try {
218: is.close();
219: } catch (IOException exc) {
220: // Ignore
221: }
222: }
223: }
224: return null;
225: }
226:
227: private boolean isPackage(String result) {
228: if (result.equals(targetClassName)) {
229: return false;
230: }
231: String resourceName = result.replace('.', '/')
232: + ".class";
233: InputStream is = classLoader
234: .getResourceAsStream(resourceName);
235: return is == null;
236: }
237:
238: public boolean isPackage(char[][] parentPackageName,
239: char[] packageName) {
240: String result = "";
241: String sep = "";
242: if (parentPackageName != null) {
243: for (int i = 0; i < parentPackageName.length; i++) {
244: result += sep;
245: String str = new String(parentPackageName[i]);
246: result += str;
247: sep = ".";
248: }
249: }
250: String str = new String(packageName);
251: if (Character.isUpperCase(str.charAt(0))) {
252: if (!isPackage(result)) {
253: return false;
254: }
255: }
256: result += sep;
257: result += str;
258: return isPackage(result);
259: }
260:
261: public void cleanup() {
262: }
263:
264: };
265:
266: final IErrorHandlingPolicy policy = DefaultErrorHandlingPolicies
267: .proceedWithAllProblems();
268:
269: final Map settings = new HashMap();
270: settings.put(CompilerOptions.OPTION_LineNumberAttribute,
271: CompilerOptions.GENERATE);
272: settings.put(CompilerOptions.OPTION_SourceFileAttribute,
273: CompilerOptions.GENERATE);
274: settings.put(CompilerOptions.OPTION_ReportDeprecation,
275: CompilerOptions.IGNORE);
276: if (ctxt.getOptions().getJavaEncoding() != null) {
277: settings.put(CompilerOptions.OPTION_Encoding, ctxt
278: .getOptions().getJavaEncoding());
279: }
280: if (ctxt.getOptions().getClassDebugInfo()) {
281: settings.put(CompilerOptions.OPTION_LocalVariableAttribute,
282: CompilerOptions.GENERATE);
283: }
284:
285: // Source JVM
286: if (ctxt.getOptions().getCompilerSourceVM() != null) {
287: String opt = ctxt.getOptions().getCompilerSourceVM();
288: if (opt.equals("1.1")) {
289: settings.put(CompilerOptions.OPTION_Source,
290: CompilerOptions.VERSION_1_1);
291: } else if (opt.equals("1.2")) {
292: settings.put(CompilerOptions.OPTION_Source,
293: CompilerOptions.VERSION_1_2);
294: } else if (opt.equals("1.3")) {
295: settings.put(CompilerOptions.OPTION_Source,
296: CompilerOptions.VERSION_1_3);
297: } else if (opt.equals("1.4")) {
298: settings.put(CompilerOptions.OPTION_Source,
299: CompilerOptions.VERSION_1_4);
300: } else if (opt.equals("1.5")) {
301: settings.put(CompilerOptions.OPTION_Source,
302: CompilerOptions.VERSION_1_5);
303: } else {
304: log.warn("Unknown source VM " + opt + " ignored.");
305: settings.put(CompilerOptions.OPTION_Source,
306: CompilerOptions.VERSION_1_5);
307: }
308: } else {
309: // Default to 1.5
310: settings.put(CompilerOptions.OPTION_Source,
311: CompilerOptions.VERSION_1_5);
312: }
313:
314: // Target JVM
315: if (ctxt.getOptions().getCompilerTargetVM() != null) {
316: String opt = ctxt.getOptions().getCompilerTargetVM();
317: if (opt.equals("1.1")) {
318: settings.put(CompilerOptions.OPTION_TargetPlatform,
319: CompilerOptions.VERSION_1_1);
320: } else if (opt.equals("1.2")) {
321: settings.put(CompilerOptions.OPTION_TargetPlatform,
322: CompilerOptions.VERSION_1_2);
323: } else if (opt.equals("1.3")) {
324: settings.put(CompilerOptions.OPTION_TargetPlatform,
325: CompilerOptions.VERSION_1_3);
326: } else if (opt.equals("1.4")) {
327: settings.put(CompilerOptions.OPTION_TargetPlatform,
328: CompilerOptions.VERSION_1_4);
329: } else if (opt.equals("1.5")) {
330: settings.put(CompilerOptions.OPTION_TargetPlatform,
331: CompilerOptions.VERSION_1_5);
332: settings.put(CompilerOptions.OPTION_Compliance,
333: CompilerOptions.VERSION_1_5);
334: } else {
335: log.warn("Unknown target VM " + opt + " ignored.");
336: settings.put(CompilerOptions.OPTION_TargetPlatform,
337: CompilerOptions.VERSION_1_5);
338: }
339: } else {
340: // Default to 1.5
341: settings.put(CompilerOptions.OPTION_TargetPlatform,
342: CompilerOptions.VERSION_1_5);
343: settings.put(CompilerOptions.OPTION_Compliance,
344: CompilerOptions.VERSION_1_5);
345: }
346:
347: final IProblemFactory problemFactory = new DefaultProblemFactory(
348: Locale.getDefault());
349:
350: final ICompilerRequestor requestor = new ICompilerRequestor() {
351: public void acceptResult(CompilationResult result) {
352: try {
353: if (result.hasProblems()) {
354: IProblem[] problems = result.getProblems();
355: for (int i = 0; i < problems.length; i++) {
356: IProblem problem = problems[i];
357: if (problem.isError()) {
358: String name = new String(problems[i]
359: .getOriginatingFileName());
360: try {
361: problemList
362: .add(ErrorDispatcher
363: .createJavacError(
364: name,
365: pageNodes,
366: new StringBuffer(
367: problem
368: .getMessage()),
369: problem
370: .getSourceLineNumber(),
371: ctxt));
372: } catch (JasperException e) {
373: log.error("Error visiting node", e);
374: }
375: }
376: }
377: }
378: if (problemList.isEmpty()) {
379: ClassFile[] classFiles = result.getClassFiles();
380: for (int i = 0; i < classFiles.length; i++) {
381: ClassFile classFile = classFiles[i];
382: char[][] compoundName = classFile
383: .getCompoundName();
384: String className = "";
385: String sep = "";
386: for (int j = 0; j < compoundName.length; j++) {
387: className += sep;
388: className += new String(compoundName[j]);
389: sep = ".";
390: }
391: byte[] bytes = classFile.getBytes();
392: String outFile = outputDir + "/"
393: + className.replace('.', '/')
394: + ".class";
395: FileOutputStream fout = new FileOutputStream(
396: outFile);
397: BufferedOutputStream bos = new BufferedOutputStream(
398: fout);
399: bos.write(bytes);
400: bos.close();
401: }
402: }
403: } catch (IOException exc) {
404: log.error("Compilation error", exc);
405: }
406: }
407: };
408:
409: ICompilationUnit[] compilationUnits = new ICompilationUnit[classNames.length];
410: for (int i = 0; i < compilationUnits.length; i++) {
411: String className = classNames[i];
412: compilationUnits[i] = new CompilationUnit(fileNames[i],
413: className);
414: }
415: Compiler compiler = new Compiler(env, policy, settings,
416: requestor, problemFactory, true);
417: compiler.compile(compilationUnits);
418:
419: if (!ctxt.keepGenerated()) {
420: File javaFile = new File(ctxt.getServletJavaFileName());
421: javaFile.delete();
422: }
423:
424: if (!problemList.isEmpty()) {
425: JavacErrorDetail[] jeds = (JavacErrorDetail[]) problemList
426: .toArray(new JavacErrorDetail[0]);
427: errDispatcher.javacError(jeds);
428: }
429:
430: if (log.isDebugEnabled()) {
431: long t2 = System.currentTimeMillis();
432: log.debug("Compiled " + ctxt.getServletJavaFileName() + " "
433: + (t2 - t1) + "ms");
434: }
435:
436: if (ctxt.isPrototypeMode()) {
437: return;
438: }
439:
440: // JSR45 Support
441: if (!options.isSmapSuppressed()) {
442: SmapUtil.installSmap(smap);
443: }
444:
445: }
446:
447: }
|