Save This Page
Home » apache-tomcat-6.0.26-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.JarURLConnection;
   27   import java.net.URL;
   28   import java.net.URLConnection;
   29   import java.util.Iterator;
   30   import java.util.List;
   31   
   32   import org.apache.jasper.JasperException;
   33   import org.apache.jasper.JspCompilationContext;
   34   import org.apache.jasper.Options;
   35   import org.apache.jasper.servlet.JspServletWrapper;
   36   
   37   /**
   38    * Main JSP compiler class. This class uses Ant for compiling.
   39    * 
   40    * @author Anil K. Vijendran
   41    * @author Mandar Raje
   42    * @author Pierre Delisle
   43    * @author Kin-man Chung
   44    * @author Remy Maucherat
   45    * @author Mark Roth
   46    */
   47   public abstract class Compiler {
   48       
   49       protected org.apache.juli.logging.Log log = org.apache.juli.logging.LogFactory
   50               .getLog(Compiler.class);
   51   
   52       // ----------------------------------------------------- Instance Variables
   53   
   54       protected JspCompilationContext ctxt;
   55   
   56       protected ErrorDispatcher errDispatcher;
   57   
   58       protected PageInfo pageInfo;
   59   
   60       protected JspServletWrapper jsw;
   61   
   62       protected TagFileProcessor tfp;
   63   
   64       protected Options options;
   65   
   66       protected Node.Nodes pageNodes;
   67   
   68       // ------------------------------------------------------------ Constructor
   69   
   70       public void init(JspCompilationContext ctxt, JspServletWrapper jsw) {
   71           this.jsw = jsw;
   72           this.ctxt = ctxt;
   73           this.options = ctxt.getOptions();
   74       }
   75   
   76       // --------------------------------------------------------- Public Methods
   77   
   78       /**
   79        * <p>
   80        * Retrieves the parsed nodes of the JSP page, if they are available. May
   81        * return null. Used in development mode for generating detailed error
   82        * messages. http://issues.apache.org/bugzilla/show_bug.cgi?id=37062.
   83        * </p>
   84        */
   85       public Node.Nodes getPageNodes() {
   86           return this.pageNodes;
   87       }
   88   
   89       /**
   90        * Compile the jsp file into equivalent servlet in .java file
   91        * 
   92        * @return a smap for the current JSP page, if one is generated, null
   93        *         otherwise
   94        */
   95       protected String[] generateJava() throws Exception {
   96   
   97           String[] smapStr = null;
   98   
   99           long t1, t2, t3, t4;
  100   
  101           t1 = t2 = t3 = t4 = 0;
  102   
  103           if (log.isDebugEnabled()) {
  104               t1 = System.currentTimeMillis();
  105           }
  106   
  107           // Setup page info area
  108           pageInfo = new PageInfo(new BeanRepository(ctxt.getClassLoader(),
  109                   errDispatcher), ctxt.getJspFile());
  110   
  111           JspConfig jspConfig = options.getJspConfig();
  112           JspConfig.JspProperty jspProperty = jspConfig.findJspProperty(ctxt
  113                   .getJspFile());
  114   
  115           /*
  116            * If the current uri is matched by a pattern specified in a
  117            * jsp-property-group in web.xml, initialize pageInfo with those
  118            * properties.
  119            */
  120           if (jspProperty.isELIgnored() != null) {
  121               pageInfo.setELIgnored(JspUtil.booleanValue(jspProperty
  122                       .isELIgnored()));
  123           }
  124           if (jspProperty.isScriptingInvalid() != null) {
  125               pageInfo.setScriptingInvalid(JspUtil.booleanValue(jspProperty
  126                       .isScriptingInvalid()));
  127           }
  128           if (jspProperty.getIncludePrelude() != null) {
  129               pageInfo.setIncludePrelude(jspProperty.getIncludePrelude());
  130           }
  131           if (jspProperty.getIncludeCoda() != null) {
  132               pageInfo.setIncludeCoda(jspProperty.getIncludeCoda());
  133           }
  134           if (jspProperty.isDeferedSyntaxAllowedAsLiteral() != null) {
  135               pageInfo.setDeferredSyntaxAllowedAsLiteral(JspUtil.booleanValue(jspProperty
  136                       .isDeferedSyntaxAllowedAsLiteral()));
  137           }
  138           if (jspProperty.isTrimDirectiveWhitespaces() != null) {
  139               pageInfo.setTrimDirectiveWhitespaces(JspUtil.booleanValue(jspProperty
  140                       .isTrimDirectiveWhitespaces()));
  141           }
  142           if (ctxt.isTagFile()) {
  143               try {
  144                   double libraryVersion = Double.parseDouble(ctxt.getTagInfo()
  145                           .getTagLibrary().getRequiredVersion());
  146                   if (libraryVersion < 2.0) {
  147                       pageInfo.setIsELIgnored("true", null, errDispatcher, true);
  148                   }
  149                   if (libraryVersion < 2.1) {
  150                       pageInfo.setDeferredSyntaxAllowedAsLiteral("true", null,
  151                               errDispatcher, true);
  152                   }
  153               } catch (NumberFormatException ex) {
  154                   errDispatcher.jspError(ex);
  155               }
  156           }
  157   
  158           ctxt.checkOutputDir();
  159           String javaFileName = ctxt.getServletJavaFileName();
  160   
  161           ServletWriter writer = null;
  162           try {
  163               /*
  164                * The setting of isELIgnored changes the behaviour of the parser
  165                * in subtle ways. To add to the 'fun', isELIgnored can be set in
  166                * any file that forms part of the translation unit so setting it
  167                * in a file included towards the end of the translation unit can
  168                * change how the parser should have behaved when parsing content
  169                * up to the point where isELIgnored was set. Arghh!
  170                * Previous attempts to hack around this have only provided partial
  171                * solutions. We now use two passes to parse the translation unit.
  172                * The first just parses the directives and the second parses the
  173                * whole translation unit once we know how isELIgnored has been set.
  174                * TODO There are some possible optimisations of this process.  
  175                */ 
  176               // Parse the file
  177               ParserController parserCtl = new ParserController(ctxt, this);
  178   
  179               // Pass 1 - the directives
  180               Node.Nodes directives =
  181                   parserCtl.parseDirectives(ctxt.getJspFile());
  182               Validator.validateDirectives(this, directives);
  183   
  184               // Pass 2 - the whole translation unit
  185               pageNodes = parserCtl.parse(ctxt.getJspFile());
  186   
  187               if (ctxt.isPrototypeMode()) {
  188                   // generate prototype .java file for the tag file
  189                   writer = setupContextWriter(javaFileName);
  190                   Generator.generate(writer, this, pageNodes);
  191                   writer.close();
  192                   writer = null;
  193                   return null;
  194               }
  195   
  196               // Validate and process attributes - don't re-validate the
  197               // directives we validated in pass 1
  198               Validator.validateExDirectives(this, pageNodes);
  199   
  200               if (log.isDebugEnabled()) {
  201                   t2 = System.currentTimeMillis();
  202               }
  203   
  204               // Collect page info
  205               Collector.collect(this, pageNodes);
  206   
  207               // Compile (if necessary) and load the tag files referenced in
  208               // this compilation unit.
  209               tfp = new TagFileProcessor();
  210               tfp.loadTagFiles(this, pageNodes);
  211   
  212               if (log.isDebugEnabled()) {
  213                   t3 = System.currentTimeMillis();
  214               }
  215   
  216               // Determine which custom tag needs to declare which scripting vars
  217               ScriptingVariabler.set(pageNodes, errDispatcher);
  218   
  219               // Optimizations by Tag Plugins
  220               TagPluginManager tagPluginManager = options.getTagPluginManager();
  221               tagPluginManager.apply(pageNodes, errDispatcher, pageInfo);
  222   
  223               // Optimization: concatenate contiguous template texts.
  224               TextOptimizer.concatenate(this, pageNodes);
  225   
  226               // Generate static function mapper codes.
  227               ELFunctionMapper.map(this, pageNodes);
  228   
  229               // generate servlet .java file
  230               writer = setupContextWriter(javaFileName);
  231               Generator.generate(writer, this, pageNodes);
  232               writer.close();
  233               writer = null;
  234   
  235               // The writer is only used during the compile, dereference
  236               // it in the JspCompilationContext when done to allow it
  237               // to be GC'd and save memory.
  238               ctxt.setWriter(null);
  239   
  240               if (log.isDebugEnabled()) {
  241                   t4 = System.currentTimeMillis();
  242                   log.debug("Generated " + javaFileName + " total=" + (t4 - t1)
  243                           + " generate=" + (t4 - t3) + " validate=" + (t2 - t1));
  244               }
  245   
  246           } catch (Exception e) {
  247               if (writer != null) {
  248                   try {
  249                       writer.close();
  250                       writer = null;
  251                   } catch (Exception e1) {
  252                       // do nothing
  253                   }
  254               }
  255               // Remove the generated .java file
  256               new File(javaFileName).delete();
  257               throw e;
  258           } finally {
  259               if (writer != null) {
  260                   try {
  261                       writer.close();
  262                   } catch (Exception e2) {
  263                       // do nothing
  264                   }
  265               }
  266           }
  267   
  268           // JSR45 Support
  269           if (!options.isSmapSuppressed()) {
  270               smapStr = SmapUtil.generateSmap(ctxt, pageNodes);
  271           }
  272   
  273           // If any proto type .java and .class files was generated,
  274           // the prototype .java may have been replaced by the current
  275           // compilation (if the tag file is self referencing), but the
  276           // .class file need to be removed, to make sure that javac would
  277           // generate .class again from the new .java file just generated.
  278           tfp.removeProtoTypeFiles(ctxt.getClassFileName());
  279   
  280           return smapStr;
  281       }
  282   
  283   	private ServletWriter setupContextWriter(String javaFileName)
  284   			throws FileNotFoundException, JasperException {
  285   		ServletWriter writer;
  286   		// Setup the ServletWriter
  287   		String javaEncoding = ctxt.getOptions().getJavaEncoding();
  288   		OutputStreamWriter osw = null;
  289   
  290   		try {
  291   		    osw = new OutputStreamWriter(
  292   		            new FileOutputStream(javaFileName), javaEncoding);
  293   		} catch (UnsupportedEncodingException ex) {
  294   		    errDispatcher.jspError("jsp.error.needAlternateJavaEncoding",
  295   		            javaEncoding);
  296   		}
  297   
  298   		writer = new ServletWriter(new PrintWriter(osw));
  299   		ctxt.setWriter(writer);
  300   		return writer;
  301   	}
  302   
  303       /**
  304        * Compile the servlet from .java file to .class file
  305        */
  306       protected abstract void generateClass(String[] smap)
  307               throws FileNotFoundException, JasperException, Exception;
  308   
  309       /**
  310        * Compile the jsp file from the current engine context
  311        */
  312       public void compile() throws FileNotFoundException, JasperException,
  313               Exception {
  314           compile(true);
  315       }
  316   
  317       /**
  318        * Compile the jsp file from the current engine context. As an side- effect,
  319        * tag files that are referenced by this page are also compiled.
  320        * 
  321        * @param compileClass
  322        *            If true, generate both .java and .class file If false,
  323        *            generate only .java file
  324        */
  325       public void compile(boolean compileClass) throws FileNotFoundException,
  326               JasperException, Exception {
  327           compile(compileClass, false);
  328       }
  329   
  330       /**
  331        * Compile the jsp file from the current engine context. As an side- effect,
  332        * tag files that are referenced by this page are also compiled.
  333        * 
  334        * @param compileClass
  335        *            If true, generate both .java and .class file If false,
  336        *            generate only .java file
  337        * @param jspcMode
  338        *            true if invoked from JspC, false otherwise
  339        */
  340       public void compile(boolean compileClass, boolean jspcMode)
  341               throws FileNotFoundException, JasperException, Exception {
  342           if (errDispatcher == null) {
  343               this.errDispatcher = new ErrorDispatcher(jspcMode);
  344           }
  345   
  346           try {
  347               String[] smap = generateJava();
  348               if (compileClass) {
  349                   generateClass(smap);
  350                   // Fix for bugzilla 41606
  351                   // Set JspServletWrapper.servletClassLastModifiedTime after successful compile
  352                   String targetFileName = ctxt.getClassFileName();
  353                   if (targetFileName != null) {
  354                       File targetFile = new File(targetFileName);
  355                       if (targetFile.exists() && jsw != null) {
  356                           jsw.setServletClassLastModifiedTime(targetFile.lastModified());
  357                       }
  358                   }
  359               }
  360           } finally {
  361               if (tfp != null && ctxt.isPrototypeMode()) {
  362                   tfp.removeProtoTypeFiles(null);
  363               }
  364               // Make sure these object which are only used during the
  365               // generation and compilation of the JSP page get
  366               // dereferenced so that they can be GC'd and reduce the
  367               // memory footprint.
  368               tfp = null;
  369               errDispatcher = null;
  370               pageInfo = null;
  371   
  372               // Only get rid of the pageNodes if in production.
  373               // In development mode, they are used for detailed
  374               // error messages.
  375               // http://issues.apache.org/bugzilla/show_bug.cgi?id=37062
  376               if (!this.options.getDevelopment()) {
  377                   pageNodes = null;
  378               }
  379   
  380               if (ctxt.getWriter() != null) {
  381                   ctxt.getWriter().close();
  382                   ctxt.setWriter(null);
  383               }
  384           }
  385       }
  386   
  387       /**
  388        * This is a protected method intended to be overridden by subclasses of
  389        * Compiler. This is used by the compile method to do all the compilation.
  390        */
  391       public boolean isOutDated() {
  392           return isOutDated(true);
  393       }
  394   
  395       /**
  396        * Determine if a compilation is necessary by checking the time stamp of the
  397        * JSP page with that of the corresponding .class or .java file. If the page
  398        * has dependencies, the check is also extended to its dependeants, and so
  399        * on. This method can by overidden by a subclasses of Compiler.
  400        * 
  401        * @param checkClass
  402        *            If true, check against .class file, if false, check against
  403        *            .java file.
  404        */
  405       public boolean isOutDated(boolean checkClass) {
  406   
  407           String jsp = ctxt.getJspFile();
  408   
  409           if (jsw != null
  410                   && (ctxt.getOptions().getModificationTestInterval() > 0)) {
  411   
  412               if (jsw.getLastModificationTest()
  413                       + (ctxt.getOptions().getModificationTestInterval() * 1000) > System
  414                       .currentTimeMillis()) {
  415                   return false;
  416               } else {
  417                   jsw.setLastModificationTest(System.currentTimeMillis());
  418               }
  419           }
  420   
  421           long jspRealLastModified = 0;
  422           try {
  423               URL jspUrl = ctxt.getResource(jsp);
  424               if (jspUrl == null) {
  425                   ctxt.incrementRemoved();
  426                   return true;
  427               }
  428               URLConnection uc = jspUrl.openConnection();
  429               if (uc instanceof JarURLConnection) {
  430                   jspRealLastModified =
  431                       ((JarURLConnection) uc).getJarEntry().getTime();
  432               } else {
  433                   jspRealLastModified = uc.getLastModified();
  434               }
  435               uc.getInputStream().close();
  436           } catch (Exception e) {
  437               log.debug("Problem accessing resource. Treat as outdated.", e);
  438               return true;
  439           }
  440   
  441           long targetLastModified = 0;
  442           File targetFile;
  443   
  444           if (checkClass) {
  445               targetFile = new File(ctxt.getClassFileName());
  446           } else {
  447               targetFile = new File(ctxt.getServletJavaFileName());
  448           }
  449   
  450           if (!targetFile.exists()) {
  451               return true;
  452           }
  453   
  454           targetLastModified = targetFile.lastModified();
  455           if (checkClass && jsw != null) {
  456               jsw.setServletClassLastModifiedTime(targetLastModified);
  457           }
  458           if (targetLastModified < jspRealLastModified) {
  459               if (log.isDebugEnabled()) {
  460                   log.debug("Compiler: outdated: " + targetFile + " "
  461                           + targetLastModified);
  462               }
  463               return true;
  464           }
  465   
  466           // determine if source dependent files (e.g. includes using include
  467           // directives) have been changed.
  468           if (jsw == null) {
  469               return false;
  470           }
  471   
  472           List depends = jsw.getDependants();
  473           if (depends == null) {
  474               return false;
  475           }
  476   
  477           Iterator it = depends.iterator();
  478           while (it.hasNext()) {
  479               String include = (String) it.next();
  480               try {
  481                   URL includeUrl = ctxt.getResource(include);
  482                   if (includeUrl == null) {
  483                       return true;
  484                   }
  485   
  486                   URLConnection iuc = includeUrl.openConnection();
  487                   long includeLastModified = 0;
  488                   if (iuc instanceof JarURLConnection) {
  489                       includeLastModified =
  490                           ((JarURLConnection) iuc).getJarEntry().getTime();
  491                   } else {
  492                       includeLastModified = iuc.getLastModified();
  493                   }
  494                   iuc.getInputStream().close();
  495   
  496                   if (includeLastModified > targetLastModified) {
  497                       return true;
  498                   }
  499               } catch (Exception e) {
  500                   log.debug("Problem accessing resource. Treat as outdated.", e);
  501                   return true;
  502               }
  503           }
  504   
  505           return false;
  506   
  507       }
  508   
  509       /**
  510        * Gets the error dispatcher.
  511        */
  512       public ErrorDispatcher getErrorDispatcher() {
  513           return errDispatcher;
  514       }
  515   
  516       /**
  517        * Gets the info about the page under compilation
  518        */
  519       public PageInfo getPageInfo() {
  520           return pageInfo;
  521       }
  522   
  523       public JspCompilationContext getCompilationContext() {
  524           return ctxt;
  525       }
  526   
  527       /**
  528        * Remove generated files
  529        */
  530       public void removeGeneratedFiles() {
  531           try {
  532               String classFileName = ctxt.getClassFileName();
  533               if (classFileName != null) {
  534                   File classFile = new File(classFileName);
  535                   if (log.isDebugEnabled())
  536                       log.debug("Deleting " + classFile);
  537                   classFile.delete();
  538               }
  539           } catch (Exception e) {
  540               // Remove as much as possible, ignore possible exceptions
  541           }
  542           try {
  543               String javaFileName = ctxt.getServletJavaFileName();
  544               if (javaFileName != null) {
  545                   File javaFile = new File(javaFileName);
  546                   if (log.isDebugEnabled())
  547                       log.debug("Deleting " + javaFile);
  548                   javaFile.delete();
  549               }
  550           } catch (Exception e) {
  551               // Remove as much as possible, ignore possible exceptions
  552           }
  553       }
  554   
  555       public void removeGeneratedClassFiles() {
  556           try {
  557               String classFileName = ctxt.getClassFileName();
  558               if (classFileName != null) {
  559                   File classFile = new File(classFileName);
  560                   if (log.isDebugEnabled())
  561                       log.debug("Deleting " + classFile);
  562                   classFile.delete();
  563               }
  564           } catch (Exception e) {
  565               // Remove as much as possible, ignore possible exceptions
  566           }
  567       }
  568   }

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