You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by ma...@apache.org on 2009/09/22 16:54:29 UTC

svn commit: r817685 - in /tomcat/trunk: java/org/apache/catalina/ java/org/apache/catalina/core/ java/org/apache/catalina/startup/ java/org/apache/jasper/compiler/ java/org/apache/jasper/resources/ java/org/apache/tomcat/ webapps/docs/config/

Author: markt
Date: Tue Sep 22 14:54:28 2009
New Revision: 817685

URL: http://svn.apache.org/viewvc?rev=817685&view=rev
Log:
Refactor the TLD JAR scanning. This a) reduces duplication between Catalina and Jasper b) allows the Jar scanning to be controlled by configuration rather than system properties and c) (hopefully) allows the scanning code to be re-used for web-fragment.xml scanning
The JSP TCK passes with this patch applied

Added:
    tomcat/trunk/java/org/apache/catalina/startup/DefaultJarScanner.java   (with props)
    tomcat/trunk/java/org/apache/jasper/compiler/JarScannerFactory.java   (with props)
    tomcat/trunk/java/org/apache/tomcat/JarScanner.java   (with props)
    tomcat/trunk/java/org/apache/tomcat/JarScannerCallback.java   (with props)
    tomcat/trunk/webapps/docs/config/jar-scanner.xml   (with props)
Modified:
    tomcat/trunk/java/org/apache/catalina/Context.java
    tomcat/trunk/java/org/apache/catalina/core/StandardContext.java
    tomcat/trunk/java/org/apache/catalina/startup/ContextRuleSet.java
    tomcat/trunk/java/org/apache/catalina/startup/LocalStrings.properties
    tomcat/trunk/java/org/apache/catalina/startup/TldConfig.java
    tomcat/trunk/java/org/apache/jasper/compiler/TldLocationsCache.java
    tomcat/trunk/java/org/apache/jasper/resources/LocalStrings.properties
    tomcat/trunk/webapps/docs/config/project.xml

Modified: tomcat/trunk/java/org/apache/catalina/Context.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/Context.java?rev=817685&r1=817684&r2=817685&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/Context.java (original)
+++ tomcat/trunk/java/org/apache/catalina/Context.java Tue Sep 22 14:54:28 2009
@@ -21,6 +21,7 @@
 
 import javax.servlet.ServletContext;
 
+import org.apache.tomcat.JarScanner;
 import org.apache.tomcat.util.http.mapper.Mapper;
 
 import org.apache.catalina.deploy.ApplicationParameter;
@@ -1081,5 +1082,19 @@
      */
     public String getRealPath(String path);
 
+    /**
+     * Get the Jar Scanner to be used to scan for JAR resources for this
+     * context.
+     * @return  The Jar Scanner configured for this context.
+     */
+    public JarScanner getJarScanner();
+
+    /**
+     * Set the Jar Scanner to be used to scan for JAR resources for this
+     * context.
+     * @param jarScanner    The Jar Scanner to be used for this context.
+     */
+    public void setJarScanner(JarScanner jarScanner);
+
 }
 

Modified: tomcat/trunk/java/org/apache/catalina/core/StandardContext.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/core/StandardContext.java?rev=817685&r1=817684&r2=817685&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/core/StandardContext.java (original)
+++ tomcat/trunk/java/org/apache/catalina/core/StandardContext.java Tue Sep 22 14:54:28 2009
@@ -85,6 +85,7 @@
 import org.apache.catalina.loader.WebappLoader;
 import org.apache.catalina.session.StandardManager;
 import org.apache.catalina.startup.ContextConfig;
+import org.apache.catalina.startup.DefaultJarScanner;
 import org.apache.catalina.startup.TldConfig;
 import org.apache.catalina.util.CharsetMapper;
 import org.apache.catalina.util.ExtensionValidator;
@@ -99,6 +100,7 @@
 import org.apache.naming.resources.ProxyDirContext;
 import org.apache.naming.resources.WARDirContext;
 import org.apache.tomcat.InstanceManager;
+import org.apache.tomcat.JarScanner;
 import org.apache.tomcat.util.modeler.Registry;
 
 /**
@@ -725,12 +727,30 @@
      */
     private boolean useHttpOnly = true;
 
+    /**
+     * The Jar scanner to use to search for Jars that might contain
+     * configuration information such as TLDs or web-fragment.xml files. 
+     */
+    private JarScanner jarScanner = null;
 
 
 
     // ----------------------------------------------------- Context Properties
 
 
+    public JarScanner getJarScanner() {
+        if (jarScanner == null) {
+            jarScanner = new DefaultJarScanner();
+        }
+        return jarScanner;
+    }
+
+
+    public void setJarScanner(JarScanner jarScanner) {
+        this.jarScanner = jarScanner;
+    }
+
+     
     public InstanceManager getInstanceManager() {
        return instanceManager;
     }
@@ -4459,6 +4479,11 @@
             
             // Create context attributes that will be required
             if (ok) {
+                getServletContext().setAttribute(
+                        JarScanner.class.getName(), getJarScanner());
+            }
+
+            if (ok) {
                 postWelcomeFiles();
             }
             

Modified: tomcat/trunk/java/org/apache/catalina/startup/ContextRuleSet.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/startup/ContextRuleSet.java?rev=817685&r1=817684&r2=817685&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/startup/ContextRuleSet.java (original)
+++ tomcat/trunk/java/org/apache/catalina/startup/ContextRuleSet.java Tue Sep 22 14:54:28 2009
@@ -203,6 +203,14 @@
         digester.addCallMethod(prefix + "Context/WrapperListener",
                                "addWrapperListener", 0);
 
+        digester.addObjectCreate(prefix + "Context/JarScanner",
+                                 "org.apache.catalina.deploy.DefaultJarScanner",
+                                 "className");
+        digester.addSetProperties(prefix + "Context/JarScanner");
+        digester.addSetNext(prefix + "Context/JarScanner",
+                            "setJarScanner",
+                            "org.apache.tomcat.JarScanner");
+
     }
 
 }

Added: tomcat/trunk/java/org/apache/catalina/startup/DefaultJarScanner.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/startup/DefaultJarScanner.java?rev=817685&view=auto
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/startup/DefaultJarScanner.java (added)
+++ tomcat/trunk/java/org/apache/catalina/startup/DefaultJarScanner.java Tue Sep 22 14:54:28 2009
@@ -0,0 +1,214 @@
+package org.apache.catalina.startup;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.JarURLConnection;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.net.URLConnection;
+import java.util.Iterator;
+import java.util.Set;
+
+import javax.servlet.ServletContext;
+
+import org.apache.tomcat.JarScanner;
+import org.apache.tomcat.JarScannerCallback;
+import org.apache.tomcat.util.res.StringManager;
+
+/**
+ * The default {@link JarScanner} implementation scans the WEB-INF/lib directory
+ * followed by the provided classloader and then works up the classloader
+ * hierarchy. This implementation is sufficient to meet the requirements of the
+ * Servlet 3.0 specification as well is to provide a number of Tomcat specific
+ * extensions. The extensions are:
+ * <ul>
+ *   <li>Scanning the classloader hierarchy (enabled by default)</li>
+ *   <li>Testing all files to see if they are JARs (disabled by default)</li>
+ *   <li>Testing all directories to see if they are exploded JARs
+ *       (disabled by default)</li>
+ * </ul>
+ * All of the extenions may be controlled via configuration.
+ */
+public class DefaultJarScanner implements JarScanner {
+
+    private static final String JAR_EXT = ".jar";
+    private static final String WEB_INF_LIB = "/WEB-INF/lib/";
+
+    private static org.apache.juli.logging.Log log=
+        org.apache.juli.logging.LogFactory.getLog( TldConfig.class );
+
+    /**
+     * The string resources for this package.
+     */
+    private static final StringManager sm =
+        StringManager.getManager(Constants.Package);
+
+
+    /**
+     * Controls the classpath scanning extenion.
+     */
+    private boolean scanClassPath = true;
+    public boolean isScanClassPath() {
+        return scanClassPath;
+    }
+    public void setScanClassPath(boolean scanClassPath) {
+        this.scanClassPath = scanClassPath;
+    }
+
+    /**
+     * Controls the testing all files to see of they are JAR files extenion.
+     */
+    private boolean scanAllFiles = false;
+    public boolean isScanAllFiles() {
+        return scanAllFiles;
+    }
+    public void setScanAllFiles(boolean scanAllFiles) {
+        this.scanAllFiles = scanAllFiles;
+    }
+
+    /**
+     * Controls the testing all directories to see of they are exploded JAR
+     * files extenion.
+     */
+    private boolean scanAllDirectories = false;
+    public boolean isScanAllDirectories() {
+        return scanAllDirectories;
+    }
+    public void setScanAllDirectories(boolean scanAllDirectories) {
+        this.scanAllDirectories = scanAllDirectories;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void scan(ServletContext context, ClassLoader classloader,
+            JarScannerCallback callback, Set<String> jarsToSkip) {
+
+        if (log.isTraceEnabled()) {
+            log.trace(sm.getString("jarScan.webinflibStart"));
+        }
+
+        // Scan WEB-INF/lib
+        Set<String> dirList = context.getResourcePaths(WEB_INF_LIB);
+        if (dirList != null) {
+            Iterator<String> it = dirList.iterator();
+            while (it.hasNext()) {
+                String path = it.next();
+                if (path.endsWith(JAR_EXT) &&
+                        !jarsToSkip.contains(
+                                path.substring(path.lastIndexOf('/')))) {
+                    // Need to scan this JAR
+                    URL url = null;
+                    try {
+                        url = context.getResource(path);
+                        process(callback, url);
+                    } catch (IOException e) {
+                        log.warn(sm.getString("jarScan.webinflibFail", url), e);
+                    }
+                }
+            }
+        }
+        
+        // Scan the classpath
+        if (scanClassPath) {
+            if (log.isTraceEnabled()) {
+                log.trace(sm.getString("jarScan.classloaderStart"));
+            }
+
+            ClassLoader loader = 
+                Thread.currentThread().getContextClassLoader();
+            
+            while (loader != null) {
+                if (loader instanceof URLClassLoader) {
+                    URL[] urls = ((URLClassLoader) loader).getURLs();
+                    for (int i=0; i<urls.length; i++) {
+                        // Extract the jarName if there is one to be found
+                        String jarName = getJarName(urls[i]);
+                        
+                        // Skip JARs with known not to be interesting and JARs
+                        // in WEB-INF/lib we have already scanned
+                        if (!(jarsToSkip.contains(jarName) ||
+                                urls[i].toString().contains(
+                                        WEB_INF_LIB + jarName))) {
+                            try {
+                                process(callback, urls[i]);
+                            } catch (IOException ioe) {
+                                log.warn(sm.getString(
+                                        "jarScan.classloaderFail",urls[i]), ioe);
+                            }
+                        }
+                    }
+                }
+                loader = loader.getParent();
+            }
+
+        }
+    }
+
+    /*
+     * Scan a URL for JARs with the optional extensions to look at all files
+     * and all directories.
+     */
+    private void process(JarScannerCallback callback, URL url)
+            throws IOException {
+
+        if (log.isTraceEnabled()) {
+            log.trace(sm.getString("jarScan.jarUrlStart", url));
+        }
+
+        URLConnection conn = url.openConnection();
+        if (conn instanceof JarURLConnection) {
+            callback.scan((JarURLConnection) conn);
+        } else {
+            String urlStr = url.toString();
+            if (urlStr.startsWith("file:")) {
+                if (urlStr.endsWith(JAR_EXT)) {
+                    URL jarURL = new URL("jar:" + urlStr + "!/");
+                    callback.scan((JarURLConnection) jarURL.openConnection());
+                } else {
+                    File f;
+                    try {
+                        f = new File(url.toURI());
+                        if (f.isFile() && scanAllFiles) {
+                            // Treat this file as a JAR
+                            URL jarURL = new URL("jar:" + urlStr + "!/");
+                            callback.scan((JarURLConnection) jarURL.openConnection());
+                        } else if (f.isDirectory() && scanAllDirectories) {
+                            File metainf = new File(f.getAbsoluteFile() +
+                                    File.separator + "META-INF");
+                            if (metainf.isDirectory()) {
+                                callback.scan(f);
+                            }
+                        }
+                    } catch (URISyntaxException e) {
+                        // Wrap the exception and re-throw
+                        IOException ioe = new IOException();
+                        ioe.initCause(e);
+                        throw ioe;
+                    }
+                }
+            }
+        }
+        
+    }
+
+    /*
+     * Extract the JAR name, if present, from a URL
+     */
+    private String getJarName(URL url) {
+        
+        String name = null;
+        
+        String path = url.getPath();
+        int end = path.indexOf(JAR_EXT);
+        if (end != -1) {
+            int start = path.lastIndexOf('/', end);
+            name = path.substring(start + 1, end + 4);
+        }
+        
+        return name;
+    }
+
+}

Propchange: tomcat/trunk/java/org/apache/catalina/startup/DefaultJarScanner.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: tomcat/trunk/java/org/apache/catalina/startup/DefaultJarScanner.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision

Modified: tomcat/trunk/java/org/apache/catalina/startup/LocalStrings.properties
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/startup/LocalStrings.properties?rev=817685&r1=817684&r2=817685&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/startup/LocalStrings.properties (original)
+++ tomcat/trunk/java/org/apache/catalina/startup/LocalStrings.properties Tue Sep 22 14:54:28 2009
@@ -83,20 +83,21 @@
 hostConfig.undeploy=Undeploying context [{0}]
 hostConfig.undeploy.error=Error undeploying web application at context path {0}
 hostConfig.undeploying=Undeploying deployed web applications
+jarScan.classloaderFail=Failed to scan [{0}] from classloader hierarchy
+jarScan.classloaderStart=Scanning for JARs in classloader hierarchy
+jarScan.jarUrlStart=Scanning JAR at URL [{0}]
+jarScan.webinflibFail=Failed to scan JAR [{0}] from WEB-INF/lib
+jarScan.webinflibStart=Scanning WEB-INF/lib for JARs
 tldConfig.addListeners=Adding {0} listeners from TLD files
 tldConfig.cce=Lifecycle event data object {0} is not a Context
-tldConfig.classloaderFail=Failed to process ''{0}'' for TLDs.
-tldConfig.classloaderStart=Scanning for TLDs in classloader hierarchy
-tldConfig.dirScan=Scanning for TLD files in directory ''{0}''
+tldConfig.dirFail=Failed to process directory [{0}] for TLD files
+tldConfig.dirScan=Scanning for TLD files in directory [{0}]
 tldConfig.execute=Error processing TLD files for context path {0}
-tldConfig.jarUrlStart=Scanning for TLD files in URL ''{0}''
-tldConfig.webinflibStart=Scanning WEB-INF/lib for JARs containing META-INF/**/*.TLD
-tldConfig.webinflibJarFail=Failed to scan JAR ''{0}'' for TLDs
-tldConfig.webinfFail=Failed to process TLD found at ''{0}''
-tldConfig.webinfScan=Scanning WEB-INF for TLD files in ''{0}''
-tldConfig.webxmlAdd=Adding path ''{0}'' for URI ''{1}''
-tldConfig.webxmlFail=Failed to process TLD with path ''{1}'' and URI ''{0}''
-tldConfig.webxmlSkip=Path ''{1}'' skipped since URI ''{0}'' is a duplicate
+tldConfig.webinfFail=Failed to process TLD found at [{0}]
+tldConfig.webinfScan=Scanning WEB-INF for TLD files in [{0}]
+tldConfig.webxmlAdd=Adding path [{0}] for URI [{1}]
+tldConfig.webxmlFail=Failed to process TLD with path [{1}] and URI [{0}]
+tldConfig.webxmlSkip=Path [{1}] skipped since URI [{0}] is a duplicate
 tldConfig.webxmlStart=Scanning <taglib> elements in web.xml
 userConfig.database=Exception loading user database
 userConfig.deploy=Deploying web application for user {0}

Modified: tomcat/trunk/java/org/apache/catalina/startup/TldConfig.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/startup/TldConfig.java?rev=817685&r1=817684&r2=817685&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/startup/TldConfig.java (original)
+++ tomcat/trunk/java/org/apache/catalina/startup/TldConfig.java Tue Sep 22 14:54:28 2009
@@ -24,10 +24,6 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.JarURLConnection;
-import java.net.URISyntaxException;
-import java.net.URL;
-import java.net.URLClassLoader;
-import java.net.URLConnection;
 import java.util.ArrayList;
 import java.util.Enumeration;
 import java.util.HashSet;
@@ -45,6 +41,8 @@
 import org.apache.catalina.LifecycleListener;
 import org.apache.catalina.core.StandardContext;
 import org.apache.catalina.core.StandardHost;
+import org.apache.tomcat.JarScanner;
+import org.apache.tomcat.JarScannerCallback;
 import org.apache.tomcat.util.res.StringManager;
 import org.apache.tomcat.util.digester.Digester;
 import org.xml.sax.InputSource;
@@ -61,27 +59,10 @@
  */
 public final class TldConfig  implements LifecycleListener {
 
-    private static final String JAR_EXT = ".jar";
     private static final String TLD_EXT = ".tld";
     private static final String WEB_INF = "/WEB-INF/";
     private static final String WEB_INF_LIB = "/WEB-INF/lib/";
     
-    // Configuration properties
-    private static final boolean SCAN_CLASSPATH = Boolean.valueOf(
-            System.getProperty(
-                "org.apache.jasper.compiler.TldLocationsCache.SCAN_CLASSPATH",
-                "true")).booleanValue();
-
-    private static final boolean SCAN_ALL_FILES = Boolean.valueOf(
-            System.getProperty(
-                "org.apache.jasper.compiler.TldLocationsCache.SCAN_ALL_FILES",
-                "false")).booleanValue();
-
-    private static final boolean SCAN_ALL_DIRS = Boolean.valueOf(
-            System.getProperty(
-                "org.apache.jasper.compiler.TldLocationsCache.SCAN_ALL_DIRS",
-                "false")).booleanValue();
-
     // Names of JARs that are known not to contain any TLDs
     private static HashSet<String> noTldJars;
 
@@ -327,7 +308,18 @@
     /**
      * Scan for and configure all tag library descriptors found in this
      * web application.
+     * 
+     * This supports a Tomcat-specific extension to the TLD search
+     * order defined in the JSP spec. It allows tag libraries packaged as JAR
+     * files to be shared by web applications by simply dropping them in a 
+     * location that all web applications have access to (e.g.,
+     * <CATALINA_HOME>/lib). It also supports some of the weird and
+     * wonderful arrangements present when Tomcat gets embedded.
      *
+     * The set of shared JARs to be scanned for TLDs is narrowed down by
+     * the <tt>noTldJars</tt> class variable, which contains the names of JARs
+     * that are known not to contain any TLDs.
+     * 
      * @exception Exception if a fatal input/output or parsing error occurs
      */
     public void execute() throws Exception {
@@ -349,14 +341,12 @@
         // Stage 3a - TLDs under WEB-INF (not lib or classes)
         tldScanResourcePaths(WEB_INF);
 
-        // Stage 3b - .jar files in WEB-INF/lib/
-        tldScanWebInfLib();
+        // Stages 3b & 4
+        JarScanner jarScanner = context.getJarScanner();
+        jarScanner.scan(context.getServletContext(),
+                context.getLoader().getClassLoader(),
+                new TldJarScannerCallback(), noTldJars);
         
-        // Stage 4 - Additional entries from the container
-        if (SCAN_CLASSPATH) {
-            tldScanClassloaders();
-        }
-
         // Now add all the listeners we found to the listeners for this context
         String list[] = getTldListeners();
 
@@ -375,6 +365,22 @@
 
     }
 
+    private class TldJarScannerCallback implements JarScannerCallback {
+
+        @Override
+        public void scan(JarURLConnection urlConn) throws IOException {
+            tldScanJar(urlConn);
+        }
+
+        @Override
+        public void scan(File file) {
+            File metaInf = new File(file, "META-INF");
+            if (metaInf.isDirectory()) {
+                tldScanDir(metaInf);
+            }
+        }
+    }
+
     // -------------------------------------------------------- Private Methods
 
 
@@ -478,136 +484,6 @@
     }
     
     /*
-     * Scan the JARs in the WEB-INF/lib directory. Skip the JARs known not to
-     * have any TLDs in them.
-     * 
-     * Keep in sync with o.a.j.comiler.TldLocationsCache
-     */
-    private void tldScanWebInfLib() {
-
-        if (log.isTraceEnabled()) {
-            log.trace(sm.getString("tldConfig.webinflibStart"));
-        }
-        ServletContext ctxt = context.getServletContext();
-        
-        Set<String> dirList = ctxt.getResourcePaths(WEB_INF_LIB);
-        if (dirList != null) {
-            Iterator<String> it = dirList.iterator();
-            while (it.hasNext()) {
-                String path = it.next();
-                if (path.endsWith(JAR_EXT) &&
-                        !noTldJars.contains(
-                                path.substring(path.lastIndexOf('/')))) {
-                    // Need to scan this JAR for TLDs
-                    URL url = null;
-                    try {
-                        url = ctxt.getResource(path);
-                        tldScanJar(url);
-                    } catch (IOException e) {
-                        log.warn(sm.getString("tldConfig.webinflibJarFail"), e);
-                    }
-                }
-            }
-        }
-    }
-
-    /*
-     * Scan the classloader hierarchy for JARs and, optionally, for JARs where
-     * the name doesn't end in .jar and directories that represent exploded
-     * JARs. The JARs under WEB-INF/lib will be skipped as they have been
-     * scanned previously.
-     *
-     * This represents a Tomcat-specific extension to the TLD search
-     * order defined in the JSP spec. It allows tag libraries packaged as JAR
-     * files to be shared by web applications by simply dropping them in a 
-     * location that all web applications have access to (e.g.,
-     * <CATALINA_HOME>/lib). It also supports some of the weird and
-     * wonderful arrangements present when Tomcat gets embedded.
-     *
-     * The set of shared JARs to be scanned for TLDs is narrowed down by
-     * the <tt>noTldJars</tt> class variable, which contains the names of JARs
-     * that are known not to contain any TLDs.
-     * 
-     * Keep in sync with o.a.j.comiler.TldLocationsCache
-     */
-    private void tldScanClassloaders() {
-
-        if (log.isTraceEnabled()) {
-            log.trace(sm.getString("tldConfig.classloaderStart"));
-        }
-
-        ClassLoader loader = 
-            Thread.currentThread().getContextClassLoader();
-        
-        while (loader != null) {
-            if (loader instanceof URLClassLoader) {
-                URL[] urls = ((URLClassLoader) loader).getURLs();
-                for (int i=0; i<urls.length; i++) {
-                    // Extract the jarName if there is one to be found
-                    String jarName = getJarName(urls[i]);
-                    
-                    // Skip JARs with known not to contain TLDs and JARs in
-                    // WEB-INF/lib we have already scanned
-                    if (!(noTldJars.contains(jarName) ||
-                            urls[i].toString().contains(
-                                    WEB_INF_LIB + jarName))) {
-                        try {
-                            tldScanJar(urls[i]);
-                        } catch (IOException ioe) {
-                            log.warn(sm.getString(
-                                    "tldConfig.classloaderFail",urls[i]), ioe);
-                        }
-                    }
-                }
-            }
-            loader = loader.getParent();
-        }
-    }
-
-    /*
-     * Keep in sync with o.a.j.comiler.TldLocationsCache
-     */
-    private void tldScanJar(URL url) throws IOException {
-        if (log.isTraceEnabled()) {
-            log.trace(sm.getString("tldConfig.jarUrlStart", url));
-        }
-
-        URLConnection conn = url.openConnection();
-        if (conn instanceof JarURLConnection) {
-            tldScanJar((JarURLConnection) conn);
-        } else {
-            String urlStr = url.toString();
-            if (urlStr.startsWith("file:")) {
-                if (urlStr.endsWith(JAR_EXT)) {
-                    URL jarURL = new URL("jar:" + urlStr + "!/");
-                    tldScanJar((JarURLConnection) jarURL.openConnection());
-                } else {
-                    File f;
-                    try {
-                        f = new File(url.toURI());
-                        if (f.isFile() && SCAN_ALL_FILES) {
-                            // Treat this file as a JAR
-                            URL jarURL = new URL("jar:" + urlStr + "!/");
-                            tldScanJar((JarURLConnection) jarURL.openConnection());
-                        } else if (f.isDirectory() && SCAN_ALL_DIRS) {
-                            File metainf = new File(f.getAbsoluteFile() +
-                                    File.separator + "META-INF");
-                            if (metainf.isDirectory()) {
-                                tldScanDir(metainf);
-                            }
-                        }
-                    } catch (URISyntaxException e) {
-                        // Wrap the exception and re-throw
-                        IOException ioe = new IOException();
-                        ioe.initCause(e);
-                        throw ioe;
-                    }
-                }
-            }
-        }
-    }
-
-    /*
      * Scans the directory identified by startPath, along with its
      * sub-directories, for TLDs.
      *
@@ -684,25 +560,6 @@
 
 
     /*
-     * Extract the JAR name, if present, from a URL
-     * 
-     * Keep in sync with o.a.j.comiler.TldLocationsCache
-     */
-    private String getJarName(URL url) {
-        
-        String name = null;
-        
-        String path = url.getPath();
-        int end = path.indexOf(JAR_EXT);
-        if (end != -1) {
-            int start = path.lastIndexOf('/', end);
-            name = path.substring(start + 1, end + 4);
-        }
-        
-        return name;
-    }
-
-    /*
      * Scan the TLD contents in the specified input stream, and register
      * any application event listeners found there.  <b>NOTE</b> - This 
      * method ensure that the InputStream is correctly closed.
@@ -779,4 +636,5 @@
             tldDigester = createTldDigester(tldNamespaceAware, tldValidation);
         }
     }
+
 }

Added: tomcat/trunk/java/org/apache/jasper/compiler/JarScannerFactory.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/jasper/compiler/JarScannerFactory.java?rev=817685&view=auto
==============================================================================
--- tomcat/trunk/java/org/apache/jasper/compiler/JarScannerFactory.java (added)
+++ tomcat/trunk/java/org/apache/jasper/compiler/JarScannerFactory.java Tue Sep 22 14:54:28 2009
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+
+package org.apache.jasper.compiler;
+
+import javax.servlet.ServletContext;
+
+import org.apache.tomcat.JarScanner;
+
+/**
+ * Provide a mechanism for Jasper to obtain a reference to the JarScanner
+ * impementation.
+ */
+public class JarScannerFactory {
+
+    /*
+     * Don't want any instances so hide the default constructor.
+     */
+    private JarScannerFactory() {
+    }
+
+    /**
+     * Obtain the {@link JarScanner} associated with the specificed {@link
+     * ServletContext}. It is obtained via a context parameter.
+     */
+    public static JarScanner getJarScanner(ServletContext ctxt) {
+        JarScanner jarScanner = 
+        	(JarScanner) ctxt.getAttribute(JarScanner.class.getName());
+        if (jarScanner == null) {
+            ctxt.log(Localizer.getMessage("jsp.warning.noJarScanner"));
+        }
+        return jarScanner;
+    }
+
+}

Propchange: tomcat/trunk/java/org/apache/jasper/compiler/JarScannerFactory.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: tomcat/trunk/java/org/apache/jasper/compiler/JarScannerFactory.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision

Modified: tomcat/trunk/java/org/apache/jasper/compiler/TldLocationsCache.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/jasper/compiler/TldLocationsCache.java?rev=817685&r1=817684&r2=817685&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/jasper/compiler/TldLocationsCache.java (original)
+++ tomcat/trunk/java/org/apache/jasper/compiler/TldLocationsCache.java Tue Sep 22 14:54:28 2009
@@ -23,10 +23,7 @@
 import java.io.InputStream;
 import java.net.JarURLConnection;
 import java.net.MalformedURLException;
-import java.net.URISyntaxException;
 import java.net.URL;
-import java.net.URLClassLoader;
-import java.net.URLConnection;
 import java.util.Enumeration;
 import java.util.Hashtable;
 import java.util.HashSet;
@@ -45,6 +42,8 @@
 import org.apache.jasper.xmlparser.TreeNode;
 import org.apache.juli.logging.Log;
 import org.apache.juli.logging.LogFactory;
+import org.apache.tomcat.JarScanner;
+import org.apache.tomcat.JarScannerCallback;
 
 /**
  * A container for all tag libraries that are defined "globally"
@@ -98,22 +97,6 @@
     private static final String JAR_EXT = ".jar";
     private static final String TLD_EXT = ".tld";
 
-    // Configuration properties
-    private static final boolean SCAN_CLASSPATH = Boolean.valueOf(
-            System.getProperty(
-                "org.apache.jasper.compiler.TldLocationsCache.SCAN_CLASSPATH",
-                "true")).booleanValue();
-
-    private static final boolean SCAN_ALL_FILES = Boolean.valueOf(
-            System.getProperty(
-                "org.apache.jasper.compiler.TldLocationsCache.SCAN_ALL_FILES",
-                "false")).booleanValue();
-
-    private static final boolean SCAN_ALL_DIRS = Boolean.valueOf(
-            System.getProperty(
-                "org.apache.jasper.compiler.TldLocationsCache.SCAN_ALL_DIRS",
-                "false")).booleanValue();
-
     // Names of JARs that are known not to contain any TLDs
     private static HashSet<String> noTldJars;
 
@@ -257,16 +240,28 @@
 
     /*
      * Keep processing order in sync with o.a.c.startup.TldConfig
+     *
+     * This supports a Tomcat-specific extension to the TLD search
+     * order defined in the JSP spec. It allows tag libraries packaged as JAR
+     * files to be shared by web applications by simply dropping them in a 
+     * location that all web applications have access to (e.g.,
+     * <CATALINA_HOME>/lib). It also supports some of the weird and
+     * wonderful arrangements present when Tomcat gets embedded.
+     *
      */
     private void init() throws JasperException {
         if (initialized) return;
         try {
             tldScanWebXml();
             tldScanResourcePaths(WEB_INF);
-            tldScanWebInfLib();
-            if (SCAN_CLASSPATH) {
-                tldScanClassloaders();
+            
+            JarScanner jarScanner = JarScannerFactory.getJarScanner(ctxt);
+            if (jarScanner != null) {
+                jarScanner.scan(ctxt,
+                        Thread.currentThread().getContextClassLoader(),
+                        new TldJarScannerCallback(), noTldJars);
             }
+
             initialized = true;
         } catch (Exception ex) {
             throw new JasperException(Localizer.getMessage(
@@ -274,6 +269,22 @@
         }
     }
 
+    private class TldJarScannerCallback implements JarScannerCallback {
+
+        @Override
+        public void scan(JarURLConnection urlConn) throws IOException {
+            tldScanJar(urlConn);
+        }
+
+        @Override
+        public void scan(File file) throws IOException {
+            File metaInf = new File(file, "META-INF");
+            if (metaInf.isDirectory()) {
+                tldScanDir(metaInf);
+            }
+        }
+    }
+
     /*
      * Populates taglib map described in web.xml.
      * 
@@ -414,115 +425,6 @@
     }
 
     /*
-     * Scan the JARs in the WEB-INF/lib directory. Skip the JARs known not to
-     * have any TLDs in them.
-     * 
-     * Keep in sync with o.a.c.startup.TldConfig
-     */
-    private void tldScanWebInfLib() throws Exception {
-        
-        Set<String> dirList = ctxt.getResourcePaths(WEB_INF_LIB);
-        if (dirList != null) {
-            Iterator<String> it = dirList.iterator();
-            while (it.hasNext()) {
-                String path = it.next();
-                if (path.endsWith(JAR_EXT) &&
-                        !noTldJars.contains(
-                                path.substring(path.lastIndexOf('/')))) {
-                    // Need to scan this JAR for TLDs
-                    URL url = null;
-                    url = ctxt.getResource(path);
-                    tldScanJar(url);
-                }
-            }
-        }
-    }
-
-    /*
-     * Scan the classloader hierarchy for JARs and, optionally, for JARs where
-     * the name doesn't end in .jar and directories that represent exploded
-     * JARs. The JARs under WEB-INF/lib will be skipped as they have been
-     * scanned previously.
-     *
-     * This represents a Tomcat-specific extension to the TLD search
-     * order defined in the JSP spec. It allows tag libraries packaged as JAR
-     * files to be shared by web applications by simply dropping them in a 
-     * location that all web applications have access to (e.g.,
-     * <CATALINA_HOME>/lib). It also supports some of the weird and
-     * wonderful arrangements present when Tomcat gets embedded.
-     *
-     * The set of shared JARs to be scanned for TLDs is narrowed down by
-     * the <tt>noTldJars</tt> class variable, which contains the names of JARs
-     * that are known not to contain any TLDs.
-     * 
-     * Keep in sync with o.a.c.startup.TldConfig
-     */
-    private void tldScanClassloaders() throws Exception {
-
-        ClassLoader loader =
-            Thread.currentThread().getContextClassLoader();
-
-        while (loader != null) {
-            if (loader instanceof URLClassLoader) {
-                URL[] urls = ((URLClassLoader) loader).getURLs();
-                for (int i=0; i<urls.length; i++) {
-                    // Extract the jarName if there is one to be found
-                    String jarName = getJarName(urls[i]);
-
-                    // Skip JARs with known not to contain TLDs and JARs in
-                    // WEB-INF/lib we have already scanned
-                    if (!(noTldJars.contains(jarName) ||
-                            urls[i].toString().contains(
-                                    "WEB-INF/lib/" + jarName))) {
-                        tldScanJar(urls[i]);
-                    }
-                }
-            }
-            loader = loader.getParent();
-        }
-    }
-
-    /*
-     * Keep in sync with o.a.c.startup.TldConfig
-     */
-    private void tldScanJar(URL url) throws IOException {
-        URLConnection conn = url.openConnection();
-        if (conn instanceof JarURLConnection) {
-            tldScanJar((JarURLConnection) conn);
-        } else {
-            String urlStr = url.toString();
-            if (urlStr.startsWith("file:")) {
-                if (urlStr.endsWith(JAR_EXT)) {
-                    URL jarURL = new URL("jar:" + urlStr + "!/");
-                    tldScanJar((JarURLConnection) jarURL.openConnection());
-                } else {
-                    File f;
-                    try {
-                        f = new File(url.toURI());
-                        if (f.isFile() && SCAN_ALL_FILES) {
-                            // Treat this file as a JAR
-                            URL jarURL = new URL("jar:" + urlStr + "!/");
-                            tldScanJar((JarURLConnection) jarURL.openConnection());
-                            tldScanJar((JarURLConnection) jarURL.openConnection());
-                        } else if (f.isDirectory() && SCAN_ALL_DIRS) {
-                            File metainf = new File(f.getAbsoluteFile() +
-                                    File.separator + "META-INF");
-                            if (metainf.isDirectory()) {
-                                tldScanDir(metainf);
-                            }
-                        }
-                    } catch (URISyntaxException e) {
-                        // Wrap the exception and re-throw
-                        IOException ioe = new IOException();
-                        ioe.initCause(e);
-                        throw ioe;
-                    }
-                }
-            }
-        }
-    }
-
-    /*
      * Scans the directory identified by startPath, along with its
      * sub-directories, for TLDs.
      *
@@ -593,25 +495,6 @@
     }
 
     /*
-     * Extract the JAR name, if present, from a URL
-     * 
-     * Keep in sync with o.a.c.startup.TldConfig
-     */
-    private String getJarName(URL url) {
-        
-        String name = null;
-        
-        String path = url.getPath();
-        int end = path.indexOf(JAR_EXT);
-        if (end != -1) {
-            int start = path.lastIndexOf('/', end);
-            name = path.substring(start + 1, end + 4);
-        }
-        
-        return name;
-    }
-
-    /*
      * Scan the TLD contents in the specified input stream and add any new URIs
      * to the map.
      * 

Modified: tomcat/trunk/java/org/apache/jasper/resources/LocalStrings.properties
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/jasper/resources/LocalStrings.properties?rev=817685&r1=817684&r2=817685&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/jasper/resources/LocalStrings.properties (original)
+++ tomcat/trunk/java/org/apache/jasper/resources/LocalStrings.properties Tue Sep 22 14:54:28 2009
@@ -454,3 +454,6 @@
 jsp.error.tag.invalid.trimdirectivewhitespaces=Tag directive: invalid value for trimDirectiveWhitespaces
 jsp.error.page.conflict.trimdirectivewhitespaces=Page directive: illegal to have multiple occurrences of 'trimDirectiveWhitespaces' with different values (old: {0}, new: {1})
 jsp.error.tag.conflict.trimdirectivewhitespaces=Tag directive: illegal to have multiple occurrences of 'trimDirectiveWhitespaces' with different values (old: {0}, new: {1})
+
+# JarScanner
+jsp.warning.noJarScanner=Warning: No org.apache.tomcat.JarScanner set in ServletContext. Jar scanning for TLDs and web-fragment.xml files is disabled
\ No newline at end of file

Added: tomcat/trunk/java/org/apache/tomcat/JarScanner.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/JarScanner.java?rev=817685&view=auto
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/JarScanner.java (added)
+++ tomcat/trunk/java/org/apache/tomcat/JarScanner.java Tue Sep 22 14:54:28 2009
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+
+package org.apache.tomcat;
+
+import java.util.Set;
+
+import javax.servlet.ServletContext;
+
+/**
+ * Scans a web application and classloader hierarchy for JAR files. Uses
+ * include TLD scanning and web-fragment.xml scanning. Uses a call-back
+ * mechanism so the caller can process each JAR found. 
+ */
+public interface JarScanner {
+
+    /**
+     * Scan the provided ServletContext and classloader for JAR files. Each JAR
+     * file found will be passed to the callback handler to be processed.
+     *  
+     * @param context       The ServletContext - used to locate and access
+     *                      WEB-INF/lib
+     * @param classloader   The classloader - used to access JARs not in
+     *                      WEB-INF/lib
+     * @param callback      The handler to process any JARs found
+     * @param jarsToSkip    List of JARs to ignore
+     */
+    public void scan(ServletContext context, ClassLoader classloader,
+            JarScannerCallback callback, Set<String> jarsToSkip);
+    
+}

Propchange: tomcat/trunk/java/org/apache/tomcat/JarScanner.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: tomcat/trunk/java/org/apache/tomcat/JarScanner.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision

Added: tomcat/trunk/java/org/apache/tomcat/JarScannerCallback.java
URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/tomcat/JarScannerCallback.java?rev=817685&view=auto
==============================================================================
--- tomcat/trunk/java/org/apache/tomcat/JarScannerCallback.java (added)
+++ tomcat/trunk/java/org/apache/tomcat/JarScannerCallback.java Tue Sep 22 14:54:28 2009
@@ -0,0 +1,18 @@
+package org.apache.tomcat;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.JarURLConnection;
+
+public interface JarScannerCallback {
+
+    /**
+     * 
+     * @param urlConn
+     * @throws IOException
+     */
+    public void scan(JarURLConnection urlConn) throws IOException;
+    
+    public void scan(File file) throws IOException ;
+
+}

Propchange: tomcat/trunk/java/org/apache/tomcat/JarScannerCallback.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: tomcat/trunk/java/org/apache/tomcat/JarScannerCallback.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision

Added: tomcat/trunk/webapps/docs/config/jar-scanner.xml
URL: http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/config/jar-scanner.xml?rev=817685&view=auto
==============================================================================
--- tomcat/trunk/webapps/docs/config/jar-scanner.xml (added)
+++ tomcat/trunk/webapps/docs/config/jar-scanner.xml Tue Sep 22 14:54:28 2009
@@ -0,0 +1,115 @@
+<?xml version="1.0"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<!DOCTYPE document [
+  <!ENTITY project SYSTEM "project.xml">
+]>
+<document url="jar-scanner.html">
+
+  &project;
+
+  <properties>
+    <title>The Jar Scanner Component</title>
+  </properties>
+
+<body>
+
+
+<section name="Introduction">
+
+  <p>The <strong>Jar Scanner</strong> element represents the component that is
+  used to scan the web application for JAR files. It is typically used during
+  web application start to identify configuration files such as TLDs or
+  web-fragment.xml files that must be processed as part of the web application
+  initialisation.</p>
+
+  <p>A Jar Scanner element MAY be nested inside a
+  <a href="context.html">Context</a> component.  If it is not included,
+  a default Jar Scanner configuration will be created automatically, which
+  is sufficient for most requirements.</p>
+
+</section>
+
+
+<section name="Attributes">
+
+  <subsection name="Common Attributes">
+
+    <p>All implementations of <strong>Jar Scanner</strong>
+    support the following attributes:</p>
+
+    <attributes>
+
+      <attribute name="className" required="false">
+        <p>Java class name of the implementation to use.  This class must
+        implement the <code>org.apache.tomcat.JarScanner</code> interface.
+        If not specified, the standard value (defined below) will be used.</p>
+      </attribute>
+
+    </attributes>
+
+  </subsection>
+
+
+  <subsection name="Standard Implementation">
+
+    <p>The standard implementation of <strong>Jar Scanner</strong> is
+    <strong>org.apache.catalina.deploy.DefaultJarScanner</strong>.
+    It supports the following additional attributes (in addition to the
+    common attributes listed above):</p>
+
+    <attributes>
+
+      <attribute name="scanClassPath" required="false">
+       <p>If true, the full web application classpath, including the shared and
+       common classloaders will be scanned for Jar files in addition to the
+       web application. The default is <code>true</code>.</p>
+      </attribute>
+
+      <attribute name="scanAllFiles" required="false">
+       <p>If true, any files found on the classpath will be checked to see if
+       they are Jar files rather than relying on the file extension being
+       <code>.jar</code>. The default is <code>false</code></p>
+      </attribute>
+
+      <attribute name="scanAllDirectories" required="false">
+       <p>If true, any directories found on the classpath will be checked to see
+       if are expanded Jar files. The default is <code>false</code></p>
+      </attribute>
+
+    </attributes>
+
+  </subsection>
+
+
+</section>
+
+
+<section name="Nested Components">
+  <p>No components may be nested inside a <strong>Jar Scanner</strong> element.
+  </p>
+</section>
+
+
+<section name="Special Features">
+  <p>No special features are associated with a <strong>Jar Scanner</strong>
+  element.</p>
+</section>
+
+</body>
+
+</document>

Propchange: tomcat/trunk/webapps/docs/config/jar-scanner.xml
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: tomcat/trunk/webapps/docs/config/jar-scanner.xml
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision

Modified: tomcat/trunk/webapps/docs/config/project.xml
URL: http://svn.apache.org/viewvc/tomcat/trunk/webapps/docs/config/project.xml?rev=817685&r1=817684&r2=817685&view=diff
==============================================================================
--- tomcat/trunk/webapps/docs/config/project.xml (original)
+++ tomcat/trunk/webapps/docs/config/project.xml Tue Sep 22 14:54:28 2009
@@ -57,6 +57,7 @@
         <item name="Listeners"             href="listeners.html"/>
         <item name="Global Resources"      href="globalresources.html"/>
         <item name="Loader"                href="loader.html"/>
+        <item name="JarScanner"            href="jar-scanner.html"/>
         <item name="Manager"               href="manager.html"/> 
         <item name="Realm"                 href="realm.html"/>
         <item name="Resources"             href="resources.html"/>



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org