Ratpacked: Apply Configuration To Configurable Module
In Ratpack we can use Guice modules to organise code to provide objects to the registry. Ratpack adds configurable modules that take an extra configuration object. Values from the configuration object are used to create new objects that are provided to our application. Using the Groovy DSL we have several ways to make a configuration object available to a configurable module.
Let's create a sample configurable module and look at the different ways to give it a configuration object. We create a module, GreetingModule
, that provides a Greeting
object. The configuration is defined in the class GreetingConfig
.
// File: src/main/groovy/com/mrhaki/ratpack/GreetingModule.groovy
package com.mrhaki.ratpack
import com.google.inject.Provides
import groovy.transform.CompileStatic
import ratpack.guice.ConfigurableModule
@CompileStatic
class GreetingModule extends ConfigurableModule {
@Override
protected void configure() {}
/**
* Method to create a new Greeting object with values
* from the GreetingConfig configuration object.
*/
@Provides
Greeting greeting(final GreetingConfig config) {
new Greeting(message: "${config.salutation}, ${config.message}")
}
}
// File: src/main/groovy/com/mrhaki/ratpack/GreetingConfig.groovy
package com.mrhaki.ratpack
import groovy.transform.CompileStatic
/**
* Configuration properties for creating
* a {@link Greeting} object using the
* configurable module {@link GreetingModule}.
*/
@CompileStatic
class GreetingConfig {
String message
String salutation
}
// File: src/main/groovy/com/mrhaki/ratpack/Greeting.groovy
package com.mrhaki.ratpack
import groovy.transform.CompileStatic
/**
* Simple class with a greeting message.
* The {@link GreetingModule} module creates
* an instance of this class.
*/
@CompileStatic
class Greeting {
String message
}
We have our configurable module and the supporting classes. Now we define the configuration and module in the bindings
block of our Ratpack Groovy application. We use the ConfigData
class to set configuration properties we later bind to the GreetingConfig
object. With ConfigData
we can define configuration properties from different sources, like files in Yaml, JSON or Java properties format. In our sample we simply define them using a Map
. In the first sample we use the module
method with a Closure
argument to configure the GreetingModule
// File: src/ratpack/Ratpack.groovy
import com.mrhaki.ratpack.Greeting
import com.mrhaki.ratpack.GreetingConfig
import com.mrhaki.ratpack.GreetingModule
import ratpack.config.ConfigData
import ratpack.config.ConfigDataBuilder
import static ratpack.groovy.Groovy.ratpack
ratpack {
bindings {
final ConfigData configData = ConfigData.of { ConfigDataBuilder builder ->
builder.props(
['greeting.salutation': 'Hi',
'greeting.message' : 'how are you doing?'])
// We can also use external files,
// system properties and environment
// variables to set configuration properties
// inside this block.
builder.build()
}
// The module methods allows a Closure argument to
// set values for the supported configuration class.
module GreetingModule, { GreetingConfig config ->
config.salutation = configData.get('/greeting/salutation', String)
config.message = configData.get('/greeting/message', String)
}
}
handlers {
// Simple handler using the created Greeting object.
get { Greeting greeting ->
render greeting.message
}
}
}
In the following sample we create an instance of GreetingConfig
using the bindInstance
method. The GreetingModule
will pick up this instance and use it automatically:
// File: src/ratpack/Ratpack.groovy
import com.mrhaki.ratpack.Greeting
import com.mrhaki.ratpack.GreetingConfig
import com.mrhaki.ratpack.GreetingModule
import ratpack.config.ConfigData
import ratpack.config.ConfigDataBuilder
import static ratpack.groovy.Groovy.ratpack
ratpack {
bindings {
final ConfigData configData = ConfigData.of { ConfigDataBuilder builder ->
builder.props(
['greeting.salutation': 'Hi',
'greeting.message' : 'how are you doing?'])
// We can also use external files,
// system properties and environment
// variables to set configuration properties
// inside this block.
builder.build()
}
// First create an instance of the GreetingConfig class.
bindInstance GreetingConfig, configData.get('/greeting', GreetingConfig)
// With the module method we use the GreetingModule and
// because there is a GreetingConfig instance available
// it is used to configure the module.
module GreetingModule
}
handlers {
// Simple handler using the created Greeting object.
get { Greeting greeting ->
render greeting.message
}
}
}
Finally we can use the moduleConfig
method. This methods accepts a configuration object as an argument directly. So we can use an instance of GreetingConfig
as method argument. We can also combine it with a Closure
argument to override configuration properties:
// File: src/ratpack/Ratpack.groovy
import com.mrhaki.ratpack.Greeting
import com.mrhaki.ratpack.GreetingConfig
import com.mrhaki.ratpack.GreetingModule
import ratpack.config.ConfigData
import ratpack.config.ConfigDataBuilder
import static ratpack.groovy.Groovy.ratpack
ratpack {
bindings {
final ConfigData configData = ConfigData.of { ConfigDataBuilder builder ->
builder.props(
['greeting.salutation': 'Hi',
'greeting.message' : 'how are you doing?'])
// We can also use external files,
// system properties and environment
// variables to set configuration properties
// inside this block.
builder.build()
}
// With the moduleConfig method we can pass an instance
// of GreetingConfig directly.
moduleConfig GreetingModule, configData.get('/greeting', GreetingConfig)
// Or we can even combine it with a Closure argument to override a
// configuration property.
//moduleConfig(
// GreetingModule,
// configData.get('/greeting', GreetingConfig)) { GreetingConfig config ->
// config.message = 'Ratpack rocks!'
//}
}
handlers {
// Simple handler using the created Greeting object.
get { Greeting greeting ->
render greeting.message
}
}
}
Written with Ratpack 1.1.1.