Ratpacked: Using Database As Custom Configuration Source
We learned about externalised configuration in a previous blog post. Ratpack provides support out of the box for several formats and configuration sources. For example we can use files in YAML, properties or JSON format, arguments passed to the application, system properties and environment variables. We can add our own configuration source by implementing the ratpack.config.ConfigSource
interface. We must override the method loadConfigData
to load configuration data from a custom source and convert it to a format that can be handled by Ratpack.
We are going to write a custom ConfigSource
implementation that will get configuration data from a database. We assume the data is in a table with the name CONFIGURATION
and has the columns KEY
and VALUE
. The format of the key is the same as for Java properties files.
package com.mrhaki.config
import groovy.sql.Sql
import ratpack.config.ConfigSource
import ratpack.config.internal.source.AbstractPropertiesConfigSource
/**
* {@link ConfigSource} implementation to read configuration
* data from a database table. The database must have a table
* CONFIGURATION with the VARCHAR columns KEY and VALUE.
* The format of the key matches that of regular Java properties.
*
* E.g. we can insert the configuration key 'app.message' like this:
* INSERT INTO CONFIGURATION(KEY, VALUE) VALUES('app.message', 'Ratpack rocks');
*
* This class extends {@link AbstractPropertiesConfigSource}, because it supports
* property key formats like we use in our database.
*/
class JdbcConfigSource extends AbstractPropertiesConfigSource {
/**
* Database JDBC url, username, password and driver.
*/
final Map sqlProperties
JdbcConfigSource(final Map sqlProperties) {
super(Optional.empty())
this.sqlProperties = sqlProperties
}
@Override
protected Properties loadProperties() throws Exception {
final Properties properties = new Properties()
Sql.withInstance(sqlProperties) { sql->
// Get key/value pairs from database.
sql.eachRow("SELECT KEY, VALUE FROM CONFIGURATION") { row ->
// Save found data in Properties object.
properties.setProperty(row.key, row.value)
}
}
return properties
}
}
To use this ConfigSource
implementation in our Ratpack application we use the add
method of ConfigDataBuilder
:
import com.mrhaki.config.JdbcConfigSource
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import ratpack.config.ConfigData
import static groovy.json.JsonOutput.prettyPrint
import static groovy.json.JsonOutput.toJson
import static ratpack.groovy.Groovy.ratpack
class SampleConfig {
String message
}
ratpack {
bindings {
final ConfigData configData = ConfigData.of { builder ->
// Add our custom JdbcConfigSource as
// configuration source.
builder.add(
new JdbcConfigSource(
driver: 'org.postgresql.Driver',
url: 'jdbc:postgresql://192.168.99.100:32768/',
user: 'postgres',
password: 'secret'))
.build()
}
// Assign all configuration properties from the /app node
// to the properties in the SampleConfig class.
bindInstance(SimpleConfig, configData.get('/app', SampleConfig))
}
handlers {
get('configprops') { SampleConfig config ->
render(prettyPrint(toJson(config)))
}
}
}
When we request configprops
we get the following result:
$ http -b localhost:5050/configprops
{
"message": "Ratpack rocks!"
}
$
Written with Ratpack 1.1.1.