org.xerial.util.FileResource Maven / Gradle / Ivy
/*--------------------------------------------------------------------------
* 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.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;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy