diff --git a/java/src/org/broadinstitute/sting/utils/classloader/PackageUtils.java b/java/src/org/broadinstitute/sting/utils/classloader/PackageUtils.java index 58bd3d8f8..ce02d4f36 100755 --- a/java/src/org/broadinstitute/sting/utils/classloader/PackageUtils.java +++ b/java/src/org/broadinstitute/sting/utils/classloader/PackageUtils.java @@ -35,7 +35,9 @@ import org.reflections.util.ClasspathHelper; import org.reflections.util.ConfigurationBuilder; import org.slf4j.LoggerFactory; +import java.lang.reflect.Method; import java.net.URL; +import java.net.URLClassLoader; import java.util.Set; import java.util.ArrayList; import java.util.List; @@ -54,11 +56,6 @@ public class PackageUtils { // turn off logging in the reflections library - they talk too much (to the wrong logger factory as well, logback) Logger logger = (ch.qos.logback.classic.Logger)LoggerFactory.getLogger(Reflections.class); logger.setLevel(Level.OFF); - - // Initialize general-purpose source tree reflector. - reflections = new Reflections( new ConfigurationBuilder() - .setUrls(getClassPathURLs()) - .setScanners(new SubTypesScanner())); } /** @@ -76,6 +73,7 @@ public class PackageUtils { */ public static List> getClassesImplementingInterface(Class iface) { // Load all classes implementing the given interface, then filter out any class that isn't concrete. + initReflections(); Set> allTypes = reflections.getSubTypesOf(iface); List> concreteTypes = new ArrayList>(); for( Class type: allTypes ) { @@ -112,6 +110,7 @@ public class PackageUtils { */ public static List> getInterfacesExtendingInterface(Class iface) { // Load all classes extending the given interface, then filter out any class that is concrete. + initReflections(); Set> allTypes = reflections.getSubTypesOf(iface); List> nonConcreteTypes = new ArrayList>(); for( Class type: allTypes ) { @@ -125,4 +124,40 @@ public class PackageUtils { public static Set getClassPathURLs() { return ClasspathHelper.getUrlsForManifestsCurrentClasspath(); } + + /** + * Adds the URL to the system class loader classpath using reflection. + * HACK: Uses reflection to modify the class path, and assumes loader is a URLClassLoader. + * @param url URL to add to the system class loader classpath. + */ + public static void addClasspath(URL url) { + try { + Method method = URLClassLoader.class.getDeclaredMethod("addURL", URL.class); + if (!method.isAccessible()) + method.setAccessible(true); + method.invoke(ClassLoader.getSystemClassLoader(), url); + resetReflections(); + } catch (Exception e) { + throw new StingException("Error adding url to the current classloader.", e); + } + } + + /** + * Create new reflections object if it does not currently exists. + */ + private static void initReflections() { + if (reflections == null) { + // Initialize general-purpose source tree reflector. + reflections = new Reflections( new ConfigurationBuilder() + .setUrls(getClassPathURLs()) + .setScanners(new SubTypesScanner())); + } + } + + /** + * Resets the reflections object after a class has been dynamically added to the classpath. + */ + private static void resetReflections() { + reflections = null; + } } diff --git a/scala/src/org/broadinstitute/sting/queue/QScriptManager.scala b/scala/src/org/broadinstitute/sting/queue/QScriptManager.scala index 4873ccf77..fafbbb1a8 100644 --- a/scala/src/org/broadinstitute/sting/queue/QScriptManager.scala +++ b/scala/src/org/broadinstitute/sting/queue/QScriptManager.scala @@ -1,15 +1,15 @@ package org.broadinstitute.sting.queue -import org.broadinstitute.sting.utils.classloader.PluginManager import scala.tools.nsc.{Global, Settings} import scala.tools.nsc.io.PlainFile -import org.broadinstitute.sting.queue.util.{Logging, ClasspathUtils, IOUtils} +import org.broadinstitute.sting.queue.util.{Logging, IOUtils} import collection.JavaConversions import java.io.File import scala.tools.nsc.reporters.AbstractReporter import java.lang.String import org.apache.log4j.Level import scala.tools.nsc.util.{FakePos, NoPosition, Position} +import org.broadinstitute.sting.utils.classloader.{PackageUtils, PluginManager} /** * Plugin manager for QScripts which loads QScripts into the current class loader. @@ -52,7 +52,7 @@ object QScriptManager extends Logging { settings.outdir.value = outdir.getPath // Set the classpath to the current class path. - ClasspathUtils.manifestAwareClassPath.foreach(path => settings.classpath.append(path.getPath)) + JavaConversions.asSet(PackageUtils.getClassPathURLs).foreach(url => settings.classpath.append(url.getPath)) val reporter = new Log4JReporter(settings) @@ -76,7 +76,7 @@ object QScriptManager extends Logging { logger.info("Compilation complete") // Add the new compilation output directory to the classpath. - ClasspathUtils.addClasspath(outdir) + PackageUtils.addClasspath(outdir.toURI.toURL) } } diff --git a/scala/src/org/broadinstitute/sting/queue/engine/DispatchJobRunner.scala b/scala/src/org/broadinstitute/sting/queue/engine/DispatchJobRunner.scala index 640596de9..ec9d0d819 100755 --- a/scala/src/org/broadinstitute/sting/queue/engine/DispatchJobRunner.scala +++ b/scala/src/org/broadinstitute/sting/queue/engine/DispatchJobRunner.scala @@ -64,7 +64,7 @@ trait DispatchJobRunner extends JobRunner { for (dir <- function.jobDirectories) dirs += IOUtils.dirLevel(dir, 2) if (dirs.size > 0) - Some("\'" + dirs.mkString("cd ", " && cd ", "") + "\'") + Some(dirs.mkString("cd ", " && cd ", "")) else None } diff --git a/scala/src/org/broadinstitute/sting/queue/util/ClasspathUtils.scala b/scala/src/org/broadinstitute/sting/queue/util/ClasspathUtils.scala deleted file mode 100755 index a55bb8ee4..000000000 --- a/scala/src/org/broadinstitute/sting/queue/util/ClasspathUtils.scala +++ /dev/null @@ -1,36 +0,0 @@ -package org.broadinstitute.sting.queue.util - -import collection.JavaConversions._ -import org.broadinstitute.sting.utils.classloader.PackageUtils -import java.io.File -import javax.print.URIException -import java.net.{URL, URLClassLoader} - -/** - * Builds the correct class path by examining the manifests - */ -object ClasspathUtils { - - /** - * Returns a list of files that build up the classpath, taking into account jar file manifests. - * @return List[File] that build up the current classpath. - */ - def manifestAwareClassPath = { - var urls = PackageUtils.getClassPathURLs - urls.map(url => try {new File(url.toURI)} catch {case urie: URIException => new File(url.getPath)}) - } - - /** - * Adds the directory to the system class loader classpath using reflection. - * HACK: Uses reflection to modify the class path, and assumes loader is a URLClassLoader - * @param path Directory to add to the system class loader classpath. - */ - def addClasspath(path: File): Unit = { - val url = path.toURI.toURL - val method = classOf[URLClassLoader].getDeclaredMethod("addURL", classOf[URL]); - if (!method.isAccessible) - method.setAccessible(true); - method.invoke(ClassLoader.getSystemClassLoader(), url); - } -} -