2009-06-19 06:43:19 +08:00
|
|
|
package org.broadinstitute.sting.utils;
|
|
|
|
|
|
2009-07-22 02:32:22 +08:00
|
|
|
import org.reflections.Reflections;
|
|
|
|
|
import org.reflections.scanners.SubTypesScanner;
|
|
|
|
|
import org.reflections.util.AbstractConfiguration;
|
2009-11-02 14:02:41 +08:00
|
|
|
import org.apache.log4j.Logger;
|
2009-07-22 02:32:22 +08:00
|
|
|
|
|
|
|
|
import java.util.Set;
|
2009-06-19 06:43:19 +08:00
|
|
|
import java.util.ArrayList;
|
2009-07-22 02:32:22 +08:00
|
|
|
import java.util.List;
|
2009-11-02 14:02:41 +08:00
|
|
|
import java.util.Collection;
|
|
|
|
|
import java.util.jar.Attributes;
|
|
|
|
|
import java.util.jar.JarFile;
|
|
|
|
|
import java.net.MalformedURLException;
|
|
|
|
|
import java.net.URL;
|
|
|
|
|
import java.io.File;
|
|
|
|
|
import java.io.IOException;
|
|
|
|
|
|
|
|
|
|
import com.google.common.collect.Lists;
|
2009-06-19 06:43:19 +08:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* PackageUtils contains some useful methods for package introspection.
|
|
|
|
|
*/
|
|
|
|
|
public class PackageUtils {
|
2009-11-02 14:02:41 +08:00
|
|
|
/**
|
|
|
|
|
* our log, which we want to capture anything from this class
|
|
|
|
|
*/
|
|
|
|
|
private static Logger logger = Logger.getLogger(PackageUtils.class);
|
|
|
|
|
|
2009-07-22 02:32:22 +08:00
|
|
|
/**
|
|
|
|
|
* A reference into our introspection utility.
|
|
|
|
|
*/
|
|
|
|
|
private static Reflections reflections = null;
|
|
|
|
|
|
|
|
|
|
static {
|
|
|
|
|
// Initialize general-purpose source tree reflector.
|
2009-11-02 14:02:41 +08:00
|
|
|
reflections = new Reflections(new AbstractConfiguration() {
|
2009-07-22 02:32:22 +08:00
|
|
|
{
|
2009-11-02 14:02:41 +08:00
|
|
|
setUrls(PackageUtils.getUrlsForClasspath(System.getProperty("java.class.path")));
|
2009-07-22 02:32:22 +08:00
|
|
|
setScanners(new SubTypesScanner());
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2009-06-19 06:43:19 +08:00
|
|
|
/**
|
|
|
|
|
* Private constructor. No instantiating this class!
|
|
|
|
|
*/
|
2009-11-02 14:02:41 +08:00
|
|
|
private PackageUtils() {
|
|
|
|
|
}
|
|
|
|
|
|
2009-07-22 02:32:22 +08:00
|
|
|
{
|
|
|
|
|
}
|
2009-06-19 06:43:19 +08:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Return the classes that implement the specified interface.
|
|
|
|
|
*
|
2009-11-02 14:02:41 +08:00
|
|
|
* @param iface the interface which returned classes should implement.
|
|
|
|
|
* @return the list of classes that implement the interface.
|
2009-06-19 06:43:19 +08:00
|
|
|
*/
|
2009-07-22 02:32:22 +08:00
|
|
|
public static <T> List<Class<? extends T>> getClassesImplementingInterface(Class<T> iface) {
|
|
|
|
|
// Load all classes implementing the given interface, then filter out any class that isn't concrete.
|
|
|
|
|
Set<Class<? extends T>> allTypes = reflections.getSubTypesOf(iface);
|
|
|
|
|
List<Class<? extends T>> concreteTypes = new ArrayList<Class<? extends T>>();
|
2009-11-02 14:02:41 +08:00
|
|
|
for (Class<? extends T> type : allTypes) {
|
|
|
|
|
if (JVMUtils.isConcrete(type))
|
2009-07-22 02:32:22 +08:00
|
|
|
concreteTypes.add(type);
|
2009-06-19 06:43:19 +08:00
|
|
|
}
|
|
|
|
|
|
2009-07-22 02:32:22 +08:00
|
|
|
return concreteTypes;
|
2009-06-19 06:43:19 +08:00
|
|
|
}
|
2009-11-02 14:02:41 +08:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* get a list of URL's, given the current classpath. This function is a fix for the
|
|
|
|
|
* reflections package, which doesn't correctly expand the classpath from a jar (it doesn't
|
|
|
|
|
* get the manifest and parse out the embedded classpth).
|
|
|
|
|
* @param classpath the current classpath
|
|
|
|
|
* @return
|
|
|
|
|
*/
|
|
|
|
|
public static Collection<URL> getUrlsForClasspath(String classpath) {
|
|
|
|
|
// if the classpath is null, we can't really do anything
|
|
|
|
|
if (classpath == null || classpath.equals(""))
|
|
|
|
|
throw new StingException("Classpath cannot be empty or null");
|
|
|
|
|
List<URL> urls = Lists.newArrayList();
|
|
|
|
|
|
|
|
|
|
// the current working directory
|
|
|
|
|
String baseDir = System.getProperty("user.dir");
|
|
|
|
|
|
|
|
|
|
// our collection of classpath's to expand
|
|
|
|
|
List<JarPath> javaClassPath = new ArrayList<JarPath>();
|
|
|
|
|
|
|
|
|
|
// the current classpath can be a list of path's seperated by a semicolon
|
|
|
|
|
String[] classPaths = classpath.split(File.pathSeparator);
|
|
|
|
|
for (String part : classPaths) {
|
|
|
|
|
extractJarClasspath(baseDir, javaClassPath, part);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// check to make sure each extracted path exists, if so add it to our list
|
|
|
|
|
if (javaClassPath.size() > 0)
|
|
|
|
|
for (JarPath path : javaClassPath) {
|
|
|
|
|
try {
|
|
|
|
|
if (path.isValid())
|
|
|
|
|
urls.add(path.toValidFile().toURL());
|
|
|
|
|
} catch (MalformedURLException e) {
|
|
|
|
|
throw new StingException("could not create url from " + path, e);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return urls;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* extract the classpath from a jar
|
|
|
|
|
*
|
|
|
|
|
* @param baseDir the base
|
|
|
|
|
* @param javaClassPath the list of jar paths
|
|
|
|
|
* @param part the current the subsection of the classpath we're processing
|
|
|
|
|
*/
|
|
|
|
|
private static void extractJarClasspath(String baseDir, List<JarPath> javaClassPath, String part) {
|
|
|
|
|
try {
|
|
|
|
|
JarFile myJar = new JarFile(part);
|
|
|
|
|
Attributes.Name classPath = new Attributes.Name("Class-Path");
|
|
|
|
|
if (myJar.getManifest().getMainAttributes().containsKey(classPath)) {
|
|
|
|
|
for (String jar : myJar.getManifest().getMainAttributes().getValue(classPath).split(" "))
|
|
|
|
|
javaClassPath.add(new JarPath(baseDir, new File(part).getParent(), jar));
|
|
|
|
|
}
|
|
|
|
|
} catch (IOException e) {
|
|
|
|
|
logger.warn("could not retreive manifest from " + part);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* a simple helper class, to determine the absolute path to a jar file
|
|
|
|
|
*/
|
|
|
|
|
static class JarPath {
|
|
|
|
|
private final String mPath;
|
|
|
|
|
private final String mFilename;
|
|
|
|
|
private final String mWorkingDir;
|
|
|
|
|
|
|
|
|
|
public JarPath(String workingDir, String path, String filename) {
|
|
|
|
|
this.mPath = path;
|
|
|
|
|
this.mFilename = filename;
|
|
|
|
|
mWorkingDir = workingDir;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public File toValidFile() {
|
|
|
|
|
if (new File(mFilename).exists())
|
|
|
|
|
return new File(mFilename);
|
|
|
|
|
if (new File(mPath + File.separator + mFilename).exists())
|
|
|
|
|
return new File(mPath + File.separator + mFilename);
|
|
|
|
|
if (new File(mWorkingDir + File.separator + mFilename).exists())
|
|
|
|
|
return new File(mWorkingDir + File.separator + mFilename);
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public boolean isValid() {
|
|
|
|
|
return (toValidFile() != null) ? true : false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2009-06-19 06:43:19 +08:00
|
|
|
}
|