Executing a method defined in a configuration file

I have a class with a method that takes a function as parameter. This function is the strategy that determines how a file is split into chunks. This is the signature of the method.

def split(r: RemoteFileInfo, append: Boolean, workDir: File, strategy: (Long) => Int = defaultStrategy): LinkedHashSet[Chunk] = {
  ...
}

There is a companion object that provides a number of predefined strategies. I wanted to make the strategy configurable by adding it to the Akka application.conf file.

This is a snippet from the application.conf.

akka {
	...
}
downloader {
	...
	dependencies {
		splitter = "com.nidkil.downloader.splitter.DefaultSplitter"
		splitterStrategy = "ratioStrategy"
		merger = "com.nidkil.downloader.merger.DefaultMerger"
		validator {
			checksum = "com.nidkil.downloader.validator.ChecksumValidator"
			size = "com.nidkil.downloader.validator.FileSizeValidator"
		}
		cleaner = "com.nidkil.downloader.cleaner.DefaultCleaner"
	}
}

I used the following code to load the strategy at runtime.

  def strategy = {
    import scala.reflect.runtime.{ universe => ru }
    val strategyName = config.getString("downloader.dependencies.splitterStrategy")
    val instanceMirror = ru.runtimeMirror(getClass.getClassLoader).reflect(DefaultSplitter)
    val strategyMethod = ru.typeOf[DefaultSplitter.type].declaration(ru.newTermName(strategyName)).asMethod

    instanceMirror.reflectMethod(strategyMethod)
  }

For further details on how the custom settings are load using an Akka extension check the following post.
Now I can load the method using the following code.

val settings = Settings(system) 
val strategy = settings.strategy
println(strategy(1024 * 1024 * 1))

To pass it as an argument to a method an extract trick is required: explicit conversion to the function signature. Recall the function signature is Long => Int. The function signature of MethodMirror is Any => Any. When passing the function as is an error is thrown ‘type mismatch; found : reflect.runtime.universe.MethodMirror required: Long => Int’. So we add an explicit conversion.

	val strategyFunc: Long => Int = strategy(_).asInstanceOf[Int]
	split(remoteFileInfo, true, workDir, strategyFunc)

Pretty neat trick, right? Happy coding 🙂

Leave a comment