Property changes on: .
___________________________________________________________________
Modified: svn:mergeinfo
Merged /tomcat/trunk:r647344,751502,793621,795143,795767,795819,795822,795824,795838,795860,795902,796016-796017,796030,801601,801637
Index: java/org/apache/catalina/startup/ContextConfig.java
===================================================================
--- java/org/apache/catalina/startup/ContextConfig.java (revision 801738)
+++ java/org/apache/catalina/startup/ContextConfig.java (working copy)
@@ -144,27 +144,21 @@
* The Digester we will use to process web application
* deployment descriptor files.
*/
- protected static Digester webDigester = null;
+ protected Digester webDigester = null;
/**
- * The Rule used to parse the web.xml
+ * The Digesters available to process web application
+ * deployment descriptor files.
*/
- protected static WebRuleSet webRuleSet = new WebRuleSet();
+ protected static Digester[] webDigesters = new Digester[4];
/**
- * Attribute value used to turn on/off XML validation
+ * The Rule used to parse the web.xml
*/
- protected static boolean xmlValidation = false;
+ protected static WebRuleSet webRuleSet = new WebRuleSet();
-
/**
- * Attribute value used to turn on/off XML namespace awarenes.
- */
- protected static boolean xmlNamespaceAware = false;
-
-
- /**
* Deployment count.
*/
protected static long deploymentCount = 0L;
@@ -517,25 +511,37 @@
* Create (if necessary) and return a Digester configured to process the
* web application deployment descriptor (web.xml).
*/
- protected static Digester createWebDigester() {
- Digester webDigester =
- createWebXmlDigester(xmlNamespaceAware, xmlValidation);
- return webDigester;
- }
-
-
- /**
- * Create (if necessary) and return a Digester configured to process the
- * web application deployment descriptor (web.xml).
- */
public static Digester createWebXmlDigester(boolean namespaceAware,
boolean validation) {
- Digester webDigester = DigesterFactory.newDigester(xmlValidation,
- xmlNamespaceAware,
- webRuleSet);
- return webDigester;
+ Digester digester = null;
+ if (!namespaceAware && !validation) {
+ if (webDigesters[0] == null) {
+ webDigesters[0] = DigesterFactory.newDigester(validation,
+ namespaceAware, webRuleSet);
}
+ digester = webDigesters[0];
+ } else if (!namespaceAware && validation) {
+ if (webDigesters[1] == null) {
+ webDigesters[1] = DigesterFactory.newDigester(validation,
+ namespaceAware, webRuleSet);
+ }
+ digester = webDigesters[1];
+ } else if (namespaceAware && !validation) {
+ if (webDigesters[2] == null) {
+ webDigesters[2] = DigesterFactory.newDigester(validation,
+ namespaceAware, webRuleSet);
+ }
+ digester = webDigesters[2];
+ } else {
+ if (webDigesters[3] == null) {
+ webDigesters[3] = DigesterFactory.newDigester(validation,
+ namespaceAware, webRuleSet);
+ }
+ digester = webDigesters[3];
+ }
+ return digester;
+ }
/**
@@ -991,11 +997,6 @@
protected void init() {
// Called from StandardContext.init()
- if (webDigester == null){
- webDigester = createWebDigester();
- webDigester.getParser();
- }
-
if (contextDigester == null){
contextDigester = createContextDigester();
contextDigester.getParser();
@@ -1040,28 +1041,36 @@
if (log.isDebugEnabled())
log.debug(sm.getString("contextConfig.start"));
- // Set properties based on DefaultContext
+ // Process the default and application web.xml files
+ // Set properties based on default context
+ boolean useXmlValidation = context.getXmlValidation();
+ boolean useXmlNamespaceAware = context.getXmlNamespaceAware();
+
Container container = context.getParent();
+ // Use the value from the host if:
+ // - override is false on the context
+ // - value has been set to false / not set on the context
if( !context.getOverride() ) {
if( container instanceof Host ) {
- // Reset the value only if the attribute wasn't
- // set on the context.
- xmlValidation = context.getXmlValidation();
- if (!xmlValidation) {
- xmlValidation = ((Host)container).getXmlValidation();
+ if (!useXmlValidation) {
+ useXmlValidation = ((Host)container).getXmlValidation();
}
- xmlNamespaceAware = context.getXmlNamespaceAware();
- if (!xmlNamespaceAware){
- xmlNamespaceAware
+ if (!useXmlNamespaceAware){
+ useXmlNamespaceAware
= ((Host)container).getXmlNamespaceAware();
}
- container = container.getParent();
}
}
- // Process the default and application web.xml files
+ if (log.isDebugEnabled()) {
+ log.debug(sm.getString("contextConfig.xmlSettings",
+ context.getName(), Boolean.valueOf(useXmlValidation),
+ Boolean.valueOf(useXmlNamespaceAware)));
+ }
+ webDigester = createWebXmlDigester(useXmlNamespaceAware, useXmlValidation);
+
defaultWebConfig();
applicationWebConfig();
if (!context.getIgnoreAnnotations()) {
Index: java/org/apache/catalina/startup/LocalStrings.properties
===================================================================
--- java/org/apache/catalina/startup/LocalStrings.properties (revision 801738)
+++ java/org/apache/catalina/startup/LocalStrings.properties (working copy)
@@ -46,6 +46,7 @@
contextConfig.tldFileException=Exception processing TLD at resource path {0} in context {1}
contextConfig.tldJarException=Exception processing JAR at resource path {0} in context {1}
contextConfig.tldResourcePath=Invalid TLD resource path {0}
+contextConfig.xmlSettings=Context [{0}] will parse web.xml and web-fragment.xml files with validation:{1} and namespaceAware:{2}
contextConfig.unavailable=Marking this application unavailable due to previous error(s)
contextConfig.altDDNotFound=alt-dd file {0} not found
embedded.alreadyStarted=Embedded service has already been started
@@ -87,8 +88,20 @@
hostConfig.undeploy=Undeploying context [{0}]
hostConfig.undeploy.error=Error undeploying web application at context path {0}
hostConfig.undeploying=Undeploying deployed web applications
+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.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.webxmlStart=Scanning elements in web.xml
userConfig.database=Exception loading user database
userConfig.deploy=Deploying web application for user {0}
userConfig.deploying=Deploying user web applications
Index: java/org/apache/catalina/startup/TldConfig.java
===================================================================
--- java/org/apache/catalina/startup/TldConfig.java (revision 801738)
+++ java/org/apache/catalina/startup/TldConfig.java (working copy)
@@ -19,35 +19,24 @@
package org.apache.catalina.startup;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
-import java.net.URISyntaxException;
+import java.net.JarURLConnection;
import java.net.URL;
import java.net.URLClassLoader;
+import java.net.URLConnection;
import java.util.ArrayList;
import java.util.Enumeration;
-import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
-import java.util.Map;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
-import javax.naming.NameClassPair;
-import javax.naming.NamingEnumeration;
-import javax.naming.NamingException;
-import javax.naming.directory.DirContext;
-import javax.servlet.ServletException;
+import javax.servlet.ServletContext;
import org.apache.catalina.Context;
-import org.apache.catalina.Globals;
import org.apache.catalina.Lifecycle;
import org.apache.catalina.LifecycleEvent;
import org.apache.catalina.LifecycleListener;
@@ -56,7 +45,9 @@
import org.apache.catalina.util.StringManager;
import org.apache.tomcat.util.digester.Digester;
import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
/**
* Startup event listener for a Context that configures application
* listeners configured in any TLD files.
@@ -67,12 +58,34 @@
*/
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();
+
// Names of JARs that are known not to contain any TLDs
private static HashSet noTldJars;
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);
+
+ /**
+ * The Digesters available to process tld files.
+ */
+ private static Digester[] tldDigesters = new Digester[4];
+
/*
* Initializes the set of JARs that are known not to contain any TLDs
*/
@@ -124,7 +137,43 @@
noTldJars.add("sunpkcs11.jar");
}
+ /**
+ * Create (if necessary) and return a Digester configured to process the
+ * tld.
+ */
+ private static Digester createTldDigester(boolean namespaceAware,
+ boolean validation) {
+ Digester digester = null;
+ if (!namespaceAware && !validation) {
+ if (tldDigesters[0] == null) {
+ tldDigesters[0] = DigesterFactory.newDigester(validation,
+ namespaceAware, new TldRuleSet());
+ }
+ digester = tldDigesters[0];
+ } else if (!namespaceAware && validation) {
+ if (tldDigesters[1] == null) {
+ tldDigesters[1] = DigesterFactory.newDigester(validation,
+ namespaceAware, new TldRuleSet());
+ }
+ digester = tldDigesters[1];
+ } else if (namespaceAware && !validation) {
+ if (tldDigesters[2] == null) {
+ tldDigesters[2] = DigesterFactory.newDigester(validation,
+ namespaceAware, new TldRuleSet());
+ }
+ digester = tldDigesters[2];
+ } else {
+ if (tldDigesters[3] == null) {
+ tldDigesters[3] = DigesterFactory.newDigester(validation,
+ namespaceAware, new TldRuleSet());
+ }
+ digester = tldDigesters[3];
+ }
+ return digester;
+ }
+
+
// ----------------------------------------------------- Instance Variables
/**
@@ -134,36 +183,51 @@
/**
- * The string resources for this package.
- */
- private static final StringManager sm =
- StringManager.getManager(Constants.Package);
-
- /**
* The Digester we will use to process tag library
* descriptor files.
*/
- private static Digester tldDigester = null;
+ private Digester tldDigester = null;
/**
* Attribute value used to turn on/off TLD validation
*/
- private static boolean tldValidation = false;
+ private boolean tldValidation = false;
/**
* Attribute value used to turn on/off TLD namespace awarenes.
*/
- private static boolean tldNamespaceAware = false;
+ private boolean tldNamespaceAware = false;
private boolean rescan=true;
+ /**
+ * Set of URIs discovered for the associated context. Used to enforce the
+ * correct processing priority. Only the TLD associated with the first
+ * instance of any URI will be processed.
+ */
+ private Set taglibUris = new HashSet();
+
private ArrayList listeners = new ArrayList();
// --------------------------------------------------------- Public Methods
/**
+ * Adds a taglib URI to the list of known URIs.
+ */
+ public void addTaglibUri(String uri) {
+ taglibUris.add(uri);
+ }
+
+ /**
+ * Determines if the provided URI is a known taglib URI.
+ */
+ public boolean isKnownTaglibUri(String uri) {
+ return taglibUris.contains(uri);
+ }
+
+ /**
* Sets the list of JARs that are known not to contain any TLDs.
*
* @param jarNames List of comma-separated names of JAR files that are
@@ -185,7 +249,7 @@
* @param tldValidation true to enable xml instance validation
*/
public void setTldValidation(boolean tldValidation){
- TldConfig.tldValidation = tldValidation;
+ this.tldValidation = tldValidation;
}
/**
@@ -194,7 +258,7 @@
*
*/
public boolean getTldValidation(){
- return tldValidation;
+ return this.tldValidation;
}
/**
@@ -203,7 +267,7 @@
*
*/
public boolean getTldNamespaceAware(){
- return tldNamespaceAware;
+ return this.tldNamespaceAware;
}
@@ -213,7 +277,7 @@
* @param tldNamespaceAware true to enable namespace awareness
*/
public void setTldNamespaceAware(boolean tldNamespaceAware){
- TldConfig.tldNamespaceAware = tldNamespaceAware;
+ this.tldNamespaceAware = tldNamespaceAware;
}
@@ -255,73 +319,37 @@
public void execute() throws Exception {
long t1=System.currentTimeMillis();
- File tldCache=null;
-
- if (context instanceof StandardContext) {
- File workDir= (File)
- ((StandardContext)context).getServletContext().getAttribute(Globals.WORK_DIR_ATTR);
- //tldCache=new File( workDir, "tldCache.ser");
- }
-
- // Option to not rescan
- if( ! rescan ) {
- // find the cache
- if( tldCache!= null && tldCache.exists()) {
- // just read it...
- processCache(tldCache);
- return;
- }
- }
-
/*
- * Acquire the list of TLD resource paths, possibly embedded in JAR
- * files, to be processed
+ * Priority order of URIs required by spec is:
+ * 1. J2EE platform taglibs - Tomcat doesn't provide these
+ * 2. web.xml entries
+ * 3. JARS in WEB-INF/lib & TLDs under WEB-INF (equal priority)
+ * 4. Additional entries from the container
+ *
+ * Keep processing order in sync with o.a.j.compiler.TldLocationsCache
*/
- Set resourcePaths = tldScanResourcePaths();
- Map jarPaths = getJarPaths();
- // Check to see if we can use cached listeners
- if (tldCache != null && tldCache.exists()) {
- long lastModified = getLastModified(resourcePaths, jarPaths);
- if (lastModified < tldCache.lastModified()) {
- processCache(tldCache);
- return;
- }
- }
+ // Stage 2 - web.xml entries
+ tldScanWebXml();
+
+ // Stage 3a - TLDs under WEB-INF (not lib or classes)
+ tldScanResourcePaths(WEB_INF);
- // Scan each accumulated resource path for TLDs to be processed
- Iterator paths = resourcePaths.iterator();
- while (paths.hasNext()) {
- String path = (String) paths.next();
- if (path.endsWith(".jar")) {
- tldScanJar(path);
- } else {
- tldScanTld(path);
- }
+ // Stage 3b - .jar files in WEB-INF/lib/
+ tldScanWebInfLib();
+
+ // Stage 4 - Additional entries from the container
+ if (SCAN_CLASSPATH) {
+ tldScanClassloaders();
}
- if (jarPaths != null) {
- paths = jarPaths.values().iterator();
- while (paths.hasNext()) {
- tldScanJar((File) paths.next());
- }
- }
+ // Now add all the listeners we found to the listeners for this context
String list[] = getTldListeners();
- if( tldCache!= null ) {
- log.debug( "Saving tld cache: " + tldCache + " " + list.length);
- try {
- FileOutputStream out=new FileOutputStream(tldCache);
- ObjectOutputStream oos=new ObjectOutputStream( out );
- oos.writeObject( list );
- oos.close();
- } catch( IOException ex ) {
- ex.printStackTrace();
- }
- }
-
if( log.isDebugEnabled() )
- log.debug( "Adding tld listeners:" + list.length);
+ log.debug(sm.getString("tldConfig.addListeners",
+ Integer.valueOf(list.length)));
+
for( int i=0; list!=null && i lastModified) lastModified = lastM;
- if (log.isDebugEnabled()) {
- log.debug( "Last modified " + path + " " + lastM);
- }
- }
-
- if (jarPaths != null) {
- paths = jarPaths.values().iterator();
- while (paths.hasNext()) {
- File jarFile = (File) paths.next();
- long lastM = jarFile.lastModified();
- if (lastM > lastModified) lastModified = lastM;
- if (log.isDebugEnabled()) {
- log.debug("Last modified " + jarFile.getAbsolutePath()
- + " " + lastM);
- }
- }
- }
-
- return lastModified;
- }
-
- private void processCache(File tldCache ) throws IOException {
- // read the cache and return;
- try {
- FileInputStream in=new FileInputStream(tldCache);
- ObjectInputStream ois=new ObjectInputStream( in );
- String list[]=(String [])ois.readObject();
- if( log.isDebugEnabled() )
- log.debug("Reusing tldCache " + tldCache + " " + list.length);
- for( int i=0; list!=null && iMETA-INF subdirectory, and scan each TLD for application
- * event listeners that need to be registered.
- *
- * @param resourcePath Resource path of the JAR file to scan
- *
- * @exception Exception if an exception occurs while scanning this JAR
+ * Get the taglib entries from web.xml and add them to the map.
+ *
+ * This is not kept in sync with o.a.j.compiler.TldLocationsCache as this
+ * code needs to scan the TLDs listed in web.xml whereas Jasper only needs
+ * the URI to TLD mappings.
*/
- private void tldScanJar(String resourcePath) throws Exception {
-
- if (log.isDebugEnabled()) {
- log.debug(" Scanning JAR at resource path '" + resourcePath + "'");
+ private void tldScanWebXml() {
+
+ if (log.isTraceEnabled()) {
+ log.trace(sm.getString("tldConfig.webxmlStart"));
}
-
- URL url = context.getServletContext().getResource(resourcePath);
- if (url == null) {
- throw new IllegalArgumentException
- (sm.getString("contextConfig.tldResourcePath",
- resourcePath));
- }
-
- File file = null;
- try {
- file = new File(url.toURI());
- } catch (URISyntaxException e) {
- // Ignore, probably an unencoded char
- file = new File(url.getFile());
- }
- try {
- file = file.getCanonicalFile();
- } catch (IOException e) {
- // Ignore
- }
- tldScanJar(file);
-
- }
-
- /**
- * Scans all TLD entries in the given JAR for application listeners.
- *
- * @param file JAR file whose TLD entries are scanned for application
- * listeners
- */
- private void tldScanJar(File file) throws Exception {
-
- JarFile jarFile = null;
- String name = null;
-
- String jarPath = file.getAbsolutePath();
-
- try {
- jarFile = new JarFile(file);
- Enumeration entries = jarFile.entries();
- while (entries.hasMoreElements()) {
- JarEntry entry = (JarEntry) entries.nextElement();
- name = entry.getName();
- if (!name.startsWith("META-INF/")) {
- continue;
- }
- if (!name.endsWith(".tld")) {
- continue;
- }
+
+ String taglibs[] = context.findTaglibs();
+ for (int i = 0; i < taglibs.length; i++) {
+ String resourcePath = context.findTaglib(taglibs[i]);
+ // Note: Whilst the Servlet 2.4 DTD implies that the location must
+ // be a context-relative path starting with '/', JSP.7.3.6.1 states
+ // explicitly how paths that do not start with '/' should be
+ // handled.
+ if (!resourcePath.startsWith("/")) {
+ resourcePath = WEB_INF + resourcePath;
+ }
+ if (taglibUris.contains(taglibs[i])) {
+ log.warn(sm.getString("tldConfig.webxmlSkip", resourcePath,
+ taglibs[i]));
+ } else {
if (log.isTraceEnabled()) {
- log.trace(" Processing TLD at '" + name + "'");
+ log.trace(sm.getString("tldConfig.webxmlAdd", resourcePath,
+ taglibs[i]));
}
try {
- tldScanStream(new InputSource(jarFile.getInputStream(entry)));
- } catch (Exception e) {
- log.error(sm.getString("contextConfig.tldEntryException",
- name, jarPath, context.getPath()),
- e);
+ InputStream stream = context.getServletContext(
+ ).getResourceAsStream(resourcePath);
+ tldScanStream(stream);
+ taglibUris.add(taglibs[i]);
+ } catch (IOException ioe) {
+ log.warn(sm.getString("tldConfig.webxmlFail", resourcePath,
+ taglibs[i]), ioe);
}
}
- } catch (Exception e) {
- log.error(sm.getString("contextConfig.tldJarException",
- jarPath, context.getPath()),
- e);
- } finally {
- if (jarFile != null) {
- try {
- jarFile.close();
- } catch (Throwable t) {
- // Ignore
- }
- }
}
}
-
- /**
- * Scan the TLD contents in the specified input stream, and register
- * any application event listeners found there. NOTE - It is
- * the responsibility of the caller to close the InputStream after this
- * method returns.
+
+ /*
+ * Scans the web application's sub-directory identified by startPath,
+ * along with its sub-directories, for TLDs.
*
- * @param resourceStream InputStream containing a tag library descriptor
+ * Initially, rootPath equals /WEB-INF/. The /WEB-INF/classes and
+ * /WEB-INF/lib sub-directories are excluded from the search, as per the
+ * JSP 2.0 spec.
*
- * @exception Exception if an exception occurs while scanning this TLD
+ * Keep in sync with o.a.j.comiler.TldLocationsCache
*/
- private void tldScanStream(InputSource resourceStream)
- throws Exception {
+ private void tldScanResourcePaths(String startPath) {
- synchronized (tldDigester) {
- try {
- tldDigester.push(this);
- tldDigester.parse(resourceStream);
- } finally {
- tldDigester.reset();
- }
+ if (log.isTraceEnabled()) {
+ log.trace(sm.getString("tldConfig.webinfScan", startPath));
}
- }
+ ServletContext ctxt = context.getServletContext();
- /**
- * Scan the TLD contents at the specified resource path, and register
- * any application event listeners found there.
- *
- * @param resourcePath Resource path being scanned
- *
- * @exception Exception if an exception occurs while scanning this TLD
- */
- private void tldScanTld(String resourcePath) throws Exception {
-
- if (log.isDebugEnabled()) {
- log.debug(" Scanning TLD at resource path '" + resourcePath + "'");
- }
-
- InputSource inputSource = null;
- try {
- InputStream stream =
- context.getServletContext().getResourceAsStream(resourcePath);
- if (stream == null) {
- throw new IllegalArgumentException
- (sm.getString("contextConfig.tldResourcePath",
- resourcePath));
+ Set dirList = ctxt.getResourcePaths(startPath);
+ if (dirList != null) {
+ Iterator it = dirList.iterator();
+ while (it.hasNext()) {
+ String path = it.next();
+ if (!path.endsWith(TLD_EXT)
+ && (path.startsWith(WEB_INF_LIB)
+ || path.startsWith("/WEB-INF/classes/"))) {
+ continue;
+ }
+ if (path.endsWith(TLD_EXT)) {
+ if (path.startsWith("/WEB-INF/tags/") &&
+ !path.endsWith("implicit.tld")) {
+ continue;
+ }
+ InputStream stream = ctxt.getResourceAsStream(path);
+ try {
+ tldScanStream(stream);
+ } catch (IOException ioe) {
+ log.warn(sm.getString("tldConfig.webinfFail", path),
+ ioe);
+ } finally {
+ if (stream != null) {
+ try {
+ stream.close();
+ } catch (Throwable t) {
+ // do nothing
+ }
+ }
+ }
+ } else {
+ tldScanResourcePaths(path);
+ }
}
- inputSource = new InputSource(stream);
- if (inputSource == null) {
- throw new IllegalArgumentException
- (sm.getString("contextConfig.tldResourcePath",
- resourcePath));
- }
- tldScanStream(inputSource);
- } catch (Exception e) {
- throw new ServletException
- (sm.getString("contextConfig.tldFileException", resourcePath,
- context.getPath()),
- e);
- }
-
- }
-
- /**
- * Accumulate and return a Set of resource paths to be analyzed for
- * tag library descriptors. Each element of the returned set will be
- * the context-relative path to either a tag library descriptor file,
- * or to a JAR file that may contain tag library descriptors in its
- * META-INF subdirectory.
- *
- * @exception IOException if an input/output error occurs while
- * accumulating the list of resource paths
- */
- private Set tldScanResourcePaths() throws IOException {
- if (log.isDebugEnabled()) {
- log.debug(" Accumulating TLD resource paths");
}
- Set resourcePaths = new HashSet();
-
- // Accumulate resource paths explicitly listed in the web application
- // deployment descriptor
- if (log.isTraceEnabled()) {
- log.trace(" Scanning elements in web.xml");
- }
- String taglibs[] = context.findTaglibs();
- for (int i = 0; i < taglibs.length; i++) {
- String resourcePath = context.findTaglib(taglibs[i]);
- // FIXME - Servlet 2.4 DTD implies that the location MUST be
- // a context-relative path starting with '/'?
- if (!resourcePath.startsWith("/")) {
- resourcePath = "/WEB-INF/" + resourcePath;
- }
- if (log.isTraceEnabled()) {
- log.trace(" Adding path '" + resourcePath +
- "' for URI '" + taglibs[i] + "'");
- }
- resourcePaths.add(resourcePath);
- }
-
- DirContext resources = context.getResources();
- if (resources != null) {
- tldScanResourcePathsWebInf(resources, "/WEB-INF", resourcePaths);
- }
-
- // Return the completed set
- return (resourcePaths);
-
}
-
+
/*
- * Scans the web application's subdirectory identified by rootPath,
- * along with its subdirectories, for TLDs.
- *
- * Initially, rootPath equals /WEB-INF. The /WEB-INF/classes and
- * /WEB-INF/lib subdirectories are excluded from the search, as per the
- * JSP 2.0 spec.
- *
- * @param resources The web application's resources
- * @param rootPath The path whose subdirectories are to be searched for
- * TLDs
- * @param tldPaths The set of TLD resource paths to add to
+ * 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 tldScanResourcePathsWebInf(DirContext resources,
- String rootPath,
- Set tldPaths)
- throws IOException {
+ private void tldScanWebInfLib() {
if (log.isTraceEnabled()) {
- log.trace(" Scanning TLDs in " + rootPath + " subdirectory");
+ log.trace(sm.getString("tldConfig.webinflibStart"));
}
+ ServletContext ctxt = context.getServletContext();
- try {
- NamingEnumeration items = resources.list(rootPath);
- while (items.hasMoreElements()) {
- NameClassPair item = (NameClassPair) items.nextElement();
- String resourcePath = rootPath + "/" + item.getName();
- if (!resourcePath.endsWith(".tld")
- && (resourcePath.startsWith("/WEB-INF/classes")
- || resourcePath.startsWith("/WEB-INF/lib"))) {
- continue;
- }
- if (resourcePath.endsWith(".tld")) {
- if (log.isTraceEnabled()) {
- log.trace(" Adding path '" + resourcePath + "'");
+ Set dirList = ctxt.getResourcePaths(WEB_INF_LIB);
+ if (dirList != null) {
+ Iterator 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);
}
- tldPaths.add(resourcePath);
- } else {
- tldScanResourcePathsWebInf(resources, resourcePath,
- tldPaths);
}
}
- } catch (NamingException e) {
- ; // Silent catch: it's valid that no /WEB-INF directory exists
}
}
- /**
- * Returns a map of the paths to all JAR files that are accessible to the
- * webapp and will be scanned for TLDs.
+ /*
+ * 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.
*
- * The map always includes all the JARs under WEB-INF/lib, as well as
- * shared JARs in the classloader delegation chain of the webapp's
- * classloader.
- *
- * The latter constitutes a Tomcat-specific extension to the TLD search
+ * 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.,
- * /common/lib).
+ * /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 noTldJars class variable, which contains the names of JARs
* that are known not to contain any TLDs.
- *
- * @return Map of JAR file paths
+ *
+ * Keep in sync with o.a.j.comiler.TldLocationsCache
*/
- private Map getJarPaths() {
+ private void tldScanClassloaders() {
- HashMap jarPathMap = null;
+ if (log.isTraceEnabled()) {
+ log.trace(sm.getString("tldConfig.classloaderStart"));
+ }
- ClassLoader webappLoader = Thread.currentThread().getContextClassLoader();
- ClassLoader loader = webappLoader;
+ ClassLoader loader =
+ Thread.currentThread().getContextClassLoader();
+
while (loader != null) {
if (loader instanceof URLClassLoader) {
URL[] urls = ((URLClassLoader) loader).getURLs();
for (int i=0; i entries = jarFile.entries();
+ while (entries.hasMoreElements()) {
+ JarEntry entry = entries.nextElement();
+ String name = entry.getName();
+ if (!name.startsWith("META-INF/")) continue;
+ if (!name.endsWith(".tld")) continue;
+ InputStream stream = jarFile.getInputStream(entry);
+ tldScanStream(stream);
+ }
+ } finally {
+ if (jarFile != null) {
+ try {
+ jarFile.close();
+ } catch (Throwable t) {
+ // ignore
+ }
+ }
}
}
+
+
+ /*
+ * 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. NOTE - This
+ * method ensure that the InputStream is correctly closed.
+ *
+ * @param resourceStream InputStream containing a tag library descriptor
+ *
+ * @throws IOException If the file cannot be read
+ */
+ private void tldScanStream(InputStream resourceStream) throws IOException {
+
+ InputSource source = new InputSource(resourceStream);
+
+ synchronized (tldDigester) {
+ try {
+ tldDigester.push(this);
+ tldDigester.parse(source);
+ } catch (SAXException s) {
+ // Hack - makes exception handling simpler
+ IOException ioe = new IOException();
+ ioe.initCause(s);
+ throw ioe;
+ } finally {
+ tldDigester.reset();
+ if (resourceStream != null) {
+ try {
+ resourceStream.close();
+ } catch (Throwable t) {
+ // do nothing
+ }
}
}
- loader = loader.getParent();
}
-
- return jarPathMap;
}
public void lifecycleEvent(LifecycleEvent event) {
@@ -752,7 +689,8 @@
setTldNamespaceAware(context.getTldNamespaceAware());
// (2) if the attribute wasn't defined on the context
- // try the host.
+ // and override is not set on the context try the host.
+ if (!context.getOverride()) {
if (!tldValidation) {
setTldValidation(
((StandardHost) context.getParent()).getXmlValidation());
@@ -762,11 +700,8 @@
setTldNamespaceAware(
((StandardHost) context.getParent()).getXmlNamespaceAware());
}
-
- tldDigester = DigesterFactory.newDigester(tldValidation,
- tldNamespaceAware,
- new TldRuleSet());
- tldDigester.getParser();
}
+ tldDigester = createTldDigester(tldNamespaceAware, tldValidation);
}
}
+}
Index: java/org/apache/catalina/startup/TldRuleSet.java
===================================================================
--- java/org/apache/catalina/startup/TldRuleSet.java (revision 801738)
+++ java/org/apache/catalina/startup/TldRuleSet.java (working copy)
@@ -20,6 +20,7 @@
import org.apache.tomcat.util.digester.Digester;
+import org.apache.tomcat.util.digester.Rule;
import org.apache.tomcat.util.digester.RuleSetBase;
@@ -87,10 +88,99 @@
*/
public void addRuleInstances(Digester digester) {
- digester.addCallMethod(prefix + "taglib/listener/listener-class",
- "addApplicationListener", 0);
+ // Note the sharing of state between rules
+ TaglibUriRule taglibUriRule = new TaglibUriRule();
+ digester.addRule(prefix + "taglib", new TaglibRule(taglibUriRule));
+
+ digester.addRule(prefix + "taglib/uri", taglibUriRule);
+
+ digester.addRule(prefix + "taglib/listener/listener-class",
+ new TaglibListenerRule(taglibUriRule));
+
}
}
+
+/*
+ * This rule only exists to reset the duplicateUri flag on the TaglibUriRule.
+ */
+final class TaglibRule extends Rule {
+ private final TaglibUriRule taglibUriRule;
+
+ public TaglibRule(TaglibUriRule taglibUriRule) {
+ this.taglibUriRule = taglibUriRule;
+ }
+
+ public void body(String namespace, String name, String text)
+ throws Exception {
+ taglibUriRule.setDuplicateUri(false);
+ }
+
+}
+
+final class TaglibUriRule extends Rule {
+
+ // This is set to false for each file processed by the TaglibRule
+ private boolean duplicateUri;
+
+ public TaglibUriRule() {
+ }
+
+ @Override
+ public void body(String namespace, String name, String text)
+ throws Exception {
+ TldConfig tldConfig =
+ (TldConfig) digester.peek(digester.getCount() - 1);
+ if (tldConfig.isKnownTaglibUri(text)) {
+ // Already seen this URI
+ duplicateUri = true;
+ // This is expected if the URI was defined in web.xml
+ // Log message at debug in this case
+ if (tldConfig.getContext().findTaglib(text) == null) {
+ digester.getLogger().info(
+ "TLD skipped. URI: " + text + " is already defined");
+ } else {
+ if (digester.getLogger().isDebugEnabled()) {
+ digester.getLogger().debug(
+ "TLD skipped. URI: " + text + " is already defined");
+ }
+ }
+ } else {
+ // New URI. Add it to known list and carry on
+ tldConfig.addTaglibUri(text);
+ }
+ }
+
+ public boolean isDuplicateUri() {
+ return duplicateUri;
+ }
+
+ public void setDuplicateUri(boolean duplciateUri) {
+ this.duplicateUri = duplciateUri;
+ }
+
+}
+
+final class TaglibListenerRule extends Rule {
+
+ private final TaglibUriRule taglibUriRule;
+
+ public TaglibListenerRule(TaglibUriRule taglibUriRule) {
+ this.taglibUriRule = taglibUriRule;
+ }
+
+ @Override
+ public void body(String namespace, String name, String text)
+ throws Exception {
+ TldConfig tldConfig =
+ (TldConfig) digester.peek(digester.getCount() - 1);
+
+ // Only process the listener if the URI is not a duplicate
+ if (!taglibUriRule.isDuplicateUri()) {
+ tldConfig.addApplicationListener(text);
+ }
+ }
+
+}
\ No newline at end of file
Index: java/org/apache/jasper/compiler/TagLibraryInfoImpl.java
===================================================================
--- java/org/apache/jasper/compiler/TagLibraryInfoImpl.java (revision 801738)
+++ java/org/apache/jasper/compiler/TagLibraryInfoImpl.java (working copy)
@@ -149,8 +149,8 @@
}
try {
- if (!location[0].endsWith("jar")) {
- // Location points to TLD file
+ if (location[1] == null) {
+ // Location points directly to TLD file
try {
in = getResourceAsStream(location[0]);
if (in == null) {
@@ -320,7 +320,7 @@
String[] location = new String[2];
location[0] = uri;
- if (location[0].endsWith("jar")) {
+ if (location[0].endsWith(".jar")) {
URL url = null;
try {
url = ctxt.getResource(location[0]);
Index: java/org/apache/jasper/compiler/TldLocationsCache.java
===================================================================
--- java/org/apache/jasper/compiler/TldLocationsCache.java (revision 801738)
+++ java/org/apache/jasper/compiler/TldLocationsCache.java (working copy)
@@ -17,6 +17,7 @@
package org.apache.jasper.compiler;
+import java.io.IOException;
import java.io.InputStream;
import java.net.JarURLConnection;
import java.net.MalformedURLException;
@@ -87,10 +88,19 @@
public static final int ROOT_REL_URI = 1;
public static final int NOROOT_REL_URI = 2;
+ private static final String WEB_INF = "/WEB-INF/";
+ private static final String WEB_INF_LIB = "/WEB-INF/lib/";
private static final String WEB_XML = "/WEB-INF/web.xml";
private static final String FILE_PROTOCOL = "file:";
- private static final String JAR_FILE_SUFFIX = ".jar";
+ 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();
+
// Names of JARs that are known not to contain any TLDs
private static HashSet noTldJars;
@@ -105,7 +115,6 @@
private boolean initialized;
private ServletContext ctxt;
- private boolean redeployMode;
//*********************************************************************
// Constructor and Initilizations
@@ -161,10 +170,6 @@
noTldJars.add("sunpkcs11.jar");
}
- public TldLocationsCache(ServletContext ctxt) {
- this(ctxt, true);
- }
-
/** Constructor.
*
* @param ctxt the servlet context of the web application in which Jasper
@@ -175,9 +180,8 @@
* because of JDK bug 4211817 fixed in this release.
* If redeployMode is false, a faster but less capable mode will be used.
*/
- public TldLocationsCache(ServletContext ctxt, boolean redeployMode) {
+ public TldLocationsCache(ServletContext ctxt) {
this.ctxt = ctxt;
- this.redeployMode = redeployMode;
mappings = new Hashtable();
initialized = false;
}
@@ -237,12 +241,18 @@
}
}
+ /*
+ * Keep processing order in sync with o.a.c.startup.TldConfig
+ */
private void init() throws JasperException {
if (initialized) return;
try {
- processWebDotXml();
- scanJars();
- processTldsInFileSystem("/WEB-INF/");
+ tldScanWebXml();
+ tldScanResourcePaths(WEB_INF);
+ tldScanWebInfLib();
+ if (SCAN_CLASSPATH) {
+ tldScanClassloaders();
+ }
initialized = true;
} catch (Exception ex) {
throw new JasperException(Localizer.getMessage(
@@ -252,8 +262,12 @@
/*
* Populates taglib map described in web.xml.
+ *
+ * This is not kept in sync with o.a.c.startup.TldConfig as the Jasper only
+ * needs the URI to TLD mappings from scan web.xml whereas TldConfig needs
+ * to scan the actual TLD files.
*/
- private void processWebDotXml() throws Exception {
+ private void tldScanWebXml() throws Exception {
InputStream is = null;
@@ -322,7 +336,7 @@
if (uriType(tagLoc) == NOROOT_REL_URI)
tagLoc = "/WEB-INF/" + tagLoc;
String tagLoc2 = null;
- if (tagLoc.endsWith(JAR_FILE_SUFFIX)) {
+ if (tagLoc.endsWith(JAR_EXT)) {
tagLoc = ctxt.getResource(tagLoc).toString();
tagLoc2 = "META-INF/taglib.tld";
}
@@ -337,83 +351,18 @@
}
}
- /**
- * Scans the given JarURLConnection for TLD files located in META-INF
- * (or a subdirectory of it), adding an implicit map entry to the taglib
- * map for any TLD that has a element.
- *
- * @param conn The JarURLConnection to the JAR file to scan
- * @param ignore true if any exceptions raised when processing the given
- * JAR should be ignored, false otherwise
- */
- private void scanJar(JarURLConnection conn, boolean ignore)
- throws JasperException {
-
- JarFile jarFile = null;
- String resourcePath = conn.getJarFileURL().toString();
- try {
- if (redeployMode) {
- conn.setUseCaches(false);
- }
- jarFile = conn.getJarFile();
- Enumeration entries = jarFile.entries();
- while (entries.hasMoreElements()) {
- JarEntry entry = (JarEntry) entries.nextElement();
- String name = entry.getName();
- if (!name.startsWith("META-INF/")) continue;
- if (!name.endsWith(".tld")) continue;
- InputStream stream = jarFile.getInputStream(entry);
- try {
- String uri = getUriFromTld(resourcePath, stream);
- // Add implicit map entry only if its uri is not already
- // present in the map
- if (uri != null && mappings.get(uri) == null) {
- mappings.put(uri, new String[]{ resourcePath, name });
- }
- } finally {
- if (stream != null) {
- try {
- stream.close();
- } catch (Throwable t) {
- // do nothing
- }
- }
- }
- }
- } catch (Exception ex) {
- if (!redeployMode) {
- // if not in redeploy mode, close the jar in case of an error
- if (jarFile != null) {
- try {
- jarFile.close();
- } catch (Throwable t) {
- // ignore
- }
- }
- }
- if (!ignore) {
- throw new JasperException(ex);
- }
- } finally {
- if (redeployMode) {
- // if in redeploy mode, always close the jar
- if (jarFile != null) {
- try {
- jarFile.close();
- } catch (Throwable t) {
- // ignore
- }
- }
- }
- }
- }
-
/*
- * Searches the filesystem under /WEB-INF for any TLD files, and adds
- * an implicit map entry to the taglib map for any TLD that has a
- * element.
+ * Scans the web application's sub-directory identified by startPath,
+ * along with its sub-directories, for TLDs and adds an implicit map entry
+ * to the taglib map for any TLD that has a element.
+ *
+ * Initially, rootPath equals /WEB-INF/. The /WEB-INF/classes and
+ * /WEB-INF/lib sub-directories are excluded from the search, as per the
+ * JSP 2.0 spec.
+ *
+ * Keep code in sync with o.a.c.startup.TldConfig
*/
- private void processTldsInFileSystem(String startPath)
+ private void tldScanResourcePaths(String startPath)
throws Exception {
Set dirList = ctxt.getResourcePaths(startPath);
@@ -421,129 +370,220 @@
Iterator it = dirList.iterator();
while (it.hasNext()) {
String path = (String) it.next();
- if (path.endsWith("/")) {
- processTldsInFileSystem(path);
- }
- if (!path.endsWith(".tld")) {
+ if (!path.endsWith(TLD_EXT)
+ && (path.startsWith(WEB_INF_LIB)
+ || path.startsWith("/WEB-INF/classes/"))) {
continue;
}
- InputStream stream = ctxt.getResourceAsStream(path);
- String uri = null;
- try {
- uri = getUriFromTld(path, stream);
- } finally {
- if (stream != null) {
- try {
- stream.close();
- } catch (Throwable t) {
- // do nothing
+ if (path.endsWith(TLD_EXT)) {
+ if (path.startsWith("/WEB-INF/tags/") &&
+ !path.endsWith("implicit.tld")) {
+ continue;
+ }
+ InputStream stream = ctxt.getResourceAsStream(path);
+ try {
+ tldScanStream(path, null, stream);
+ } finally {
+ if (stream != null) {
+ try {
+ stream.close();
+ } catch (Throwable t) {
+ // do nothing
+ }
}
}
+ } else {
+ tldScanResourcePaths(path);
}
- // Add implicit map entry only if its uri is not already
- // present in the map
- if (uri != null && mappings.get(uri) == null) {
- mappings.put(uri, new String[] { path, null });
- }
}
}
}
/*
- * Returns the value of the uri element of the given TLD, or null if the
- * given TLD does not contain any such element.
+ * 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 String getUriFromTld(String resourcePath, InputStream in)
- throws JasperException
- {
- // Parse the tag library descriptor at the specified resource path
- TreeNode tld = new ParserUtils().parseXMLDocument(resourcePath, in);
- TreeNode uri = tld.findChild("uri");
- if (uri != null) {
- String body = uri.getBody();
- if (body != null)
- return body;
- }
+ private void tldScanWebInfLib() throws Exception {
- return null;
+ Set dirList = ctxt.getResourcePaths(WEB_INF_LIB);
+ if (dirList != null) {
+ Iterator 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);
}
+ }
+ }
+ }
/*
- * Scans all JARs accessible to the webapp's classloader and its
- * parent classloaders for TLDs.
+ * 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.
*
- * The list of JARs always includes the JARs under WEB-INF/lib, as well as
- * all shared JARs in the classloader delegation chain of the webapp's
- * classloader.
- *
- * Considering JARs in the classloader delegation chain constitutes a
- * Tomcat-specific extension to the TLD search
+ * 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.,
- * /common/lib).
+ * /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 noTldJars 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 scanJars() throws Exception {
+ private void tldScanClassloaders() throws Exception {
- ClassLoader webappLoader
- = Thread.currentThread().getContextClassLoader();
- ClassLoader loader = webappLoader;
+ ClassLoader loader =
+ Thread.currentThread().getContextClassLoader();
while (loader != null) {
if (loader instanceof URLClassLoader) {
URL[] urls = ((URLClassLoader) loader).getURLs();
for (int i=0; i element.
+ *
+ * @param conn The JarURLConnection to the JAR file to scan
+ *
+ * Keep in sync with o.a.c.startup.TldConfig
+ */
+ private void tldScanJar(JarURLConnection conn) throws IOException {
+
+ JarFile jarFile = null;
+ String resourcePath = conn.getJarFileURL().toString();
+ try {
+ conn.setUseCaches(false);
+ jarFile = conn.getJarFile();
+ Enumeration entries = jarFile.entries();
+ while (entries.hasMoreElements()) {
+ JarEntry entry = entries.nextElement();
+ String name = entry.getName();
+ if (!name.startsWith("META-INF/")) continue;
+ if (!name.endsWith(".tld")) continue;
+ InputStream stream = jarFile.getInputStream(entry);
+ tldScanStream(resourcePath, name, stream);
}
+ } finally {
+ if (jarFile != null) {
+ try {
+ jarFile.close();
+ } catch (Throwable t) {
+ // ignore
+ }
+ }
+ }
+ }
- loader = loader.getParent();
+ /*
+ * 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;
}
/*
- * Determines if the JAR file with the given jarPath needs to be
- * scanned for TLDs.
+ * Scan the TLD contents in the specified input stream and add any new URIs
+ * to the map.
*
- * @param loader The current classloader in the parent chain
- * @param webappLoader The webapp classloader
- * @param jarPath The JAR file path
- *
- * @return TRUE if the JAR file identified by jarPath needs to be
- * scanned for TLDs, FALSE otherwise
+ * @param resourcePath Path of the resource
+ * @param entryName If the resource is a JAR file, the name of the entry
+ * in the JAR file
+ * @param stream The input stream for the resource
+ * @throws IOException
*/
- private boolean needScanJar(ClassLoader loader, ClassLoader webappLoader,
- String jarPath) {
- if (loader == webappLoader) {
- // JARs under WEB-INF/lib must be scanned unconditionally according
- // to the spec.
- return true;
- } else {
- String jarName = jarPath;
- int slash = jarPath.lastIndexOf('/');
- if (slash >= 0) {
- jarName = jarPath.substring(slash + 1);
+ private void tldScanStream(String resourcePath, String entryName,
+ InputStream stream) throws IOException {
+ try {
+ // Parse the tag library descriptor at the specified resource path
+ String uri = null;
+
+ TreeNode tld =
+ new ParserUtils().parseXMLDocument(resourcePath, stream);
+ TreeNode uriNode = tld.findChild("uri");
+ if (uriNode != null) {
+ String body = uriNode.getBody();
+ if (body != null)
+ uri = body;
}
- return (!noTldJars.contains(jarName));
+
+ // Add implicit map entry only if its uri is not already
+ // present in the map
+ if (uri != null && mappings.get(uri) == null) {
+ mappings.put(uri, new String[]{ resourcePath, entryName });
}
+ } catch (JasperException e) {
+ // Hack - makes exception handling simpler
+ IOException ioe = new IOException();
+ ioe.initCause(e);
+ throw ioe;
+ } finally {
+ if (stream != null) {
+ try {
+ stream.close();
+ } catch (Throwable t) {
+ // do nothing
}
}
+ }
+ }
+
+}
Index: java/org/apache/jasper/JspC.java
===================================================================
--- java/org/apache/jasper/JspC.java (revision 801738)
+++ java/org/apache/jasper/JspC.java (working copy)
@@ -1253,7 +1253,7 @@
context =new JspCServletContext
(new PrintWriter(System.out),
new URL("file:" + uriRoot.replace('\\','/') + '/'));
- tldLocationsCache = new TldLocationsCache(context, true);
+ tldLocationsCache = new TldLocationsCache(context);
} catch (MalformedURLException me) {
System.out.println("**" + me);
}
Index: webapps/docs/config/systemprops.xml
===================================================================
--- webapps/docs/config/systemprops.xml (revision 801738)
+++ webapps/docs/config/systemprops.xml (working copy)
@@ -83,6 +83,15 @@
true will be used.
+
+ When scanning the class path for TLDs, should Jasper scan all JAR files
+ in the classpath, including those provided by the web application's parent
+ clasloaders? This is intended for sharing tag libraries between multiple
+ web applications by making the JAR available via the common or shared
+ classloader. If not specified, the default value of true will
+ be used.
+
+
If true, any tag buffer that expands beyond
org.apache.jasper.Constants.DEFAULT_TAG_BUFFER_SIZE will be