Skip to content

Instantly share code, notes, and snippets.

@mpilquist
Created July 15, 2013 18:07
Show Gist options
  • Save mpilquist/6002064 to your computer and use it in GitHub Desktop.
Save mpilquist/6002064 to your computer and use it in GitHub Desktop.
Automatic discovery of reference.conf files in OSGi
import scala.collection.JavaConverters._
import java.net.URL
import java.util.Enumeration
import com.typesafe.config._
import org.osgi.framework.Bundle
import org.osgi.framework.wiring._
object OsgiConfigFactory {
def load(bundle: Bundle): Config = {
val bundles = transitiveBundles(bundle)
val classLoader = new ClassLoader() {
override def findResource(name: String): URL = {
def tryGetResource(bundle: Bundle): Option[URL] =
Option(bundle.getResource(name))
val cls = bundles.foldLeft(None: Option[URL]) { (cls, bundle) => cls orElse tryGetResource(bundle) }
cls getOrElse getParent.getResource(name)
}
override def findResources(name: String): Enumeration[URL] = {
val resources = bundles.map { bundle => Option(bundle.getResources(name)).map { _.asScala.toList }.getOrElse(Nil) }.flatten
java.util.Collections.enumeration(resources.asJava)
}
}
ConfigFactory.load(classLoader)
}
private def transitiveBundles(b: Bundle): Set[Bundle] = {
@annotation.tailrec def process(processed: Set[Bundle], remaining: Set[Bundle]): Set[Bundle] = {
if (remaining.isEmpty) {
processed
} else {
val (bundle, rest) = (remaining.head, remaining.tail)
if (processed contains bundle) {
process(processed, rest)
} else {
val wiring = bundle.adapt(classOf[BundleWiring])
val requiredWires: List[BundleWire] = wiring.getRequiredWires(BundleRevision.PACKAGE_NAMESPACE).asScala.toList
val direct: Set[Bundle] = requiredWires.flatMap { wire => Option(wire.getProviderWiring) map { _.getBundle } }.toSet
process(processed + bundle, rest ++ (direct -- processed))
}
}
}
process(Set.empty, Set(b))
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment