KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > jasper > compiler > Compiler


1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements. See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */

17
18 package org.apache.jasper.compiler;
19
20 import java.io.File JavaDoc;
21 import java.io.FileNotFoundException JavaDoc;
22 import java.io.FileOutputStream JavaDoc;
23 import java.io.OutputStreamWriter JavaDoc;
24 import java.io.PrintWriter JavaDoc;
25 import java.io.UnsupportedEncodingException JavaDoc;
26 import java.net.URL JavaDoc;
27 import java.net.URLConnection JavaDoc;
28 import java.util.Iterator JavaDoc;
29 import java.util.List JavaDoc;
30
31 import org.apache.jasper.JasperException;
32 import org.apache.jasper.JspCompilationContext;
33 import org.apache.jasper.Options;
34 import org.apache.jasper.servlet.JspServletWrapper;
35
36 /**
37  * Main JSP compiler class. This class uses Ant for compiling.
38  *
39  * @author Anil K. Vijendran
40  * @author Mandar Raje
41  * @author Pierre Delisle
42  * @author Kin-man Chung
43  * @author Remy Maucherat
44  * @author Mark Roth
45  */

46 public abstract class Compiler {
47     
48     protected org.apache.commons.logging.Log log = org.apache.commons.logging.LogFactory
49             .getLog(Compiler JavaDoc.class);
50
51     // ----------------------------------------------------- Instance Variables
52

53     protected JspCompilationContext ctxt;
54
55     protected ErrorDispatcher errDispatcher;
56
57     protected PageInfo pageInfo;
58
59     protected JspServletWrapper jsw;
60
61     protected TagFileProcessor tfp;
62
63     protected Options options;
64
65     protected Node.Nodes pageNodes;
66
67     // ------------------------------------------------------------ Constructor
68

69     public void init(JspCompilationContext ctxt, JspServletWrapper jsw) {
70         this.jsw = jsw;
71         this.ctxt = ctxt;
72         this.options = ctxt.getOptions();
73     }
74
75     // --------------------------------------------------------- Public Methods
76

77     /**
78      * <p>
79      * Retrieves the parsed nodes of the JSP page, if they are available. May
80      * return null. Used in development mode for generating detailed error
81      * messages. http://issues.apache.org/bugzilla/show_bug.cgi?id=37062.
82      * </p>
83      */

84     public Node.Nodes getPageNodes() {
85         return this.pageNodes;
86     }
87
88     /**
89      * Compile the jsp file into equivalent servlet in .java file
90      *
91      * @return a smap for the current JSP page, if one is generated, null
92      * otherwise
93      */

94     protected String JavaDoc[] generateJava() throws Exception JavaDoc {
95
96         String JavaDoc[] smapStr = null;
97
98         long t1, t2, t3, t4;
99
100         t1 = t2 = t3 = t4 = 0;
101
102         if (log.isDebugEnabled()) {
103             t1 = System.currentTimeMillis();
104         }
105
106         // Setup page info area
107
pageInfo = new PageInfo(new BeanRepository(ctxt.getClassLoader(),
108                 errDispatcher), ctxt.getJspFile());
109
110         JspConfig jspConfig = options.getJspConfig();
111         JspConfig.JspProperty jspProperty = jspConfig.findJspProperty(ctxt
112                 .getJspFile());
113
114         /*
115          * If the current uri is matched by a pattern specified in a
116          * jsp-property-group in web.xml, initialize pageInfo with those
117          * properties.
118          */

119         if (jspProperty.isELIgnored() != null) {
120             pageInfo.setELIgnored(JspUtil.booleanValue(jspProperty
121                     .isELIgnored()));
122         }
123         if (jspProperty.isScriptingInvalid() != null) {
124             pageInfo.setScriptingInvalid(JspUtil.booleanValue(jspProperty
125                     .isScriptingInvalid()));
126         }
127         if (jspProperty.getIncludePrelude() != null) {
128             pageInfo.setIncludePrelude(jspProperty.getIncludePrelude());
129         }
130         if (jspProperty.getIncludeCoda() != null) {
131             pageInfo.setIncludeCoda(jspProperty.getIncludeCoda());
132         }
133         if (jspProperty.isDeferedSyntaxAllowedAsLiteral() != null) {
134             pageInfo.setDeferredSyntaxAllowedAsLiteral(JspUtil.booleanValue(jspProperty
135                     .isDeferedSyntaxAllowedAsLiteral()));
136         }
137         if (jspProperty.isTrimDirectiveWhitespaces() != null) {
138             pageInfo.setTrimDirectiveWhitespaces(JspUtil.booleanValue(jspProperty
139                     .isTrimDirectiveWhitespaces()));
140         }
141
142         ctxt.checkOutputDir();
143         String JavaDoc javaFileName = ctxt.getServletJavaFileName();
144         ServletWriter writer = null;
145
146         try {
147             // Setup the ServletWriter
148
String JavaDoc javaEncoding = ctxt.getOptions().getJavaEncoding();
149             OutputStreamWriter JavaDoc osw = null;
150
151             try {
152                 osw = new OutputStreamWriter JavaDoc(
153                         new FileOutputStream JavaDoc(javaFileName), javaEncoding);
154             } catch (UnsupportedEncodingException JavaDoc ex) {
155                 errDispatcher.jspError("jsp.error.needAlternateJavaEncoding",
156                         javaEncoding);
157             }
158
159             writer = new ServletWriter(new PrintWriter JavaDoc(osw));
160             ctxt.setWriter(writer);
161
162             // Reset the temporary variable counter for the generator.
163
JspUtil.resetTemporaryVariableName();
164
165             // Parse the file
166
ParserController parserCtl = new ParserController(ctxt, this);
167             pageNodes = parserCtl.parse(ctxt.getJspFile());
168
169             if (ctxt.isPrototypeMode()) {
170                 // generate prototype .java file for the tag file
171
Generator.generate(writer, this, pageNodes);
172                 writer.close();
173                 writer = null;
174                 return null;
175             }
176
177             // Validate and process attributes
178
Validator.validate(this, pageNodes);
179
180             if (log.isDebugEnabled()) {
181                 t2 = System.currentTimeMillis();
182             }
183
184             // Collect page info
185
Collector.collect(this, pageNodes);
186
187             // Compile (if necessary) and load the tag files referenced in
188
// this compilation unit.
189
tfp = new TagFileProcessor();
190             tfp.loadTagFiles(this, pageNodes);
191
192             if (log.isDebugEnabled()) {
193                 t3 = System.currentTimeMillis();
194             }
195
196             // Determine which custom tag needs to declare which scripting vars
197
ScriptingVariabler.set(pageNodes, errDispatcher);
198
199             // Optimizations by Tag Plugins
200
TagPluginManager tagPluginManager = options.getTagPluginManager();
201             tagPluginManager.apply(pageNodes, errDispatcher, pageInfo);
202
203             // Optimization: concatenate contiguous template texts.
204
TextOptimizer.concatenate(this, pageNodes);
205
206             // Generate static function mapper codes.
207
ELFunctionMapper.map(this, pageNodes);
208
209             // generate servlet .java file
210
Generator.generate(writer, this, pageNodes);
211             writer.close();
212             writer = null;
213
214             // The writer is only used during the compile, dereference
215
// it in the JspCompilationContext when done to allow it
216
// to be GC'd and save memory.
217
ctxt.setWriter(null);
218
219             if (log.isDebugEnabled()) {
220                 t4 = System.currentTimeMillis();
221                 log.debug("Generated " + javaFileName + " total=" + (t4 - t1)
222                         + " generate=" + (t4 - t3) + " validate=" + (t2 - t1));
223             }
224
225         } catch (Exception JavaDoc e) {
226             if (writer != null) {
227                 try {
228                     writer.close();
229                     writer = null;
230                 } catch (Exception JavaDoc e1) {
231                     // do nothing
232
}
233             }
234             // Remove the generated .java file
235
new File JavaDoc(javaFileName).delete();
236             throw e;
237         } finally {
238             if (writer != null) {
239                 try {
240                     writer.close();
241                 } catch (Exception JavaDoc e2) {
242                     // do nothing
243
}
244             }
245         }
246
247         // JSR45 Support
248
if (!options.isSmapSuppressed()) {
249             smapStr = SmapUtil.generateSmap(ctxt, pageNodes);
250         }
251
252         // If any proto type .java and .class files was generated,
253
// the prototype .java may have been replaced by the current
254
// compilation (if the tag file is self referencing), but the
255
// .class file need to be removed, to make sure that javac would
256
// generate .class again from the new .java file just generated.
257
tfp.removeProtoTypeFiles(ctxt.getClassFileName());
258
259         return smapStr;
260     }
261
262     /**
263      * Compile the servlet from .java file to .class file
264      */

265     protected abstract void generateClass(String JavaDoc[] smap)
266             throws FileNotFoundException JavaDoc, JasperException, Exception JavaDoc;
267
268     /**
269      * Compile the jsp file from the current engine context
270      */

271     public void compile() throws FileNotFoundException JavaDoc, JasperException,
272             Exception JavaDoc {
273         compile(true);
274     }
275
276     /**
277      * Compile the jsp file from the current engine context. As an side- effect,
278      * tag files that are referenced by this page are also compiled.
279      *
280      * @param compileClass
281      * If true, generate both .java and .class file If false,
282      * generate only .java file
283      */

284     public void compile(boolean compileClass) throws FileNotFoundException JavaDoc,
285             JasperException, Exception JavaDoc {
286         compile(compileClass, false);
287     }
288
289     /**
290      * Compile the jsp file from the current engine context. As an side- effect,
291      * tag files that are referenced by this page are also compiled.
292      *
293      * @param compileClass
294      * If true, generate both .java and .class file If false,
295      * generate only .java file
296      * @param jspcMode
297      * true if invoked from JspC, false otherwise
298      */

299     public void compile(boolean compileClass, boolean jspcMode)
300             throws FileNotFoundException JavaDoc, JasperException, Exception JavaDoc {
301         if (errDispatcher == null) {
302             this.errDispatcher = new ErrorDispatcher(jspcMode);
303         }
304
305         try {
306             String JavaDoc[] smap = generateJava();
307             if (compileClass) {
308                 generateClass(smap);
309             }
310         } finally {
311             if (tfp != null) {
312                 tfp.removeProtoTypeFiles(null);
313             }
314             // Make sure these object which are only used during the
315
// generation and compilation of the JSP page get
316
// dereferenced so that they can be GC'd and reduce the
317
// memory footprint.
318
tfp = null;
319             errDispatcher = null;
320             pageInfo = null;
321
322             // Only get rid of the pageNodes if in production.
323
// In development mode, they are used for detailed
324
// error messages.
325
// http://issues.apache.org/bugzilla/show_bug.cgi?id=37062
326
if (!this.options.getDevelopment()) {
327                 pageNodes = null;
328             }
329
330             if (ctxt.getWriter() != null) {
331                 ctxt.getWriter().close();
332                 ctxt.setWriter(null);
333             }
334         }
335     }
336
337     /**
338      * This is a protected method intended to be overridden by subclasses of
339      * Compiler. This is used by the compile method to do all the compilation.
340      */

341     public boolean isOutDated() {
342         return isOutDated(true);
343     }
344
345     /**
346      * Determine if a compilation is necessary by checking the time stamp of the
347      * JSP page with that of the corresponding .class or .java file. If the page
348      * has dependencies, the check is also extended to its dependeants, and so
349      * on. This method can by overidden by a subclasses of Compiler.
350      *
351      * @param checkClass
352      * If true, check against .class file, if false, check against
353      * .java file.
354      */

355     public boolean isOutDated(boolean checkClass) {
356
357         String JavaDoc jsp = ctxt.getJspFile();
358
359         if (jsw != null
360                 && (ctxt.getOptions().getModificationTestInterval() > 0)) {
361
362             if (jsw.getLastModificationTest()
363                     + (ctxt.getOptions().getModificationTestInterval() * 1000) > System
364                     .currentTimeMillis()) {
365                 return false;
366             } else {
367                 jsw.setLastModificationTest(System.currentTimeMillis());
368             }
369         }
370
371         long jspRealLastModified = 0;
372         try {
373             URL JavaDoc jspUrl = ctxt.getResource(jsp);
374             if (jspUrl == null) {
375                 ctxt.incrementRemoved();
376                 return false;
377             }
378             URLConnection JavaDoc uc = jspUrl.openConnection();
379             jspRealLastModified = uc.getLastModified();
380             uc.getInputStream().close();
381         } catch (Exception JavaDoc e) {
382             return true;
383         }
384
385         long targetLastModified = 0;
386         File JavaDoc targetFile;
387
388         if (checkClass) {
389             targetFile = new File JavaDoc(ctxt.getClassFileName());
390         } else {
391             targetFile = new File JavaDoc(ctxt.getServletJavaFileName());
392         }
393
394         if (!targetFile.exists()) {
395             return true;
396         }
397
398         targetLastModified = targetFile.lastModified();
399         if (checkClass && jsw != null) {
400             jsw.setServletClassLastModifiedTime(targetLastModified);
401         }
402         if (targetLastModified < jspRealLastModified) {
403             if (log.isDebugEnabled()) {
404                 log.debug("Compiler: outdated: " + targetFile + " "
405                         + targetLastModified);
406             }
407             return true;
408         }
409
410         // determine if source dependent files (e.g. includes using include
411
// directives) have been changed.
412
if (jsw == null) {
413             return false;
414         }
415
416         List JavaDoc depends = jsw.getDependants();
417         if (depends == null) {
418             return false;
419         }
420
421         Iterator JavaDoc it = depends.iterator();
422         while (it.hasNext()) {
423             String JavaDoc include = (String JavaDoc) it.next();
424             try {
425                 URL JavaDoc includeUrl = ctxt.getResource(include);
426                 if (includeUrl == null) {
427                     return true;
428                 }
429
430                 URLConnection JavaDoc includeUconn = includeUrl.openConnection();
431                 long includeLastModified = includeUconn.getLastModified();
432                 includeUconn.getInputStream().close();
433
434                 if (includeLastModified > targetLastModified) {
435                     return true;
436                 }
437             } catch (Exception JavaDoc e) {
438                 return true;
439             }
440         }
441
442         return false;
443
444     }
445
446     /**
447      * Gets the error dispatcher.
448      */

449     public ErrorDispatcher getErrorDispatcher() {
450         return errDispatcher;
451     }
452
453     /**
454      * Gets the info about the page under compilation
455      */

456     public PageInfo getPageInfo() {
457         return pageInfo;
458     }
459
460     public JspCompilationContext getCompilationContext() {
461         return ctxt;
462     }
463
464     /**
465      * Remove generated files
466      */

467     public void removeGeneratedFiles() {
468         try {
469             String JavaDoc classFileName = ctxt.getClassFileName();
470             if (classFileName != null) {
471                 File JavaDoc classFile = new File JavaDoc(classFileName);
472                 if (log.isDebugEnabled())
473                     log.debug("Deleting " + classFile);
474                 classFile.delete();
475             }
476         } catch (Exception JavaDoc e) {
477             // Remove as much as possible, ignore possible exceptions
478
}
479         try {
480             String JavaDoc javaFileName = ctxt.getServletJavaFileName();
481             if (javaFileName != null) {
482                 File JavaDoc javaFile = new File JavaDoc(javaFileName);
483                 if (log.isDebugEnabled())
484                     log.debug("Deleting " + javaFile);
485                 javaFile.delete();
486             }
487         } catch (Exception JavaDoc e) {
488             // Remove as much as possible, ignore possible exceptions
489
}
490     }
491
492     public void removeGeneratedClassFiles() {
493         try {
494             String JavaDoc classFileName = ctxt.getClassFileName();
495             if (classFileName != null) {
496                 File JavaDoc classFile = new File JavaDoc(classFileName);
497                 if (log.isDebugEnabled())
498                     log.debug("Deleting " + classFile);
499                 classFile.delete();
500             }
501         } catch (Exception JavaDoc e) {
502             // Remove as much as possible, ignore possible exceptions
503
}
504     }
505 }
506
Popular Tags