Blog JVM Stuff.

Grails - Java-Based Configuration

Spring 3.0 introduced an interesting alternative to XML file-based Spring container configuration. After Spring 2.5 already introduced the annotation-based configuration, it added a new way to configure the Spring bean container: via java-based configuration (the SpringConfig project was taken included in the Spring framework).

Java-Based Configuration

As its name implies, Java-based Spring container configuration is about using Java code instead of XML or annotations to configure Spring beans. This way reminds of Google Guice, a dependency injection framework solely using Java code to setup the dependency injection components. In Spring, the org.springframework.context.annotation package holds the following annotations that can be used as an alternative to XML files to annotate certain classes as Spring context configuration classes:

  • @Configuration

The @Configuration class indicates that a class is defining multiple methods creating Spring-managed beans. The @Configuration class needs to be found by the annotation processing configuration. We will have a look how that can be configured in a Grails application.

  • @Bean

The @Bean annotation is mainly applied on methods (although it can be applied on annotation types too). It indicates that a method returns a bean manager by the Spring application container. The default strategy for the bean name is to use the name of the bean generating method.

  • @ComponentScan

The @ComponentScan annotation can be applied on @Configuation classes to configure component scanning for certain Java packages or classes.

  • @DependsOn

The @DependsOn annotation can be used to indicate that a bean depends on the creation of other beans. It defines a happens-before relationship in terms of the container-managed order of bean creations.

  • @Import

The @Import annotation can be used to import @Configuration classes into the annotated class. It resembles the <beans:import/> XML tag.

  • @ImportResource

The @ImportResource annotation can be used to import bean definitions into the current @Configuration class.

  • @Lazy

The @Lazy anntotation indicates a bean has to be created by the Spring container in a lazy manner.

  • @Profile

The @Profile annotation can be used to annotate @Configuration classes for certain profiles. The current profile can be set by using a VM argument or programatically by calling the ConfigurableEnvironment.setActiveProfiles(String ...) method.

  • @PropertySource

The @PropertySource adds property files to the current Spring environment.

  • @Scope

The @Scope annotation indicates the bean scope the bean is created in.

Now let's have a look at how Java-based Spring configuration can be used in a Grails application.

Enabling Java-Based Configs

Let's assume we have a package my.app.config that holds all configuration classes. In a Grails application we need to add this packacke in Config.groovy to the grails.spring.bean.packages bean scanning path list.


grails.spring.bean.packages = ['my.app.config']

VoilĂ , now we can use the annotations described above inside the my.app.config package. The classes can either be implemented as Groovy or Java classes.

The Java-based Spring configuration can even be used in a mixed-mode: there can still be a resources.groovy or a resources.xml or more Spring configuration files in the grails-app/conf/spring directory, the Spring bean container will merge and resolve the bean definitions from the various sources.

Configuration Example

The Spring Reactor project comes with a pretty neat AsyncTaskExecutor implementation that uses the LMAX Disruptor library under the hoods. If we wanted to use the reactor.spring.core.task.WorkQueueAsyncTaskExecutor from Reactors Spring module, we can do so by defining a Java-based bean configuration.

In the case of the Reactor project, we're already provided with a pre-defined configuration annotation from the Reactor project that we have to use additionally on our @Configuration class: the @EnableReactor annotation.

The @EnableRector annotation uses the @Import annotation to import a default configuration into our @Configuration class:


@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(ReactorBeanDefinitionRegistrar.class)
public @interface EnableReactor {
    // ...
}

The ReactorBeanDefinitionRegistrar uses another cool feature of the Java-based Spring configuration. It implements the o.s.context.annotation.ImportBeanDefinitionRegistrar interface to register beans in the current application context if not already defined by the user configuration.


public class ReactorBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {

  private static final String DEFAULT_ENV_NAME = "reactorEnv";

  @Override
  public void registerBeanDefinitions(AnnotationMetadata meta, BeanDefinitionRegistry registry) {
    Map attrs = meta.getAnnotationAttributes(EnableReactor.class.getName());

    // Create a root Enivronment
    if (!registry.containsBeanDefinition(DEFAULT_ENV_NAME)) {
      ...
      registry.registerBeanDefinition(DEFAULT_ENV_NAME, envBeanDef.getBeanDefinition());
    }
  }
}

The ImportBeanDefinitionRegistrar implementation can be used along @Configuration classes as annotation parameters for the @Import annotation in our configuration class:


@Configuration
@EnableReactor
class ReactorConfiguration {

}

To add a WorkQueueAsyncTaskExecutor bean to this configuration we simply have to provide a @Bean annotated method:


@Configuration
@EnableReactor
class ReactorConfiguration {

  @Bean
  AsyncTaskExecutor taskExecutor(Environment env) {
    return new WorkQueueAsyncTaskExecutor(env)
      .setName("workQueueAsyncTaskExecutor")
      .setBacklog(2048)
      .setProducerType(ProducerType.MULTI)
      .setWaitStrategy(new SleepingWaitStrategy()) 
  }
}

Since the method is named taskExecutor our bean has the same name. And of course, we could use arbitrary Java code to initialize our bean. Once defined, we can refer to taskExecutor in every configuration artefact of our application, let it be resources.groovy, resources.xml or any other configuration files.

Please don't confuse the Environment parameter with the org.springframework.core.env.Environment interface, the parameter is of type reactor.core.Environment and is injected automatically, after being created by the @EnableRector annotation.

If we have a look at our code example above, we could decided to move all the builder method arguments to our app.properties file. We can use the @PropertySource configuration annotation to include this file in our current configuration:


@Configuration
@PropertySource('classpath:/my/app/config/app.properties')
@EnableReactor
class ReactorConfiguration {

  @Autowired
  Environment environment

  @Bean
  AsyncTaskExecutor taskExecutor(reactor.core.Environment env) {
    return new WorkQueueAsyncTaskExecutor(env)
      .setName(environment.getProperty("queue.name"))
      .setBacklog(environment.getProperty("queue.backlog", Integer.class))
      .setProducerType(ProducerType.MULTI)
      .setWaitStrategy(new SleepingWaitStrategy()) 
  }
}

As can be seen above, the queue.name and queue.backlog settings in the app.properties file can be accessed via the org.springframework.core.env.Environment bean. This bean needs to be autowired in our configuration to access the message resources. This shows another impressive feature of Spring's Java-based configuration: @Configuration classes are themselves treated as beans. This means we can use for example @Autowired to inject beans into our @Configuration class. The Spring documentation shows an even better example:


@Configuration
public class ServiceConfig {

  @Autowired
  private AccountRepository accountRepository;

  @Bean
  public TransferService transferService() {
    return new TransferServiceImpl(accountRepository);
  }
}

@Configuration
public class RepositoryConfig {

  @Autowired
  private DataSource dataSource;

  @Bean
  public AccountRepository accountRepository() {
    return new JdbcAccountRepository(dataSource);
  }
}

@Configuration
@Import({ServiceConfig.class, RepositoryConfig.class})
public class SystemTestConfig {

  @Bean
  public DataSource dataSource() {
    // return new DataSource
  }
}

public static void main(String[] args) {
  ApplicationContext ctx = new AnnotationConfigApplicationContext(SystemTestConfig.class);
  // everything wires up across configuration classes...
  TransferService transferService = ctx.getBean(TransferService.class);
  transferService.transfer(100.00, "A123", "C456");
}

We can even auto-wire @Configuration classes themselves:


@Configuration
public class ServiceConfig {

  @Autowired
  private RepositoryConfig repositoryConfig;

  @Bean
  public TransferService transferService() {
    // navigate through the config class to the @Bean method!
    return new TransferServiceImpl(repositoryConfig.accountRepository());
  }
}

These examples show that the Java-based configuration approach can provide us with much more modularity and reusability than using (the already mighty) Spring bean Groovy DSL which is, by the way, part of Spring 4. As every Grails application is a Spring application, we can use this approach to better structure application provided beans.

Conclusion

Spring 3 introduced another configuration approach besides the XML configuration files and annotation-based configuration: the so-called Java-based configuration. Spring provides a buch of annotations enabling to define beans in pure Java/Groovy code with even better modularity and reusability as can be found in Grails Spring DSL files. This article is an introduction to Java-based configuration and shows how to enable the mechanism in Grails applications.

Grails - Environments in BuildConfig

As of Grails 2.3 it is possible to use the Environment class everywhere in BuildConfig.groovy. This can be useful for environment-specific settings regarding all the configuration that can be done in BuildConfig.groovy including dependencies and plugins.

What's the deal?

Recently I came across an issue with the UI performance plugin (like mentioned by someone on the Grails user list) where we needed to exclude dependencies to be only used in the test environment. Before Grails 2.3.x it was only possible to use the Environment class inside the dependencies or plugins closure:



dependencies {
    
    // ...

    if (Environment.current != Environment.PRODUCTION)  {
        test "org.gebish:geb-junit4:0.9.2"
        test "org.seleniumhq.selenium:selenium-support:2.39.0"
        test "org.seleniumhq.selenium:selenium-firefox-driver:2.39.0"
        test "org.seleniumhq.selenium:selenium-chrome-driver:2.39.0"
    }
}

plugins {
    
    // ...

    test ":spock:0.7"
    test(":cucumber:0.10.0") {
        exclude "spock-core"
    }

    test ":code-coverage:1.2.7"
    test ":geb:0.9.2"
}

This little trick was possible because the closure was evaluated at a point of time where the Environment already had been initialized. Something along the lines of


grails.server.port.http = 8080

Environment.executeForEnvironment(Environment.DEVELOPMENT)  {
    grails.server.port.http = 8082  
}

wouldn't have been successful caused by the Environment class not being initialized at runtime.

This behaviour has been fixed in Grails 2.3, the BuildConfig DSL has even been extended to support the environments block feature. We can use it to specify environment-specific dependencies blocks or other BuildConfig configuration settings:


environments {
    test {
        dependencies {
            test "org.gebish:geb-junit4:0.9.2"
            test "org.seleniumhq.selenium:selenium-support:2.39.0"
            test "org.seleniumhq.selenium:selenium-firefox-driver:2.39.0"
            test "org.seleniumhq.selenium:selenium-chrome-driver:2.39.0"
        }
    }
}

Conclusion

Before 2.3.x the Environment could only be used restrictively in BuildConfig.groovy. With 2.3.x this issue has been fixed and support for the environments block has been added to the BuildConfig DSL.

Grails Quick Tip - Cleaning Up

Mr. Haki, once again, wrote a really cool blog post about grails clean and how it can be configured to delete all or only certain generated files in the working directory.

When reading the blog post a trick came to my mind that was once mentioned by Burt Beckwith in his excellent book Programming Grails.

Burt said he often replaces the standard configuration in BuildConfig.groovy


grails.project.class.dir = "target/classes"
grails.project.test.class.dir = "target/test-classes"
grails.project.test.reports.dir = "target/test-reports"

with


grails.project.work.dir = "target"

This has the advantage that all generated classes, including plugin-classes, are saved in a single directory. This is really cool as installed plugins would otherwise be saved and cached in the ~/.grails/ directory.

Grails Work Dir Target

Once things mess up and a clean state is needed, a simple rm -rf target gives us a completely zero state in terms of generated artefacts.

Grails Audit Logging

One of my projects needed a way to perform audit logging for Grails Hibernate domain classes. The audit log should contain at least the time and the property name and values that have been updated/inserted for a specific domain class.

I came across the Grails Audit-Loggin Plugin but unfortunately there were various reasons why the plugin wasn't a good fit for us:

  • configuration of the included fields was needed (instead of the excluded ones)
  • usage of Hibernate stateless sessions for writing the AuditLog domain objects (better performance)
  • some things seemed to be broken after writing the first integration tests, e.g. keeping the correct version number in the audit log
  • more object-oriented structure to enable encapsulated unit tests and easier writing of integration tests
  • last but not least: we wanted full control over the ongoing development of the plugin because the audit logging will be an important functionality of the application

In a nutshell: we started a new plugin that was initially based on the Grails Audit-Plugin to get some core components (like the AuditLogListener) without starting completely from scratch.

Grails Hibernate Audit Log Plugin

That's how we named the new plugin. Right now the audit log mechanism registers itself only by the hibernateDatastore, no other datastores are supported. Besides completely changing the interal structure of the plugin, we threw some features over board we hadn't any use for. We thought it would be better to keep it simple instead of preparing for complex scenarios we didn't see any use for in our application.

As the time of writing, the plugin supports the following configuration variables:


// All Hibernate audit log configuration variables
auditLog.disabled = false        // globally disable audit logging

// Defines how to retrieve the actor name - the name of the principal that will be persisted
auditLog.sessionAttribute = ""   // the session attribute under which the actor name is found
auditLog.actorKey = ""           // the request attribute key under which the actor name is found
auditLog.actorClosure = null     // a closure for getting the current actor name

auditLog.defaultInclude = []     // optional list of globally included properties
auditLog.defaultIgnore = []      // optional list of globally excluded properties

// audit log persistence settings
auditLog.tablename = null        // custom AuditLog table name, defaults to "audit_log"
auditLog.truncateLength = null   // maximum length for property values after String conversion

The auditLog.disabled switch is global one to turn off audit logging for the entire application. If it is false an additional step is needed to enable audit logging for a particular domain class:


class Person {

  static auditable = true

  String name
  String surName

  static constraints = {
  }
}

The domain class needs to have a static property auditable = true. Alternatively, the static property might be referring to a map to provide local configuration attributes:


class Person {

  static auditable = [include: ['name']]

  String name
  String surName

  static constraints = {
  }
}

As a default setting all domain class properties are enabled for audit logging as long as include (or defaultInclude in the Config.groovy) or ignore (or defaultIgnore in Config.groovy) aren't specified in the auditable map. In the case of include only the specified properties are logged, in the case of exclude all other persistent properties are logged.

At runtime

Once the audit log is enabled for a domain class all insert/update/delete operations will be kept track of by the plugin in the audit_log table. Actually the table comes as GORM domain class AuditLogEvent that is supplied by the plugin. For every property values that changes a new AuditLogEvent is created. Here are the domain class properties:


class AuditLogEvent {

  Date dateCreated

  String actor
  String uri
  String className
  String persistedObjectId

  String eventName // one of ['INSERT', 'UDPATE', 'DELETE']
  String propertyName
  String oldValue
  String newValue
}

All properties should be self speaking except for the actor and the uri properties (I guess). The actor property has been introduced to keep track of the principal (name) that triggered the event. In the configuration options above the actorClosure was shown that can be specified to retrieve the principal name from the HTTP request or session. The uri contains the web URI that was used to initially trigger the domain class change.

Here is a testcase method that shows how the AuditLogEvent will be filled when a new Person object is saved to the DB:


@Test
void testInsertEvent() {
  def p = new Person(name: "Andre", surName: "Steingress").save(flush: true)

  def auditLogEvent = AuditLogEvent.findByClassName('Person')
  assert auditLogEvent != null

  assert auditLogEvent.actor == 'system'
  assert auditLogEvent.className == 'Person'
  assert auditLogEvent.dateCreated != null
  assert auditLogEvent.eventName == AuditLogEventRepository.EVENT_NAME_INSERT
  assert auditLogEvent.newValue == 'Andre'
  assert auditLogEvent.oldValue == null
  assert auditLogEvent.persistedObjectId == p.id as String
  assert auditLogEvent.propertyName == 'name'
}

As the AuditLogEvent class is a pure Grails domain class its dynamic methods can be used for querying the audit log table.

Be aware that the oldValue (on upates) and the newValue will be stored for every property (as per configuration) of the auditable domain class. One way to truncate these strings is by using the auditLog.truncateLength option. In the most current version all values are persisted as type String by using the default Groovy type coercion to String. This will definitely change in future versions as needed.

Installation

The plugin is available at Github. A plugin zip can be created with grails package-plugin from the root project directory. Right now the plugin is not stable enough to be published via the Grails plugin portal but as time goes by a stable version will definitely be published in the portal.

Conclusion

The Grails Hibernate Audit Log Plugin can be used for audit logging changes in Grails domain classes. Every domain class under target needs to specify a static auditable property that is either true or contains a Map of local settings. The plugin is currently only accessible via Github but a stable version is planned to be released at the Grails plugin portal.

Grails Tests with Cucumber Cont'd

My previous blog post has been about introducing Cucumber in a Grails application. This post is a follow up on a particular requirement that came up in the course of writing the first Cucumber specifications.

One point of criticism was the lack of auto-complete support for Geb methods and variables which are available in our Cucumber step implementations. As mentioned, the Geb BindingUpdater adds a browser variable and multiple methods to be used in the Cucumber step implementation code. For example, calling browser.go link can be shortened to:


package steps

import pages.admin.LoginPage
import static cucumber.api.groovy.EN.*

Given(~'^a user opens the browser$') {->

}
When(~'^she opens the "([^"]*)" link$') { String link ->
   go link       // instead of browser.go link    
}
Then(~'^she will get a login page$') {->
    
}

As the project team is entirely using IntelliJ, I decided to write a GDSL file. GDSLs can be used to add auto-completion support to Groovy DSLs in IntelliJ - exactly what we needed.

Thanks to Peter Gromov from JetBrains I could come up with a GDSL that even has support for generic method type parameters:


/**
 * Enables code completion for Geb inside Cucumber step implementations.
 */
def forwardedMethods = [
  "go", "to", "via", "at", "waitFor",
  "withAlert", "withNoAlert", "withConfirm", "withNoConfirm",
  "download", "downloadStream", "downloadText", "downloadBytes", "downloadContent", "report", "reportGroup", "cleanReportGroupDir"]

def scriptContext = context(
  filetypes: ['.groovy'], 
  pathRegexp: ".*/test/cucumber/.*", 
  scope: closureScope())

contributor(scriptContext) {
    property name: 'browser', type: 'geb.Browser'

    def methods = findClass('geb.Browser').methods
    methods.findAll { it.name in forwardedMethods }.each { def browserMethod ->

        def params = [:]
        browserMethod.parameterList.parameters.each { param ->
            params.put(
              param.name, 
              com.intellij.psi.util.TypeConversionUtil.erasure(param.type).canonicalText)
        }

        method name: browserMethod.name, type: com.intellij.psi.util.TypeConversionUtil.erasure(browserMethod.returnType).canonicalText, params: params
    }
}

The GDSL registers all methods which are bound by the BindingUpdater plus it adds the browser variable of type geb.Browser for all Groovy script files in the test/cucumber/ directory. TypeConversionUtil is used to type erase the method result and parameter types, so for example <T extends Page> T at(Class<T> pageClass) will be erased to Page at(Class pageClass). One little attack against the DRY principle is the hard-coded list of forwarded methods, that's something that could be improved with a little IntelliJ PSI kung-fu.

After throwing this as CucumberGebSupport.gdsl in the test/cucumber folder (which is being registered as test-source folder), IntelliJ will recognize the file and enable the auto-completion support as specified.

IntelliJ Auto-Completion for Geb in Cucumber

Conclusion

IntelliJ comes with a neat mechanism that allows to add auto-completion support for custom Groovy DSLs. So-called GDSL files can be used to specify delegation classes, introduce variables and do other fancy stuff that needs to be done to have auto-completion for Groovy DSLs.