001: /*
002: * Copyright 1999,2004 The Apache Software Foundation.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.apache.jasper.compiler;
018:
019: import java.io.File;
020: import java.io.FileNotFoundException;
021: import java.io.PrintStream;
022: import java.io.IOException;
023: import java.io.ByteArrayOutputStream;
024: import java.util.StringTokenizer;
025: import java.util.List;
026: import java.util.ArrayList;
027: import java.util.Arrays;
028: import java.lang.reflect.Method;
029: import java.lang.reflect.InvocationTargetException;
030: import java.net.URL;
031: import java.net.URLClassLoader;
032:
033: import org.apache.jasper.JasperException;
034:
035: /**
036: * Main JSP compiler class. This class uses 7Bee for compiling.
037: *
038: * @author Dmitriy Rogatkin
039: */
040: public class BeeCompiler extends Compiler {
041:
042: protected static Object javacLock = new Object();
043:
044: private Class javaCompiler;
045:
046: static {
047: System.setErr(new SystemLogHandler(System.err));
048: }
049:
050: /**
051: * Compile the servlet from .java file to .class file
052: */
053: protected void generateClass(String[] smap)
054: throws FileNotFoundException, JasperException, Exception {
055:
056: long t1 = 0;
057: if (log.isDebugEnabled())
058: t1 = System.currentTimeMillis();
059:
060: List<String> parameters = new ArrayList<String>(20);
061: parameters.add("-encoding");
062: parameters.add(ctxt.getOptions().getJavaEncoding());
063:
064: String javaFileName = new File(ctxt.getServletJavaFileName())
065: .getPath();
066: String classpath = ctxt.getClassPath();
067:
068: String sep = File.pathSeparator; // System.getProperty("path.separator");
069:
070: StringBuffer errorReport = new StringBuffer();
071:
072: StringBuffer info = new StringBuffer();
073: info.append("Compile: javaFileName=" + javaFileName + "\n");
074:
075: // Start capturing the System.err output for this thread
076: SystemLogHandler.setThread();
077:
078: // Initializing classpath
079: String path = System.getProperty("java.class.path");
080: info.append(" cmd cp=" + path + "\n");
081: info.append(" ctx cp=" + classpath + "\n");
082: path += sep;
083: path += classpath;
084:
085: if (log.isDebugEnabled())
086: log.debug("Using classpath: " + path);
087:
088: parameters.add("-classpath");
089: parameters.add(path);
090:
091: // Initializing sourcepath
092: parameters.add("-sourcepath");
093: parameters.add(options.getScratchDir().getPath());
094:
095: info.append(" work dir=" + options.getScratchDir() + "\n");
096:
097: // Initialize and set java extensions
098: String extdirs = System.getProperty("java.ext.dirs");
099: if (extdirs != null) {
100: parameters.add("-extdirs");
101: parameters.add(extdirs);
102: info.append(" extension dir=" + extdirs + "\n");
103: }
104:
105: if (ctxt.getOptions().getFork()) {
106: String endorsed = System.getProperty("java.endorsed.dirs");
107: if (endorsed != null) {
108: parameters.add("-endorseddirs"); // "-J-Djava.endorsed.dirs="+endorsed
109: parameters.add(endorsed);
110: info.append(" endorsed dir=" + endorsed + "\n");
111: } else {
112: info.append(" no endorsed dirs specified\n");
113: }
114: }
115:
116: if (ctxt.getOptions().getClassDebugInfo())
117: parameters.add("-g");
118:
119: Exception ie = null;
120:
121: // Set the Java compiler to use
122: if (javaCompiler == null) {
123: // assumption, there is no dynamic changing Java compiler
124: String compiler = options.getCompiler();
125: if (compiler == null)
126: compiler = "com.sun.tools.javac.Main";
127: // verify compiler
128: try {
129: javaCompiler = Class.forName(compiler);
130: } catch (ClassNotFoundException cnfe) {
131: // try to figure out class path to compiler
132: String compileClassPath = System
133: .getProperty("java.home");
134: if (compileClassPath == null)
135: try {
136: compileClassPath = System.getenv("JAVA_HOME");
137: if (compileClassPath == null)
138: compileClassPath = System
139: .getenv("java_home");
140: } catch (SecurityException se) {
141:
142: }
143:
144: if (compileClassPath != null) {
145: // HACK for now
146: compileClassPath = compileClassPath.replace("jre",
147: "jdk");
148: compileClassPath += "/lib/tools.jar";
149: info.append(" checking default compiler in "
150: + compileClassPath + "\n");
151: try {
152: javaCompiler = Class.forName(compiler, true,
153: new URLClassLoader(new URL[] { new URL(
154: "file", "localhost",
155: compileClassPath) }));
156: } catch (Error er) {
157: log
158: .error(
159: "Setting up Java compiler error ",
160: er);
161: } catch (Exception ex) {
162: log.error(
163: "Setting up Java compiler exception ",
164: ex);
165: }
166: } else
167: info.append(" no Java home path specified\n");
168: }
169: info.append(" compiler=" + compiler + "\n");
170: }
171:
172: if (options.getCompilerTargetVM() != null) {
173: parameters.add("-target");
174: parameters.add(options.getCompilerTargetVM());
175: info.append(" compilerTargetVM="
176: + options.getCompilerTargetVM() + "\n");
177: }
178:
179: if (options.getCompilerSourceVM() != null) {
180: parameters.add("-source");
181: parameters.add(options.getCompilerSourceVM());
182: info.append(" compilerSourceVM="
183: + options.getCompilerSourceVM() + "\n");
184: }
185:
186: info.append(" JavaPath=" + ctxt.getJavaPath() + "\n");
187:
188: parameters.add(javaFileName);
189:
190: boolean compilationErrors = false;
191: String errorCapture = null;
192: if (javaCompiler != null)
193: try {
194: Integer success;
195: Method cm = javaCompiler.getMethod("compile",
196: new Class[] { String[].class });
197: if (ctxt.getOptions().getFork()) {
198: success = (Integer) cm.invoke(null,
199: new Object[] { parameters
200: .toArray(new String[parameters
201: .size()]) });
202: } else {
203: synchronized (javacLock) {
204: success = (Integer) cm.invoke(null,
205: new Object[] { parameters
206: .toArray(new String[parameters
207: .size()]) });
208: }
209: }
210: if (success.intValue() != 0)
211: compilationErrors = true;
212: } catch (Throwable t) {
213: if (t instanceof ThreadDeath)
214: throw (ThreadDeath) t;
215: if (t instanceof InvocationTargetException)
216: t = t.getCause();
217: if (t instanceof Exception)
218: ie = (Exception) t;
219: else
220: ie = new Exception(t);
221: log.error("Javac exception ", t);
222: log.error("Env: " + info.toString());
223: } finally {
224: // Stop capturing the System.err output for this thread
225: errorCapture = SystemLogHandler.unsetThread();
226: }
227: if (compilationErrors && errorCapture != null) {
228: errorReport.append(System.getProperty("line.separator"));
229: errorReport.append(errorCapture);
230: }
231:
232: if (!ctxt.keepGenerated()) {
233: if (new File(javaFileName).delete() == false)
234: log.error("Couldn't delete source: " + javaFileName);
235: }
236:
237: if (compilationErrors || ie != null) {
238: String errorReportString = errorReport.toString();
239: log.error("Error compiling file: " + javaFileName + " "
240: + errorReportString);
241: JavacErrorDetail[] javacErrors = ErrorDispatcher
242: .parseJavacErrors(errorReportString, javaFileName,
243: pageNodes);
244: if (javacErrors != null) {
245: errDispatcher.javacError(javacErrors);
246: } else {
247: errDispatcher.javacError(errorReportString, ie);
248: }
249: }
250:
251: if (log.isDebugEnabled()) {
252: long t2 = System.currentTimeMillis();
253: log.debug("Compiled " + ctxt.getServletJavaFileName() + " "
254: + (t2 - t1) + "ms");
255: }
256:
257: if (ctxt.isPrototypeMode()) {
258: return;
259: }
260:
261: // JSR45 Support
262: if (!options.isSmapSuppressed()) {
263: log.debug("Install Smap "
264: + (smap == null ? "null" : Arrays.toString(smap)));
265: SmapUtil.installSmap(smap);
266: }
267: }
268:
269: protected static class SystemLogHandler extends PrintStream {
270:
271: // ----------------------------------------------------------- Constructors
272:
273: /**
274: * Construct the handler to capture the output of the given steam.
275: */
276: public SystemLogHandler(PrintStream wrapped) {
277: super (wrapped);
278: this .wrapped = wrapped;
279: }
280:
281: // ----------------------------------------------------- Instance Variables
282:
283: /**
284: * Wrapped PrintStream.
285: */
286: protected PrintStream wrapped = null;
287:
288: /**
289: * Thread <-> PrintStream associations.
290: */
291: protected static ThreadLocal streams = new ThreadLocal();
292:
293: /**
294: * Thread <-> ByteArrayOutputStream associations.
295: */
296: protected static ThreadLocal data = new ThreadLocal();
297:
298: // --------------------------------------------------------- Public Methods
299:
300: public PrintStream getWrapped() {
301: return wrapped;
302: }
303:
304: /**
305: * Start capturing thread's output.
306: */
307: public static void setThread() {
308: ByteArrayOutputStream baos = new ByteArrayOutputStream();
309: data.set(baos);
310: streams.set(new PrintStream(baos));
311: }
312:
313: /**
314: * Stop capturing thread's output and return captured data as a String.
315: */
316: public static String unsetThread() {
317: ByteArrayOutputStream baos = (ByteArrayOutputStream) data
318: .get();
319: if (baos == null) {
320: return null;
321: }
322: streams.set(null);
323: data.set(null);
324: return baos.toString();
325: }
326:
327: // ------------------------------------------------------ Protected Methods
328:
329: /**
330: * Find PrintStream to which the output must be written to.
331: */
332: protected PrintStream findStream() {
333: PrintStream ps = (PrintStream) streams.get();
334: if (ps == null) {
335: ps = wrapped;
336: }
337: return ps;
338: }
339:
340: // ---------------------------------------------------- PrintStream Methods
341:
342: public void flush() {
343: findStream().flush();
344: }
345:
346: public void close() {
347: findStream().close();
348: }
349:
350: public boolean checkError() {
351: return findStream().checkError();
352: }
353:
354: protected void setError() {
355: //findStream().setError();
356: }
357:
358: public void write(int b) {
359: findStream().write(b);
360: }
361:
362: public void write(byte[] b) throws IOException {
363: findStream().write(b);
364: }
365:
366: public void write(byte[] buf, int off, int len) {
367: findStream().write(buf, off, len);
368: }
369:
370: public void print(boolean b) {
371: findStream().print(b);
372: }
373:
374: public void print(char c) {
375: findStream().print(c);
376: }
377:
378: public void print(int i) {
379: findStream().print(i);
380: }
381:
382: public void print(long l) {
383: findStream().print(l);
384: }
385:
386: public void print(float f) {
387: findStream().print(f);
388: }
389:
390: public void print(double d) {
391: findStream().print(d);
392: }
393:
394: public void print(char[] s) {
395: findStream().print(s);
396: }
397:
398: public void print(String s) {
399: findStream().print(s);
400: }
401:
402: public void print(Object obj) {
403: findStream().print(obj);
404: }
405:
406: public void println() {
407: findStream().println();
408: }
409:
410: public void println(boolean x) {
411: findStream().println(x);
412: }
413:
414: public void println(char x) {
415: findStream().println(x);
416: }
417:
418: public void println(int x) {
419: findStream().println(x);
420: }
421:
422: public void println(long x) {
423: findStream().println(x);
424: }
425:
426: public void println(float x) {
427: findStream().println(x);
428: }
429:
430: public void println(double x) {
431: findStream().println(x);
432: }
433:
434: public void println(char[] x) {
435: findStream().println(x);
436: }
437:
438: public void println(String x) {
439: findStream().println(x);
440: }
441:
442: public void println(Object x) {
443: findStream().println(x);
444: }
445:
446: }
447:
448: }
|