package sbt
package classpath
import java.io.File
import java.net.{URI, URL, URLClassLoader}
abstract class LoaderBase(urls: Seq[URL], parent: ClassLoader) extends URLClassLoader(urls.toArray, parent)
{
require(parent != null)
@throws(classOf[ClassNotFoundException])
override final def loadClass(className: String, resolve: Boolean): Class[_] =
{
val loaded = findLoadedClass(className)
val found =
if(loaded == null)
doLoadClass(className)
else
loaded
if(resolve)
resolveClass(found)
found
}
protected def doLoadClass(className: String): Class[_]
protected final def defaultLoadClass(className: String): Class[_] = super.loadClass(className, false)
}
class SelfFirstLoader(classpath: Seq[URL], parent: ClassLoader) extends LoaderBase(classpath, parent)
{
@throws(classOf[ClassNotFoundException])
override final def doLoadClass(className: String): Class[_] =
{
try { findClass(className) }
catch { case _: ClassNotFoundException => defaultLoadClass(className) }
}
}
private class IntermediateLoader(urls: Array[URL], parent: ClassLoader) extends LoaderBase(urls, parent)
{
def doLoadClass(className: String): Class[_] =
{
if(className.startsWith(Loaders.SbtPackage))
findClass(className)
else
defaultLoadClass(className)
}
}
class FilteredLoader(parent: ClassLoader, filter: ClassFilter) extends ClassLoader(parent)
{
require(parent != null)
def this(parent: ClassLoader, excludePackages: Iterable[String]) = this(parent, new ExcludePackagesFilter(excludePackages))
@throws(classOf[ClassNotFoundException])
override final def loadClass(className: String, resolve: Boolean): Class[_] =
{
if(filter.include(className))
super.loadClass(className, resolve)
else
throw new ClassNotFoundException(className)
}
}
private class SelectiveLoader(urls: Array[URL], parent: ClassLoader, filter: ClassFilter) extends URLClassLoader(urls, parent)
{
require(parent != null)
def this(urls: Array[URL], parent: ClassLoader, includePackages: Iterable[String]) = this(urls, parent, new IncludePackagesFilter(includePackages))
@throws(classOf[ClassNotFoundException])
override final def loadClass(className: String, resolve: Boolean): Class[_] =
{
if(filter.include(className))
super.loadClass(className, resolve)
else
{
val loaded = parent.loadClass(className)
if(resolve)
resolveClass(loaded)
loaded
}
}
}
trait ClassFilter
{
def include(className: String): Boolean
}
abstract class PackageFilter(packages: Iterable[String]) extends ClassFilter
{
require(packages.forall(_.endsWith(".")))
protected final def matches(className: String): Boolean = packages.exists(className.startsWith)
}
class ExcludePackagesFilter(exclude: Iterable[String]) extends PackageFilter(exclude)
{
def include(className: String): Boolean = !matches(className)
}
class IncludePackagesFilter(include: Iterable[String]) extends PackageFilter(include)
{
def include(className: String): Boolean = matches(className)
}
private[sbt] class LazyFrameworkLoader(runnerClassName: String, urls: Array[URL], parent: ClassLoader, grandparent: ClassLoader)
extends LoaderBase(urls, parent)
{
def doLoadClass(className: String): Class[_] =
{
if(Loaders.isNestedOrSelf(className, runnerClassName))
findClass(className)
else if(Loaders.isSbtClass(className))
grandparent.loadClass(className)
else
parent.loadClass(className)
}
}
private object Loaders
{
val SbtPackage = "sbt."
def isNestedOrSelf(className: String, checkAgainst: String) =
className == checkAgainst || className.startsWith(checkAgainst + "$")
def isSbtClass(className: String) = className.startsWith(Loaders.SbtPackage)
}
final class NativeCopyConfig(val tempDirectory: File, val explicitLibraries: Seq[File], val searchPaths: Seq[File])
trait NativeCopyLoader extends ClassLoader
{
protected val config: NativeCopyConfig
import config._
private[this] val mapped = new collection.mutable.HashMap[String, String]
override protected def findLibrary(name: String): String =
synchronized { mapped.getOrElseUpdate(name, findLibrary0(name)) }
private[this] def findLibrary0(name: String): String =
{
val mappedName = System.mapLibraryName(name)
val explicit = explicitLibraries.filter(_.getName == mappedName).toStream
val search = searchPaths.toStream flatMap relativeLibrary(mappedName)
(explicit ++ search).headOption.map(copy).orNull
}
private[this] def relativeLibrary(mappedName: String)(base: File): Seq[File] =
{
val f = new File(base, mappedName)
if(f.isFile) f :: Nil else Nil
}
private[this] def copy(f: File): String =
{
val target = new File(tempDirectory, f.getName)
IO.copyFile(f, target)
target.getAbsolutePath
}
}