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:
parent
ff5b0ec1b6
commit
f7363cf935
|
|
@ -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.
|
||||
|
|
|
|||
Loading…
Reference in New Issue