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 ) { public WalkerManager( String pluginDirectory ) {
try { 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>(); List<Class> walkerClasses = new ArrayList<Class>();
// Load all classes that live in this jar. // 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. // 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 ); File extensionPath = new File( pluginDirectory );
if(extensionPath.exists()) if(extensionPath.exists()) {
walkerClasses.addAll( loadClassesFromPath( extensionPath ) ); List<String> filesInPath = findFilesInPath( extensionPath, "", "class", false );
walkerClasses.addAll( loadExternalClasses( extensionPath, filesInPath ) );
}
walkerClasses = filterWalkers(walkerClasses); walkerClasses = filterWalkers(walkerClasses);
@ -95,10 +95,10 @@ public class WalkerManager {
* Determines which jar file contains the WalkerManager class. * Determines which jar file contains the WalkerManager class.
* @return Jar file containing the WalkerManager class. * @return Jar file containing the WalkerManager class.
*/ */
private File getThisJarFile() throws IOException { private File getThisLocation() throws IOException {
try { try {
java.net.URI jarURI = getClass().getProtectionDomain().getCodeSource().getLocation().toURI(); java.net.URI locationURI = getClass().getProtectionDomain().getCodeSource().getLocation().toURI();
return new File( jarURI ); return new File( locationURI );
} }
catch(java.net.URISyntaxException ex) { catch(java.net.URISyntaxException ex) {
// a URISyntaxException here must be an IO error; wrap as such. // 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, * Loads concrete classes from a jar which are both in the same package or 'sub-package' of baseClass,
* and which extend from baseClass. * and which extend from baseClass.
@ -125,7 +141,7 @@ public class WalkerManager {
String jarEntryName = jarEntry.getName(); String jarEntryName = jarEntry.getName();
if(jarEntryName.endsWith(".class")) if(jarEntryName.endsWith(".class"))
{ {
String className = jarEntryName.substring(0,jarEntryName.lastIndexOf(".class")).replace('/','.'); String className = fileNameToClassName(jarEntryName);
subclasses.add( Class.forName(className) ); subclasses.add( Class.forName(className) );
} }
jarEntry = jarInputStream.getNextJarEntry(); 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. * @param path source path from which to load classes.
* @return A list of all loose classes contained in the path directory. * @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 { throws IOException {
List<Class> subclasses = new ArrayList<Class>(); List<Class> subclasses = new ArrayList<Class>();
@ -155,14 +195,9 @@ public class WalkerManager {
ClassLoader cl = new URLClassLoader(new URL[] { pathURL }); ClassLoader cl = new URLClassLoader(new URL[] { pathURL });
File[] classFiles = path.listFiles( List<String> filesInPath = findFilesInPath( path, "", "class", false );
new FilenameFilter() { public boolean accept( File f, String s ) { return s.endsWith(".class"); } }); for( String file: filesInPath ) {
for(File classFile: classFiles) { String className = fileNameToClassName( file );
// 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"));
try { try {
subclasses.add(cl.loadClass(className)); 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. // Class not found from a list of classes just looked up is an IO error. Wrap and throw.
throw new IOException(ex); throw new IOException(ex);
} }
} }
return subclasses; 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. * Given a list of classes, return a list of those classes which extend from the Walker base interface.
* @param classes Arbitrary list of classes. * @param classes Arbitrary list of classes.