Property changes on: . ___________________________________________________________________ Modified: svn:mergeinfo Merged /tomcat/trunk:r647344,751502,793621 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 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) @@ -20,12 +20,8 @@ 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.URL; import java.net.URLClassLoader; @@ -47,7 +43,6 @@ import javax.servlet.ServletException; 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; @@ -57,6 +52,7 @@ import org.apache.tomcat.util.digester.Digester; import org.xml.sax.InputSource; + /** * Startup event listener for a Context that configures application * listeners configured in any TLD files. @@ -73,6 +69,17 @@ 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 +131,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 +177,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 +243,7 @@ * @param tldValidation true to enable xml instance validation */ public void setTldValidation(boolean tldValidation){ - TldConfig.tldValidation = tldValidation; + this.tldValidation = tldValidation; } /** @@ -194,7 +252,7 @@ * */ public boolean getTldValidation(){ - return tldValidation; + return this.tldValidation; } /** @@ -203,7 +261,7 @@ * */ public boolean getTldNamespaceAware(){ - return tldNamespaceAware; + return this.tldNamespaceAware; } @@ -213,7 +271,7 @@ * @param tldNamespaceAware true to enable namespace awareness */ public void setTldNamespaceAware(boolean tldNamespaceAware){ - TldConfig.tldNamespaceAware = tldNamespaceAware; + this.tldNamespaceAware = tldNamespaceAware; } @@ -255,71 +313,33 @@ 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 */ - Set resourcePaths = tldScanResourcePaths(); - Map jarPaths = getJarPaths(); + 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; - } - } - // Scan each accumulated resource path for TLDs to be processed - Iterator paths = resourcePaths.iterator(); + Iterator paths = resourcePaths.iterator(); while (paths.hasNext()) { - String path = (String) paths.next(); + String path = paths.next(); if (path.endsWith(".jar")) { tldScanJar(path); } else { tldScanTld(path); } } + if (jarPaths != null) { - paths = jarPaths.values().iterator(); - while (paths.hasNext()) { - tldScanJar((File) paths.next()); + Iterator files = jarPaths.values().iterator(); + while (files.hasNext()) { + tldScanJar(files.next()); } } 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); 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 @@ -449,9 +408,9 @@ try { jarFile = new JarFile(file); - Enumeration entries = jarFile.entries(); + Enumeration entries = jarFile.entries(); while (entries.hasMoreElements()) { - JarEntry entry = (JarEntry) entries.nextElement(); + JarEntry entry = entries.nextElement(); name = entry.getName(); if (!name.startsWith("META-INF/")) { continue; @@ -558,11 +517,11 @@ * @exception IOException if an input/output error occurs while * accumulating the list of resource paths */ - private Set tldScanResourcePaths() throws IOException { + private Set tldScanResourcePaths() throws IOException { if (log.isDebugEnabled()) { log.debug(" Accumulating TLD resource paths"); } - Set resourcePaths = new HashSet(); + Set resourcePaths = new HashSet(); // Accumulate resource paths explicitly listed in the web application // deployment descriptor @@ -609,7 +568,7 @@ */ private void tldScanResourcePathsWebInf(DirContext resources, String rootPath, - Set tldPaths) + Set tldPaths) throws IOException { if (log.isTraceEnabled()) { @@ -617,9 +576,9 @@ } try { - NamingEnumeration items = resources.list(rootPath); + NamingEnumeration items = resources.list(rootPath); while (items.hasMoreElements()) { - NameClassPair item = (NameClassPair) items.nextElement(); + NameClassPair item = items.nextElement(); String resourcePath = rootPath + "/" + item.getName(); if (!resourcePath.endsWith(".tld") && (resourcePath.startsWith("/WEB-INF/classes") @@ -661,9 +620,9 @@ * * @return Map of JAR file paths */ - private Map getJarPaths() { + private Map getJarPaths() { - HashMap jarPathMap = null; + HashMap jarPathMap = null; ClassLoader webappLoader = Thread.currentThread().getContextClassLoader(); ClassLoader loader = webappLoader; @@ -709,7 +668,7 @@ || noTldJars == null || !noTldJars.contains(file.getName())) { if (jarPathMap == null) { - jarPathMap = new HashMap(); + jarPathMap = new HashMap(); jarPathMap.put(path, file); } else if (!jarPathMap.containsKey(path)) { jarPathMap.put(path, file); @@ -752,7 +711,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 +722,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,65 @@ */ public void addRuleInstances(Digester digester) { - digester.addCallMethod(prefix + "taglib/listener/listener-class", - "addApplicationListener", 0); + TaglibUriRule taglibUriRule = new TaglibUriRule(); + + digester.addRule(prefix + "taglib/uri", taglibUriRule); + digester.addRule(prefix + "taglib/listener/listener-class", + new TaglibListenerRule(taglibUriRule)); + } } + +final class TaglibUriRule extends Rule { + + 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; + digester.getLogger().info( + "TLD skipped. URI: " + text + " is already defined"); + } else { + // New URI. Add it to known list and carry on + duplicateUri = false; + tldConfig.addTaglibUri(text); + } + } + + public boolean isDuplicateUri() { + return duplicateUri; + } +} + +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: STATUS.txt =================================================================== --- STATUS.txt (revision 801738) +++ STATUS.txt (working copy) @@ -206,3 +206,6 @@ http://people.apache.org/~markt/patches/2009-08-06-ADforJNDIRealm.patch +1: markt -1: + +* Port TLD processing improvements from trunk + There have been quite a few changes to TLD processing and they are tightly coupled \ No newline at end of file