/* * JBoss, Home of Professional Open Source * Copyright 2006, JBoss Inc., and individual contributors as indicated * by the @authors tag. See the copyright.txt in the distribution for a * full listing of individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.drools.repository; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Proxy; import java.net.URISyntaxException; import java.net.URL; import java.net.URLClassLoader; import java.util.ArrayList; import java.util.Enumeration; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Utility methods to aid in class/resource loading. * * @author kevin */ public class ClassUtil { private static Logger logger = LoggerFactory.getLogger(ClassUtil.class); /** * Load the specified class. * @param className The name of the class to load. * @param caller The class of the caller. * @return The specified class. * @throws ClassNotFoundException If the class cannot be found. */ public static Class forName(final String className, final Class caller) throws ClassNotFoundException { final ClassLoader threadClassLoader = Thread.currentThread().getContextClassLoader() ; if (threadClassLoader != null) { try { return Class.forName(className, true, threadClassLoader) ; } catch (final ClassNotFoundException cnfe) { if (cnfe.getException() != null) { throw cnfe ; } } } final ClassLoader classLoader = caller.getClassLoader() ; if (classLoader != null) { try { return Class.forName(className, true, classLoader) ; } catch (final ClassNotFoundException cnfe) { if (cnfe.getException() != null) { throw cnfe ; } } } return Class.forName(className, true, ClassLoader.getSystemClassLoader()) ; } /** * Resolve a proxy for the specified interfaces. * @param interfaces The interfaces associated with the proxy. * @param caller The class of the caller. * @return The specified proxy class. * @throws ClassNotFoundException If the class cannot be found. */ public static Class resolveProxy(final String[] interfaces, final Class caller) throws ClassNotFoundException { final int numInterfaces = (interfaces == null ? 0 : interfaces.length) ; if (numInterfaces == 0) { throw new ClassNotFoundException("Cannot generate proxy with no interfaces") ; } final Class[] interfaceClasses = new Class[numInterfaces] ; for(int count = 0 ; count < numInterfaces ; count++) { interfaceClasses[count] = forName(interfaces[count], caller) ; } final ClassLoader proxyClassLoader ; final ClassLoader threadClassLoader = Thread.currentThread().getContextClassLoader() ; if (threadClassLoader != null) { proxyClassLoader = threadClassLoader ; } else { final ClassLoader classLoader = caller.getClassLoader() ; if (classLoader != null) { proxyClassLoader = classLoader ; } else { proxyClassLoader = ClassLoader.getSystemClassLoader() ; } } return Proxy.getProxyClass(proxyClassLoader, interfaceClasses) ; } /** * Get the specified resource as a stream. * @param resourceName The name of the class to load. * @param caller The class of the caller. * @return The input stream for the resource or null if not found. */ public static InputStream getResourceAsStream(final String resourceName, final Class caller) { final String resource ; if (resourceName.startsWith("/")) { resource = resourceName.substring(1) ; } else { final Package callerPackage = caller.getPackage() ; if (callerPackage != null) { resource = callerPackage.getName().replace('.', '/') + '/' + resourceName ; } else { resource = resourceName ; } } final ClassLoader threadClassLoader = Thread.currentThread().getContextClassLoader() ; if (threadClassLoader != null) { final InputStream is = threadClassLoader.getResourceAsStream(resource) ; if (is != null) { return is ; } } final ClassLoader classLoader = caller.getClassLoader() ; if (classLoader != null) { final InputStream is = classLoader.getResourceAsStream(resource) ; if (is != null) { return is ; } } return ClassLoader.getSystemResourceAsStream(resource) ; } public static URL getResource(final String resourceName, final Class<?> caller) { final String resource ; if (resourceName.startsWith("/")) { resource = resourceName.substring(1) ; } else { final Package callerPackage = caller.getPackage() ; if (callerPackage != null) { resource = callerPackage.getName().replace('.', '/') + '/' + resourceName ; } else { resource = resourceName ; } } final ClassLoader threadClassLoader = Thread.currentThread().getContextClassLoader() ; if (threadClassLoader != null) { final URL url = threadClassLoader.getResource(resource) ; if (url != null) { return url ; } } final ClassLoader classLoader = caller.getClassLoader() ; if (classLoader != null) { final URL url = classLoader.getResource(resource) ; if (url != null) { return url ; } } return ClassLoader.getSystemResource(resource) ; } public static List<URL> getResources(String resourcePath, Class<?> caller) throws IOException { ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); if(resourcePath.startsWith("/")) { resourcePath = resourcePath.substring(1); } if (classLoader != null) { return toList(classLoader.getResources(resourcePath)); } classLoader = caller.getClassLoader(); if (classLoader != null) { return toList(classLoader.getResources(resourcePath)); } return new ArrayList<URL>(); } private static <T> List<T> toList(Enumeration<T> objects) { List<T> theList = new ArrayList<T>(); while(objects.hasMoreElements()) { theList.add(objects.nextElement()); } return theList; } /** * Get a package name and convert it to a path value, so it can be used * in calls to methods like {@link #getResourceAsStream}. * <p/> * Adds a '/' prefix and converts all '." characters to '/'. Doesn't add a * trailing slash. * * @param packageObj The package. * @return The package path. */ public static String getPath(Package packageObj) { return "/" + packageObj.getName().replace('.', '/'); } public static List<String> getResourceList(String regex, Class caller) { ClasspathResourceFilter filter = new ClasspathResourceFilter(regex); ClassLoader classLoader; classLoader = Thread.currentThread().getContextClassLoader(); if(classLoader instanceof URLClassLoader) { filter.filter((URLClassLoader) classLoader); } classLoader = caller.getClassLoader(); if(classLoader instanceof URLClassLoader) { filter.filter((URLClassLoader) classLoader); } return filter.getResourceList(); } private static class ClasspathResourceFilter { private List<String> resourceList = new ArrayList<String>(); private Pattern pattern; private ClasspathResourceFilter(String regex) { pattern = Pattern.compile(regex); } private void filter(URLClassLoader classLoader) { URL[] cpUrls = classLoader.getURLs(); for (int i = 0; i < cpUrls.length; i++) { try { File file = new File(cpUrls[i].toURI()); if(file.isDirectory()) { searchClasspathDirTree(file, ""); } else { searchArchive(file); } } catch (URISyntaxException e) { logger.warn("Error searching classpath resource URL '" + cpUrls[i] + "' for resource '" + pattern.pattern() + "': " + e.getMessage()); } catch (IOException e) { logger.warn("Error searching classpath resource URL '" + cpUrls[i] + "' for resource '" + pattern.pattern() + "': " + e.getMessage()); } } } private void searchClasspathDirTree(File rootDir, String subDir) { File currentDir = new File(rootDir, subDir); File[] contents = currentDir.listFiles(); for(File file: contents) { if(file.isDirectory()) { String subSubDir = subDir + "/" + file.getName(); searchClasspathDirTree(rootDir, subSubDir); } else { String resClasspathPath = file.toURI().toString().substring(rootDir.toURI().toString().length() - 1); if(isToBeAdded(resClasspathPath)) { resourceList.add(resClasspathPath); } } } } private void searchArchive(File archiveFile) throws IOException { ZipFile zip = new ZipFile(archiveFile); Enumeration<? extends ZipEntry> entries = zip.entries(); while (entries.hasMoreElements()) { ZipEntry entry = entries.nextElement(); String resClasspathPath = "/" + entry.getName(); if(isToBeAdded(resClasspathPath)) { resourceList.add(resClasspathPath); } } } private boolean isToBeAdded(String resClasspathPath) { if(resourceList.contains(resClasspathPath)) { // Already in the list e.g. same resource in different archives... return false; } Matcher matcher = pattern.matcher(resClasspathPath); return matcher.matches(); } private List<String> getResourceList() { return resourceList; } } }