Save This Page
Home » apache-tomcat-6.0.16-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 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           return context.getResource(canonicalURI(res));
  288       }
  289   
  290       public Set getResourcePaths(String path) {
  291           return context.getResourcePaths(canonicalURI(path));
  292       }
  293   
  294       /** 
  295        * Gets the actual path of a URI relative to the context of
  296        * the compilation.
  297        */
  298       public String getRealPath(String path) {
  299           if (context != null) {
  300               return context.getRealPath(path);
  301           }
  302           return path;
  303       }
  304   
  305       /**
  306        * Returns the tag-file-name-to-JAR-file map of this compilation unit,
  307        * which maps tag file names to the JAR files in which the tag files are
  308        * packaged.
  309        *
  310        * The map is populated when parsing the tag-file elements of the TLDs
  311        * of any imported taglibs. 
  312        */
  313       public URL getTagFileJarUrl(String tagFile) {
  314           return this.tagFileJarUrls.get(tagFile);
  315       }
  316   
  317       public void setTagFileJarUrl(String tagFile, URL tagFileURL) {
  318           this.tagFileJarUrls.put(tagFile, tagFileURL);
  319       }
  320   
  321       /**
  322        * Returns the JAR file in which the tag file for which this
  323        * JspCompilationContext was created is packaged, or null if this
  324        * JspCompilationContext does not correspond to a tag file, or if the
  325        * corresponding tag file is not packaged in a JAR.
  326        */
  327       public URL getTagFileJarUrl() {
  328           return this.tagFileJarUrl;
  329       }
  330   
  331       /* ==================== Common implementation ==================== */
  332   
  333       /**
  334        * Just the class name (does not include package name) of the
  335        * generated class. 
  336        */
  337       public String getServletClassName() {
  338   
  339           if (className != null) {
  340               return className;
  341           }
  342   
  343           if (isTagFile) {
  344               className = tagInfo.getTagClassName();
  345               int lastIndex = className.lastIndexOf('.');
  346               if (lastIndex != -1) {
  347                   className = className.substring(lastIndex + 1);
  348               }
  349           } else {
  350               int iSep = jspUri.lastIndexOf('/') + 1;
  351               className = JspUtil.makeJavaIdentifier(jspUri.substring(iSep));
  352           }
  353           return className;
  354       }
  355   
  356       public void setServletClassName(String className) {
  357           this.className = className;
  358       }
  359       
  360       /**
  361        * Path of the JSP URI. Note that this is not a file name. This is
  362        * the context rooted URI of the JSP file. 
  363        */
  364       public String getJspFile() {
  365           return jspUri;
  366       }
  367   
  368       /**
  369        * Are we processing something that has been declared as an
  370        * errorpage? 
  371        */
  372       public boolean isErrorPage() {
  373           return isErrPage;
  374       }
  375   
  376       public void setErrorPage(boolean isErrPage) {
  377           this.isErrPage = isErrPage;
  378       }
  379   
  380       public boolean isTagFile() {
  381           return isTagFile;
  382       }
  383   
  384       public TagInfo getTagInfo() {
  385           return tagInfo;
  386       }
  387   
  388       public void setTagInfo(TagInfo tagi) {
  389           tagInfo = tagi;
  390       }
  391   
  392       /**
  393        * True if we are compiling a tag file in prototype mode.
  394        * ie we only generate codes with class for the tag handler with empty
  395        * method bodies.
  396        */
  397       public boolean isPrototypeMode() {
  398           return protoTypeMode;
  399       }
  400   
  401       public void setPrototypeMode(boolean pm) {
  402           protoTypeMode = pm;
  403       }
  404   
  405       /**
  406        * Package name for the generated class is make up of the base package
  407        * name, which is user settable, and the derived package name.  The
  408        * derived package name directly mirrors the file heirachy of the JSP page.
  409        */
  410       public String getServletPackageName() {
  411           if (isTagFile()) {
  412               String className = tagInfo.getTagClassName();
  413               int lastIndex = className.lastIndexOf('.');
  414               String pkgName = "";
  415               if (lastIndex != -1) {
  416                   pkgName = className.substring(0, lastIndex);
  417               }
  418               return pkgName;
  419           } else {
  420               String dPackageName = getDerivedPackageName();
  421               if (dPackageName.length() == 0) {
  422                   return basePackageName;
  423               }
  424               return basePackageName + '.' + getDerivedPackageName();
  425           }
  426       }
  427   
  428       protected String getDerivedPackageName() {
  429           if (derivedPackageName == null) {
  430               int iSep = jspUri.lastIndexOf('/');
  431               derivedPackageName = (iSep > 0) ?
  432                       JspUtil.makeJavaPackage(jspUri.substring(1,iSep)) : "";
  433           }
  434           return derivedPackageName;
  435       }
  436   	    
  437       /**
  438        * The package name into which the servlet class is generated.
  439        */
  440       public void setServletPackageName(String servletPackageName) {
  441           this.basePackageName = servletPackageName;
  442       }
  443   
  444       /**
  445        * Full path name of the Java file into which the servlet is being
  446        * generated. 
  447        */
  448       public String getServletJavaFileName() {
  449           if (servletJavaFileName == null) {
  450               servletJavaFileName = getOutputDir() + getServletClassName() + ".java";
  451           }
  452           return servletJavaFileName;
  453       }
  454   
  455       /**
  456        * Get hold of the Options object for this context. 
  457        */
  458       public Options getOptions() {
  459           return options;
  460       }
  461   
  462       public ServletContext getServletContext() {
  463           return context;
  464       }
  465   
  466       public JspRuntimeContext getRuntimeContext() {
  467           return rctxt;
  468       }
  469   
  470       /**
  471        * Path of the Java file relative to the work directory.
  472        */
  473       public String getJavaPath() {
  474   
  475           if (javaPath != null) {
  476               return javaPath;
  477           }
  478   
  479           if (isTagFile()) {
  480   	    String tagName = tagInfo.getTagClassName();
  481               javaPath = tagName.replace('.', '/') + ".java";
  482           } else {
  483               javaPath = getServletPackageName().replace('.', '/') + '/' +
  484                          getServletClassName() + ".java";
  485   	}
  486           return javaPath;
  487       }
  488   
  489       public String getClassFileName() {
  490           if (classFileName == null) {
  491               classFileName = getOutputDir() + getServletClassName() + ".class";
  492           }
  493           return classFileName;
  494       }
  495   
  496       /**
  497        * Get the content type of this JSP.
  498        *
  499        * Content type includes content type and encoding.
  500        */
  501       public String getContentType() {
  502           return contentType;
  503       }
  504   
  505       public void setContentType(String contentType) {
  506           this.contentType = contentType;
  507       }
  508   
  509       /**
  510        * Where is the servlet being generated?
  511        */
  512       public ServletWriter getWriter() {
  513           return writer;
  514       }
  515   
  516       public void setWriter(ServletWriter writer) {
  517           this.writer = writer;
  518       }
  519   
  520       /**
  521        * Gets the 'location' of the TLD associated with the given taglib 'uri'.
  522        * 
  523        * @return An array of two Strings: The first element denotes the real
  524        * path to the TLD. If the path to the TLD points to a jar file, then the
  525        * second element denotes the name of the TLD entry in the jar file.
  526        * Returns null if the given uri is not associated with any tag library
  527        * 'exposed' in the web application.
  528        */
  529       public String[] getTldLocation(String uri) throws JasperException {
  530           String[] location = 
  531               getOptions().getTldLocationsCache().getLocation(uri);
  532           return location;
  533       }
  534   
  535       /**
  536        * Are we keeping generated code around?
  537        */
  538       public boolean keepGenerated() {
  539           return getOptions().getKeepGenerated();
  540       }
  541   
  542       // ==================== Removal ==================== 
  543   
  544       public void incrementRemoved() {
  545           if (removed == 0 && rctxt != null) {
  546               rctxt.removeWrapper(jspUri);
  547           }
  548           removed++;
  549       }
  550   
  551       public boolean isRemoved() {
  552           if (removed > 1 ) {
  553               return true;
  554           }
  555           return false;
  556       }
  557   
  558       // ==================== Compile and reload ====================
  559       
  560       public void compile() throws JasperException, FileNotFoundException {
  561           createCompiler();
  562           if (isPackagedTagFile || jspCompiler.isOutDated()) {
  563               try {
  564                   jspCompiler.removeGeneratedFiles();
  565                   jspLoader = null;
  566                   jspCompiler.compile();
  567                   jsw.setReload(true);
  568                   jsw.setCompilationException(null);
  569               } catch (JasperException ex) {
  570                   // Cache compilation exception
  571                   jsw.setCompilationException(ex);
  572                   throw ex;
  573               } catch (Exception ex) {
  574                   JasperException je = new JasperException(
  575                               Localizer.getMessage("jsp.error.unable.compile"),
  576                               ex);
  577                   // Cache compilation exception
  578                   jsw.setCompilationException(je);
  579                   throw je;
  580               }
  581           }
  582       }
  583   
  584       // ==================== Manipulating the class ====================
  585   
  586       public Class load() 
  587           throws JasperException, FileNotFoundException
  588       {
  589           try {
  590               getJspLoader();
  591               
  592               String name;
  593               if (isTagFile()) {
  594                   name = tagInfo.getTagClassName();
  595               } else {
  596                   name = getServletPackageName() + "." + getServletClassName();
  597               }
  598               servletClass = jspLoader.loadClass(name);
  599           } catch (ClassNotFoundException cex) {
  600               throw new JasperException(Localizer.getMessage("jsp.error.unable.load"),
  601                                         cex);
  602           } catch (Exception ex) {
  603               throw new JasperException(Localizer.getMessage("jsp.error.unable.compile"),
  604                                         ex);
  605           }
  606           removed = 0;
  607           return servletClass;
  608       }
  609   
  610       // ==================== protected methods ==================== 
  611   
  612       static Object outputDirLock = new Object();
  613   
  614       public void checkOutputDir() {
  615           if (outputDir != null) {
  616               if (!(new File(outputDir)).exists()) {
  617                   makeOutputDir();
  618               }
  619           } else {
  620               createOutputDir();
  621           }
  622       }
  623           
  624       protected boolean makeOutputDir() {
  625           synchronized(outputDirLock) {
  626               File outDirFile = new File(outputDir);
  627               return (outDirFile.exists() || outDirFile.mkdirs());
  628           }
  629       }
  630   
  631       protected void createOutputDir() {
  632           String path = null;
  633           if (isTagFile()) {
  634   	    String tagName = tagInfo.getTagClassName();
  635               path = tagName.replace('.', '/');
  636   	    path = path.substring(0, path.lastIndexOf('/'));
  637           } else {
  638               path = getServletPackageName().replace('.', '/');
  639   	}
  640   
  641               // Append servlet or tag handler path to scratch dir
  642               try {
  643                   baseUrl = options.getScratchDir().toURL();
  644                   String outUrlString = baseUrl.toString() + '/' + path;
  645                   URL outUrl = new URL(outUrlString);
  646                   outputDir = outUrl.getFile() + File.separator;
  647                   if (!makeOutputDir()) {
  648                       throw new IllegalStateException(Localizer.getMessage("jsp.error.outputfolder"));
  649                   }
  650               } catch (MalformedURLException e) {
  651                   throw new IllegalStateException(Localizer.getMessage("jsp.error.outputfolder"), e);
  652               }
  653       }
  654       
  655       protected static final boolean isPathSeparator(char c) {
  656          return (c == '/' || c == '\\');
  657       }
  658   
  659       protected static final String canonicalURI(String s) {
  660          if (s == null) return null;
  661          StringBuffer result = new StringBuffer();
  662          final int len = s.length();
  663          int pos = 0;
  664          while (pos < len) {
  665              char c = s.charAt(pos);
  666              if ( isPathSeparator(c) ) {
  667                  /*
  668                   * multiple path separators.
  669                   * 'foo///bar' -> 'foo/bar'
  670                   */
  671                  while (pos+1 < len && isPathSeparator(s.charAt(pos+1))) {
  672                      ++pos;
  673                  }
  674   
  675                  if (pos+1 < len && s.charAt(pos+1) == '.') {
  676                      /*
  677                       * a single dot at the end of the path - we are done.
  678                       */
  679                      if (pos+2 >= len) break;
  680   
  681                      switch (s.charAt(pos+2)) {
  682                          /*
  683                           * self directory in path
  684                           * foo/./bar -> foo/bar
  685                           */
  686                      case '/':
  687                      case '\\':
  688                          pos += 2;
  689                          continue;
  690   
  691                          /*
  692                           * two dots in a path: go back one hierarchy.
  693                           * foo/bar/../baz -> foo/baz
  694                           */
  695                      case '.':
  696                          // only if we have exactly _two_ dots.
  697                          if (pos+3 < len && isPathSeparator(s.charAt(pos+3))) {
  698                              pos += 3;
  699                              int separatorPos = result.length()-1;
  700                              while (separatorPos >= 0 && 
  701                                     ! isPathSeparator(result
  702                                                       .charAt(separatorPos))) {
  703                                  --separatorPos;
  704                              }
  705                              if (separatorPos >= 0)
  706                                  result.setLength(separatorPos);
  707                              continue;
  708                          }
  709                      }
  710                  }
  711              }
  712              result.append(c);
  713              ++pos;
  714          }
  715          return result.toString();
  716       }
  717   }
  718   

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