Ratpack has a lot of options to add configuration data to our application. We can use for example YAML and JSON files, properties, environment variables and Java system properties. Groovy has the ConfigSlurper
class to parse Groovy script with configuration data. It even supports an environments
block to set configuration value for a specific environment. If we want to support Groovy scripts as configuration definition we write a class that implements the ratpack.config.ConfigSource
interface.
We create a new class ConfigSlurperConfigSource
and implement the ConfigSource
interface. We must implement the loadConfigData
method in which we read the Groovy configuration and transform it to a ObjectNode
so Ratpack can use it:
// File: src/main/groovy/mrhaki/ratpack/config/ConfigSlurperConfigSource.groovy package mrhaki.ratpack.config import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.databind.node.ArrayNode import com.fasterxml.jackson.databind.node.ObjectNode import groovy.transform.CompileDynamic import groovy.transform.CompileStatic import ratpack.config.ConfigSource import ratpack.file.FileSystemBinding import java.nio.file.Path @CompileStatic class ConfigSlurperConfigSource implements ConfigSource { private final String configScript private final URL scriptUrl private final String environment ConfigSlurperConfigSource(final String configScript) { this(configScript, '') } ConfigSlurperConfigSource(final String configScript, final String environment) { this.configScript = configScript this.environment = environment } ConfigSlurperConfigSource(final Path configPath) { this(configPath, '') } ConfigSlurperConfigSource(final Path configPath, final String environment) { this(configPath.toUri(), environment) } ConfigSlurperConfigSource(final URI configUri) { this(configUri, '') } ConfigSlurperConfigSource(final URI configUri, final String environment) { this(configUri.toURL(), environment) } ConfigSlurperConfigSource(final URL configUrl) { this(configUrl, '') } ConfigSlurperConfigSource(final URL configUrl, final String environment) { this.scriptUrl = configUrl this.environment = environment } @Override ObjectNode loadConfigData( final ObjectMapper objectMapper, final FileSystemBinding fileSystemBinding) throws Exception { // Create ConfigSlurper for given environment. final ConfigSlurper configSlurper = new ConfigSlurper(environment) // Read configuration. final ConfigObject configObject = configScript ? configSlurper.parse(configScript) : configSlurper.parse(scriptUrl) // Transform configuration to node tree final ObjectNode rootNode = objectMapper.createObjectNode() populate(rootNode, configObject) return rootNode } @CompileDynamic private populate(final ObjectNode node, final ConfigObject config) { // Loop through configuration. // ConfigObject also implements Map interface, // so we can loop through key/value pairs. config.each { key, value -> // Value is another configuration, // this means the nested configuration // block. if (value instanceof Map) { populate(node.putObject(key), value) } else { // If value is a List we convert it to // an array node. if (value instanceof List) { final ArrayNode listNode = node.putArray(key) value.each { listValue -> listNode.add(listValue) } } else { // Put key/value pair in node. node.put(key, value) } } } } }
We have several options to pass the Groovy configuration to the ConfigSlurperConfigSource
class. We can use a String
, URI
, URL
or Path
reference. Let's create a file with some configuration data.
// File: src/ratpack/application.groovy app { serverPort = 9000 } environments { development { app { serverName = 'local' } } production { app { serverName = 'cloud' serverPort = 80 } } }
Next we create a Ratpack application using the Groovy DSL. In the serverConfig
section we use our new ConfigSlurperConfigSource
:
// File: src/ratpack/ratpack.groovy import com.google.common.io.Resources import com.mrhaki.config.ConfigSlurperConfigSource import static groovy.json.JsonOutput.prettyPrint import static groovy.json.JsonOutput.toJson import static ratpack.groovy.Groovy.ratpack //final Logger log = LoggerFactory.getLogger('ratpack') ratpack { serverConfig { // Use Groovy configuration. add new ConfigSlurperConfigSource('''\ app { message = 'Ratpack swings!' }''') // Use external Groovy configuration script file. add new ConfigSlurperConfigSource( Resources.getResource('application.groovy'), 'development') require '/app', SimpleConfig } handlers { get('configprops') { SimpleConfig config -> render(prettyPrint(toJson(config))) } } } // Simple configuration. class SimpleConfig { String message String serverName Integer serverPort }
Let's check the output of the configprops
endpoint:
$ http -b localhost:5050/configprops { "message": "Ratpack swings!", "serverName": "local", "serverPort": 9000 }
Now we set the environment to production
in our Ratpack application:
// File: src/ratpack/ratpack.groovy ... ratpack { serverConfig { ... // Use external Groovy configuration script file. add new ConfigSlurperConfigSource( Resources.getResource('application.groovy'), 'production') ... } ... }
If we check configprops
again we see different configuration values:
$ http -b localhost:5050/configprops { "message": "Ratpack swings!", "serverName": "cloud", "serverPort": 80 }
Written with Ratpack 1.3.3.