In a previous post we learned how to use the NamedDomainObjectContainer
class. We could create new objects using a nice DSL in Gradle. But what if we want to use DSL syntax to create objects within objects? We can use the same mechanism to achieve this by nesting NamedDomainObjectContainer
objects.
We want to support the following DSL to create a collection of Server
objects, where each server can have multiple Node
objects:
Continue reading →
Interesting links for week 7 2016:
Continue reading →
Gradle offers the NamedDomainObjectContainer
class to create a collection of objects defined using a clean DSL. The only requirement for the objects we want to create is that they have a constructor that takes a String
argument and a name
property to identify the object. The value for the name
property must be unique within the collection of objects. We create a new instance of a NamedDomainObjectContainer
with the container
method of the Gradle Project
class. We can add the NamedDomainObjectContainer
instance to the extensions
property of our project
, so we can use a DSL to create instances of objects that need to be in the NamedDomainObjectContainer
object in our project.
The following code shows a simple build script in which we want to create a collection of Product
objects. The creation of the NamedDomainObjectContainer
object is done in a plugin so we only have to apply the plugin to use the DSL to create Product
objects:
Continue reading →
When we want to debug our Ratpack application written in Java we can simply use the Debug action on the main application class. When we described the application with the Groovy DSL we must add a Groovy runtime configuration to our project in IntelliJ IDEA to support debugging of the (R|r)atpack.groovy
script file.
First we select Run | Edit configurations.... IntelliJ IDEA opens a new dialog window where we can add or modify run/debug configurations. We select the option New configuration and choose the option Groovy:
Continue reading →
It is actually very easy to run a Ratpack application in the Groovy Console. The Groovy Console is a GUI application that is distributed with Groovy and allows us to write and run Groovy scripts. We start the Groovy Console with the groovyConsole
command: $ groovyConsole
. To run a Ratpack application we only have to add a dependency to Ratpack using the @Grab
annotation. We can write an application with the Groovy DSL and select Script | Run from the menu. If we make a change in the script file we invoke the Run command again. The Ratpack application restarts with our changes. This is very useful for trying out some Ratpack features without much hassle.
The following screenshot shows a simple Ratpack application. At the bottom we see the logging output of the running application:
Continue reading →
Interesting links for week 6 2016:
Continue reading →
To set the base directory for serving static files in a Ratpack application we can use the baseDir
method of the ServerConfigBuilder
class. We must provide a Path
or File
to this method. If we want to serve files from the class path, for example a JAR file or directory, we can use the find
method of the class BaseDir
. The find
method will search the class path for a marker file with the name .ratpack
. If the file is found then the directory or JAR file it is found in is used as the root of the file system. Normally the root of the class path is searched, but we can change the search path with an argument for the find
method.
In the following sample Ratpack application we use the value web-resources/.ratpack.base.dir
for the BaseDir.find
method. So in our class path we must have a web-resources
directory with the file .ratpack.base.dir
that will serve as the root file system for serving static files.
Continue reading →
Since Gradle 2.11 we can specify the test framework to use when we initialise a project with the init
task. There is a new option for this task: --test-framework
. By default JUnit dependencies are added, but if we specify the value spock
the Spock libraries are included in the dependencies section of our build.gradle
file.
Let's run the init
task to create a Java project with Spock as test framework:
Continue reading →
In a previous post we have seen how to execute a Groovy script in our source directories. But what if we want to use the Groovy command line to execute a Groovy script? Suppose we want to evaluate a small Groovy script expressed by a String value, that we normally would invoke like $ groovy -e "println 'Hello Groovy!'"
. Or we want to use the command line option -l
to start Groovy in listening mode with a script to handle requests. We can achieve this by creating a task with type JavaExec
or by using the Gradle javaexec
method. We must set the Java main class to groovy.ui.Main
which is the class that is used for running the Groovy command line.
In the following sample build file we create a new task runGroovyScript
of type JavaExec
. We also create a new dependency configuration groovyScript
so we can use a separate class path for running our Groovy scripts.
Continue reading →
When we use the Context.render
method Ratpack's rendering mechanism kicks in. The type of the argument we pass to the render
method is used to look up the correct renderer. The renderer implements the Renderer
interface and provides the real output. We can add functionality that can work with the object of the Renderer
implementation before the actual output is created. We do this by adding a class or object to the registry that implements the RenderableDecorator
interface. The interface has a method decorate
that accepts the Context
and object that needs to be rendered. The code is invoked after the Context.render
method, but before the Renderer.render
method. This is especially useful when we use template renderers with a view model and with a RenderableDecorator
implementation we can augment the view model with some general attributes. Suppose we have a Ratpack application that uses the Groovy text template engine provided by the TextTemplateModule
. The module adds a Renderer
for TextTemplate
objects. Let's write a RenderableDecorator
implementation for the TextTemplate
, where we add an extra attribute createdOn
to the view model:
// File: src/main/groovy/com/mrhaki/ratpack/CreatedOnRendererDecorator.groovy
package com.mrhaki.ratpack
import ratpack.exec.Promise
import ratpack.groovy.template.TextTemplate
import ratpack.handling.Context
import ratpack.render.RenderableDecorator
import java.time.Clock
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
/**
* Add extra attribute to view model for all TextTemplate renderers.
*/
class CreatedOnRendererDecorator implements RenderableDecorator {
/**
* Apply this decorator for TextTemplate renderers.
*
* @return TextTemplate class.
*/
@Override
Class getType() {
return TextTemplate
}
/**
* Add an extra attribute createdOn to the view model with the current
* date and time.
*
* @param context Context to get Clock instance for this Ratpack application from.
* @param template Template with view model to extend.
* @return Promise with new TextTemplate instance with the extended view model.
*/
@Override
Promise decorate(final Context context, final TextTemplate template) {
final footerModel = [createdOn: createdOn(context)]
return Promise.value(
new TextTemplate(
template.model + footerModel,
template.id,
template.type))
}
/**
* Create formatted date/time String based on
* the Clock available on the Ratpack registry.
*
* @param context Context to get Clock instance from.
* @return Formatted date/time String.
*/
private String createdOn(final Context context) {
final Clock clock = context.get(Clock)
final LocalDateTime now = LocalDateTime.now(clock)
final DateTimeFormatter formatter =
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
return formatter.format(now)
}
}
Continue reading →
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.
Continue reading →
In a previous post we learned about the get
and getAll
methods to get objects from the registry. Ratpack also provides the first
method to get objects from the registry. This method accepts a Function
that is applied to the elements of a given type. The first element where the Function
returns a non null value is returned encapsulated in an Optional
object. If the Function
returns a null value for all elements than Optional.empty()
is returned.
package com.mrhaki.ratpack
import ratpack.registry.Registry
import ratpack.registry.RegistrySpec
import spock.lang.Specification
class FindFirstRegistrySpec extends Specification {
Registry registry
def setup() {
// Setup registry with two objects of type User.
registry = Registry.of { RegistrySpec registrySpec ->
registrySpec.add(new User(username: 'mrhaki'))
registrySpec.add('hubert')
registrySpec.add(new User(username: 'hubert'))
registrySpec.add('mrhaki')
}
}
def "find User where username starts with mr"() {
when:
// First element that returns a non null value
// is return encapsulated in an Optional.
final Optional user = registry.first(User) { user ->
// If username property starts with
// "mr" than return user as non null value.
user.username.startsWith("mr") ? user : null
}
then:
user.get().username == 'mrhaki'
}
}
Continue reading →