/*
* $Id: ClassSearchUtils.java,v 1.1 2009/03/01 12:01:11 rah003 Exp $
*
* Copyright 2009 Sun Microsystems, Inc., 4150 Network Circle,
* Santa Clara, California 95054, U.S.A. All rights reserved.
*
* This library 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 library 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 library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
import java.awt.HeadlessException;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.StringTokenizer;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.logging.Logger;
public class ClassSearchUtils {
private static final Logger log = Logger.getAnonymousLogger();
/**
* Classloader to be used to obtain resources from file system.
*/
private ClassLoader classloader;
/**
* List of the resource found in the classpath.
*/
private ArrayList list;
/**
* Extension of the resource to be found in the classpath.
*/
private String extension;
private String prefix;
/**
* Search for the resource with the extension in the classpath. Method
* self-instantiate factory for every call to ensure thread safety.
* @param extension Mandatory extension of the resource. If all resources
* are required extension should be empty string. Null extension is not
* allowed and will cause method to fail.
* @return List of all resources with specified extension.
*/
public static List<Class<?>> searchClassPath(String prefix) {
return searchClassPath(prefix, ".class");
}
/**
* Search for the resource with the extension in the classpath. Method
* self-instantiate factory for every call to ensure thread safety.
* @param extension Mandatory extension of the resource. If all resources
* are required extension should be empty string. Null extension is not
* allowed and will cause method to fail.
* @return List of all resources with specified extension.
*/
public static List searchClassPath(String prefix, String extension) {
ClassSearchUtils factory = new ClassSearchUtils();
factory.prefix = prefix;
return factory.find(extension);
}
/**
* Search for the resource with the extension in the classpath.
* @param extension Mandatory extension of the resource. If all resources
* are required extension should be empty string. Null extension is not
* allowed and will cause method to fail.
* @return List of all resources with specified extension.
*/
private List<Class<?>> find(String extension) {
this.extension = extension;
this.list = new ArrayList();
this.classloader = this.getClass().getClassLoader();
String classpath = System.getProperty("java.class.path");
try {
Method method =
this.classloader.getClass().getMethod("getClassPath", (Class<?>) null);
if (method != null) {
classpath = (String) method.invoke(this.classloader, (Object) null);
}
} catch (Exception e) {
// ignore
}
if (classpath == null) {
classpath = System.getProperty("java.class.path");
}
StringTokenizer tokenizer =
new StringTokenizer(classpath, File.pathSeparator);
String token;
File dir;
String name;
while (tokenizer.hasMoreTokens()) {
token = tokenizer.nextToken();
dir = new File(token);
if (dir.isDirectory()) {
lookInDirectory("", dir);
}
if (dir.isFile()) {
name = dir.getName().toLowerCase();
if (name.endsWith(".zip") || name.endsWith(".jar")) {
this.lookInArchive(dir);
}
}
}
return this.list;
}
/**
* @param name Name of to parent directories in java class notation (dot
* separator)
* @param dir Directory to be searched for classes.
*/
private void lookInDirectory(String name, File dir) {
log.fine( "Looking in directory [" + dir.getName() + "].");
File[] files = dir.listFiles();
File file;
String fileName;
final int size = files.length;
for (int i = 0; i < size; i++) {
file = files[i];
fileName = file.getName();
if (file.isFile()
&& fileName.toLowerCase().endsWith(this.extension)) {
try {
if (this.extension.equalsIgnoreCase(".class")) {
fileName = fileName.substring(0, fileName.length() - 6);
// filter ignored resources
if (!(name + fileName).startsWith(this.prefix)) {
continue;
}
log.fine(
"Found class: [" + name + fileName + "].");
this.list.add(Class.forName(name + fileName));
} else {
this.list.add(
this.classloader.getResource(
name.replace('.', File.separatorChar)
+ fileName));
}
} catch (ClassNotFoundException e) {
// ignore
} catch (NoClassDefFoundError e) {
//ignore too
} catch (ExceptionInInitializerError e) {
if (e.getCause() instanceof HeadlessException) {
// running in headless env ... ignore
} else {
throw e;
}
}
}
// search recursively.
// I don't like that but we will see how it will work.
if (file.isDirectory()) {
lookInDirectory(name + fileName + ".", file);
}
}
}
/**
* Search archive files for required resource.
* @param archive Jar or zip to be searched for classes or other resources.
*/
private void lookInArchive(File archive) {
log.fine(
"Looking in archive ["
+ archive.getName()
+ "] for extension ["
+ this.extension
+ "].");
JarFile jarFile = null;
try {
jarFile = new JarFile(archive);
} catch (IOException e) {
log.warning(
"Non fatal error. Unable to read jar item.");
return;
}
Enumeration entries = jarFile.entries();
JarEntry entry;
String entryName;
while (entries.hasMoreElements()) {
entry = (JarEntry) entries.nextElement();
entryName = entry.getName();
if (entryName.toLowerCase().endsWith(this.extension)) {
try {
if (this.extension.equalsIgnoreCase(".class")) {
// convert name into java classloader notation
entryName =
entryName.substring(0, entryName.length() - 6);
entryName = entryName.replace('/', '.');
// filter ignored resources
if (!entryName.startsWith(this.prefix)) {
continue;
}
log.fine(
"Found class: [" + entryName + "]. ");
this.list.add(Class.forName(entryName));
} else {
this.list.add(this.classloader.getResource(entryName));
log.fine(
"Found appropriate resource with name ["
+ entryName
+ "]. Resource instance:"
+ this.classloader.getResource(entryName));
}
} catch (Throwable e) {
// ignore
log.warning(
"Unable to load resource ["
+ entryName
+ "] form file ["
+ archive.getAbsolutePath()
+ "].");
}
}
}
}
}