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.FilePermission;
   23   import java.net.URL;
   24   import java.net.URLClassLoader;
   25   import java.security.CodeSource;
   26   import java.security.PermissionCollection;
   27   import java.security.Policy;
   28   import java.security.cert.Certificate;
   29   import java.util.Iterator;
   30   import java.util.Map;
   31   import java.util.concurrent.ConcurrentHashMap;
   32   
   33   import javax.servlet.ServletContext;
   34   import javax.servlet.jsp.JspFactory;
   35   
   36   import org.apache.jasper.Constants;
   37   import org.apache.jasper.JspCompilationContext;
   38   import org.apache.jasper.Options;
   39   import org.apache.jasper.runtime.JspFactoryImpl;
   40   import org.apache.jasper.security.SecurityClassLoad;
   41   import org.apache.jasper.servlet.JspServletWrapper;
   42   import org.apache.juli.logging.Log;
   43   import org.apache.juli.logging.LogFactory;
   44   
   45   /**
   46    * Class for tracking JSP compile time file dependencies when the
   47    * &060;%@include file="..."%&062; directive is used.
   48    *
   49    * A background thread periodically checks the files a JSP page
   50    * is dependent upon.  If a dpendent file changes the JSP page
   51    * which included it is recompiled.
   52    *
   53    * Only used if a web application context is a directory.
   54    *
   55    * @author Glenn L. Nielsen
   56    * @version $Revision: 505593 $
   57    */
   58   public final class JspRuntimeContext {
   59   
   60       // Logger
   61       private Log log = LogFactory.getLog(JspRuntimeContext.class);
   62   
   63       /*
   64        * Counts how many times the webapp's JSPs have been reloaded.
   65        */
   66       private int jspReloadCount;
   67   
   68       /**
   69        * Preload classes required at runtime by a JSP servlet so that
   70        * we don't get a defineClassInPackage security exception.
   71        */
   72       static {
   73           JspFactoryImpl factory = new JspFactoryImpl();
   74           SecurityClassLoad.securityClassLoad(factory.getClass().getClassLoader());
   75           if( System.getSecurityManager() != null ) {
   76               String basePackage = "org.apache.jasper.";
   77               try {
   78                   factory.getClass().getClassLoader().loadClass( basePackage +
   79                                                                  "runtime.JspFactoryImpl$PrivilegedGetPageContext");
   80                   factory.getClass().getClassLoader().loadClass( basePackage +
   81                                                                  "runtime.JspFactoryImpl$PrivilegedReleasePageContext");
   82                   factory.getClass().getClassLoader().loadClass( basePackage +
   83                                                                  "runtime.JspRuntimeLibrary");
   84                   factory.getClass().getClassLoader().loadClass( basePackage +
   85                                                                  "runtime.JspRuntimeLibrary$PrivilegedIntrospectHelper");
   86                   factory.getClass().getClassLoader().loadClass( basePackage +
   87                                                                  "runtime.ServletResponseWrapperInclude");
   88                   factory.getClass().getClassLoader().loadClass( basePackage +
   89                                                                  "servlet.JspServletWrapper");
   90               } catch (ClassNotFoundException ex) {
   91                   throw new IllegalStateException(ex);
   92               }
   93           }
   94   
   95           JspFactory.setDefaultFactory(factory);
   96       }
   97   
   98       // ----------------------------------------------------------- Constructors
   99   
  100       /**
  101        * Create a JspRuntimeContext for a web application context.
  102        *
  103        * Loads in any previously generated dependencies from file.
  104        *
  105        * @param context ServletContext for web application
  106        */
  107       public JspRuntimeContext(ServletContext context, Options options) {
  108   
  109           this.context = context;
  110           this.options = options;
  111   
  112           // Get the parent class loader
  113           parentClassLoader =
  114               (URLClassLoader) Thread.currentThread().getContextClassLoader();
  115           if (parentClassLoader == null) {
  116               parentClassLoader =
  117                   (URLClassLoader)this.getClass().getClassLoader();
  118           }
  119   
  120   	if (log.isDebugEnabled()) {
  121   	    if (parentClassLoader != null) {
  122   		log.debug(Localizer.getMessage("jsp.message.parent_class_loader_is",
  123   					       parentClassLoader.toString()));
  124   	    } else {
  125   		log.debug(Localizer.getMessage("jsp.message.parent_class_loader_is",
  126   					       "<none>"));
  127   	    }
  128           }
  129   
  130           initClassPath();
  131   
  132   	if (context instanceof org.apache.jasper.servlet.JspCServletContext) {
  133   	    return;
  134   	}
  135   
  136           if (Constants.IS_SECURITY_ENABLED) {
  137               initSecurity();
  138           }
  139   
  140           // If this web application context is running from a
  141           // directory, start the background compilation thread
  142           String appBase = context.getRealPath("/");         
  143           if (!options.getDevelopment()
  144                   && appBase != null
  145                   && options.getCheckInterval() > 0) {
  146               lastCheck = System.currentTimeMillis();
  147           }                                            
  148       }
  149   
  150       // ----------------------------------------------------- Instance Variables
  151   
  152       /**
  153        * This web applications ServletContext
  154        */
  155       private ServletContext context;
  156       private Options options;
  157       private URLClassLoader parentClassLoader;
  158       private PermissionCollection permissionCollection;
  159       private CodeSource codeSource;                    
  160       private String classpath;
  161       private long lastCheck = -1L;
  162   
  163       /**
  164        * Maps JSP pages to their JspServletWrapper's
  165        */
  166       private Map<String, JspServletWrapper> jsps = new ConcurrentHashMap<String, JspServletWrapper>();
  167    
  168   
  169       // ------------------------------------------------------ Public Methods
  170   
  171       /**
  172        * Add a new JspServletWrapper.
  173        *
  174        * @param jspUri JSP URI
  175        * @param jsw Servlet wrapper for JSP
  176        */
  177       public void addWrapper(String jspUri, JspServletWrapper jsw) {
  178           jsps.put(jspUri, jsw);
  179       }
  180   
  181       /**
  182        * Get an already existing JspServletWrapper.
  183        *
  184        * @param jspUri JSP URI
  185        * @return JspServletWrapper for JSP
  186        */
  187       public JspServletWrapper getWrapper(String jspUri) {
  188           return jsps.get(jspUri);
  189       }
  190   
  191       /**
  192        * Remove a  JspServletWrapper.
  193        *
  194        * @param jspUri JSP URI of JspServletWrapper to remove
  195        */
  196       public void removeWrapper(String jspUri) {
  197           jsps.remove(jspUri);
  198       }
  199   
  200       /**
  201        * Returns the number of JSPs for which JspServletWrappers exist, i.e.,
  202        * the number of JSPs that have been loaded into the webapp.
  203        *
  204        * @return The number of JSPs that have been loaded into the webapp
  205        */
  206       public int getJspCount() {
  207           return jsps.size();
  208       }
  209   
  210       /**
  211        * Get the SecurityManager Policy CodeSource for this web
  212        * applicaiton context.
  213        *
  214        * @return CodeSource for JSP
  215        */
  216       public CodeSource getCodeSource() {
  217           return codeSource;
  218       }
  219   
  220       /**
  221        * Get the parent URLClassLoader.
  222        *
  223        * @return URLClassLoader parent
  224        */
  225       public URLClassLoader getParentClassLoader() {
  226           return parentClassLoader;
  227       }
  228   
  229       /**
  230        * Get the SecurityManager PermissionCollection for this
  231        * web application context.
  232        *
  233        * @return PermissionCollection permissions
  234        */
  235       public PermissionCollection getPermissionCollection() {
  236           return permissionCollection;
  237       }
  238   
  239       /**
  240        * Process a "destory" event for this web application context.
  241        */                                                        
  242       public void destroy() {
  243           Iterator servlets = jsps.values().iterator();
  244           while (servlets.hasNext()) {
  245               ((JspServletWrapper) servlets.next()).destroy();
  246           }
  247       }
  248   
  249       /**
  250        * Increments the JSP reload counter.
  251        */
  252       public synchronized void incrementJspReloadCount() {
  253           jspReloadCount++;
  254       }
  255   
  256       /**
  257        * Resets the JSP reload counter.
  258        *
  259        * @param count Value to which to reset the JSP reload counter
  260        */
  261       public synchronized void setJspReloadCount(int count) {
  262           this.jspReloadCount = count;
  263       }
  264   
  265       /**
  266        * Gets the current value of the JSP reload counter.
  267        *
  268        * @return The current value of the JSP reload counter
  269        */
  270       public int getJspReloadCount() {
  271           return jspReloadCount;
  272       }
  273   
  274   
  275       /**
  276        * Method used by background thread to check the JSP dependencies
  277        * registered with this class for JSP's.
  278        */
  279       public void checkCompile() {
  280   
  281           if (lastCheck < 0) {
  282               // Checking was disabled
  283               return;
  284           }
  285           long now = System.currentTimeMillis();
  286           if (now > (lastCheck + (options.getCheckInterval() * 1000L))) {
  287               lastCheck = now;
  288           } else {
  289               return;
  290           }
  291           
  292           Object [] wrappers = jsps.values().toArray();
  293           for (int i = 0; i < wrappers.length; i++ ) {
  294               JspServletWrapper jsw = (JspServletWrapper)wrappers[i];
  295               JspCompilationContext ctxt = jsw.getJspEngineContext();
  296               // JspServletWrapper also synchronizes on this when
  297               // it detects it has to do a reload
  298               synchronized(jsw) {
  299                   try {
  300                       ctxt.compile();
  301                   } catch (FileNotFoundException ex) {
  302                       ctxt.incrementRemoved();
  303                   } catch (Throwable t) {
  304                       jsw.getServletContext().log("Background compile failed",
  305   						t);
  306                   }
  307               }
  308           }
  309   
  310       }
  311   
  312       /**
  313        * The classpath that is passed off to the Java compiler.
  314        */
  315       public String getClassPath() {
  316           return classpath;
  317       }
  318   
  319   
  320       // -------------------------------------------------------- Private Methods
  321   
  322   
  323       /**
  324        * Method used to initialize classpath for compiles.
  325        */
  326       private void initClassPath() {
  327   
  328           URL [] urls = parentClassLoader.getURLs();
  329           StringBuffer cpath = new StringBuffer();
  330           String sep = System.getProperty("path.separator");
  331   
  332           for(int i = 0; i < urls.length; i++) {
  333               // Tomcat 4 can use URL's other than file URL's,
  334               // a protocol other than file: will generate a
  335               // bad file system path, so only add file:
  336               // protocol URL's to the classpath.
  337               
  338               if( urls[i].getProtocol().equals("file") ) {
  339                   cpath.append((String)urls[i].getFile()+sep);
  340               }
  341           }    
  342   
  343   	cpath.append(options.getScratchDir() + sep);
  344   
  345           String cp = (String) context.getAttribute(Constants.SERVLET_CLASSPATH);
  346           if (cp == null || cp.equals("")) {
  347               cp = options.getClassPath();
  348           }
  349   
  350           classpath = cpath.toString() + cp;
  351   
  352           if(log.isDebugEnabled()) {
  353               log.debug("Compilation classpath initialized: " + getClassPath());
  354           }
  355       }
  356   
  357       /**
  358        * Method used to initialize SecurityManager data.
  359        */
  360       private void initSecurity() {
  361   
  362           // Setup the PermissionCollection for this web app context
  363           // based on the permissions configured for the root of the
  364           // web app context directory, then add a file read permission
  365           // for that directory.
  366           Policy policy = Policy.getPolicy();
  367           if( policy != null ) {
  368               try {          
  369                   // Get the permissions for the web app context
  370                   String docBase = context.getRealPath("/");
  371                   if( docBase == null ) {
  372                       docBase = options.getScratchDir().toString();
  373                   }
  374                   String codeBase = docBase;
  375                   if (!codeBase.endsWith(File.separator)){
  376                       codeBase = codeBase + File.separator;
  377                   }
  378                   File contextDir = new File(codeBase);
  379                   URL url = contextDir.getCanonicalFile().toURL();
  380                   codeSource = new CodeSource(url,(Certificate[])null);
  381                   permissionCollection = policy.getPermissions(codeSource);
  382   
  383                   // Create a file read permission for web app context directory
  384                   if (!docBase.endsWith(File.separator)){
  385                       permissionCollection.add
  386                           (new FilePermission(docBase,"read"));
  387                       docBase = docBase + File.separator;
  388                   } else {
  389                       permissionCollection.add
  390                           (new FilePermission
  391                               (docBase.substring(0,docBase.length() - 1),"read"));
  392                   }
  393                   docBase = docBase + "-";
  394                   permissionCollection.add(new FilePermission(docBase,"read"));
  395   
  396                   // Create a file read permission for web app tempdir (work)
  397                   // directory
  398                   String workDir = options.getScratchDir().toString();
  399                   if (!workDir.endsWith(File.separator)){
  400                       permissionCollection.add
  401                           (new FilePermission(workDir,"read"));
  402                       workDir = workDir + File.separator;
  403                   }
  404                   workDir = workDir + "-";
  405                   permissionCollection.add(new FilePermission(workDir,"read"));
  406   
  407                   // Allow the JSP to access org.apache.jasper.runtime.HttpJspBase
  408                   permissionCollection.add( new RuntimePermission(
  409                       "accessClassInPackage.org.apache.jasper.runtime") );
  410   
  411                   if (parentClassLoader instanceof URLClassLoader) {
  412                       URL [] urls = parentClassLoader.getURLs();
  413                       String jarUrl = null;
  414                       String jndiUrl = null;
  415                       for (int i=0; i<urls.length; i++) {
  416                           if (jndiUrl == null
  417                                   && urls[i].toString().startsWith("jndi:") ) {
  418                               jndiUrl = urls[i].toString() + "-";
  419                           }
  420                           if (jarUrl == null
  421                                   && urls[i].toString().startsWith("jar:jndi:")
  422                                   ) {
  423                               jarUrl = urls[i].toString();
  424                               jarUrl = jarUrl.substring(0,jarUrl.length() - 2);
  425                               jarUrl = jarUrl.substring(0,
  426                                        jarUrl.lastIndexOf('/')) + "/-";
  427                           }
  428                       }
  429                       if (jarUrl != null) {
  430                           permissionCollection.add(
  431                                   new FilePermission(jarUrl,"read"));
  432                           permissionCollection.add(
  433                                   new FilePermission(jarUrl.substring(4),"read"));
  434                       }
  435                       if (jndiUrl != null)
  436                           permissionCollection.add(
  437                                   new FilePermission(jndiUrl,"read") );
  438                   }
  439               } catch(Exception e) {
  440                   context.log("Security Init for context failed",e);
  441               }
  442           }
  443       }
  444   
  445   
  446   }

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