blob: 8004798507eb578badef44a89a25e5a4b6082f6a [file] [log] [blame]
/*
* 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.openejb.config;
import org.apache.openejb.OpenEJBException;
import org.apache.openejb.util.URLs;
import org.apache.xbean.finder.UrlSet;
import org.apache.xbean.finder.filter.Filters;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLClassLoader;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.WeakHashMap;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import static org.apache.openejb.config.NewLoaderLogic.applyBuiltinExcludes;
import static org.apache.openejb.util.URLs.toFile;
/**
* TLD file urls cached on a per classloader basis. Helps with sharing TLD
* files between webapps by placing them in a parent classloader.
*
* Each webapp will be able to retrieve the cached version of the URLs and
* therefore only needs to scan its own libraries, the parent libraries will
* already have been scanned.
*
* For a tiny bit of performance, we will scan the StandardClassloader at boot
* in a separate thread so it should be primed in advance of any deployment.
*
* @version $Rev$ $Date$
*/
public class TldScanner {
private static Map<ClassLoader, Set<URL>> cache = new WeakHashMap<ClassLoader, Set<URL>>();
public static Set<URL> scan(final ClassLoader classLoader) throws OpenEJBException {
if (classLoader == null) return Collections.EMPTY_SET;
final Set<URL> urls = cache.get(classLoader);
if (urls != null) return urls;
final Set<URL> result = scanClassLoaderForTagLibs(classLoader);
cache.put(classLoader, result);
return result;
}
public static Set<URL> scanClassLoaderForTagLibs(final ClassLoader classLoader) throws OpenEJBException {
final Set<URL> tldUrls = new HashSet<URL>();
if (classLoader == null) return tldUrls;
if (classLoader == Object.class.getClassLoader()) return tldUrls;
tldUrls.addAll(scan(classLoader.getParent()));
UrlSet urlSet = new UrlSet();
if (classLoader instanceof URLClassLoader) {
final URLClassLoader urlClassLoader = (URLClassLoader) classLoader;
urlSet = new UrlSet(urlClassLoader.getURLs());
} else {
try {
urlSet = new UrlSet(classLoader);
} catch (IOException e) {
DeploymentLoader.logger.warning("Error scanning class loader for JSP tag libraries", e);
}
}
try {
urlSet = URLs.cullSystemJars(urlSet);
urlSet = applyBuiltinExcludes(urlSet, Filters.tokens("jstl-1.2", "myfaces-impl"));
} catch (IOException e) {
DeploymentLoader.logger.warning("Error scanning class loader for JSP tag libraries", e);
}
for (URL url : urlSet.getUrls()) {
if (url.getProtocol().equals("jar")) {
try {
String path = url.getPath();
if (path.endsWith("!/")) {
path = path.substring(0, path.length() - 2);
}
url = new URL(path);
} catch (MalformedURLException e) {
DeploymentLoader.logger.warning("JSP tag library location bad: " + url.toExternalForm(), e);
continue;
}
}
if (!url.getProtocol().equals("file")) {
continue;
}
File file = toFile(url);
try {
file = file.getCanonicalFile().getAbsoluteFile();
} catch (IOException e) {
DeploymentLoader.logger.warning("JSP tag library location bad: " + file.getAbsolutePath(), e);
continue;
}
tldUrls.addAll(scanForTagLibs(file));
}
return tldUrls;
}
public static Set<URL> scanWarForTagLibs(final File war) {
final Set<URL> urls = new HashSet<URL>();
final File webInfDir = new File(war, "WEB-INF");
if (!webInfDir.isDirectory()) return urls;
// skip the lib and classes dir in WEB-INF
final LinkedList<File> files = new LinkedList<File>();
final File[] list = webInfDir.listFiles();
if (list != null) {
for (final File file : list) {
if ("lib".equals(file.getName()) || "classes".equals(file.getName())) {
continue;
}
files.add(file);
}
}
if (files.isEmpty()) return urls;
// recursively scan the directories
while (!files.isEmpty()) {
File file = files.removeFirst();
if (file.isDirectory()) {
final File[] a = file.listFiles();
if (a != null) {
files.addAll(Arrays.asList(a));
}
} else if (file.getName().endsWith(".tld")) {
try {
file = file.getCanonicalFile().getAbsoluteFile();
urls.add(file.toURI().toURL());
} catch (IOException e) {
DeploymentLoader.logger.warning("JSP tag library location bad: " + file.getAbsolutePath(), e);
}
}
}
return urls;
}
public static Set<URL> scanForTagLibs(final File file) {
final Set<URL> tldLocations = new HashSet<URL>();
try {
final String location = file.toURI().toURL().toExternalForm();
if (location.endsWith(".jar")) {
final Set<URL> urls = scanJarForTagLibs(file);
tldLocations.addAll(urls);
} else if (file.getName().endsWith(".tld")) {
final URL url = file.toURI().toURL();
tldLocations.add(url);
}
} catch (IOException e) {
DeploymentLoader.logger.warning("Error scanning for JSP tag libraries: " + file.getAbsolutePath(), e);
}
return tldLocations;
}
static Set<URL> scanJarForTagLibs(final File file) {
final Set<URL> urls = new HashSet<URL>();
if (!file.isFile()) return urls;
JarFile jarFile = null;
try {
jarFile = new JarFile(file);
final URL jarFileUrl = new URL("jar", "", -1, file.toURI().toURL().toExternalForm() + "!/");
for (final JarEntry entry : Collections.list(jarFile.entries())) {
final String name = entry.getName();
if (!name.startsWith("META-INF/") || !name.endsWith(".tld")) {
continue;
}
final URL url = new URL(jarFileUrl, name);
urls.add(url);
}
} catch (IOException e) {
DeploymentLoader.logger.warning("Error scanning jar for JSP tag libraries: " + file.getAbsolutePath(), e);
} finally {
if (jarFile != null) {
try {
jarFile.close();
} catch (IOException e) {
// exception ignored
}
}
}
return urls;
}
}