All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.xerial.util.FileResource Maven / Gradle / Ivy

There is a newer version: 3.4.0
Show newest version
/*--------------------------------------------------------------------------
 *  Copyright 2007 Taro L. Saito
 *
 *  Licensed 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.
 *--------------------------------------------------------------------------*/
//--------------------------------------
// XerialJ
//
// FileResource.java
// Since: Jul 5, 2007 10:57:31 AM
//
// $URL:http://www.xerial.org/svn/project/XerialJ/trunk/XerialJ/src/main/java/org/xerial/util/FileResource.java $
// $Author:leo $
//--------------------------------------
package org.xerial.util;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.reflect.Modifier;
import java.net.MalformedURLException;
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.jar.JarEntry;
import java.util.jar.JarFile;

import org.xerial.util.io.VirtualFile;
import org.xerial.util.log.Logger;

/**
 * Gets file URLs by using the {@link ClassLoader} facility. This utility can be
 * used to hold file resources within a package.
 * 
 * 
 * Usage: 
 * 
 * // if YourClass belongs to a package org.xerial.util, the following code searches org/xerial/util/sample.txt in the source folder (or jar file) 
 * URL fileResourceURL = FileResource.find(YourClass.class, "sample.txt");
 * 
 * // another form of the previous line
 * URL fileResourceURL2 = FileResource.find("org.xerial.util", "sample.txt");
 * 
 * // short-hand code to get Reader (equivalent to call new BufferedReader(new InputStreamReader(URL#openStream())) )
 * BufferedReader reader = FileResource.open(YourClass.class, "sample.txt");
 * 
*
* * @author leo * */ public class FileResource { private static Logger _logger = Logger.getLogger(FileResource.class); /** * A virtual file implementation for usual files * * @author leo * */ public static class SystemFile implements VirtualFile { private File file; private String logicalPath; public SystemFile(File file, String logicalPath) { this.file = file; this.logicalPath = logicalPath; } public String getLogicalPath() { return logicalPath; } public URL getURL() { try { return file.toURI().toURL(); } catch (MalformedURLException e) { throw new IllegalArgumentException(e); } } public boolean isDirectory() { return file.isDirectory(); } @Override public String toString() { return getURL().toString(); } } /** * A virtual file implementation for file resources contained in a JAR file * * @author leo * */ public static class FileInJarArchive implements VirtualFile { private URL resourceURL; private String logicalPath; boolean isDirectory; public FileInJarArchive(URL resourceURL, String logicalPath, boolean isDirectory) { this.resourceURL = resourceURL; this.logicalPath = logicalPath; this.isDirectory = isDirectory; if (this.resourceURL == null) throw new IllegalArgumentException("resource URL cannot be null: " + logicalPath); } public String getLogicalPath() { return logicalPath; } public URL getURL() { return resourceURL; } public boolean isDirectory() { return isDirectory; } @Override public String toString() { return getURL().toString(); } } /** * list up resources recursively under the given base package name * * @param basePackageName * package name to search. e.g. org.xerial.util * @return the list of resources represented as {@link VirtualFile} */ public static List listResources(String basePackageName) { return listResources(basePackageName, new ResourceFilter() { public boolean accept(String resourcePath) { return true; } }); } /** * Lists up all resources satisfying the given resourceFilter from the * current class loader * * @param resourceFilter * @return the list of resources matching the condition specified in the * resourceFilter */ public static List listResources(ResourceFilter resourceFilter) { return listResources(FileResource.class.getClassLoader(), resourceFilter); } /** * Lists up all resources satisfying the given resourceFilter from the given * current class loader * * @param resourceFilter * @param classLoader * @return the list of resources matching the condition specified in the * resourceFilter */ public static List listResources(ClassLoader classLoader, ResourceFilter resourceFilter) { List classLoaderList = getAllAncestorOrSelfClassLoaders(classLoader); ArrayList fileList = new ArrayList(); for (URLClassLoader cl : classLoaderList) { for (URL url : cl.getURLs()) { fileList.addAll(listResources(url, "", resourceFilter)); } } return fileList; } /** * Lists up all resources recursively under the given resourceURL. If the * resourceURL is file, this method searches its sub directories, when it is * Jar file, it searches contents of the Jar file for other resources. * * @param resourceURL * @param resourceFilter * @return the list of resources matching the given resource filter */ public static List listResources(URL resourceURL, String packagePath, ResourceFilter resourceFilter) { _logger.trace("listResource: url=" + resourceURL); ArrayList fileList = new ArrayList(); if (resourceURL == null) return fileList; String protocol = resourceURL.getProtocol(); if (protocol.equals("file")) { String resourceURLString = resourceURL.toString(); collectFileResources(resourceURLString, fileList, packagePath, resourceFilter); } else if (protocol.equals("jar")) { // retrieve jar contents String path = resourceURL.getPath(); int pos = path.indexOf("!"); if (pos < 0) throw new IllegalArgumentException("invalid resource URL: " + resourceURL); String jarPath = path.substring(0, pos); String filePath = path.substring(pos + 2); try { String jarURLString = "jar:" + jarPath; jarPath = jarPath.replaceAll("%20", " ").replace("file:", ""); filePath = filePath.replaceAll("%20", " "); // File jarFile = new File(jarPath); JarFile jf = new JarFile(jarPath); for (Enumeration entryEnum = jf.entries(); entryEnum.hasMoreElements();) { JarEntry jarEntry = entryEnum.nextElement(); String physicalURL = jarURLString + "!/" + jarEntry.getName(); URL jarFileURL = new URL(physicalURL); String logicalName = extractLogicalName(packagePath, jarEntry.getName()); if (logicalName != null && resourceFilter.accept(logicalName)) fileList.add(new FileInJarArchive(jarFileURL, logicalName, jarEntry .isDirectory())); } } catch (MalformedURLException e) { _logger.error(e); } catch (IOException e) { _logger.error(e); } } else { throw new UnsupportedOperationException( "resources other than file or jar are not supported: " + resourceURL); } return fileList; } /** * list up resources recursively under the given base package name * * @param basePackageName * package name to search. e.g. org.xerial.util * @return the list of resources represented as {@link VirtualFile} */ public static List listResources(String basePackageName, ResourceFilter resourceFilter) { return listResources(FileResource.class.getClassLoader(), basePackageName, resourceFilter); } /** * list up resources recursively under the given base package name * * @param classLoader * @param basePackageName * package name to search. e.g. org.xerial.util * @return the list of resources represented as {@link VirtualFile} */ public static List listResources(ClassLoader classLoader, String basePackageName, ResourceFilter resourceFilter) { String packagePath = packagePath(basePackageName); List resourceURLList = getURLListFromAllAncestorOrSelfClassLoaders(classLoader, packagePath); ArrayList fileList = new ArrayList(); for (URL resourceURL : resourceURLList) { fileList.addAll(listResources(resourceURL, packagePath, resourceFilter)); } return fileList; } private static void collectFileResources(String resourceURLString, ArrayList fileList, String packagePath, ResourceFilter resourceFilter) { if (resourceURLString.endsWith(".svn")) { return; // omit the .svn folder } String logicalName = extractLogicalName(packagePath, resourceURLString); if (logicalName == null) throw new IllegalArgumentException("packagePath=" + packagePath + ", resourceURL=" + resourceURLString); try { File file = new File(new URL(resourceURLString).toURI()); if (resourceFilter.accept(file.getPath())) fileList.add(new SystemFile(file, logicalName)); if (file.isDirectory()) { for (File childFile : file.listFiles()) { String childResourceURL = resourceURLString + (resourceURLString.endsWith("/") ? "" : "/") + childFile.getName(); collectFileResources(childResourceURL, fileList, packagePath, resourceFilter); } } } catch (MalformedURLException e) { _logger.error(e); } catch (URISyntaxException e) { _logger.error(e); } } private static String extractLogicalName(String packagePath, String resourcePath) { if (!packagePath.endsWith("/")) packagePath = packagePath + "/"; int pos = resourcePath.indexOf(packagePath); if (pos < 0) return null; String logicalName = resourcePath.substring(pos + packagePath.length()); return logicalName; } /** * Retrieves all {@link URLClassLoader}s that can be found from this class * * @return the list of {@link URLClassLoader}s */ public static ArrayList getAllAncestorOrSelfClassLoaders(ClassLoader classLoader) { ArrayList classLoaderSet = new ArrayList(); for (ClassLoader clCursor = classLoader; clCursor != null; clCursor = clCursor.getParent()) { if (URLClassLoader.class.isInstance(clCursor)) { URLClassLoader urlClassLoader = (URLClassLoader) clCursor; classLoaderSet.add(urlClassLoader); } } return classLoaderSet; } private static ArrayList getURLListFromAllAncestorOrSelfClassLoaders( ClassLoader classLoader, String packageAsPath) { String path = !packageAsPath.endsWith("/") ? packageAsPath + "/" : packageAsPath; ArrayList classLoaderSet = getAllAncestorOrSelfClassLoaders(classLoader); ArrayList resultURLList = new ArrayList(); try { for (URLClassLoader loader : classLoaderSet) { for (Enumeration resourceEnum = loader.findResources(path); resourceEnum .hasMoreElements();) { URL url = resourceEnum.nextElement(); resultURLList.add(url); } } } catch (IOException e) { _logger.error(e); } return resultURLList; } private static String packagePath(Class< ? > referenceClass) { return packagePath(referenceClass.getPackage()); } private static String packagePath(Package basePackage) { return packagePath(basePackage.getName()); } private static String packagePath(String packageName) { String packageAsPath = packageName.replaceAll("\\.", "/"); return packageAsPath.endsWith("/") ? packageAsPath : packageAsPath + "/"; } /** * Opens a stream to a file resource that belongs to the same package to the * specified referenceClass * * @param referenceClass * the reference class * @param resouceFileName * the file name of the resource, relative to the package of the * referenceClass * @return {@link BufferedReader} of the resource * @throws IOException * when failed to open the file resource */ public static BufferedReader open(Class< ? > referenceClass, String resouceFileName) throws IOException { URL url = find(referenceClass, resouceFileName); if (url != null) { return new BufferedReader(new InputStreamReader(url.openStream())); } else return null; } public static BufferedReader open(Class< ? > referenceClass, String resouceFileName, String encoding) throws IOException { URL url = find(referenceClass, resouceFileName); if (url != null) { return new BufferedReader(new InputStreamReader(url.openStream(), encoding)); } else return null; } /** * Opens a stream to a file resource that belongs to the specified package * * @param basePackage * the base package to load resources * @param resouceFileName * the file name of the resource, relative to the package * @return {@link BufferedReader} of the resource * @throws IOException * when failed to open the file resource */ public static BufferedReader open(Package basePackage, String resourceFileName) throws IOException { URL url = find(basePackage, resourceFileName); if (url != null) { return new BufferedReader(new InputStreamReader(url.openStream())); } else return null; } public static BufferedInputStream openByteStream(Class< ? > referenceClass, String resourceFileName) throws IOException { URL url = find(referenceClass, resourceFileName); if (url != null) { return new BufferedInputStream(url.openStream()); } else return null; } /** * Open the resource using BufferedInputStream * * @param basePackage * @param resourceFileName * @return * @throws IOException */ public static BufferedInputStream openByteStream(Package basePackage, String resourceFileName) throws IOException { URL url = find(basePackage, resourceFileName); if (url != null) { return new BufferedInputStream(url.openStream()); } else return null; } /** * Gets the {@link URL} of the file resource * * @param referenceClass * the base class to find resources * @param resourceFileName * the resource file name relative to the package of the * referenceClass * @return the URL of the file resource */ public static URL find(Class< ? > referenceClass, String resourceFileName) { return find(referenceClass.getPackage(), resourceFileName); } /** * Finds the {@link URL} of the resource * * @param basePackage * the base package to find the resource * @param resourceFileName * the resource file name relative to the package folder * @return the URL of the specified resource */ public static URL find(Package basePackage, String resourceFileName) { return find(basePackage.getName(), resourceFileName); } /** * Finds the {@link URL} of the resource * * @param packageName * the base package name to find the resource * @param resourceFileName * the resource file name relative to the package folder * @return the URL of the specified resource */ public static URL find(String packageName, String resourceFileName) { String packagePath = packagePath(packageName); String resourcePath = packagePath + resourceFileName; if (!resourcePath.startsWith("/")) resourcePath = "/" + resourcePath; _logger.trace("search resource: " + resourcePath); URL r = FileResource.class.getResource(resourcePath); if (r == null) return Thread.currentThread().getContextClassLoader().getResource(resourcePath); else return r; } /* * public static ArrayList listResourcesInJar(URL jarURL) { if * (!jarURL.getProtocol().equals("file")) throw new * IllegalArgumentException("not found the jar: " + jarURL); * * String jarURLString = "jar:" + jarPath; * * File jarFile = new File(jarURL.toString()); JarFile jf = new * JarFile(jarFile); for (Enumeration entryEnum = jf.entries(); * entryEnum.hasMoreElements();) { JarEntry jarEntry = * entryEnum.nextElement(); jarEntry.isDirectory(); * * String physicalURL = jarURLString + "!/" + jarEntry.getName(); } } */ public static URL findFromJAR(String jarPath, String filePath) { try { URL jarURL = new URL(jarPath); if (!jarURL.getProtocol().equals("file")) throw new IllegalArgumentException("not found the jar: " + jarURL); // String jarURLString = "jar:" + jarPath; File jarFile = new File(jarURL.toString()); JarFile jf = new JarFile(jarFile); for (Enumeration entryEnum = jf.entries(); entryEnum.hasMoreElements();) { JarEntry jarEntry = entryEnum.nextElement(); jarEntry.isDirectory(); // String physicalURL = jarURLString + "!/" + // jarEntry.getName(); } } catch (MalformedURLException e) { _logger.error(e); throw new IllegalArgumentException("cannot find the jar: " + jarPath); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } return null; } /** * Finds the {@link URL} of the resource * * @param resourceFileName * the resource file name, relative to the root package * @return the URL of the specified resource */ public static URL find(String resourceFileName) { return find("", resourceFileName); } @SuppressWarnings("unchecked") public static List> findClasses(Package searchPath, Class toSearch, ClassLoader classLoader) { List> result = new ArrayList>(); String packageName = searchPath.getName(); List classFileList = FileResource.listResources(packageName, new ResourceFilter() { public boolean accept(String resourcePath) { return resourcePath.endsWith(".class"); } }); for (VirtualFile vf : classFileList) { String logicalPath = vf.getLogicalPath(); int dot = logicalPath.lastIndexOf("."); if (dot <= 0) continue; String className = packageName + "." + logicalPath.substring(0, dot).replaceAll("/", "."); try { Class< ? > c = Class.forName(className, false, classLoader); if (!Modifier.isAbstract(c.getModifiers()) && toSearch.isAssignableFrom(c)) { // found a target class result.add((Class) c); } } catch (ClassNotFoundException e) { continue; } } return result; } /** * Create a temporary file from the specified resource, then return the path * to the temporary file * * @param * @param searchBase * @param path * @param tempDir * @return * @throws IOException */ public static File copyToTemp(Class searchBase, String path, File tempDir) throws IOException { BufferedInputStream resource = openByteStream(searchBase, path); if (resource == null) throw new FileNotFoundException(path); File tmp = FileUtil.createTempFile(tempDir, "tmp-", new File(path).getName()); FileUtil.copy(resource, tmp); return tmp; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy