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 🙂