Support for loading from either a jar or a class directory. Fixes troubles with IntelliJ debugging.

git-svn-id: file:///humgen/gsa-scr1/gsa-engineering/svn_contents/trunk@162 348d0f76-0448-11de-a6fe-93d51630548a
This commit is contained in:
hanna 2009-03-24 03:56:49 +00:00
parent ff5b0ec1b6
commit f7363cf935
1 changed files with 117 additions and 25 deletions

View File

@ -34,22 +34,22 @@ public class WalkerManager {
public WalkerManager( String pluginDirectory ) {
try {
final File jarFile = getThisJarFile();
if(pluginDirectory == null)
pluginDirectory = jarFile.getParent() + File.separator + "walkers";
System.out.println("plugin directory: " + pluginDirectory);
List<Class> walkerClasses = new ArrayList<Class>();
// Load all classes that live in this jar.
walkerClasses.addAll( loadClassesFromJar( jarFile ) );
final File location = getThisLocation();
walkerClasses.addAll( loadClassesFromLocation( location ) );
// Load all classes that live in the extension path.
if(pluginDirectory == null)
pluginDirectory = location.getParent() + File.separator + "walkers";
System.out.println("plugin directory: " + pluginDirectory);
File extensionPath = new File( pluginDirectory );
if(extensionPath.exists())
walkerClasses.addAll( loadClassesFromPath( extensionPath ) );
if(extensionPath.exists()) {
List<String> filesInPath = findFilesInPath( extensionPath, "", "class", false );
walkerClasses.addAll( loadExternalClasses( extensionPath, filesInPath ) );
}
walkerClasses = filterWalkers(walkerClasses);
@ -95,10 +95,10 @@ public class WalkerManager {
* Determines which jar file contains the WalkerManager class.
* @return Jar file containing the WalkerManager class.
*/
private File getThisJarFile() throws IOException {
private File getThisLocation() throws IOException {
try {
java.net.URI jarURI = getClass().getProtectionDomain().getCodeSource().getLocation().toURI();
return new File( jarURI );
java.net.URI locationURI = getClass().getProtectionDomain().getCodeSource().getLocation().toURI();
return new File( locationURI );
}
catch(java.net.URISyntaxException ex) {
// a URISyntaxException here must be an IO error; wrap as such.
@ -106,6 +106,22 @@ public class WalkerManager {
}
}
/**
* Load classes internal to the classpath from an arbitrary location.
* @param location Location from which to load classes.
* @return List of classes.
* @throws IOException Problem occurred reading classes.
*/
private List<Class> loadClassesFromLocation( File location )
throws IOException {
if( location.getAbsolutePath().endsWith(".jar") )
return loadClassesFromJar( location );
else {
List<String> classFileNames = findFilesInPath( location, "", "class", true );
return loadInternalClasses( classFileNames );
}
}
/**
* Loads concrete classes from a jar which are both in the same package or 'sub-package' of baseClass,
* and which extend from baseClass.
@ -125,7 +141,7 @@ public class WalkerManager {
String jarEntryName = jarEntry.getName();
if(jarEntryName.endsWith(".class"))
{
String className = jarEntryName.substring(0,jarEntryName.lastIndexOf(".class")).replace('/','.');
String className = fileNameToClassName(jarEntryName);
subclasses.add( Class.forName(className) );
}
jarEntry = jarInputStream.getNextJarEntry();
@ -143,11 +159,35 @@ public class WalkerManager {
}
/**
* Load loose classes from the specified directory.
* Loads a list of classes currently on the classpath.
* @param classFileNames List of files representing classes.
* @return class objects.
* @throws IOException Unable to open any of the found classes.
*/
private List<Class> loadInternalClasses( List<String> classFileNames )
throws IOException {
List<Class> internalClasses = new ArrayList<Class>();
for( String classFileName: classFileNames ) {
String className = fileNameToClassName( classFileName );
try {
internalClasses.add( Class.forName(className) );
}
catch(ClassNotFoundException ex) {
// A ClassNotFoundException here must be an IO error; wrap as such.
throw new IOException(ex);
}
}
return internalClasses;
}
/**
* Load loose classes, external to the classloader, from the specified directory.
* @param path source path from which to load classes.
* @return A list of all loose classes contained in the path directory.
*/
private List<Class> loadClassesFromPath(final File path)
private List<Class> loadExternalClasses(final File path, List<String> classFileNames)
throws IOException {
List<Class> subclasses = new ArrayList<Class>();
@ -155,14 +195,9 @@ public class WalkerManager {
ClassLoader cl = new URLClassLoader(new URL[] { pathURL });
File[] classFiles = path.listFiles(
new FilenameFilter() { public boolean accept( File f, String s ) { return s.endsWith(".class"); } });
for(File classFile: classFiles) {
// Poor person's way of getting the classname: assume classes are unpackaged.
// Chop out the classname section of the URL, and assume the class is unpackaged.
String fileName = classFile.getName();
String className = fileName.substring(fileName.lastIndexOf(File.separator)+1,fileName.lastIndexOf(".class"));
List<String> filesInPath = findFilesInPath( path, "", "class", false );
for( String file: filesInPath ) {
String className = fileNameToClassName( file );
try {
subclasses.add(cl.loadClass(className));
}
@ -170,12 +205,69 @@ public class WalkerManager {
// Class not found from a list of classes just looked up is an IO error. Wrap and throw.
throw new IOException(ex);
}
}
return subclasses;
}
/**
* Find the files in the given directory matching the given extension.
* @param basePath Path to search.
* @param relativePrefix What directory should the given files be presented relative to?
* @param extension Extension for which to search.
* @param recursive Search recursively. Beware of symlinks!
* @return A list of files matching the specified criteria.
* TODO: Move to a utils class.
* TODO: Test recursive traversal in the presence of a symlink.
*/
private List<String> findFilesInPath(final File basePath, final String relativePrefix, final String extension, boolean recursive) {
List<String> filesInPath = new ArrayList();
File[] contents = basePath.listFiles( new OrFilenameFilter( new DirectoryFilter(), new ExtensionFilter( extension ) ) );
for( File content: contents ) {
String relativeFileName = relativePrefix.trim().length() != 0 ?
relativePrefix + File.separator + content.getName() :
content.getName();
if ( relativeFileName.endsWith(extension) )
filesInPath.add(relativeFileName);
else if( content.isDirectory() && recursive )
filesInPath.addAll( findFilesInPath( content, relativeFileName, extension, recursive ) );
}
return filesInPath;
}
/**
* Convert a filename of the form a/b/c.class to a.b.c. Makes no assurances about whether the
* class is valid on any classloader.
* @param fileName Filename to convert.
* @return classname represented by that file.
* TODO: Move to a utils class.
*/
private String fileNameToClassName( String fileName ) {
return fileName.substring(0,fileName.lastIndexOf(".class")).replace('/','.');
}
/**
* The following are general-purpose file selection filters.
* TODO: Move to a utils class.
*/
private class ExtensionFilter implements FilenameFilter {
private String extensionName = null;
public ExtensionFilter( String extensionName ) { this.extensionName = extensionName; }
public boolean accept( File f, String s ) { return s.endsWith("." + extensionName); }
}
private class DirectoryFilter implements FilenameFilter {
public boolean accept( File f, String s ) { return new File( f, s ).isDirectory(); }
}
private class OrFilenameFilter implements FilenameFilter {
private FilenameFilter lhs = null, rhs = null;
public OrFilenameFilter( FilenameFilter lhs, FilenameFilter rhs ) { this.lhs = lhs; this.rhs = rhs; }
public boolean accept( File f, String s ) { return lhs.accept( f, s ) || rhs.accept( f, s ); }
}
/**
* Given a list of classes, return a list of those classes which extend from the Walker base interface.
* @param classes Arbitrary list of classes.