Save This Page
Home » apache-tomcat-6.0.16-src » org.apache » jasper » compiler » [javadoc | source]
    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;
   21   import java.io.FileNotFoundException;
   22   import java.io.FileOutputStream;
   23   import java.io.OutputStreamWriter;
   24   import java.io.PrintWriter;
   25   import java.io.UnsupportedEncodingException;
   26   import java.net.URL;
   27   import java.net.URLConnection;
   28   import java.util.Iterator;
   29   import java.util.List;
   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.juli.logging.Log log = org.apache.juli.logging.LogFactory
   49               .getLog(Compiler.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[] generateJava() throws Exception {
   95   
   96           String[] 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 javaFileName = ctxt.getServletJavaFileName();
  144   
  145           ServletWriter writer = null;
  146           try {
  147   
  148               // Reset the temporary variable counter for the generator.
  149               JspUtil.resetTemporaryVariableName();
  150   
  151               // Parse the file
  152               ParserController parserCtl = new ParserController(ctxt, this);
  153               pageNodes = parserCtl.parse(ctxt.getJspFile());
  154   
  155               if (ctxt.isPrototypeMode()) {
  156                   // generate prototype .java file for the tag file
  157                   writer = setupContextWriter(javaFileName);
  158                   Generator.generate(writer, this, pageNodes);
  159                   writer.close();
  160                   writer = null;
  161                   return null;
  162               }
  163   
  164               // Validate and process attributes
  165               Validator.validate(this, pageNodes);
  166   
  167               if (log.isDebugEnabled()) {
  168                   t2 = System.currentTimeMillis();
  169               }
  170   
  171               // Collect page info
  172               Collector.collect(this, pageNodes);
  173   
  174               // Compile (if necessary) and load the tag files referenced in
  175               // this compilation unit.
  176               tfp = new TagFileProcessor();
  177               tfp.loadTagFiles(this, pageNodes);
  178   
  179               if (log.isDebugEnabled()) {
  180                   t3 = System.currentTimeMillis();
  181               }
  182   
  183               // Determine which custom tag needs to declare which scripting vars
  184               ScriptingVariabler.set(pageNodes, errDispatcher);
  185   
  186               // Optimizations by Tag Plugins
  187               TagPluginManager tagPluginManager = options.getTagPluginManager();
  188               tagPluginManager.apply(pageNodes, errDispatcher, pageInfo);
  189   
  190               // Optimization: concatenate contiguous template texts.
  191               TextOptimizer.concatenate(this, pageNodes);
  192   
  193               // Generate static function mapper codes.
  194               ELFunctionMapper.map(this, pageNodes);
  195   
  196               // generate servlet .java file
  197               writer = setupContextWriter(javaFileName);
  198               Generator.generate(writer, this, pageNodes);
  199               writer.close();
  200               writer = null;
  201   
  202               // The writer is only used during the compile, dereference
  203               // it in the JspCompilationContext when done to allow it
  204               // to be GC'd and save memory.
  205               ctxt.setWriter(null);
  206   
  207               if (log.isDebugEnabled()) {
  208                   t4 = System.currentTimeMillis();
  209                   log.debug("Generated " + javaFileName + " total=" + (t4 - t1)
  210                           + " generate=" + (t4 - t3) + " validate=" + (t2 - t1));
  211               }
  212   
  213           } catch (Exception e) {
  214               if (writer != null) {
  215                   try {
  216                       writer.close();
  217                       writer = null;
  218                   } catch (Exception e1) {
  219                       // do nothing
  220                   }
  221               }
  222               // Remove the generated .java file
  223               new File(javaFileName).delete();
  224               throw e;
  225           } finally {
  226               if (writer != null) {
  227                   try {
  228                       writer.close();
  229                   } catch (Exception e2) {
  230                       // do nothing
  231                   }
  232               }
  233           }
  234   
  235           // JSR45 Support
  236           if (!options.isSmapSuppressed()) {
  237               smapStr = SmapUtil.generateSmap(ctxt, pageNodes);
  238           }
  239   
  240           // If any proto type .java and .class files was generated,
  241           // the prototype .java may have been replaced by the current
  242           // compilation (if the tag file is self referencing), but the
  243           // .class file need to be removed, to make sure that javac would
  244           // generate .class again from the new .java file just generated.
  245           tfp.removeProtoTypeFiles(ctxt.getClassFileName());
  246   
  247           return smapStr;
  248       }
  249   
  250   	private ServletWriter setupContextWriter(String javaFileName)
  251   			throws FileNotFoundException, JasperException {
  252   		ServletWriter writer;
  253   		// Setup the ServletWriter
  254   		String javaEncoding = ctxt.getOptions().getJavaEncoding();
  255   		OutputStreamWriter osw = null;
  256   
  257   		try {
  258   		    osw = new OutputStreamWriter(
  259   		            new FileOutputStream(javaFileName), javaEncoding);
  260   		} catch (UnsupportedEncodingException ex) {
  261   		    errDispatcher.jspError("jsp.error.needAlternateJavaEncoding",
  262   		            javaEncoding);
  263   		}
  264   
  265   		writer = new ServletWriter(new PrintWriter(osw));
  266   		ctxt.setWriter(writer);
  267   		return writer;
  268   	}
  269   
  270       /**
  271        * Compile the servlet from .java file to .class file
  272        */
  273       protected abstract void generateClass(String[] smap)
  274               throws FileNotFoundException, JasperException, Exception;
  275   
  276       /**
  277        * Compile the jsp file from the current engine context
  278        */
  279       public void compile() throws FileNotFoundException, JasperException,
  280               Exception {
  281           compile(true);
  282       }
  283   
  284       /**
  285        * Compile the jsp file from the current engine context. As an side- effect,
  286        * tag files that are referenced by this page are also compiled.
  287        * 
  288        * @param compileClass
  289        *            If true, generate both .java and .class file If false,
  290        *            generate only .java file
  291        */
  292       public void compile(boolean compileClass) throws FileNotFoundException,
  293               JasperException, Exception {
  294           compile(compileClass, false);
  295       }
  296   
  297       /**
  298        * Compile the jsp file from the current engine context. As an side- effect,
  299        * tag files that are referenced by this page are also compiled.
  300        * 
  301        * @param compileClass
  302        *            If true, generate both .java and .class file If false,
  303        *            generate only .java file
  304        * @param jspcMode
  305        *            true if invoked from JspC, false otherwise
  306        */
  307       public void compile(boolean compileClass, boolean jspcMode)
  308               throws FileNotFoundException, JasperException, Exception {
  309           if (errDispatcher == null) {
  310               this.errDispatcher = new ErrorDispatcher(jspcMode);
  311           }
  312   
  313           try {
  314               String[] smap = generateJava();
  315               if (compileClass) {
  316                   generateClass(smap);
  317               }
  318           } finally {
  319               if (tfp != null) {
  320                   tfp.removeProtoTypeFiles(null);
  321               }
  322               // Make sure these object which are only used during the
  323               // generation and compilation of the JSP page get
  324               // dereferenced so that they can be GC'd and reduce the
  325               // memory footprint.
  326               tfp = null;
  327               errDispatcher = null;
  328               pageInfo = null;
  329   
  330               // Only get rid of the pageNodes if in production.
  331               // In development mode, they are used for detailed
  332               // error messages.
  333               // http://issues.apache.org/bugzilla/show_bug.cgi?id=37062
  334               if (!this.options.getDevelopment()) {
  335                   pageNodes = null;
  336               }
  337   
  338               if (ctxt.getWriter() != null) {
  339                   ctxt.getWriter().close();
  340                   ctxt.setWriter(null);
  341               }
  342           }
  343       }
  344   
  345       /**
  346        * This is a protected method intended to be overridden by subclasses of
  347        * Compiler. This is used by the compile method to do all the compilation.
  348        */
  349       public boolean isOutDated() {
  350           return isOutDated(true);
  351       }
  352   
  353       /**
  354        * Determine if a compilation is necessary by checking the time stamp of the
  355        * JSP page with that of the corresponding .class or .java file. If the page
  356        * has dependencies, the check is also extended to its dependeants, and so
  357        * on. This method can by overidden by a subclasses of Compiler.
  358        * 
  359        * @param checkClass
  360        *            If true, check against .class file, if false, check against
  361        *            .java file.
  362        */
  363       public boolean isOutDated(boolean checkClass) {
  364   
  365           String jsp = ctxt.getJspFile();
  366   
  367           if (jsw != null
  368                   && (ctxt.getOptions().getModificationTestInterval() > 0)) {
  369   
  370               if (jsw.getLastModificationTest()
  371                       + (ctxt.getOptions().getModificationTestInterval() * 1000) > System
  372                       .currentTimeMillis()) {
  373                   return false;
  374               } else {
  375                   jsw.setLastModificationTest(System.currentTimeMillis());
  376               }
  377           }
  378   
  379           long jspRealLastModified = 0;
  380           try {
  381               URL jspUrl = ctxt.getResource(jsp);
  382               if (jspUrl == null) {
  383                   ctxt.incrementRemoved();
  384                   return false;
  385               }
  386               URLConnection uc = jspUrl.openConnection();
  387               jspRealLastModified = uc.getLastModified();
  388               uc.getInputStream().close();
  389           } catch (Exception e) {
  390               return true;
  391           }
  392   
  393           long targetLastModified = 0;
  394           File targetFile;
  395   
  396           if (checkClass) {
  397               targetFile = new File(ctxt.getClassFileName());
  398           } else {
  399               targetFile = new File(ctxt.getServletJavaFileName());
  400           }
  401   
  402           if (!targetFile.exists()) {
  403               return true;
  404           }
  405   
  406           targetLastModified = targetFile.lastModified();
  407           if (checkClass && jsw != null) {
  408               jsw.setServletClassLastModifiedTime(targetLastModified);
  409           }
  410           if (targetLastModified < jspRealLastModified) {
  411               if (log.isDebugEnabled()) {
  412                   log.debug("Compiler: outdated: " + targetFile + " "
  413                           + targetLastModified);
  414               }
  415               return true;
  416           }
  417   
  418           // determine if source dependent files (e.g. includes using include
  419           // directives) have been changed.
  420           if (jsw == null) {
  421               return false;
  422           }
  423   
  424           List depends = jsw.getDependants();
  425           if (depends == null) {
  426               return false;
  427           }
  428   
  429           Iterator it = depends.iterator();
  430           while (it.hasNext()) {
  431               String include = (String) it.next();
  432               try {
  433                   URL includeUrl = ctxt.getResource(include);
  434                   if (includeUrl == null) {
  435                       return true;
  436                   }
  437   
  438                   URLConnection includeUconn = includeUrl.openConnection();
  439                   long includeLastModified = includeUconn.getLastModified();
  440                   includeUconn.getInputStream().close();
  441   
  442                   if (includeLastModified > targetLastModified) {
  443                       return true;
  444                   }
  445               } catch (Exception e) {
  446                   return true;
  447               }
  448           }
  449   
  450           return false;
  451   
  452       }
  453   
  454       /**
  455        * Gets the error dispatcher.
  456        */
  457       public ErrorDispatcher getErrorDispatcher() {
  458           return errDispatcher;
  459       }
  460   
  461       /**
  462        * Gets the info about the page under compilation
  463        */
  464       public PageInfo getPageInfo() {
  465           return pageInfo;
  466       }
  467   
  468       public JspCompilationContext getCompilationContext() {
  469           return ctxt;
  470       }
  471   
  472       /**
  473        * Remove generated files
  474        */
  475       public void removeGeneratedFiles() {
  476           try {
  477               String classFileName = ctxt.getClassFileName();
  478               if (classFileName != null) {
  479                   File classFile = new File(classFileName);
  480                   if (log.isDebugEnabled())
  481                       log.debug("Deleting " + classFile);
  482                   classFile.delete();
  483               }
  484           } catch (Exception e) {
  485               // Remove as much as possible, ignore possible exceptions
  486           }
  487           try {
  488               String javaFileName = ctxt.getServletJavaFileName();
  489               if (javaFileName != null) {
  490                   File javaFile = new File(javaFileName);
  491                   if (log.isDebugEnabled())
  492                       log.debug("Deleting " + javaFile);
  493                   javaFile.delete();
  494               }
  495           } catch (Exception e) {
  496               // Remove as much as possible, ignore possible exceptions
  497           }
  498       }
  499   
  500       public void removeGeneratedClassFiles() {
  501           try {
  502               String classFileName = ctxt.getClassFileName();
  503               if (classFileName != null) {
  504                   File classFile = new File(classFileName);
  505                   if (log.isDebugEnabled())
  506                       log.debug("Deleting " + classFile);
  507                   classFile.delete();
  508               }
  509           } catch (Exception e) {
  510               // Remove as much as possible, ignore possible exceptions
  511           }
  512       }
  513   }

Save This Page
Home » apache-tomcat-6.0.16-src » org.apache » jasper » compiler » [javadoc | source]