Save This Page
Home » apache-tomcat-6.0.26-src » org.apache » jasper » [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;
   19   
   20   import java.io.File;
   21   import java.io.FileNotFoundException;
   22   import java.net.MalformedURLException;
   23   import java.net.URL;
   24   import java.net.URLClassLoader;
   25   import java.util.HashMap;
   26   import java.util.Map;
   27   import java.util.Set;
   28   
   29   import javax.servlet.ServletContext;
   30   import javax.servlet.jsp.tagext.TagInfo;
   31   
   32   import org.apache.jasper.compiler.Compiler;
   33   import org.apache.jasper.compiler.JspRuntimeContext;
   34   import org.apache.jasper.compiler.JspUtil;
   35   import org.apache.jasper.compiler.Localizer;
   36   import org.apache.jasper.compiler.ServletWriter;
   37   import org.apache.jasper.servlet.JasperLoader;
   38   import org.apache.jasper.servlet.JspServletWrapper;
   39   
   40   /**
   41    * A place holder for various things that are used through out the JSP
   42    * engine. This is a per-request/per-context data structure. Some of
   43    * the instance variables are set at different points.
   44    *
   45    * Most of the path-related stuff is here - mangling names, versions, dirs,
   46    * loading resources and dealing with uris. 
   47    *
   48    * @author Anil K. Vijendran
   49    * @author Harish Prabandham
   50    * @author Pierre Delisle
   51    * @author Costin Manolache
   52    * @author Kin-man Chung
   53    */
   54   public class JspCompilationContext {
   55   
   56       protected org.apache.juli.logging.Log log =
   57           org.apache.juli.logging.LogFactory.getLog(JspCompilationContext.class);
   58   
   59       protected Map<String, URL> tagFileJarUrls;
   60       protected boolean isPackagedTagFile;
   61   
   62       protected String className;
   63       protected String jspUri;
   64       protected boolean isErrPage;
   65       protected String basePackageName;
   66       protected String derivedPackageName;
   67       protected String servletJavaFileName;
   68       protected String javaPath;
   69       protected String classFileName;
   70       protected String contentType;
   71       protected ServletWriter writer;
   72       protected Options options;
   73       protected JspServletWrapper jsw;
   74       protected Compiler jspCompiler;
   75       protected String classPath;
   76   
   77       protected String baseURI;
   78       protected String outputDir;
   79       protected ServletContext context;
   80       protected URLClassLoader loader;
   81   
   82       protected JspRuntimeContext rctxt;
   83   
   84       protected volatile int removed = 0;
   85   
   86       protected URLClassLoader jspLoader;
   87       protected URL baseUrl;
   88       protected Class servletClass;
   89   
   90       protected boolean isTagFile;
   91       protected boolean protoTypeMode;
   92       protected TagInfo tagInfo;
   93       protected URL tagFileJarUrl;
   94   
   95       // jspURI _must_ be relative to the context
   96       public JspCompilationContext(String jspUri,
   97                                    boolean isErrPage,
   98                                    Options options,
   99                                    ServletContext context,
  100                                    JspServletWrapper jsw,
  101                                    JspRuntimeContext rctxt) {
  102   
  103           this.jspUri = canonicalURI(jspUri);
  104           this.isErrPage = isErrPage;
  105           this.options = options;
  106           this.jsw = jsw;
  107           this.context = context;
  108   
  109           this.baseURI = jspUri.substring(0, jspUri.lastIndexOf('/') + 1);
  110           // hack fix for resolveRelativeURI
  111           if (baseURI == null) {
  112               baseURI = "/";
  113           } else if (baseURI.charAt(0) != '/') {
  114               // strip the basde slash since it will be combined with the
  115               // uriBase to generate a file
  116               baseURI = "/" + baseURI;
  117           }
  118           if (baseURI.charAt(baseURI.length() - 1) != '/') {
  119               baseURI += '/';
  120           }
  121   
  122           this.rctxt = rctxt;
  123           this.tagFileJarUrls = new HashMap<String, URL>();
  124           this.basePackageName = Constants.JSP_PACKAGE_NAME;
  125       }
  126   
  127       public JspCompilationContext(String tagfile,
  128                                    TagInfo tagInfo, 
  129                                    Options options,
  130                                    ServletContext context,
  131                                    JspServletWrapper jsw,
  132                                    JspRuntimeContext rctxt,
  133                                    URL tagFileJarUrl) {
  134           this(tagfile, false, options, context, jsw, rctxt);
  135           this.isTagFile = true;
  136           this.tagInfo = tagInfo;
  137           this.tagFileJarUrl = tagFileJarUrl;
  138           if (tagFileJarUrl != null) {
  139               isPackagedTagFile = true;
  140           }
  141       }
  142   
  143       /* ==================== Methods to override ==================== */
  144       
  145       /** ---------- Class path and loader ---------- */
  146   
  147       /**
  148        * The classpath that is passed off to the Java compiler. 
  149        */
  150       public String getClassPath() {
  151           if( classPath != null )
  152               return classPath;
  153           return rctxt.getClassPath();
  154       }
  155   
  156       /**
  157        * The classpath that is passed off to the Java compiler. 
  158        */
  159       public void setClassPath(String classPath) {
  160           this.classPath = classPath;
  161       }
  162   
  163       /**
  164        * What class loader to use for loading classes while compiling
  165        * this JSP?
  166        */
  167       public ClassLoader getClassLoader() {
  168           if( loader != null )
  169               return loader;
  170           return rctxt.getParentClassLoader();
  171       }
  172   
  173       public void setClassLoader(URLClassLoader loader) {
  174           this.loader = loader;
  175       }
  176   
  177       public ClassLoader getJspLoader() {
  178           if( jspLoader == null ) {
  179               jspLoader = new JasperLoader
  180               (new URL[] {baseUrl},
  181                       getClassLoader(),
  182                       rctxt.getPermissionCollection(),
  183                       rctxt.getCodeSource());
  184           }
  185           return jspLoader;
  186       }
  187   
  188       /** ---------- Input/Output  ---------- */
  189       
  190       /**
  191        * The output directory to generate code into.  The output directory
  192        * is make up of the scratch directory, which is provide in Options,
  193        * plus the directory derived from the package name.
  194        */
  195       public String getOutputDir() {
  196   	if (outputDir == null) {
  197   	    createOutputDir();
  198   	}
  199   
  200           return outputDir;
  201       }
  202   
  203       /**
  204        * Create a "Compiler" object based on some init param data. This
  205        * is not done yet. Right now we're just hardcoding the actual
  206        * compilers that are created. 
  207        */
  208       public Compiler createCompiler() throws JasperException {
  209           if (jspCompiler != null ) {
  210               return jspCompiler;
  211           }
  212           jspCompiler = null;
  213           if (options.getCompilerClassName() != null) {
  214               jspCompiler = createCompiler(options.getCompilerClassName());
  215           } else {
  216               if (options.getCompiler() == null) {
  217                   jspCompiler = createCompiler("org.apache.jasper.compiler.JDTCompiler");
  218                   if (jspCompiler == null) {
  219                       jspCompiler = createCompiler("org.apache.jasper.compiler.AntCompiler");
  220                   }
  221               } else {
  222                   jspCompiler = createCompiler("org.apache.jasper.compiler.AntCompiler");
  223                   if (jspCompiler == null) {
  224                       jspCompiler = createCompiler("org.apache.jasper.compiler.JDTCompiler");
  225                   }
  226               }
  227           }
  228           if (jspCompiler == null) {
  229               throw new IllegalStateException(Localizer.getMessage("jsp.error.compiler"));
  230           }
  231           jspCompiler.init(this, jsw);
  232           return jspCompiler;
  233       }
  234   
  235       protected Compiler createCompiler(String className) {
  236           Compiler compiler = null; 
  237           try {
  238               compiler = (Compiler) Class.forName(className).newInstance();
  239           } catch (InstantiationException e) {
  240               log.warn(Localizer.getMessage("jsp.error.compiler"), e);
  241           } catch (IllegalAccessException e) {
  242               log.warn(Localizer.getMessage("jsp.error.compiler"), e);
  243           } catch (NoClassDefFoundError e) {
  244               if (log.isDebugEnabled()) {
  245                   log.debug(Localizer.getMessage("jsp.error.compiler"), e);
  246               }
  247           } catch (ClassNotFoundException e) {
  248               if (log.isDebugEnabled()) {
  249                   log.debug(Localizer.getMessage("jsp.error.compiler"), e);
  250               }
  251           }
  252           return compiler;
  253       }
  254       
  255       public Compiler getCompiler() {
  256           return jspCompiler;
  257       }
  258   
  259       /** ---------- Access resources in the webapp ---------- */
  260   
  261       /** 
  262        * Get the full value of a URI relative to this compilations context
  263        * uses current file as the base.
  264        */
  265       public String resolveRelativeUri(String uri) {
  266           // sometimes we get uri's massaged from File(String), so check for
  267           // a root directory deperator char
  268           if (uri.startsWith("/") || uri.startsWith(File.separator)) {
  269               return uri;
  270           } else {
  271               return baseURI + uri;
  272           }
  273       }
  274   
  275       /**
  276        * Gets a resource as a stream, relative to the meanings of this
  277        * context's implementation.
  278        * @return a null if the resource cannot be found or represented 
  279        *         as an InputStream.
  280        */
  281       public java.io.InputStream getResourceAsStream(String res) {
  282           return context.getResourceAsStream(canonicalURI(res));
  283       }
  284   
  285   
  286       public URL getResource(String res) throws MalformedURLException {
  287           URL result = null;
  288   
  289           if (res.startsWith("/META-INF/")) {
  290               // This is a tag file packaged in a jar that is being compiled
  291               URL jarUrl = tagFileJarUrls.get(res);
  292               if (jarUrl == null) {
  293                   jarUrl = tagFileJarUrl;
  294               }
  295               if (jarUrl != null) {
  296                   result = new URL(jarUrl.toExternalForm() + res.substring(1));
  297               }
  298           } else if (res.startsWith("jar:file:")) {
  299                   // This is a tag file packaged in a jar that is being checked
  300                   // for a dependency
  301                   result = new URL(res);
  302   
  303           } else {
  304               result = context.getResource(canonicalURI(res));
  305           }
  306           return result;
  307       }
  308   
  309   
  310       public Set getResourcePaths(String path) {
  311           return context.getResourcePaths(canonicalURI(path));
  312       }
  313   
  314       /** 
  315        * Gets the actual path of a URI relative to the context of
  316        * the compilation.
  317        */
  318       public String getRealPath(String path) {
  319           if (context != null) {
  320               return context.getRealPath(path);
  321           }
  322           return path;
  323       }
  324   
  325       /**
  326        * Returns the tag-file-name-to-JAR-file map of this compilation unit,
  327        * which maps tag file names to the JAR files in which the tag files are
  328        * packaged.
  329        *
  330        * The map is populated when parsing the tag-file elements of the TLDs
  331        * of any imported taglibs. 
  332        */
  333       public URL getTagFileJarUrl(String tagFile) {
  334           return this.tagFileJarUrls.get(tagFile);
  335       }
  336   
  337       public void setTagFileJarUrl(String tagFile, URL tagFileURL) {
  338           this.tagFileJarUrls.put(tagFile, tagFileURL);
  339       }
  340   
  341       /**
  342        * Returns the JAR file in which the tag file for which this
  343        * JspCompilationContext was created is packaged, or null if this
  344        * JspCompilationContext does not correspond to a tag file, or if the
  345        * corresponding tag file is not packaged in a JAR.
  346        */
  347       public URL getTagFileJarUrl() {
  348           return this.tagFileJarUrl;
  349       }
  350   
  351       /* ==================== Common implementation ==================== */
  352   
  353       /**
  354        * Just the class name (does not include package name) of the
  355        * generated class. 
  356        */
  357       public String getServletClassName() {
  358   
  359           if (className != null) {
  360               return className;
  361           }
  362   
  363           if (isTagFile) {
  364               className = tagInfo.getTagClassName();
  365               int lastIndex = className.lastIndexOf('.');
  366               if (lastIndex != -1) {
  367                   className = className.substring(lastIndex + 1);
  368               }
  369           } else {
  370               int iSep = jspUri.lastIndexOf('/') + 1;
  371               className = JspUtil.makeJavaIdentifier(jspUri.substring(iSep));
  372           }
  373           return className;
  374       }
  375   
  376       public void setServletClassName(String className) {
  377           this.className = className;
  378       }
  379       
  380       /**
  381        * Path of the JSP URI. Note that this is not a file name. This is
  382        * the context rooted URI of the JSP file. 
  383        */
  384       public String getJspFile() {
  385           return jspUri;
  386       }
  387   
  388       /**
  389        * Are we processing something that has been declared as an
  390        * errorpage? 
  391        */
  392       public boolean isErrorPage() {
  393           return isErrPage;
  394       }
  395   
  396       public void setErrorPage(boolean isErrPage) {
  397           this.isErrPage = isErrPage;
  398       }
  399   
  400       public boolean isTagFile() {
  401           return isTagFile;
  402       }
  403   
  404       public TagInfo getTagInfo() {
  405           return tagInfo;
  406       }
  407   
  408       public void setTagInfo(TagInfo tagi) {
  409           tagInfo = tagi;
  410       }
  411   
  412       /**
  413        * True if we are compiling a tag file in prototype mode.
  414        * ie we only generate codes with class for the tag handler with empty
  415        * method bodies.
  416        */
  417       public boolean isPrototypeMode() {
  418           return protoTypeMode;
  419       }
  420   
  421       public void setPrototypeMode(boolean pm) {
  422           protoTypeMode = pm;
  423       }
  424   
  425       /**
  426        * Package name for the generated class is make up of the base package
  427        * name, which is user settable, and the derived package name.  The
  428        * derived package name directly mirrors the file heirachy of the JSP page.
  429        */
  430       public String getServletPackageName() {
  431           if (isTagFile()) {
  432               String className = tagInfo.getTagClassName();
  433               int lastIndex = className.lastIndexOf('.');
  434               String pkgName = "";
  435               if (lastIndex != -1) {
  436                   pkgName = className.substring(0, lastIndex);
  437               }
  438               return pkgName;
  439           } else {
  440               String dPackageName = getDerivedPackageName();
  441               if (dPackageName.length() == 0) {
  442                   return basePackageName;
  443               }
  444               return basePackageName + '.' + getDerivedPackageName();
  445           }
  446       }
  447   
  448       protected String getDerivedPackageName() {
  449           if (derivedPackageName == null) {
  450               int iSep = jspUri.lastIndexOf('/');
  451               derivedPackageName = (iSep > 0) ?
  452                       JspUtil.makeJavaPackage(jspUri.substring(1,iSep)) : "";
  453           }
  454           return derivedPackageName;
  455       }
  456   	    
  457       /**
  458        * The package name into which the servlet class is generated.
  459        */
  460       public void setServletPackageName(String servletPackageName) {
  461           this.basePackageName = servletPackageName;
  462       }
  463   
  464       /**
  465        * Full path name of the Java file into which the servlet is being
  466        * generated. 
  467        */
  468       public String getServletJavaFileName() {
  469           if (servletJavaFileName == null) {
  470               servletJavaFileName = getOutputDir() + getServletClassName() + ".java";
  471           }
  472           return servletJavaFileName;
  473       }
  474   
  475       /**
  476        * Get hold of the Options object for this context. 
  477        */
  478       public Options getOptions() {
  479           return options;
  480       }
  481   
  482       public ServletContext getServletContext() {
  483           return context;
  484       }
  485   
  486       public JspRuntimeContext getRuntimeContext() {
  487           return rctxt;
  488       }
  489   
  490       /**
  491        * Path of the Java file relative to the work directory.
  492        */
  493       public String getJavaPath() {
  494   
  495           if (javaPath != null) {
  496               return javaPath;
  497           }
  498   
  499           if (isTagFile()) {
  500   	    String tagName = tagInfo.getTagClassName();
  501               javaPath = tagName.replace('.', '/') + ".java";
  502           } else {
  503               javaPath = getServletPackageName().replace('.', '/') + '/' +
  504                          getServletClassName() + ".java";
  505   	}
  506           return javaPath;
  507       }
  508   
  509       public String getClassFileName() {
  510           if (classFileName == null) {
  511               classFileName = getOutputDir() + getServletClassName() + ".class";
  512           }
  513           return classFileName;
  514       }
  515   
  516       /**
  517        * Get the content type of this JSP.
  518        *
  519        * Content type includes content type and encoding.
  520        */
  521       public String getContentType() {
  522           return contentType;
  523       }
  524   
  525       public void setContentType(String contentType) {
  526           this.contentType = contentType;
  527       }
  528   
  529       /**
  530        * Where is the servlet being generated?
  531        */
  532       public ServletWriter getWriter() {
  533           return writer;
  534       }
  535   
  536       public void setWriter(ServletWriter writer) {
  537           this.writer = writer;
  538       }
  539   
  540       /**
  541        * Gets the 'location' of the TLD associated with the given taglib 'uri'.
  542        * 
  543        * @return An array of two Strings: The first element denotes the real
  544        * path to the TLD. If the path to the TLD points to a jar file, then the
  545        * second element denotes the name of the TLD entry in the jar file.
  546        * Returns null if the given uri is not associated with any tag library
  547        * 'exposed' in the web application.
  548        */
  549       public String[] getTldLocation(String uri) throws JasperException {
  550           String[] location = 
  551               getOptions().getTldLocationsCache().getLocation(uri);
  552           return location;
  553       }
  554   
  555       /**
  556        * Are we keeping generated code around?
  557        */
  558       public boolean keepGenerated() {
  559           return getOptions().getKeepGenerated();
  560       }
  561   
  562       // ==================== Removal ==================== 
  563   
  564       public void incrementRemoved() {
  565           if (removed == 0 && rctxt != null) {
  566               rctxt.removeWrapper(jspUri);
  567           }
  568           removed++;
  569       }
  570   
  571       public boolean isRemoved() {
  572           if (removed > 0 ) {
  573               return true;
  574           }
  575           return false;
  576       }
  577   
  578       // ==================== Compile and reload ====================
  579       
  580       public void compile() throws JasperException, FileNotFoundException {
  581           createCompiler();
  582           if (jspCompiler.isOutDated()) {
  583               if (isRemoved()) {
  584                   throw new FileNotFoundException(jspUri);
  585               }
  586               try {
  587                   jspCompiler.removeGeneratedFiles();
  588                   jspLoader = null;
  589                   jspCompiler.compile();
  590                   jsw.setReload(true);
  591                   jsw.setCompilationException(null);
  592               } catch (JasperException ex) {
  593                   // Cache compilation exception
  594                   jsw.setCompilationException(ex);
  595                   throw ex;
  596               } catch (Exception ex) {
  597                   JasperException je = new JasperException(
  598                               Localizer.getMessage("jsp.error.unable.compile"),
  599                               ex);
  600                   // Cache compilation exception
  601                   jsw.setCompilationException(je);
  602                   throw je;
  603               }
  604           }
  605       }
  606   
  607       // ==================== Manipulating the class ====================
  608   
  609       public Class load() 
  610           throws JasperException, FileNotFoundException
  611       {
  612           try {
  613               getJspLoader();
  614               
  615               String name;
  616               if (isTagFile()) {
  617                   name = tagInfo.getTagClassName();
  618               } else {
  619                   name = getServletPackageName() + "." + getServletClassName();
  620               }
  621               servletClass = jspLoader.loadClass(name);
  622           } catch (ClassNotFoundException cex) {
  623               throw new JasperException(Localizer.getMessage("jsp.error.unable.load"),
  624                                         cex);
  625           } catch (Exception ex) {
  626               throw new JasperException(Localizer.getMessage("jsp.error.unable.compile"),
  627                                         ex);
  628           }
  629           removed = 0;
  630           return servletClass;
  631       }
  632   
  633       // ==================== protected methods ==================== 
  634   
  635       static Object outputDirLock = new Object();
  636   
  637       public void checkOutputDir() {
  638           if (outputDir != null) {
  639               if (!(new File(outputDir)).exists()) {
  640                   makeOutputDir();
  641               }
  642           } else {
  643               createOutputDir();
  644           }
  645       }
  646           
  647       protected boolean makeOutputDir() {
  648           synchronized(outputDirLock) {
  649               File outDirFile = new File(outputDir);
  650               return (outDirFile.exists() || outDirFile.mkdirs());
  651           }
  652       }
  653   
  654       protected void createOutputDir() {
  655           String path = null;
  656           if (isTagFile()) {
  657               String tagName = tagInfo.getTagClassName();
  658               path = tagName.replace('.', File.separatorChar);
  659               path = path.substring(0, path.lastIndexOf(File.separatorChar));
  660           } else {
  661               path = getServletPackageName().replace('.',File.separatorChar);
  662           }
  663   
  664               // Append servlet or tag handler path to scratch dir
  665               try {
  666                   File base = options.getScratchDir();
  667                   baseUrl = base.toURI().toURL();
  668                   outputDir = base.getAbsolutePath() + File.separator + path + 
  669                       File.separator;
  670                   if (!makeOutputDir()) {
  671                       throw new IllegalStateException(Localizer.getMessage("jsp.error.outputfolder"));
  672                   }
  673               } catch (MalformedURLException e) {
  674                   throw new IllegalStateException(Localizer.getMessage("jsp.error.outputfolder"), e);
  675               }
  676       }
  677       
  678       protected static final boolean isPathSeparator(char c) {
  679          return (c == '/' || c == '\\');
  680       }
  681   
  682       protected static final String canonicalURI(String s) {
  683          if (s == null) return null;
  684          StringBuffer result = new StringBuffer();
  685          final int len = s.length();
  686          int pos = 0;
  687          while (pos < len) {
  688              char c = s.charAt(pos);
  689              if ( isPathSeparator(c) ) {
  690                  /*
  691                   * multiple path separators.
  692                   * 'foo///bar' -> 'foo/bar'
  693                   */
  694                  while (pos+1 < len && isPathSeparator(s.charAt(pos+1))) {
  695                      ++pos;
  696                  }
  697   
  698                  if (pos+1 < len && s.charAt(pos+1) == '.') {
  699                      /*
  700                       * a single dot at the end of the path - we are done.
  701                       */
  702                      if (pos+2 >= len) break;
  703   
  704                      switch (s.charAt(pos+2)) {
  705                          /*
  706                           * self directory in path
  707                           * foo/./bar -> foo/bar
  708                           */
  709                      case '/':
  710                      case '\\':
  711                          pos += 2;
  712                          continue;
  713   
  714                          /*
  715                           * two dots in a path: go back one hierarchy.
  716                           * foo/bar/../baz -> foo/baz
  717                           */
  718                      case '.':
  719                          // only if we have exactly _two_ dots.
  720                          if (pos+3 < len && isPathSeparator(s.charAt(pos+3))) {
  721                              pos += 3;
  722                              int separatorPos = result.length()-1;
  723                              while (separatorPos >= 0 && 
  724                                     ! isPathSeparator(result
  725                                                       .charAt(separatorPos))) {
  726                                  --separatorPos;
  727                              }
  728                              if (separatorPos >= 0)
  729                                  result.setLength(separatorPos);
  730                              continue;
  731                          }
  732                      }
  733                  }
  734              }
  735              result.append(c);
  736              ++pos;
  737          }
  738          return result.toString();
  739       }
  740   }
  741   

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