Author: markt Date: Mon Dec 14 21:12:35 2009 New Revision: 890479 URL: http://svn.apache.org/viewvc?rev=890479&view=rev Log: Fix TLD scanning in JARs for JspC. This copies the DefaultJarScanner from Tomcat. Less invasive than the alternative refactoring that will have to wait for another day.
Added: tomcat/trunk/java/org/apache/jasper/compiler/InternalJarScanner.java (with props) Modified: tomcat/trunk/java/org/apache/catalina/startup/DefaultJarScanner.java tomcat/trunk/java/org/apache/jasper/compiler/JarScannerFactory.java tomcat/trunk/java/org/apache/jasper/resources/LocalStrings.properties Modified: tomcat/trunk/java/org/apache/catalina/startup/DefaultJarScanner.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/startup/DefaultJarScanner.java?rev=890479&r1=890478&r2=890479&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/catalina/startup/DefaultJarScanner.java (original) +++ tomcat/trunk/java/org/apache/catalina/startup/DefaultJarScanner.java Mon Dec 14 21:12:35 2009 @@ -48,6 +48,8 @@ * (disabled by default)</li> * </ul> * All of the extensions may be controlled via configuration. + * + * Keep in sync with org.apache.jasper.compiler.InternalJarScanner */ public class DefaultJarScanner implements JarScanner { Added: tomcat/trunk/java/org/apache/jasper/compiler/InternalJarScanner.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/jasper/compiler/InternalJarScanner.java?rev=890479&view=auto ============================================================================== --- tomcat/trunk/java/org/apache/jasper/compiler/InternalJarScanner.java (added) +++ tomcat/trunk/java/org/apache/jasper/compiler/InternalJarScanner.java Mon Dec 14 21:12:35 2009 @@ -0,0 +1,236 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jasper.compiler; + +import java.io.File; +import java.io.IOException; +import java.net.JarURLConnection; +import java.net.URISyntaxException; +import java.net.URL; +import java.net.URLClassLoader; +import java.net.URLConnection; +import java.util.Iterator; +import java.util.Set; + +import javax.servlet.ServletContext; + +import org.apache.juli.logging.Log; +import org.apache.juli.logging.LogFactory; +import org.apache.tomcat.JarScanner; +import org.apache.tomcat.JarScannerCallback; + +/** + * The default {...@link JarScanner} implementation scans the WEB-INF/lib directory + * followed by the provided classloader and then works up the classloader + * hierarchy. This implementation is sufficient to meet the requirements of the + * Servlet 3.0 specification as well as to provide a number of Tomcat specific + * extensions. The extensions are: + * <ul> + * <li>Scanning the classloader hierarchy (enabled by default)</li> + * <li>Testing all files to see if they are JARs (disabled by default)</li> + * <li>Testing all directories to see if they are exploded JARs + * (disabled by default)</li> + * </ul> + * All of the extensions may be controlled via configuration. + * + * Keep in sync with org.apache.catalina.startup.DefaultJarScanner + */ +public class InternalJarScanner implements JarScanner { + + private static final String JAR_EXT = ".jar"; + private static final String WEB_INF_LIB = "/WEB-INF/lib/"; + + private static final Log log = LogFactory.getLog(InternalJarScanner.class); + + /** + * Controls the classpath scanning extension. + */ + private boolean scanClassPath = true; + public boolean isScanClassPath() { + return scanClassPath; + } + public void setScanClassPath(boolean scanClassPath) { + this.scanClassPath = scanClassPath; + } + + /** + * Controls the testing all files to see of they are JAR files extension. + */ + private boolean scanAllFiles = false; + public boolean isScanAllFiles() { + return scanAllFiles; + } + public void setScanAllFiles(boolean scanAllFiles) { + this.scanAllFiles = scanAllFiles; + } + + /** + * Controls the testing all directories to see of they are exploded JAR + * files extension. + */ + private boolean scanAllDirectories = false; + public boolean isScanAllDirectories() { + return scanAllDirectories; + } + public void setScanAllDirectories(boolean scanAllDirectories) { + this.scanAllDirectories = scanAllDirectories; + } + + /** + * {...@inheritdoc} + */ + @Override + public void scan(ServletContext context, ClassLoader classloader, + JarScannerCallback callback, Set<String> jarsToSkip) { + + if (log.isTraceEnabled()) { + log.trace(Localizer.getMessage("jsp.jarScan.webinflibStart")); + } + + // Scan WEB-INF/lib + Set<String> dirList = context.getResourcePaths(WEB_INF_LIB); + if (dirList != null) { + Iterator<String> it = dirList.iterator(); + while (it.hasNext()) { + String path = it.next(); + if (path.endsWith(JAR_EXT) && + !jarsToSkip.contains( + path.substring(path.lastIndexOf('/')))) { + // Need to scan this JAR + URL url = null; + try { + url = context.getResource(path); + process(callback, url); + } catch (IOException e) { + if (url == null) { + log.warn(Localizer.getMessage( + "jsp.jarScan.webinflibFail", + path), e); + } else { + log.warn(Localizer.getMessage( + "jsp.jarScan.webinflibFail", + url.toString()), e); + } + } + } + } + } + + // Scan the classpath + if (scanClassPath) { + if (log.isTraceEnabled()) { + log.trace(Localizer.getMessage("jsp.jarScan.classloaderStart")); + } + + ClassLoader loader = + Thread.currentThread().getContextClassLoader(); + + while (loader != null) { + if (loader instanceof URLClassLoader) { + URL[] urls = ((URLClassLoader) loader).getURLs(); + for (int i=0; i<urls.length; i++) { + // Extract the jarName if there is one to be found + String jarName = getJarName(urls[i]); + + // Skip JARs with known not to be interesting and JARs + // in WEB-INF/lib we have already scanned + if (!(jarsToSkip.contains(jarName) || + urls[i].toString().contains( + WEB_INF_LIB + jarName))) { + try { + process(callback, urls[i]); + } catch (IOException ioe) { + log.warn(Localizer.getMessage( + "jsp.jarScan.classloaderFail", + urls[i].toString()), ioe); + } + } + } + } + loader = loader.getParent(); + } + + } + } + + /* + * Scan a URL for JARs with the optional extensions to look at all files + * and all directories. + */ + private void process(JarScannerCallback callback, URL url) + throws IOException { + + if (log.isTraceEnabled()) { + log.trace(Localizer.getMessage("jsp.jarScan.jarUrlStart", + url.toString())); + } + + URLConnection conn = url.openConnection(); + if (conn instanceof JarURLConnection) { + callback.scan((JarURLConnection) conn); + } else { + String urlStr = url.toString(); + if (urlStr.startsWith("file:") || urlStr.startsWith("jndi:")) { + if (urlStr.endsWith(JAR_EXT)) { + URL jarURL = new URL("jar:" + urlStr + "!/"); + callback.scan((JarURLConnection) jarURL.openConnection()); + } else { + File f; + try { + f = new File(url.toURI()); + if (f.isFile() && scanAllFiles) { + // Treat this file as a JAR + URL jarURL = new URL("jar:" + urlStr + "!/"); + callback.scan((JarURLConnection) jarURL.openConnection()); + } else if (f.isDirectory() && scanAllDirectories) { + File metainf = new File(f.getAbsoluteFile() + + File.separator + "META-INF"); + if (metainf.isDirectory()) { + callback.scan(f); + } + } + } catch (URISyntaxException e) { + // Wrap the exception and re-throw + IOException ioe = new IOException(); + ioe.initCause(e); + throw ioe; + } + } + } + } + + } + + /* + * Extract the JAR name, if present, from a URL + */ + private String getJarName(URL url) { + + String name = null; + + String path = url.getPath(); + int end = path.indexOf(JAR_EXT); + if (end != -1) { + int start = path.lastIndexOf('/', end); + name = path.substring(start + 1, end + 4); + } + + return name; + } + +} Propchange: tomcat/trunk/java/org/apache/jasper/compiler/InternalJarScanner.java ------------------------------------------------------------------------------ svn:eol-style = native Propchange: tomcat/trunk/java/org/apache/jasper/compiler/InternalJarScanner.java ------------------------------------------------------------------------------ svn:keywords = Date Author Id Revision Modified: tomcat/trunk/java/org/apache/jasper/compiler/JarScannerFactory.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/jasper/compiler/JarScannerFactory.java?rev=890479&r1=890478&r2=890479&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/jasper/compiler/JarScannerFactory.java (original) +++ tomcat/trunk/java/org/apache/jasper/compiler/JarScannerFactory.java Mon Dec 14 21:12:35 2009 @@ -30,10 +30,8 @@ */ public class JarScannerFactory { - /* - * Don't want any instances so hide the default constructor. - */ private JarScannerFactory() { + // Don't want any instances so hide the default constructor. } /** @@ -45,6 +43,7 @@ (JarScanner) ctxt.getAttribute(JarScanner.class.getName()); if (jarScanner == null) { ctxt.log(Localizer.getMessage("jsp.warning.noJarScanner")); + jarScanner = new InternalJarScanner(); } return jarScanner; } Modified: tomcat/trunk/java/org/apache/jasper/resources/LocalStrings.properties URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/jasper/resources/LocalStrings.properties?rev=890479&r1=890478&r2=890479&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/jasper/resources/LocalStrings.properties (original) +++ tomcat/trunk/java/org/apache/jasper/resources/LocalStrings.properties Mon Dec 14 21:12:35 2009 @@ -456,4 +456,9 @@ jsp.error.tag.conflict.trimdirectivewhitespaces=Tag directive: illegal to have multiple occurrences of 'trimDirectiveWhitespaces' with different values (old: {0}, new: {1}) # JarScanner -jsp.warning.noJarScanner=Warning: No org.apache.tomcat.JarScanner set in ServletContext. Jar scanning for TLDs and web-fragment.xml files is disabled \ No newline at end of file +jsp.warning.noJarScanner=Warning: No org.apache.tomcat.JarScanner set in ServletContext. Falling back to internal JarScanner implementation. +jsp.jarScan.webinflibStart=Scanning WEB-INF/lib for JARs +jsp.jarScan.webinflibFail=Failed to scan JAR [{0}] from WEB-INF/lib +jsp.jarScan.classloaderStart=Scanning for JARs in classloader hierarchy +jsp.jarScan.classloaderFail=Failed to scan [{0}] from classloader hierarchy +jsp.jarScan.jarUrlStart=Scanning JAR at URL [{0}] --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org