craigmcc 02/03/14 15:58:36 Modified: catalina/src/share/org/apache/catalina/startup ContextConfig.java HostConfig.java LocalStrings.properties Log: Refactor the TLD scanning code in ContextConfig to improve clarity, avoid redundant parsing of the same TLD, and some wasted effort trying to parse a JAR as an XML document (and vice versa) in the old code. Currently, the jarFile.close() statement to close a JAR file after scanning is still commented out (as it was before). Closing the JAR file here seems to mess up the WebappClassLoader (which has already included this JAR file in its repository of available URLs) by causing "Zip File Is Closed" exceptions when it attempts to load classes from that JAR. In HostConfig, the only change was to close the JAR in a finally block when expanding a WAR, even if an exception has occurred. Revision Changes Path 1.60 +221 -130 jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/startup/ContextConfig.java Index: ContextConfig.java =================================================================== RCS file: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/startup/ContextConfig.java,v retrieving revision 1.59 retrieving revision 1.60 diff -u -r1.59 -r1.60 --- ContextConfig.java 5 Mar 2002 01:53:11 -0000 1.59 +++ ContextConfig.java 14 Mar 2002 23:58:35 -0000 1.60 @@ -1,7 +1,7 @@ /* - * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/startup/ContextConfig.java,v 1.59 2002/03/05 01:53:11 craigmcc Exp $ - * $Revision: 1.59 $ - * $Date: 2002/03/05 01:53:11 $ + * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/startup/ContextConfig.java,v 1.60 2002/03/14 23:58:35 craigmcc Exp $ + * $Revision: 1.60 $ + * $Date: 2002/03/14 23:58:35 $ * * ==================================================================== * @@ -77,16 +77,20 @@ import java.net.URL; import java.util.ArrayList; import java.util.Enumeration; +import java.util.HashSet; +import java.util.Iterator; import java.util.MissingResourceException; import java.util.ResourceBundle; +import java.util.Set; import java.util.Stack; import java.util.jar.JarEntry; import java.util.jar.JarFile; -import javax.servlet.ServletContext; import javax.naming.NamingException; import javax.naming.NameClassPair; import javax.naming.NamingEnumeration; import javax.naming.directory.DirContext; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; import org.apache.catalina.Authenticator; import org.apache.catalina.Container; import org.apache.catalina.Context; @@ -127,7 +131,7 @@ * of that Context, and the associated defined servlets. * * @author Craig R. McClanahan - * @version $Revision: 1.59 $ $Date: 2002/03/05 01:53:11 $ + * @version $Revision: 1.60 $ $Date: 2002/03/14 23:58:35 $ */ public final class ContextConfig @@ -591,8 +595,14 @@ applicationConfig(); // Scan tag library descriptor files for additional listener classes - if (ok) - tldConfig(); + if (ok) { + try { + tldScan(); + } catch (Exception e) { + log(e.getMessage(), e); + ok = false; + } + } // Configure a certificates exposer valve, if required if (ok) @@ -781,76 +791,24 @@ /** - * Scan the tag library descriptors of all tag libraries we can find, and - * register any application descriptor classes that are found there. + * Scan for and configure all tag library descriptors found in this + * web application. + * + * @exception Exception if a fatal input/output or parsing error occurs */ - private void tldConfig() { - - // Acquire a Digester to use for parsing - synchronized (tldDigester) { - - // First, scan tag libraries declared in our deployment descriptor - if (debug >= 1) - log("Scanning web.xml tag libraries"); - ArrayList resourcePaths = new ArrayList(); // Already done TLDs - String taglibs[] = context.findTaglibs(); - for (int i = 0; i < taglibs.length; i++) { - - // Calculate the resource path of the next tag library to check - String resourcePath = context.findTaglib(taglibs[i]); - if (!resourcePath.startsWith("/")) - resourcePath = "/WEB-INF/web.xml/../" + resourcePath; - if (debug >= 2) - log(" URI='" + taglibs[i] + "', ResourcePath='" + - resourcePath + "'"); - if (resourcePaths.contains(resourcePath)) { - if (debug >= 2) - log(" Already processed"); - continue; - } - resourcePaths.add(resourcePath); + private void tldScan() throws Exception { - // Process either a JAR file or a TLD at this location - if (!tldConfigJar(resourcePath, tldDigester)) - tldConfigTld(resourcePath, tldDigester); + // Acquire this list of TLD resource paths to be processed + Set resourcePaths = tldScanResourcePaths(); - } - - // Second, scan tag libraries defined in tld files in /WEB-INF - if (debug >= 1) - log("Scanning TLD files in /WEB-INF"); - DirContext resources = context.getResources(); - String webinfName = "/WEB-INF"; - // Looking up directory /WEB-INF in the context - try { - NamingEnumeration enum = resources.list(webinfName); - while (enum.hasMoreElements()) { - NameClassPair ncPair = (NameClassPair) enum.nextElement(); - String filename = webinfName + "/" + ncPair.getName(); - if (!filename.endsWith(".tld")) - continue; - tldConfigTld(filename, tldDigester); - } - } catch (NamingException e) { - // Silent catch: it's valid that no /WEB-INF directory exists - } - - // Third, scan tag libraries defined in JAR files - if (debug >= 1) - log("Scanning library JAR files"); - String libName = "/WEB-INF/lib"; - // Looking up directory /WEB-INF/lib in the context - try { - NamingEnumeration enum = resources.list(libName); - while (enum.hasMoreElements()) { - NameClassPair ncPair = (NameClassPair) enum.nextElement(); - String filename = libName + "/" + ncPair.getName(); - if (!filename.endsWith(".jar")) - continue; - tldConfigJar(filename, tldDigester); - } - } catch (NamingException e) { - // Silent catch: it's ok that no /WEB-INF/lib directory exists + // Scan each accumulated resource paths 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); } } @@ -858,106 +816,239 @@ /** - * Process a TLD (if there is one) in the JAR file (if there is one) at - * the specified resource path. Return <code>true</code> if we actually - * found and processed such a TLD, or <code>false</code> otherwise. + * Scan the JAR file at the specified resource path for TLDs in the + * <code>META-INF</code> subdirectory, and scan them for application + * event listeners that need to be registered. * - * @param resourcePath Context-relative resource path - * @param digester Digester to use for parsing + * @param resourcePath Resource path of the JAR file to scan + * + * @exception Exception if an exception occurs while scanning this JAR */ - private boolean tldConfigJar(String resourcePath, Digester digester) { + private void tldScanJar(String resourcePath) throws Exception { + + if (debug >= 1) { + log(" Scanning JAR at resource path '" + resourcePath + "'"); + } JarFile jarFile = null; - InputStream stream = null; + String name = null; + InputStream inputStream = null; try { URL url = context.getServletContext().getResource(resourcePath); - if (url == null) - return (false); + if (url == null) { + throw new IllegalArgumentException + (sm.getString("contextConfig.tldResourcePath", + resourcePath)); + } url = new URL("jar:" + url.toString() + "!/"); JarURLConnection conn = (JarURLConnection) url.openConnection(); + conn.setUseCaches(false); jarFile = conn.getJarFile(); - boolean found = false; Enumeration entries = jarFile.entries(); while (entries.hasMoreElements()) { JarEntry entry = (JarEntry) entries.nextElement(); - String name = entry.getName(); - if (!name.startsWith("META-INF/")) + name = entry.getName(); + if (!name.startsWith("META-INF/")) { continue; - if (!name.endsWith(".tld")) + } + if (!name.endsWith(".tld")) { continue; - if (debug >= 2) - log(" tldConfigJar(" + resourcePath + - "): Processing entry '" + name + "'"); - stream = jarFile.getInputStream(entry); - synchronized (digester) { - digester.clear(); - digester.push(context); - digester.parse(stream); } - stream.close(); - found = true; + if (debug >= 2) { + log(" Processing TLD at '" + name + "'"); + } + inputStream = jarFile.getInputStream(entry); + tldScanStream(inputStream); + inputStream.close(); + inputStream = null; + name = null; } - // FIXME jarFile.close(); - return (found); + // FIXME - Closing the JAR file messes up the class loader??? + // jarFile.close(); } catch (Exception e) { - if (debug >= 2) - log(" tldConfigJar(" + resourcePath + "): " + e); - if (stream != null) { + if (name == null) { + throw new ServletException + (sm.getString("contextConfig.tldJarException", + resourcePath), e); + } else { + throw new ServletException + (sm.getString("contextConfig.tldEntryException", + name, resourcePath), e); + } + } finally { + if (inputStream != null) { try { - stream.close(); + inputStream.close(); } catch (Throwable t) { ; } + inputStream = null; } if (jarFile != null) { - try { - jarFile.close(); - } catch (Throwable t) { - ; - } + // FIXME - Closing the JAR file messes up the class loader??? + // try { + // jarFile.close(); + // } catch (Throwable t) { + // ; + // } + jarFile = null; } - return (false); } } /** - * Process a TLD (if there is one) at the specified resource path. - * Return <code>true</code> if we actually found and processed such - * a TLD, or <code>false</code> otherwise. + * Scan the TLD contents in the specified input stream, and register + * any application event listeners found there. <b>NOTE</b> - It is + * the responsibility of the caller to close the InputStream after this + * method returns. * - * @param resourcePath Context-relative resource path - * @param digester Digester to use for parsing + * @param resourceStream InputStream containing a tag library descriptor + * + * @exception Exception if an exception occurs while scanning this TLD */ - private boolean tldConfigTld(String resourcePath, Digester digester) { + private void tldScanStream(InputStream resourceStream) + throws Exception { - InputStream stream = null; + synchronized (tldDigester) { + tldDigester.clear(); + tldDigester.push(context); + tldDigester.parse(resourceStream); + } + + } + + + /** + * 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 (debug >= 1) { + log(" Scanning TLD at resource path '" + resourcePath + "'"); + } + + InputStream inputStream = null; try { - stream = + inputStream = context.getServletContext().getResourceAsStream(resourcePath); - if (stream == null) - return (false); - synchronized (digester) { - digester.clear(); - digester.push(context); - digester.parse(stream); + if (inputStream == null) { + throw new IllegalArgumentException + (sm.getString("contextConfig.tldResourcePath", + resourcePath)); } - stream.close(); - return (true); + tldScanStream(inputStream); + inputStream.close(); + inputStream = null; } catch (Exception e) { - if (debug >= 2) - log(" tldConfigTld(" + resourcePath + "): " + e); - if (stream != null) { + throw new ServletException + (sm.getString("contextConfig.tldFileException", resourcePath), + e); + } finally { + if (inputStream != null) { try { - stream.close(); + inputStream.close(); } catch (Throwable t) { ; } + inputStream = null; + } + } + + } + + + /** + * 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 + * <code>META-INF</code> subdirectory. + * + * @exception IOException if an input/output error occurs while + * accumulating the list of resource paths + */ + private Set tldScanResourcePaths() throws IOException { + + if (debug >= 1) { + log(" Accumulating TLD resource paths"); + } + Set resourcePaths = new HashSet(); + + // Accumulate resource paths explicitly listed in the web application + // deployment descriptor + if (debug >= 2) { + log(" Scanning <taglib> 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.3 DTD implies that the location MUST be + // a context-relative path starting with '/'? + if (!resourcePath.startsWith("/")) { + resourcePath = "/WEB-INF/web.xml/../" + resourcePath; + } + if (debug >= 3) { + log(" Adding path '" + resourcePath + + "' for URI '" + taglibs[i] + "'"); + } + resourcePaths.add(resourcePath); + } + + // Scan TLDs in the /WEB-INF subdirectory of the web application + if (debug >= 2) { + log(" Scanning TLDs in /WEB-INF subdirectory"); + } + DirContext resources = context.getResources(); + try { + NamingEnumeration items = resources.list("/WEB-INF"); + while (items.hasMoreElements()) { + NameClassPair item = (NameClassPair) items.nextElement(); + String resourcePath = "/WEB-INF/" + item.getName(); + // FIXME - JSP 1.2 is not explicit about whether we should + // scan subdirectories of /WEB-INF for TLDs also + if (!resourcePath.endsWith(".tld")) { + continue; + } + if (debug >= 3) { + log(" Adding path '" + resourcePath + "'"); + } + resourcePaths.add(resourcePath); + } + } catch (NamingException e) { + ; // Silent catch: it's valid that no /WEB-INF directory exists + } + + // Scan JARs in the /WEB-INF/lib subdirectory of the web application + if (debug >= 2) { + log(" Scanning JARs in /WEB-INF/lib subdirectory"); + } + try { + NamingEnumeration items = resources.list("/WEB-INF/lib"); + while (items.hasMoreElements()) { + NameClassPair item = (NameClassPair) items.nextElement(); + String resourcePath = "/WEB-INF/lib/" + item.getName(); + if (!resourcePath.endsWith(".jar")) { + continue; + } + if (debug >= 3) { + log(" Adding path '" + resourcePath + "'"); + } + resourcePaths.add(resourcePath); } - return (false); + } catch (NamingException e) { + ; // Silent catch: it's valid that no /WEB-INF/lib directory exists } + + // Return the completed set + return (resourcePaths); } 1.19 +63 -4 jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/startup/HostConfig.java Index: HostConfig.java =================================================================== RCS file: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/startup/HostConfig.java,v retrieving revision 1.18 retrieving revision 1.19 diff -u -r1.18 -r1.19 --- HostConfig.java 5 Mar 2002 01:55:02 -0000 1.18 +++ HostConfig.java 14 Mar 2002 23:58:35 -0000 1.19 @@ -1,7 +1,7 @@ /* - * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/startup/HostConfig.java,v 1.18 2002/03/05 01:55:02 craigmcc Exp $ - * $Revision: 1.18 $ - * $Date: 2002/03/05 01:55:02 $ + * $Header: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/startup/HostConfig.java,v 1.19 2002/03/14 23:58:35 craigmcc Exp $ + * $Revision: 1.19 $ + * $Date: 2002/03/14 23:58:35 $ * * ==================================================================== * @@ -102,7 +102,7 @@ * * @author Craig R. McClanahan * @author Remy Maucherat - * @version $Revision: 1.18 $ $Date: 2002/03/05 01:55:02 $ + * @version $Revision: 1.19 $ $Date: 2002/03/14 23:58:35 $ */ public class HostConfig @@ -656,6 +656,7 @@ // Expand the WAR into the new document base directory JarURLConnection juc = (JarURLConnection) war.openConnection(); juc.setUseCaches(false); + /* JarFile jarFile = juc.getJarFile(); if (getDebug() >= 2) { log(" Have opened JAR file successfully"); @@ -690,6 +691,64 @@ input.close(); } jarFile.close(); + */ + JarFile jarFile = null; + InputStream input = null; + try { + jarFile = juc.getJarFile(); + if (getDebug() >= 2) { + log(" Have opened JAR file successfully"); + } + Enumeration jarEntries = jarFile.entries(); + if (getDebug() >= 2) { + log(" Have retrieved entries enumeration"); + } + while (jarEntries.hasMoreElements()) { + JarEntry jarEntry = (JarEntry) jarEntries.nextElement(); + String name = jarEntry.getName(); + if (getDebug() >= 2) { + log(" Am processing entry " + name); + } + int last = name.lastIndexOf('/'); + if (last >= 0) { + File parent = new File(docBase, + name.substring(0, last)); + if (getDebug() >= 2) { + log(" Creating parent directory " + parent); + } + parent.mkdirs(); + } + if (name.endsWith("/")) { + continue; + } + if (getDebug() >= 2) { + log(" Creating expanded file " + name); + } + input = jarFile.getInputStream(jarEntry); + expand(input, docBase, name); + input.close(); + input = null; + } + jarFile.close(); + jarFile = null; + } finally { + if (input != null) { + try { + input.close(); + } catch (Throwable t) { + ; + } + input = null; + } + if (jarFile != null) { + try { + jarFile.close(); + } catch (Throwable t) { + ; + } + jarFile = null; + } + } // Return the absolute path to our new document base directory return (docBase.getAbsolutePath()); 1.14 +4 -0 jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/startup/LocalStrings.properties Index: LocalStrings.properties =================================================================== RCS file: /home/cvs/jakarta-tomcat-4.0/catalina/src/share/org/apache/catalina/startup/LocalStrings.properties,v retrieving revision 1.13 retrieving revision 1.14 diff -u -r1.13 -r1.14 --- LocalStrings.properties 25 Oct 2001 00:23:03 -0000 1.13 +++ LocalStrings.properties 14 Mar 2002 23:58:35 -0000 1.14 @@ -19,6 +19,10 @@ contextConfig.missingRealm=No Realm has been configured to authenticate against contextConfig.start=ContextConfig: Processing START contextConfig.stop=ContextConfig: Processing STOP +contextConfig.tldEntryException=Exception processing TLD {0} in JAR at resource path {1} +contextConfig.tldFileException=Exception processing TLD at resource path {0} +contextConfig.tldJarException=Exception processing JAR at resource path {0} +contextConfig.tldResourcePath=Invalid TLD resource path {0} contextConfig.unavailable=Marking this application unavailable due to previous error(s) embedded.alreadyStarted=Embedded service has already been started embedded.noEngines=No engines have been defined yet
-- To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]> For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>