Loading...

Monday, April 27, 2015

Grails Goodness: Custom Data Binding with @DataBinding Annotation

Grails has a data binding mechanism that will convert request parameters to properties of an object of different types. We can customize the default data binding in different ways. One of them is using the @DataBinding annotation. We use a closure as argument for the annotation in which we must return the converted value. We get two arguments, the first is the object the data binding is applied to and the second is the source with all original values of type SimpleMapDataBindingSource. The source could for example be a map like structure or the parameters of a request object.

In the next example code we have a Product class with a ProductId class. We write a custom data binding to convert the String value with the pattern {code}-{identifier} to a ProductId object:

package mrhaki.grails.binding

import grails.databinding.BindUsing

class Product {

    // Use custom data binding with @BindUsing annotation.
    @BindUsing({ product, source ->

        // Source parameter contains the original values.
        final String productId = source['productId']

        // ID format is like {code}-{identifier},
        // eg. TOYS-067e6162.
        final productIdParts = productId.split('-')

        // Closure must return the actual for 
        // the property.
        new ProductId(
            code: productIdParts[0],
            identifier: productIdParts[1])

    })
    ProductId productId

    String name

}

// Class for product identifier.
class ProductId {
    String code
    String identifier
}

The following specification shows the data binding in action:

package mrhaki.grails.binding

import grails.test.mixin.TestMixin
import grails.test.mixin.support.GrailsUnitTestMixin
import spock.lang.Specification
import grails.databinding.SimpleMapDataBindingSource

@TestMixin(GrailsUnitTestMixin)
class ProductSpec extends Specification {

    def dataBinder

    def setup() {
        // Use Grails data binding
        dataBinder = applicationContext.getBean('grailsWebDataBinder')
    }

    void "productId parameter should be converted to a valid ProductId object"() {
        given:
        final Product product = new Product()

        and:
        final SimpleMapDataBindingSource source = 
            [productId: 'OFFCSPC-103910ab24', name: 'Swingline Stapler']

        when:
        dataBinder.bind(product, source)

        then:
        with(product) {
            name == 'Swingline Stapler'

            with(productId) {
                identifier == '103910ab24'
                code == 'OFFCSPC'
            }
        }
    }

}

If we would have a controller with the request parameters productId=OFFCSPC-103910ab24&name=Swingline%20Stapler the data binding of Grails can create a Product instance and set the properties with the correct values.

Written with Grails 2.5.0 and 3.0.1.

Friday, April 24, 2015

Grails Goodness: Adding Health Check Indicators

With Grails 3 we also get Spring Boot Actuator. We can use Spring Boot Actuator to add some production-ready features for monitoring and managing our Grails application. One of the features is the addition of some endpoints with information about our application. By default we already have a /health endpoint when we start a Grails (3+) application. It gives back a JSON response with status UP. Let's expand this endpoint and add a disk space, database and url health check indicator.

We can set the application property endpoints.health.sensitive to false (securing these endpoints will be another blog post) and we automatically get a disk space health indicator. The default threshold is set to 10MB, so when the disk space is lower than 10MB the status is set to DOWN. The following snippet shows the change in the grails-app/conf/application.yml to set the property:

...
---
endpoints:
    health:
        sensitive: false
...

If we invoke the /health endpoint we get the following output:

{
    "status": "UP",
    "diskSpace": {
        "status": "UP",
        "free": 97169154048,
        "threshold": 10485760
    }
}

If we want to change the threshold we can create a Spring bean of type DiskSpaceHealthIndicatorProperties and name diskSpaceHealthIndicatorProperties to override the default bean. Since Grails 3 we can override doWithSpring method in the Application class to define Spring beans:

package healthcheck

import grails.boot.GrailsApp
import grails.boot.config.GrailsAutoConfiguration
import org.springframework.boot.actuate.health.DiskSpaceHealthIndicatorProperties

class Application extends GrailsAutoConfiguration {

    static void main(String[] args) {
        GrailsApp.run(Application)
    }

    @Override
    Closure doWithSpring() {
        { ->
            diskSpaceHealthIndicatorProperties(DiskSpaceHealthIndicatorProperties) {
                // Set threshold to 250MB.
                threshold = 250 * 1024 * 1024
            }
        }
    }
}

Spring Boot Actuator already contains implementations for checking SQL databases, Mongo, Redis, Solr and RabbitMQ. We can activate those when we add them as Spring beans to our application context. Then they are automatically picked up and added to the results of the /health endpoint. In the following example we create a Spring bean databaseHealth of type DataSourceHealthIndicator:

package healthcheck

import grails.boot.GrailsApp
import grails.boot.config.GrailsAutoConfiguration
import org.springframework.boot.actuate.health.DataSourceHealthIndicator
import org.springframework.boot.actuate.health.DiskSpaceHealthIndicatorProperties

class Application extends GrailsAutoConfiguration {

    static void main(String[] args) {
        GrailsApp.run(Application)
    }

    @Override
    Closure doWithSpring() {
        { ->
            // Configure data source health indicator based
            // on the dataSource in the application context.
            databaseHealthCheck(DataSourceHealthIndicator, dataSource)

            diskSpaceHealthIndicatorProperties(DiskSpaceHealthIndicatorProperties) {
                threshold = 250 * 1024 * 1024
            }
        }
    }
}

To create our own health indicator class we must implement the HealthIndicator interface. The easiest way is to extend the AbstractHealthIndicator class and override the method doHealthCheck. It might be nice to have a health indicator that can check if a URL is reachable. For example if we need to access a REST API reachable through HTTP in our application we can check if it is available.

package healthcheck

import org.springframework.boot.actuate.health.AbstractHealthIndicator
import org.springframework.boot.actuate.health.Health

class UrlHealthIndicator extends AbstractHealthIndicator {

    private final String url

    private final int timeout

    UrlHealthIndicator(final String url, final int timeout = 10 * 1000) {
        this.url = url
        this.timeout = timeout
    }

    @Override
    protected void doHealthCheck(Health.Builder builder) throws Exception {
        final HttpURLConnection urlConnection =
                (HttpURLConnection) url.toURL().openConnection()

        final int responseCode =
                urlConnection.with {
                    requestMethod = 'HEAD'
                    readTimeout = timeout
                    connectTimeout = timeout
                    connect()
                    responseCode
                }

        // If code in 200 to 399 range everything is fine.
        responseCode in (200..399) ?
                builder.up() :
                builder.down(
                        new Exception(
                                "Invalid responseCode '${responseCode}' checking '${url}'."))
    }
}

In our Application class we create a Spring bean for this health indicator so it is picked up by the Spring Boot Actuator code:

package healthcheck

import grails.boot.GrailsApp
import grails.boot.config.GrailsAutoConfiguration
import org.springframework.boot.actuate.health.DataSourceHealthIndicator
import org.springframework.boot.actuate.health.DiskSpaceHealthIndicatorProperties

class Application extends GrailsAutoConfiguration {

    static void main(String[] args) {
        GrailsApp.run(Application)
    }

    @Override
    Closure doWithSpring() {
        { ->
            // Create instance for URL health indicator.
            urlHealthCheck(UrlHealthIndicator, 'http://intranet', 2000)

            databaseHealthCheck(DataSourceHealthIndicator, dataSource)

            diskSpaceHealthIndicatorProperties(DiskSpaceHealthIndicatorProperties) {
                threshold = 250 * 1024 * 1024
            }
        }
    }
}

Now when we run our Grails application and access the /health endpoint we get the following JSON:

{
    "status": "DOWN",
    "urlHealthCheck": {
        "status": "DOWN"
        "error": "java.net.UnknownHostException: intranet",
    },
    "databaseHealthCheck": {
        "status": "UP"
        "database": "H2",
        "hello": 1,
    },
    "diskSpace": {
        "status": "UP",
        "free": 96622411776,
        "threshold": 262144000
    },
}

Notice that the URL health check fails so the complete status is set to DOWN.

Written with Grails 3.0.1.

Thursday, April 23, 2015

Grails Goodness: Log Startup Info

We can let Grails log some extra information when the application starts. Like the process ID (PID) of the application and on which machine the application starts. And the time needed to start the application. The GrailsApp class has a property logStartupInfo which is true by default. If the property is true than some extra lines are logged at INFO and DEBUG level of the logger of our Application class.

So in order to see this information we must configure our logging in the logback.groovy file. Suppose our Application class is in the package mrhaki.grails.sample.Application then we add the following line to see the output of the startup logging on the console:

...
logger 'mrhaki.grails.sample.Application', DEBUG, ['STDOUT'], false
...

When we run our Grails application we see the following in our console:

...
INFO mrhaki.grails.sample.Application - Starting Application on mrhaki-jdriven.local with PID 20948 (/Users/mrhaki/Projects/blog/posts/sample/build/classes/main started by mrhaki in /Users/mrhaki/Projects/mrhaki.com/blog/posts/sample/)
DEBUG mrhaki.grails.sample.Application - Running with Spring Boot v1.2.3.RELEASE, Spring v4.1.6.RELEASE
INFO mrhaki.grails.sample.Application - Started Application in 8.29 seconds (JVM running for 9.906)
Grails application running at http://localhost:8080
...

If we want to add some extra logging we can override the logStartupInfo method:

package mrhaki.grails.sample

import grails.boot.GrailsApp
import grails.boot.config.GrailsAutoConfiguration
import grails.util.*
import groovy.transform.InheritConstructors

class Application extends GrailsAutoConfiguration {

    static void main(String[] args) {
        // Use extended GrailsApp to run.
        new StartupGrailsApp(Application).run(args)
    }

}

@InheritConstructors
class StartupGrailsApp extends GrailsApp {
    @Override
    protected void logStartupInfo(boolean isRoot) {
        // Show default info.
        super.logStartupInfo(isRoot)

        // And add some extra logging information.
        // We use the same logger if we get the
        // applicationLog property.
        if (applicationLog.debugEnabled) {
            final metaInfo = Metadata.getCurrent()
            final String grailsVersion = GrailsUtil.grailsVersion
            applicationLog.debug "Running with Grails v${grailsVersion}"

            final sysprops = System.properties
            applicationLog.debug "Running on ${sysprops.'os.name'} v${sysprops.'os.version'}"
        }
    }
}

If we run the application we see in the console:

...
DEBUG mrhaki.grails.sample.Application - Running with Spring Boot v1.2.3.RELEASE, Spring v4.1.6.RELEASE
DEBUG mrhaki.grails.sample.Application - Running with Grails v3.0.0
DEBUG mrhaki.grails.sample.Application - Running on Mac OS X v10.10.3
...

Written with Grails 3.0.1.

Wednesday, April 22, 2015

Grails Goodness: Save Application PID in File

Since Grails 3 we can borrow a lot of the Spring Boot features in our applications. If we look in our Application.groovy file that is created when we create a new Grails application we see the class GrailsApp. This class extends SpringApplication so we can use all the methods and properties of SpringApplication in our Grails application. Spring Boot and Grails comes with the class ApplicationPidFileWriter in the package org.springframework.boot.actuate.system. This class saves the application PID (Process ID) in a file application.pid when the application starts.

In the following example Application.groovy we create an instance of ApplicationPidFileWriter and register it with the GrailsApp:

package mrhaki.grails.sample

import grails.boot.GrailsApp
import grails.boot.config.GrailsAutoConfiguration
import org.springframework.boot.actuate.system.ApplicationPidFileWriter

class Application extends GrailsAutoConfiguration {

    static void main(String[] args) {
        final GrailsApp app = new GrailsApp(Application)

        // Register PID file writer.
        app.addListeners(new ApplicationPidFileWriter())

        app.run(args)
    }

}

So when we run our application a new file application.pid is created in the current directory and contains the PID:

$ grails run-app

From another console we read the contents of the file with the PID:

$ cat application.pid
20634
$

The default file name is application.pid, but we can use another name if we want to. We can use another constructor for the ApplicationPidFileWriter where we specify the file name. Or we can use a system property or environment variable with the name PIDFILE. But we can also set it with the configuration property spring.pidfile. We use the latest option in our Grails application. In the next example application.yml we set this property:

...
spring:
    pidfile: sample-app.pid
...

When we start our Grails application we get the file sample-app.pid with the application PID as contents.

Written with Grails 3.0.1.

Awesome Asciidoctor: Display Keyboard Shortcuts

When we want to explain in our documentation which keys a user must press to get to a function we can use the keyboard macro in Asciidoctor. The macro will output the key nicely formatted as a real key on the keyboard. The syntax of the macro is kbd:[key]. To get the desired output we must set the document attribute experimental otherwise the macro is not used.

In the next Asciidoctor example file we use the keyboard macro:

= Keyboard macro

With the keyboard macro `kbd:[shortcut]`
we can include nicely formatted keyboard
shortcuts.

// We must enable experimental attribute.
:experimental:

// Define unicode for Apple Command key.
:commandkey: &#89w84;

Press kbd:[{commandkey} + 1] or kbd:[Ctrl + 1] 
to access the _Project_ view.

To zoom out press kbd:[Ctrl + -].

Find files with kbd:[Ctrl + Alt + N] or kbd:[{commandkey} + Shift + N].

When we transform this to HTML with the built-in HTML5 templates we get the following output:

Written with Asciidoctor 1.5.2.

Gradle Goodness: Handle Copying Duplicate Files

In Gradle we can configure how duplicate files should be handled by the Copy task. Actually we can configure how duplicate files are handled by any task that implements the CopySpec interface. For example archive tasks also implements this interface. We must use the setDuplicatesStrategy method to configure how Gradle behaves. The parameter is a value of the enumeration DuplicatesStrategy. We can use the values from the enum class or use String values, which are automatically converted to enum DuplicatesStrategy values.

We can choose the following strategies:

  • include: default strategy where the last duplicate file 'wins'.
  • exclude: only the first found duplicate file is copied and 'wins'.
  • warn: shows a warning on the console, but the last duplicate file 'wins' like with the include strategy.
  • fail: the build fails where duplicate files are found.

The following build file create four task of type Copy, each with a different duplicate strategy. In the directories src/manual and src/website we have a file COPY.txt. The content is simply a text line respectively COPY from src/manual and COPY from src/website:

// For each duplicate strategy we create a copy task.
['warn', 'include', 'exclude', 'fail'].each { strategy ->
    task "copyDuplicatesStrategy${strategy.capitalize()}"(type: Copy) {
        from 'src/manual'
        from 'src/webroot'

        into "$buildDir/copy"

        // Only the value for this property differs for
        // each created task.
        duplicatesStrategy = strategy

        // Print the used duplicates strategy when 
        // the task starts.
        doFirst {
            println "Copying with duplicates strategy '${strategy}'."
        }

        // Print the contents of the copied file COPY.txt.
        doLast {
            println "Contents of COPY.txt:"
            println file("$buildDir/copy/COPY.txt").text
        }
    }
}

We can now invoke the four tasks and see how Gradle reacts:

$ gradle copyDuplicatesStrategyWarn
:copyDuplicatesStrategyWarn
Copying with duplicates strategy 'warn'.
Encountered duplicate path "COPY.txt" during copy operation configured with DuplicatesStrategy.WARN
Contents of COPY.txt:
COPY from src/webroot


BUILD SUCCESSFUL

Total time: 3.728 secs
$ gradle copyDuplicatesStrategyInclude
:copyDuplicatesStrategyInclude
Copying with duplicates strategy 'include'.
Contents of COPY.txt:
COPY from src/webroot


BUILD SUCCESSFUL

Total time: 2.744 secs
$ gradle copyDuplicatesStrategyExclude 
:copyDuplicatesStrategyExclude
Copying with duplicates strategy 'exclude'.
Contents of COPY.txt:
COPY from src/manual


BUILD SUCCESSFUL

Total time: 2.784 secs
$ gradle copyDuplicatesStrategyFail
:copyDuplicatesStrategyFail
Copying with duplicates strategy 'fail'.
:copyDuplicatesStrategyFail FAILED

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':copyDuplicatesStrategyFail'.
> Encountered duplicate path "COPY.txt" during copy operation configured with DuplicatesStrategy.FAIL

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output.

BUILD FAILED

Total time: 2.786 secs

Written with Gradle 2.3.

Gradle Goodness: Use Git Commit Id in Build Script

The nice thing about Gradle is that we can use Java libraries in our build script. This way we can add extra functionality to our build script in an easy way. We must use the classpath dependency configuration for our build script to include the library. For example we can include the library Grgit, which provides an easy way to interact with Git from Java or Groovy code. This library is also the basis for the Gradle Git plugin.

In the next example build file we add the Grgit library to our build script classpath. Then we use the open method of the Grgit class. From the returned object we invoke the head to get the commit id identified as id. With the abbreviatedId property we get the shorter version of the Git commit id. The build file also includes the application plugin. We customize the applicationDistribution CopySpec from the plugin and expand the properties in a VERSION file. This way our distribution always includes a plain text file VERSION with the Git commit id of the code.

buildscript {

    repositories {
        jcenter()
    }

    dependencies {
        // Add dependency for build script,
        // so we can access Git from our
        // build script.
        classpath 'org.ajoberstar:grgit:1.1.0'
    }

}

apply plugin: 'java'
apply plugin: 'application'

ext {
    // Open the Git repository in the current directory.
    git = org.ajoberstar.grgit.Grgit.open(file('.'))

    // Get commit id of HEAD.
    revision = git.head().id
    // Alternative is using abbreviatedId of head() method.
    // revision = git.head().abbreviatedId
}

// Use abbreviatedId commit id in the version.
version = "2.0.1.${git.head().abbreviatedId}"

// application plugin extension properties.
mainClassName = 'sample.Hello'
applicationName = 'sample'

// Customize applicationDistribution
// CopySpec from application plugin extension.
applicationDistribution.with {
    from('src/dist') {
        include 'VERSION'
        expand(
            buildDate: new Date(), 
            // Use revision with Git commit id:
            revision : revision,
            version  : project.version,
            appName  : applicationName)
    }
}

// Contents for src/dist/VERSION:
/*
Version: ${version}
Revision: ${revision}
Build-date: ${buildDate.format('dd-MM-yyyy HH:mm:ss')}
Application-name: ${appName}
*/

assemble.dependsOn installDist

When we run the build task for our project we get the following contents in our VERSION file:

Version: 2.0.1.e2ab261
Revision: e2ab2614011ff4be18c03e4dc1f86ab9ec565e6c
Build-date: 22-04-2015 13:53:31
Application-name: sample

Written with Gradle 2.3.

Monday, April 20, 2015

Awesome Asciidoctor: Adding Custom Content to Head and Footer

When we convert our Asciidoctor markup to HTML we automatically get a head and footer element. We can add custom content to the HTML head element and to the HTML div with id footer. We must set a document attribute and create the files that contain the HTML that needs to be added to the head or footer. We have three different document attributes we can set to include the custom content files:

  • :docinfo: include document specific content. Files to be included must be named <docname>-docinfo.html for head element and <docname>-docinfo-footer.html for footer content.
  • :docinfo1: include general custom content. Files to be included must be named docinfo.htmtl for head element and docinfo-footer.html for footer content.
  • :docinfo2: include document specific and general custom content. Files to be included must be named <docname>-docinfo.html and docinfo.html for head element and <docname>-docinfo-footer.html and docinfo-footer.html for footer content.

In this sample we create the files docinfo.html and docinfo-footer.html we want to include in the generated output from the following Asciidoctor source file:

= Asciidoctor custom header and footer
Hubert A. Klein Ikkink
// Document specific and general custom
// content files are used:
:docinfo2: 
// Include general custom content files:
//:docinfo1:
// Include document specific content files:
//:docinfo:
// In generated HTML this is transformed
// to <meta name="description" content="..."/>
:description: Sample document with custom header and footer parts.
// In generated HTML this is transformed
// to <meta name="keywords" content="..."/>
:keywords: Asciidoctor, header, footer, docinfo

Using the `docinfo` attributes we can include custom content
in the header and footer. Contents of the files 
named `docinfo.html` and `docinfo-footer.html` are included.

We can choose between general or document specific custom
header and footer content.

Our docinfo.html looks like this:

<!-- Change some CSS. -->
<style>
/* Change CSS overflow for table of contents. */
#toc.toc2, #toc { overflow: scroll; }

/* Change styling for footer text. */
.footer-text { color: rgba(255,255,255,.8); }
</style>

<!-- We could also include Javascript 
     for example in this document. -->

For the custom footer we create the file docinfo-footer.html:

<p class="footer-text">
<!-- We can use document attributes: -->
Generated with Asciidoctor v{asciidoctor-version}.
</p>

The following screenshot shows the generated HTML page:

And here is part of the generated head element:

<head>

...

<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="generator" content="Asciidoctor 1.5.2">
<meta name="description" content="Sample document with custom header and footer parts.">
<meta name="keywords" content="Asciidoctor, header, footer, docinfo">
<meta name="author" content="Hubert A. Klein Ikkink">
<title>Asciidoctor custom header and footer</title>

...

<!-- Change some CSS. -->
<style>
/* Change CSS overflow for table of contents. */
#toc.toc2, #toc { overflow: scroll; }

/* Change styling for footer text. */
.footer-text { color: rgba(255,255,255,.8); }
</style>

<!-- We could also include Javascript
     for example in this document. -->
</head>

Written with Asciidoctor 1.5.2.

Sunday, April 19, 2015

Gradle Goodness: Alter Start Scripts from Application Plugin

For Java or Groovy projects we can use the application plugin in Gradle to run and package our application. The plugin adds for example the startScripts task which creates OS specific scripts to run the project as a JVM application. This task is then used again by the installDist that installs the application, and distZip and distTar tasks that create a distributable archive of the application. The startScripts tasks has the properties unixScript and windowsScript that are the actual OS specific script files to run the application. We can use these properties to change the contents of the files.

In the following sample we add the directory configuration to the CLASSPATH definition:

...
startScripts {

    // Support closures to add an additional element to 
    // CLASSPATH definition in the start script files.
    def configureClasspathVar = { findClasspath, pathSeparator, line ->

        // Looking for the line that starts with either CLASSPATH=
        // or set CLASSPATH=, defined by the findClasspath closure argument.
        line = line.replaceAll(~/^${findClasspath}=.*$/) { original ->

            // Get original line and append it 
            // with the configuration directory.
            // Use specified path separator, which is different
            // for Windows or Unix systems.
            original += "${pathSeparator}configuration"
        }

    }

    def configureUnixClasspath = configureClasspathVar.curry('CLASSPATH', ':')
    def configureWindowsClasspath = configureClasspathVar.curry('set CLASSPATH', ';')

    // The default script content is generated and
    // with the doLast method we can still alter
    // the contents before the complete task ends.
    doLast {

        // Alter the start script for Unix systems.
        unixScript.text = 
            unixScript
                .readLines()
                .collect(configureUnixClasspath)
                .join('\n')

        // Alter the start script for Windows systems.
        windowsScript.text = 
            windowsScript
                .readLines()
                .collect(configureWindowsClasspath)
                .join('\r\n')

    }

}
...

This post was inspired by the Gradle build file I saw at the Gaiden project.

Written with Gradle 2.3.

Friday, April 17, 2015

Spring Sweets: Using @Value for Constructor Arguments

In Spring we can use the @Value annotation to set property or arguments values based on a SpEL expression. If we want to use the @Value annotation for a constructor argument we must not forget to add the @Autowired annotation on the constructor as well.

// File: sample/Message.groovy
package sample

import org.springframework.beans.factory.annotation.*
import org.springframework.stereotype.*

@Component
class Message {

    final String text

    // Use @Autowired to get @Value to work.
    @Autowired
    Message(
        // Refer to configuration property
        // app.message.text to set value for 
        // constructor argument text.
        @Value('${app.message.text}') final String text) {
        this.text = text
    }

}

Written with Spring 4.1.6.