From 2ef15b17d8d06d766e83974a2d30e2040ac1871b Mon Sep 17 00:00:00 2001 From: markt Date: Mon, 14 Sep 2009 12:39:45 +0000 Subject: [PATCH] Fix https://issues.apache.org/bugzilla/show_bug.cgi?id=47834 As well as the JAR as directory feature requested, this adds looking at all files to see if they are JARs rather than using the presence of a .jar extension. These features are optional for the Servlet spec but required for RFC66 in an OSGI environment. Both options are configurable with system properties and default to off. git-svn-id: https://svn.apache.org/repos/asf/tomcat/trunk@814617 13f79535-47bb-0310-9956-ffa450edef68 --- .../catalina/startup/LocalStrings.properties | 1 + java/org/apache/catalina/startup/TldConfig.java | 84 ++++++++++++++++++++-- .../apache/jasper/compiler/TagLibraryInfoImpl.java | 27 ++++--- .../apache/jasper/compiler/TldLocationsCache.java | 78 ++++++++++++++++++-- webapps/docs/config/systemprops.xml | 17 +++++ 5 files changed, 188 insertions(+), 19 deletions(-) diff --git a/java/org/apache/catalina/startup/LocalStrings.properties b/java/org/apache/catalina/startup/LocalStrings.properties index cadc30ecc..6a93bd726 100644 --- a/java/org/apache/catalina/startup/LocalStrings.properties +++ b/java/org/apache/catalina/startup/LocalStrings.properties @@ -94,6 +94,7 @@ 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.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 diff --git a/java/org/apache/catalina/startup/TldConfig.java b/java/org/apache/catalina/startup/TldConfig.java index 33bf53d42..530bb71b3 100644 --- a/java/org/apache/catalina/startup/TldConfig.java +++ b/java/org/apache/catalina/startup/TldConfig.java @@ -19,9 +19,12 @@ package org.apache.catalina.startup; +import java.io.File; +import java.io.FileInputStream; 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; @@ -69,6 +72,16 @@ public final class TldConfig implements LifecycleListener { "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 noTldJars; @@ -564,10 +577,73 @@ public final class TldConfig implements LifecycleListener { tldScanJar((JarURLConnection) conn); } else { String urlStr = url.toString(); - if (urlStr.startsWith("file:") - && urlStr.endsWith(JAR_EXT)) { - URL jarURL = new URL("jar:" + urlStr + "!/"); - tldScanJar((JarURLConnection) jarURL.openConnection()); + 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. + * + * Keep in sync with o.a.j.comiler.TldLocationsCache + */ + private void tldScanDir(File start) { + + if (log.isTraceEnabled()) { + log.trace(sm.getString("tldConfig.dirScan", start.getAbsolutePath())); + } + + File[] fileList = start.listFiles(); + if (fileList != null) { + for (int i = 0; i < fileList.length; i++) { + // Scan recursively + if (fileList[i].isDirectory()) { + tldScanDir(fileList[i]); + } else if (fileList[i].getAbsolutePath().endsWith(TLD_EXT)) { + InputStream stream = null; + try { + stream = new FileInputStream(fileList[i]); + tldScanStream(stream); + } catch (IOException ioe) { + log.warn(sm.getString("tldConfig.dirFail", + fileList[i].getAbsolutePath()), + ioe); + } finally { + if (stream != null) { + try { + stream.close(); + } catch (Throwable t) { + // do nothing + } + } + } + } } } } diff --git a/java/org/apache/jasper/compiler/TagLibraryInfoImpl.java b/java/org/apache/jasper/compiler/TagLibraryInfoImpl.java index b3b7e92b5..63725b324 100644 --- a/java/org/apache/jasper/compiler/TagLibraryInfoImpl.java +++ b/java/org/apache/jasper/compiler/TagLibraryInfoImpl.java @@ -17,6 +17,7 @@ package org.apache.jasper.compiler; +import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.InputStream; @@ -111,20 +112,24 @@ class TagLibraryInfoImpl extends TagLibraryInfo implements TagConstants { // the following is a workaround until these problems are resolved. private InputStream getResourceAsStream(String uri) throws FileNotFoundException { - try { - // see if file exists on the filesystem first - String real = ctxt.getRealPath(uri); - if (real == null) { + // Is uri absolute? + if (uri.startsWith("file:")) { + return new FileInputStream(new File(uri.substring(5))); + } else { + try { + // see if file exists on the filesystem + String real = ctxt.getRealPath(uri); + if (real == null) { + return ctxt.getResourceAsStream(uri); + } else { + return new FileInputStream(real); + } + } catch (FileNotFoundException ex) { + // if file not found on filesystem, get the resource through + // the context return ctxt.getResourceAsStream(uri); - } else { - return new FileInputStream(real); } - } catch (FileNotFoundException ex) { - // if file not found on filesystem, get the resource through - // the context - return ctxt.getResourceAsStream(uri); } - } /** diff --git a/java/org/apache/jasper/compiler/TldLocationsCache.java b/java/org/apache/jasper/compiler/TldLocationsCache.java index dc8134076..40a57fe0b 100644 --- a/java/org/apache/jasper/compiler/TldLocationsCache.java +++ b/java/org/apache/jasper/compiler/TldLocationsCache.java @@ -17,10 +17,13 @@ package org.apache.jasper.compiler; +import java.io.File; +import java.io.FileInputStream; import java.io.IOException; 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; @@ -101,6 +104,16 @@ public class TldLocationsCache { "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 noTldJars; @@ -478,10 +491,67 @@ public class TldLocationsCache { tldScanJar((JarURLConnection) conn); } else { String urlStr = url.toString(); - if (urlStr.startsWith(FILE_PROTOCOL) - && urlStr.endsWith(JAR_EXT)) { - URL jarURL = new URL("jar:" + urlStr + "!/"); - tldScanJar((JarURLConnection) jarURL.openConnection()); + 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. + * + * Keep in sync with o.a.c.startup.TldConfig + */ + private void tldScanDir(File start) throws IOException { + + File[] fileList = start.listFiles(); + if (fileList != null) { + for (int i = 0; i < fileList.length; i++) { + // Scan recursively + if (fileList[i].isDirectory()) { + tldScanDir(fileList[i]); + } else if (fileList[i].getAbsolutePath().endsWith(TLD_EXT)) { + InputStream stream = null; + try { + stream = new FileInputStream(fileList[i]); + tldScanStream( + fileList[i].toURI().toString(), null, stream); + } finally { + if (stream != null) { + try { + stream.close(); + } catch (Throwable t) { + // do nothing + } + } + } + } } } } diff --git a/webapps/docs/config/systemprops.xml b/webapps/docs/config/systemprops.xml index 8d60ed9dd..b024f3978 100644 --- a/webapps/docs/config/systemprops.xml +++ b/webapps/docs/config/systemprops.xml @@ -103,6 +103,23 @@ be used.

+ +

When scanning the class path for TLDs, should Jasper scan all files + as if they are JAR files even if they do not have a .jar file extension? + This is intended for use in embedded environments where custom + classloaders allow for archives on the classpath with non-standard file + extensions. If not specified, the default value of false will + be used.

+
+ + +

When scanning the class path for TLDs, should Jasper scan all + directories as if they are unpacked JAR files? This is intended for use in + embedded environments where custom classloaders allow for directories + representing unpacked WAR files on the classpath. If not specified, the + default value of false will be used.

+
+

If true, any tag buffer that expands beyond org.apache.jasper.Constants.DEFAULT_TAG_BUFFER_SIZE will be -- 2.11.0