In a Scala application that is using Typesafe Config, I want to add the possibility to reload a Config at runtime. A Config instance is immutable. Here is what I have so far:
package config
trait Settings {
private[config] var config: Config = ConfigFactory.empty()
def engine: EngineSettings
}
trait EngineSettings {
def weight: Int
def offset: Int
}
class AppSettings {
override def engine = new EngineSettings {
override def weight = config.getInt("engine.weight")
override def offset = config.getInt("engine.offset")
}
}
object Settings {
private val namedSettings = new TrieMap[String, AppSettings]
def load(configName: String = "local"): Settings = {
// load config
// create or update AppSettings
// add to map and return
}
}
Initially a Settings instance is created using Settings.load. That instance reference is handed to other classes. Then a second thread can reload the underlying Config by calling Settings.load again. Here is how you access it:
class Engine(settings: Settings) {
def calculate() = {
val weight = settings.engine.weight
// do some stuff
val offset = settings.engine.offset
}
}
There are two problems:
How can I improve this design :)
Configurations from a fileBy default, the ConfigFactory looks for a configuration file called application. conf. If willing to use a different configuration file (e.g.: another. conf), we just need to indicate a different file name and path to load (e.g.: ConfigFactory. load("another")).
public final class ConfigFactory extends java.lang.Object. Contains static methods for creating Config instances. See also ConfigValueFactory which contains static methods for converting Java values into a ConfigObject . You can then convert a ConfigObject into a Config with ConfigObject.
You could turn config
into a method with support for config cache invalidation (and with sensible defaults), so you can choose between dynamic (default in the following sample) and performance.
In general I suggest you use a good Scala typesafe wrapper of TypeSafe's Config such as Ficus (e.g. Gradle-stype artifact dependency net.ceedubs:ficus_2.11:1.1.1
)
package config
import scala.collection.concurrent.TrieMap
import com.typesafe.config.{Config, ConfigFactory}
import net.ceedubs.ficus.Ficus._
trait Settings {
protected[config] def config (
name: String = "local",
invalidateCache: Boolean = false
): Config = {
if (invalidateCache) { ConfigFactory invalidateCaches }
ConfigFactory load name
}
def engine: EngineSettings
}
trait EngineSettings {
def weight: Int
def offset: Int
}
class AppSettings(val name: String = "local") extends Settings {
val c = config()
override def engine = new EngineSettings {
override def weight = c.as[Int]("engine.weight")
override def offset = c.as[Int]("engine.offset")
}
}
object Settings {
private val namedSettings = new TrieMap[String, AppSettings]
def load(configName: String = "local"): Settings = {
// e.g.
val loadedUpToDate = new AppSettings
namedSettings +=
((configName + "." + System.currentTimeMillis, loadedUpToDate))
new Settings {
override def engine = loadedUpToDate.engine
}
}
}
I think this solves your issues because:
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With