Search

Dark theme | Light theme

October 29, 2012

Gradle Effective Implementation Guide Released

A year ago I was approached by Packt Publishing and they asked me if I was interested in writing a book about Gradle. I knew beforehand it would take a lot of my spare time, but afterwards I can say it was worth it. Now a year later the book is published. My parents ordered the special cake you see on the photo to celebrate that the book is now released. It tasted delicious :-)


October 26, 2012

Gradle Goodness: Distribute Custom Gradle in Our Company

The Gradle wrapper allows us to let developers use Gradle without the need for every developer to install Gradle. We can add the output of the Gradle wrapper task to version control. Developers only need to checkout the source for a project and invoke the gradlew or gradlew.bat scripts. The scripts will look for a Gradle distribution and download it to the local computer of a developer. We can customize the Gradle wrapper and provide a different source for the Gradle distribution. For example we can add the Gradle distribution ZIP file on our company intranet. We then use the distributionUrl property of the Wrapper task to reference the intranet location where we place the Gradle distribution ZIP file.

In the following sample file we use the distributionUrl property to reference our company intranet:

task createWrapper(type: Wrapper) {
    distributionUrl = 'http://intranet/tools/gradle-1.2-bin.zip'
}

When we execute the createWrapper task the wrapper script files and supporting files are created in the project directory. It is fine to remove the createWrapper task from the build file. If we want to change the location of the Gradle distribution ZIP file or if the version changes we change the file gradle/wrapper/gradle-wrapper.properties. This file has a key distributionUrl. We can change the value of this key, save the file, add it to version control. If other developers checkout the project the new Gradle distribution location is used and they will use the Gradle version we want them to use.

In a previous post we saw an initialization or init script that could be applied for all projects that are developed in our company. To distribute this script we can customize the Gradle distribution, put it on our company intranet and use the Gradle wrapper properties to reference this customized Gradle distribution. It turns out it is very easy to create a customized Gradle distribution with custom init scripts, plugin code, classpath extensions or anything else that can be part of a Gradle distribution. The code in this post is based on the samples from Luke Daley's presentation at SpringOne 2GX 2012. These samples can be found at Github.

In the following build file we customize a default Gradle distribution. First the Gradle distribution ZIP file for a specific Gradle version is downloaded. We create a new custom Gradle distribution ZIP file with a custom version number based on the downloaded ZIP file. We add a init script from the src/scripts/init.d directory. We can add also other files like JAR files to the custom Gradle distribution ZIP file. We have applied the base plugin and therefore can use configurations. We also reconfigure the uploadCompanyGradle task so we can use SCP to copy the resulting Gradle ZIP file to our company intranet webserver.

// Base plugin adds configuration
// support and build<Configuration> 
// and upload<Configuration> tasks.
apply plugin: 'base'

// Version is the version of the
// company Gradle. This can be independent
// of the Gradle version.
version = '1.0.2'

ext {
    // Gradle version to use as template for 
    // the custom Gradle distribution.
    gradleVersion = '1.2'
}

// Extra configuration to store
// company Gradle ZIP artifact and
// use for uploading.
configurations {
    companyGradle    
}


task downloadGradle(type: DownloadGradle) {
    description 'Download Gradle version from Gradle distributions website'

    gradleVersion project.gradleVersion
    destinationDir file("$buildDir/gradle-downloads")
}

task companyGradleZip(type: Zip, dependsOn: downloadGradle) {
    description 'Add extra files to company Gradle distribution'

    // Name for company Gradle ZIP distribution.
    baseName = 'company-gradle'
    classifier = 'bin'

    from zipTree(downloadGradle.destinationFile)
    into("${downloadGradle.distributionNameBase}") {
        into('init.d') {
            from "src/scripts/init.d"
        }
        // We can do extra stuff here 
        // to add to the company Gradle
        // distribution ZIP file.
    }    
}

artifacts {
    companyGradle companyGradleZip
}

// Configure upload task for company
// Gradle distribution ZIP.
uploadCompanyGradle {
    repositories {
        // Add SSH resolver to copy the resulting
        // company Gradle distribution to the 
        // company webserver.
        // user and userPassword are defined in external
        // gradle.properties file.
        add(new org.apache.ivy.plugins.resolver.SshResolver()) {
            name = 'company-intranet'           
            user = intranetUsername         
            userPassword = intranetPassword
            host = 'intranet'

            addArtifactPattern "/Library/WebServer/Documents/tools/[artifact]-[revision]-[classifier].[ext]"           
        }
    }
    uploadDescriptor = false

    // We can also use Maven repositories
    // (or other custom repositories) to upload.
}


class DownloadGradle extends DefaultTask {
    @Input 
    String gradleVersion
    
    @Input 
    File destinationDir
    
    @Input 
    String gradleDownloadBase = "http://services.gradle.org/distributions"

    @TaskAction 
    doDownloadGradle() {
        destinationFile.bytes = new URL(downloadUrl).bytes
    }

    String getDownloadUrl() {
        "$gradleDownloadBase/$downloadFileName"
    }

    String getDistributionNameBase() {
        "gradle-$gradleVersion"
    }

    String getDownloadFileName() {
        "$distributionNameBase-bin.zip"
    }

    @OutputFile 
    File getDestinationFile() {
        new File(destinationDir, downloadFileName)
    }
}

We create a very simple init script in the directory src/scripts/init.d. This file is added to the init.d directory of our company Gradle distribution. Files in this directory are automatically executed.

// File: src/scripts/init.d/sample.gradle
println "You are running the build with the Company Gradle"

In a project where we want to use the company Gradle distribution we either set the distributionUrl property of the Wrapper task or change the property distributionUrl in the file gradle/wrapper/gradle-wrapper.properties.

# File: gradle/wrapper/gradle-wrapper.properties
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=http://intranet/tools/company-gradle-1.0.2-bin.zip

When we use the gradlew script for the first time our company Gradle distribution ZIP file is downloaded and extracted. Notice the line "You are running the build with the Company Gradle" in the output from the sample.gradle init script.

$ ./gradlew tasks
Downloading http://intranet/tools/company-gradle-1.0.2-bin.zip
.................................................................................
.................................................................................
.................................................................................
.................................................................................
.................................................................................
.................................................................................
.................................................................................
.................................................................................
.................................................................................
.................................................................................
.................................................................................
.................................................................................
.................................................................................
.................................................................................
.................................................................................
.................................................................................
.................................................................................
.................................................................................
.................................................................................
....................
Unzipping /Users/mrhaki/.gradle/wrapper/dists/company-gradle-1.0.2-bin/6scnmmqpv8l6j6f30lud9v9o6o/company-gradle-1.0.2-bin.zip to /Users/mrhaki/.gradle/wrapper/dists/company-gradle-1.0.2-bin/6scnmmqpv8l6j6f30lud9v9o6o
Set executable permissions for: /Users/mrhaki/.gradle/wrapper/dists/company-gradle-1.0.2-bin/6scnmmqpv8l6j6f30lud9v9o6o/gradle-1.2/bin/gradle
You are running the build with the Company Gradle
:tasks

------------------------------------------------------------
All tasks runnable from root project
------------------------------------------------------------

Help tasks
----------
dependencies - Displays the dependencies of root project 'simple-project'.
help - Displays a help message
projects - Displays the sub-projects of root project 'simple-project'.
properties - Displays the properties of root project 'simple-project'.
tasks - Displays the tasks runnable from root project 'simple-project' (some of the displayed tasks may belong to subprojects).

Other tasks
-----------
wrapper

To see all tasks and more detail, run with --all.

BUILD SUCCESSFUL

Total time: 3.643 secs

We have seen how easy it is to distribute Gradle in our company. Even customizing the distribution ZIP file is easy to do and will ensure all developers share the same (customized) Gradle version and use the same configuration.

Code written with Gradle 1.2

The code is available at Github.

October 25, 2012

Groovy Goodness: Pretty Print XML

The easiest way to pretty print an XML structure is with the XmlUtil class. The class has a serialize() method which is overloaded for several parameter types like String, GPathResult and Node. We can pass an OutputSteam or Writer object as argument to write the pretty formatted XML to. If we don't specify these the serialize() method return a String value.

import groovy.xml.*

def prettyXml = '''\<?xml version="1.0" encoding="UTF-8"?><languages>
  <language id="1">Groovy</language>
  <language id="2">Java</language>
  <language id="3">Scala</language>
</languages>
'''


// Pretty print a non-formatted XML String.
def xmlString = '<languages><language id="1">Groovy</language><language id="2">Java</language><language id="3">Scala</language></languages>'
assert XmlUtil.serialize(xmlString) == prettyXml

// Use Writer object as extra argument.
def xmlOutput = new StringWriter()
XmlUtil.serialize xmlString, xmlOutput
assert xmlOutput.toString() == prettyXml

// Pretty print a Node.
Node languagesNode = new XmlParser().parseText(xmlString)
assert XmlUtil.serialize(languagesNode) == prettyXml


// Pretty print a GPathResult.
def langagesResult = new XmlSlurper().parseText(xmlString)
assert XmlUtil.serialize(langagesResult) == prettyXml


// Pretty print org.w3c.dom.Element.
org.w3c.dom.Document doc = DOMBuilder.newInstance().parseText(xmlString)
org.w3c.dom.Element root = doc.documentElement
assert XmlUtil.serialize(root) == prettyXml


// Little trick to pretty format
// the result of StreamingMarkupBuilder.bind(). 
def languagesXml = {
    languages {
        language id: 1, 'Groovy'
        language id: 2, 'Java'
        language id: 3, 'Scala'
    }
}
def languagesBuilder = new StreamingMarkupBuilder()
assert XmlUtil.serialize(languagesBuilder.bind(languagesXml)) == prettyXml

If we already have a groovy.util.Node object we can also use the XmlNodePrinter. For example if we use XmlParser to parse XML we get a Node object. We create a new instance of the XmlNodePrinter and use the print() method to output the node with child nodes. If we don't specify a Writer object the output is send to System.out.

import groovy.xml.*

// Get groovy.util.Node value.
def xmlString = '<languages><language id="1">Groovy</language><language id="2">Java</language><language id="3">Scala</language></languages>'
Node languages = new XmlParser().parseText(xmlString)


// Create output with all default settings.
def xmlOutput = new StringWriter()
def xmlNodePrinter = new XmlNodePrinter(new PrintWriter(xmlOutput))
xmlNodePrinter.print(languages)

assert xmlOutput.toString() == '''\
<languages>
  <language id="1">
    Groovy
  </language>
  <language id="2">
    Java
  </language>
  <language id="3">
    Scala
  </language>
</languages>
'''


// Create output and set indent character
// one space.
// (can also by \t for tabs, or other characters)
xmlOutput = new StringWriter()
xmlNodePrinter = new XmlNodePrinter(new PrintWriter(xmlOutput), " " /* indent */)
xmlNodePrinter.print(languages)

assert xmlOutput.toString() == '''\
<languages>
 <language id="1">
  Groovy
 </language>
 <language id="2">
  Java
 </language>
 <language id="3">
  Scala
 </language>
</languages>
'''


// Use properties preserveWhitespace,
// expandEmptyElements and quote to
// change the formatting.
xmlOutput = new StringWriter()
xmlNodePrinter = new XmlNodePrinter(new PrintWriter(xmlOutput))
xmlNodePrinter.with {
    preserveWhitespace = true
    expandEmptyElements = true
    quote = "'" // Use single quote for attributes
}
xmlNodePrinter.print(languages)

assert xmlOutput.toString() == """\
<languages>
  <language id='1'>Groovy</language>
  <language id='2'>Java</language>
  <language id='3'>Scala</language>
</languages>
"""

Code written with Groovy 2.0.5

Gradle Goodness: Task Output Annotations Create Directory Automatically

One of the great features of Gradle is incremental build support. With incremental build support a task is only executed if it is really necessary. For example if a task generates files and the files have not changed than Gradle can skip the task. This speeds up the build process, which is good. If we write our own tasks we can use annotations for properties and methods to make them behave correctly for incremental build support. The @OutputDirectory annotation for example can be used for a property or method that defines a directory that is used by the task to put files in. The nice thing is that once we have designated such a directory as the output directory we don't have to write code to create the directory if it doesn't exist. Gradle will automatically create the directory if it doesn't exist yet. If we use the @OutputFile or @OutputFiles annotation the directory part of the file name is created if it doesn't exist.

In the following example build file we create a new task SplitXmlTask with the property destinationDir and we apply the @OutputDirectory annotation. If the directory doesn't exist Gradle will create it when we execute the task.

task splitNames(type: SplitXmlTask) {
    xmlSource = file('src/xml/names.xml')
    destinationDir = file("$buildDir/splitter/names")
    splitOn = 'person'
}

defaultTasks 'splitNames'

class SplitXmlTask extends DefaultTask {
    @Input
    String splitOn

    @InputFile
    File xmlSource

    // Output directory, will be created
    // automatically if it doesn't exist yet.
    @OutputDirectory
    File destinationDir

    @TaskAction
    def splitXml() {
        def slurper = new XmlParser().parse(xmlSource)

        // Find all nodes where the tag name
        // equals the value for splitOn.
        // For each node we create a new file in 
        // the destinationDir directory with the 
        // complete XML node as contents.
        slurper.'**'.findAll { it.name() == splitOn }.each { node ->
            def outputFile = new File(destinationDir, "${node.name.text()}.xml")
            outputFile.withPrintWriter { writer ->
                writer.println '<?xml version="1.0"?>'
                new XmlNodePrinter(writer).print(node)
            }
        }
    }
}

Source for XML in src/xml/names.xml:

<?xml version="1.0"?>
<people>
    <person>
        <name>mrhaki</name>
        <country>The Netherlands</country>
    </person>
    <person>
        <name>hubert</name>
        <country>The Netherlands</country>
    </person>
</people>

When we run the task and the build is successful we see two files in the directory build/splitter/names:

$ gradle
:splitNames

BUILD SUCCESSFUL

Total time: 2.208 secs
$ ls build/splitter/names/
hubert.xml mrhaki.xml

Written with Gradle 1.2

October 24, 2012

Gradle Goodness: Init Script for Adding Extra Plugins to Existing Projects

Gradle is very flexible. One of the ways to alter the build configuration is with initialization or init scripts. These are like other Gradle scripts but are executed before the build. We can use different ways to add the init script to a build. For example we can use the command-line option -I or --init-script, place the script in the init.d directory of our GRADLE_HOME directory or USER_HOME/.gradle directory or place a file init.gradle in our USER_HOME/.gradle directory.

We can also use the apply(from:) method to include such a script in our build file. We can reference a file location, but also a URL. Imagine we place an init script on our company intranet to be shared by all developers, then we can include the script with the apply(from:) method. In the following build file we use this syntax to include the script:

apply plugin: 'java'
apply from: 'http://intranet/source/quality.gradle'

version = '2.1.1'
group = 'com.mrhaki.gradle.sample

The following script is an init script where we add the Checkstyle plugin to projects with the Java plugin and the Codenarc plugin to projects with the Groovy plugin. Because the Groovy plugin extends the Java plugin the Checkstyle plugin is added to the Groovy project as well.

Notice we also add the downloadCheckstyleConfig task. With this task we download from the intranet the Checkstyle configuration that needs to be used by the Checkstyle tasks.

// File: quality.gradle
allprojects {
    afterEvaluate { project ->
        def groovyProject = project.plugins.hasPlugin('groovy')
        def javaProject = project.plugins.hasPlugin('java')

        if (javaProject) {
            // Add Checkstyle plugin.
            project.apply plugin: 'checkstyle'

            // Task to download common Checkstyle configuration
            // from company intranet.
            task downloadCheckstyleConfig(type: DownloadFileTask) {
                description = 'Download company Checkstyle configuration'
                
                url = 'http://intranet/source/company-style.xml'
                destinationFile = checkstyle.configFile
            }

            // For each Checkstyle task we make sure
            // the company Checkstyle configuration is 
            // first downloaded.
            tasks.withType(Checkstyle) { 
                it.dependsOn 'downloadCheckstyleConfig'
            }
        }

        if (groovyProject) {
            // Add Codenarc plugin.
            project.apply plugin: 'codenarc'
        }
    }
}

class DownloadFileTask extends DefaultTask {
    @Input
    String url

    @OutputFile
    File destinationFile

    @TaskAction
    def downloadFile() {
        destinationFile.bytes = new URL(url).bytes
    }
}

Code written with Gradle 1.2

October 23, 2012

Gradle Goodness: Exclude Transitive Dependency from All Configurations

We can exclude transitive dependencies easily from specific configurations. To exclude them from all configurations we can use Groovy's spread-dot operator and invoke the exclude() method on each configuration. We can only define the group, module or both as arguments for the exclude() method.

The following part of a build file shows how we can exclude a dependency from all configurations:

...
configurations {
    all*.exclude group: 'xml-apis', module: 'xmlParserAPIs'
}

// Equivalent to:
configurations {
    all.collect { configuration ->
        configuration.exclude group: 'xml-apis', module: 'xmlParserAPIs'
    }
}
...

Written with Gradle 1.2

October 22, 2012

Gradle Goodness: Running Java Applications from External Dependency

With Gradle we can execute Java applications using the JavaExec task or the javaexec() method. If we want to run Java code from an external dependency we must first pull in the dependency with the Java application code. The best way to do this is to create a new dependency configuration. When we configure a task with type JavaExec we can set the classpath to the external dependency. Notice we cannot use the buildscript{} script block to set the classpath. A JavaExec task will fork a new Java process so any classpath settings via buildscript{} are ignored.

In the following example build script we want to execute the Java class org.apache.cxf.tools.wsdlto.WSDLToJava from Apache CXF to generate Java classes from a given WSDL. We define a new dependency configuration with the name cxf and use it to assign the CXF dependencies to it. We use the classpath property of the JavaExec task to assign the configuration dependency.

// File: build.gradle

// Base plugin for task rule clean<task>
apply plugin: 'base'

repositories.mavenCentral()

// New configuration for CXF dependencies.
configurations { cxf }

ext {
    // CXF version.
    cxfVersion = '2.6.2'

    // Artifacts for CXF dependency.
    cxfArtifacts = [
        'cxf-tools-wsdlto-frontend-jaxws', 
        'cxf-tools-wsdlto-databinding-jaxb', 
        'cxf-tools-common', 
        'cxf-tools-wsdlto-core'
    ]
}

dependencies {
    // Assign CXF dependencies to configuration.
    cxfArtifacts.each { artifact ->
        cxf "org.apache.cxf:$artifact:$cxfVersion"
    }
}

// Custom task to generate Java classes
// from WSDL.
task wsdl2java(type: JavaExec) {
    ext {
        wsdlFile = 'src/wsdl/service-contract.wsdl'
        outputDir = file("$buildDir/generated/cxf")
    }

    inputs.file file(wsdlFile)
    outputs.dir outputDir

    // Main Java class to invoke.
    main = 'org.apache.cxf.tools.wsdlto.WSDLToJava'

    // Set classpath to dependencies assigned
    // to the cxf configuration.
    classpath = configurations.cxf

    // Arguments to be passed to WSDLToJava.
    args '-d', outputDir
    args '-client'
    args '-verbose'
    args '-validate'
    args wsdlFile
}

Code written with Gradle 1.2

October 11, 2012

Grassroots Groovy: Parse XML with XmlSlurper from Java

We can introduce Groovy into our Java projects at grassroots level. Even if we aren't allowed to run the Groovy compiler we can use other ways to run Groovy code. As long as we can include the Groovy libraries as a compile dependency than we can already use Groovy from Java. In this post we see how we can use the power of XmlSlurper to parse XML from our Java code.

To execute a Groovy script from we can use a GroovyShell object and invoke the evaluate() method. The evaluate() method can parse a Groovy script as File or Reader object. We can also use a String value to be evaluated. The last statement of the script that is evaluated can be assigned to a Java variable. To pass variables to the script we use the Binding object. This is a map of variables and their values. We assign values to the variables in the Java code and in the Groovy script we can use the variable values.

In the example we need to be able to parse a XML document with the following structure and find users with a given age:

<?xml version="1.0"?>
<users>
    <user age="39">mrhaki</user>
    <user age="39">hubert</user>
    <user age="23">chris</user>
</users>

We first define a simple Java interface with a method getUsersWithAge(int):

package com.mrhaki.groovy.grassroots.xml;

import com.mrhaki.groovy.grassroots.model.User;

import java.util.List;

public interface DataExtractor {
    /**
     * Get list of User object parsed from
     * an input source like XML.
     *
     * @param age Age of users to look for.
     * @return List of found users.
     */
    List<User> getUsersWithAge(final int age);
}

We have the following User class:

package com.mrhaki.groovy.grassroots.model;

public class User {

    private final String username;
    private final int age;

    public User(final String username, final int age) {
        this.username = username;
        this.age = age;
    }

    public String getUsername() {
        return username;
    }

    public int getAge() {
        return age;
    }
}

The following class is an implementation of the DataExtractor interface and uses Groovy code to find all users from an XML source with a given age:

package com.mrhaki.groovy.grassroots.xml;

import com.mrhaki.groovy.grassroots.model.User;
import groovy.lang.Binding;
import groovy.lang.GroovyShell;

import java.util.List;

/**
 * Use XML input source to extract data from.
 */
public class XMLDataExtractor implements DataExtractor {
    /**
     * XML input source String.
     */
    private final String xml;

    public XMLDataExtractor(final String xml) {
        this.xml = xml;
    }

    @Override
    public List<User> getUsersWithAge(final int age) {
        // First we create the binding with variables
        // to be used in the Groovy script.
        final Binding binding = new Binding();
        binding.setVariable("xml", xml);
        binding.setVariable("age", age);

        // Create Groovy shell to run script and
        // set binding with variables for the script.
        final GroovyShell shell = new GroovyShell(getClass().getClassLoader(), binding);

        // Create Groovy script as String.
        // We use the XmlSlurper to parse the XML String and
        // return a list of found objects.
        final ScriptBuilder parseScript = new ScriptBuilder();
        parseScript.addLine("import com.mrhaki.groovy.grassroots.model.User");
        parseScript.addLine("def slurper = new XmlSlurper().parseText(xml)");
        parseScript.addLine("slurper.user.findAll { it.@age == age }.collect { new User(it.text(), it.@age.toInteger()) } ");

        // Evaluate script. The last line of the script is
        // automatically the return statement, so the value
        // is assigned to result.
        // We could also assign it to a variable in the script and
        // use binding.getVariable() to get the value.
        final Object result = shell.evaluate(parseScript.build());

        return (List<User>) result;
    }

    /**
     * Utility builder class to create a Groovy script
     * as String with the correct line endings.
     */
    private final class ScriptBuilder {
        private StringBuilder script = new StringBuilder();

        public ScriptBuilder addLine(final String scriptLine) {
            script.append(scriptLine);
            script.append(newLine());
            return this;
        }

        private String newLine() {
            return System.getProperty("line.separator");
        }

        public String build() {
            return script.toString();
        }
    }

}

Ronan gave some good comments based on this version of the XMLDataExtractor class. We can reduce the Groovy code to be executed to a single line. We can add the import for the User with an ImportCustomizer. And in the binding we can immediately bind the result of the new XmlParser().parseText(xml) method to the slurper variable. Here is another version of the XMLDataExtractor class:

package com.mrhaki.groovy.grassroots.xml;

import com.mrhaki.groovy.grassroots.model.User;
import groovy.lang.Binding;
import groovy.lang.GroovyShell;
import groovy.util.XmlSlurper;
import org.codehaus.groovy.control.CompilerConfiguration;
import org.codehaus.groovy.control.customizers.ImportCustomizer;
import org.xml.sax.SAXException;

import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.util.List;

/**
 * Use XML input source to extract data from.
 */
public class XMLDataExtractor implements DataExtractor {
    /**
     * XML input source String.
     */
    private final String xml;

    public XMLDataExtractor(final String xml) {
        this.xml = xml;
    }

    @Override
    public List<User> getUsersWithAge(final int age) {
        // First we create the binding with variables
        // to be used in the Groovy script.
        final Binding binding = createBinding(age);

        // Create Groovy shell to run script and
        // set binding with variables for the script.
        final GroovyShell shell = createGroovyShell(binding);

        // Evaluate script. The line of the script is
        // automatically the return statement, so the value
        // is assigned to result.
        final Object result = shell.evaluate("slurper.user.findAll { it.@age == age }.collect { new User(it.text(), it.@age.toInteger()) } ");

        return (List<User>) result;
    }

    private GroovyShell createGroovyShell(final Binding binding) {
        // Add import for User class to script compiler configuration.
        final ImportCustomizer imports = new ImportCustomizer();
        imports.addImports("com.mrhaki.groovy.grassroots.model.User");
        final CompilerConfiguration config = new CompilerConfiguration();
        config.addCompilationCustomizers(imports);

        return new GroovyShell(getClass().getClassLoader(), binding, config);
    }

    private Binding createBinding(final int age) {
        final Binding binding = new Binding();
        try {
            binding.setVariable("slurper", new XmlSlurper().parseText(xml));
        } catch (IOException e) {
            throw new RuntimeException(e);
        } catch (SAXException e) {
            throw new RuntimeException(e);
        } catch (ParserConfigurationException e) {
            throw new RuntimeException(e);
        }
        binding.setVariable("age", age);
        return binding;
    }

}

To finish it up we can here see some simple tests to check the results of our XMLDataExtractor object:

package com.mrhaki.groovy.grassroots.xml;

import static org.junit.Assert.assertEquals;

import com.mrhaki.groovy.grassroots.model.User;
import org.junit.Test;

import java.util.List;

public class XMLDataExtractorTest {

    @Test
    public void numberOfUsersWithGivenAgeMustReflectNumbeOfUsersInXML() {
        final String sample = createSampleXml();
        final DataExtractor extractor = getExtractor(sample);

        final List<User> users = extractor.getUsersWithAge(39);

        assertEquals(2, users.size());
    }

    @Test
    public void foundUserMustHaveCorrectPropertyValues() {
        final String sample = createSampleXml();
        final DataExtractor extractor = getExtractor(sample);

        final List<User> users = extractor.getUsersWithAge(23);

        final User user = users.get(0);
        assertEquals("chris", user.getUsername());
        assertEquals(23, user.getAge());
    }

    private String createSampleXml() {
        final StringBuilder xml = new StringBuilder("<?xml version=\"1.0\"?>");
        xml.append("<users>");
        xml.append(createUserSampleXml("mrhaki", 39));
        xml.append(createUserSampleXml("hubert", 39));
        xml.append(createUserSampleXml("chris", 23));
        xml.append("</users>");
        return xml.toString();
    }

    private String createUserSampleXml(final String username, final int age) {
        return String.format("<user age=\"%2$s\">%1$s</user>", username, age);
    }

    protected DataExtractor getExtractor(final String sample) {
        return new XMLDataExtractor(sample);
    }

}

We have to add Groovy as a compile dependency to a Java project. The following build script defines a dependency on the Groovy XML module. Since Groovy 2 we don't have to include all of Groovy, but we can pick the modules we need and add them to our project:

// File: build.gradle
apply {
    plugin 'java'
    plugin 'idea'
}

version = 1.0

repositories {
    mavenLocal()
    mavenCentral()
}

ext {
    groovyVersion = '2.0.+'
    junitVersion = '4.+'
}

dependencies {
    compile "org.codehaus.groovy:groovy-xml:$groovyVersion"
    testCompile "junit:junit:$junitVersion"
}

October 9, 2012

Groovy Goodness: Create a List with Default Values

Since Groovy 1.8.7 we can create a list and use the withDefault() method to define a default value for elements that are not yet in the list. We use a closure as argument of the method, which returns the default value. We can even access the index of the element in the closure as an argument.

Besides the withDefault() method we can use the withLazyDefault() which is just another name for the same functionality. If we request a value for an index that is greater or equal to the size of the list, the list will automatically grow up to the specified index. Any gaps are filled with the value null.

We can also use the withEagerDefault() method. If we use this method the gaps are filled with the result from the closure we pass to the method. So instead of the value null the return result from the closure is used.

The following example script shows the results from using the withDefault() (withLazyDefault()) and withEagerDefault():

def lazy = ['abc', 42].withDefault { 'default' } // Or .withLazyDefault {}

// List grows because 3 is bigger than
// current lazy list size. Value is
// for element at index 3 is set with value
// from init closure.
assert lazy[3] == 'default'

// Gap at index 2 is filled with null value.
assert lazy == ['abc', 42, null, 'default']

// Because value at index 2 is set to null
// before, the init closure is invoked
// for this index now.
assert lazy[2] == 'default'

// List is now filled.
assert lazy == ['abc', 42, 'default', 'default']


def eager = ['abc', 42].withEagerDefault { 'default' }

// Here the list also grows, because
// index 3 is bigger than eager list size.
assert eager[3] == 'default'

// The gaps in the list are now
// filled with the value from
// the init closure.
assert eager == ['abc', 42, 'default', 'default']

// Value is already set because we
// used withEagerDefault.
assert eager[2] == 'default'


// We can use the index value as argument
// for the init closure.
def sample = [1,2,3].withDefault { index ->
    index % 2
}

assert sample[3] == 1
assert sample[4] == 0

(Written with Groovy 2.0.5)

Groovy Goodness: Getting the First and Last Element of an Iterable

Since Groovy 1.8.7 we can use the first() and last() methods on Iterable objects. With the first() method we get the first element and with the last() method we get the last element:

def list = 0..100

assert list.first() == 0
assert list.last() == 100

def abc = 'abc' as Character[]

assert abc.first() == 'a'
assert abc.last() == 'c'

def s = ['Groovy', 'Gradle', 'Grails', 'Rocks'] as Set

assert s.first() == 'Groovy'
assert s.last() == 'Rocks'

(Written with Groovy 2.0.5)

October 8, 2012

Groovy Goodness: Using Groovy for Git Hooks

Git supports hooks, which are scripts that are fired when certain events happens. The scripts are simply shell scripts and we can use Groovy to run those scripts. We must make Groovy the script language with the hash-bang (#!) header in the Git hook script file. And then we are ready to go and use Groovy as the script language for the Git hooks.

Git hooks are placed in the .git/hooks directory of our project. We create an example script that will use growlnotify to create a notification message with information from the Git commit action. growlnotify is a command-line tool for Mac OSX to send out messages to Growl. Other operating systems also have tools to create notification message from the command-line.

We must create the file post-commit in the directory .git/hooks. The file must have execute rights: $ chmod +x post-commit. In the first line of the file we make sure Groovy is used. In the rest of the script we use Groovy to invoke git log and get information about the commit. Then we create a message and invoke growlnotify with the correct arguments so Growl can show the message.

#!/usr/bin/env groovy

// Arguments for git log command.
def logArgs = ['max-count': '1', 'pretty': 'format:%an commited %s {%h}']

// Invoke git log command.
def gitLog = logArgs.inject(['git', 'log']) { cmd, k, v -> 
    cmd << "--$k=$v" 
}.execute()

// Get git log message to be used as notification message.
def message = gitLog.text

// Set icon and title for message.
def iconPath = '/Users/mrhaki/Pictures/git-icon-black.png'
def title = 'Git commit'

// Notify user of commit with growlnotify.
def notifyArgs = [message: message, title: title, image: iconPath]
notifyArgs.inject(['growlnotify']) { cmd, k, v ->
    cmd << "--$k" << v
}.execute()

In the following screenshot we see the output shown with Growl:

Some script hook files take an argument. We can use the argument in our Groovy code and write code to handle it. In the following example we check if the commit message is empty. If the message is empty we return with an exit code that is not 0. Git will terminate the commit until the script return 0. We write a simple implementation of the commit-msg hook:

#!/usr/bin/env groovy

import static java.lang.System.*

// First argument is the name of the 
// temporary commit message file.
def msgFileName = args[0]

// Get the commit message file.
def msgFile = new File(msgFileName)

// Read commit message from file.
def commitMessage = msgFile.text

if (!commitMessage) {
    err.println 'Commit message is empty'
    exit 1
}

exit 0

(Written with Groovy 2.0.4 and Git 1.7.5.4)

October 5, 2012

Gradle Goodness: Getting Announcements from Gradle Build

We can use the Gradle announce plugin to send announcements from the build process. We can send data to Twitter (I don't know if our followers are waiting for this, but if you want to you can), but also to notification applications on our local computers. For Mac OSX Growl is supported, for Linux notify-send and for Windows Snarl.

The plugin adds an announce object with the announce() method. The method accepts two arguments. The first argument is the message and the second argument is either twitter or local to indicate where to send the announcement.

apply plugin: 'announce'

task info {
    doLast {
        announce.announce "Running $it.name", 'local'
        println gradle.gradleVersion
    }
}

Here we see the announcement as Growl message:

We can also get an announcement object for only sending announcement to the local notification applications. We can use a send() method that accepts a title for the announcement as first argument and the message as second argument. To get the local announcement object we invoke announce.local:

apply plugin: 'announce'

task info {
    doLast {
        // Now we can specify a title and message
        announce.local.send "Gradle Info Task", 'Running'
        println gradle.gradleVersion
    }
}

To automatically send out notifications when a task is executed we can implement the TaskExecutionListener interface. From the implementation we can use the announce.local object. In the following example build file we create the class TaskAnnouncer and use the addTaskExecutionListener() method to add it to the TaskExecutionGraph available through gradle.taskGraph:

apply {
    plugin 'announce'
}    

gradle.taskGraph.addTaskExecutionListener new TaskAnnouncer(localAnnouncer: announce.local)

task info {
    doLast {
        println gradle.gradleVersion
    }
}

class TaskAnnouncer implements TaskExecutionListener {
    Announcer localAnnouncer

    @Override
    void afterExecute(final Task task, final TaskState state) {
        String message
        if (state.failure) {
            message = "Failure: $state.failure.message"
        } else if (state.executed) {
            message = 'Done'
        } else if (state.skipped) {
            message = "Skipped: $state.skipMessage"
        }
        send task, message
    }

    @Override
    void beforeExecute(final Task task) {
        send task, 'Ready to run'
    }

    private void send(final Task task, final String message) {
        final String title = "Gradle build: $task.project.name:$task.name"
        localAnnouncer.send title, message
    }
}

Automatically announce build results

To get the build results after running a build we only have to apply the build-announcements plugin to our Gradle build. This plugin uses the local notification applications to send out a message with a summary of the build. If the build failed we get a message with the task name that failed. For a successful build we can see how many task were executed.

apply {
    plugin 'announce'
    plugin 'build-announcements'
}    

task info {
    doLast {
        println gradle.gradleVersion
    }
}

The following screenshots show the result of a successful and non-successful build:

Apply for all Gradle builds

To add the plugins to all Gradle builds on our local computer we can create a so-called init script. Init scripts are executed before a project build script. We can place the init scripts at several locations. Let's create a new init script announce.gradle in our $USER_HOME/.gradle/init.d directory. If we don't have this directory yet, we can create it ourselves. All files in this directory are treated as init scripts by Gradle and are executed automatically. Here is the contents of the announce.gradle script:

rootProject {
    apply {
        plugin 'announce'
        plugin 'build-announcements'
    }    
}

October 3, 2012

Groovy Goodness: Using Project Coin Features Also With Older Java Versions

Since Groovy 2 we can use a subset of the Project Coin features from Java 7. But we don't have to run Java 7 to use them in Groovy code. We can use the new features even if we run our Groovy code on older Java versions.

Groovy didn't have to add all Project Coin features, because some are already supported in Groovy, like the switch statement on String objects or diamond operator. A feature that is added is a syntax enhancement to define binary literals. We can now use binary integral literals by prefixing the value with 0b:

// Binary notation.
int x = 0b101
assert x == 5

The underscore in number literals is now supported in Groovy. We can define numbers and use an underscore to make them more readable. The value is not changed:

import static java.text.NumberFormat.getInstance as formatter
import static java.util.Locale.US

// Use underscore for number literals.
double d = 89_192.29
assert formatter(US).format(d) == '89,192.29'

long longNumber = 1230_3910_1929_182931
assert longNumber == 123039101929182931

int length = 5_10
assert length == 510

long hex = 0x00_ff
assert hex == 255

We can define a multi-catch exception in Groovy 2. We specify more than exception in the catch clause separated by a pipe (|) symbol:

import java.lang.reflect.*

// Multicatch.
@groovy.transform.ToString
class Person {
    String name
}

try {
    final Person p = new Person(name: 'mrhaki')
    final Method toString = p.class.getMethod("toString1", null)
    final Object result = toString.invoke(p, null)
} catch (NoSuchMethodException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
    assert e
}

(Code written with Groovy 2.0.4)

October 2, 2012

Groovy Goodness: Return Closure From Another Closure or Method

Groovy closures are powerful. A closure can be passed to methods as argument or defined as a variable. We can even return closures from methods or other closures. We can use the returned closure to execute the logic from the closure with the explicit call() method or the implicit syntax with just the closure object followed by opening and closing parentheses (()).

// Method returns a closure. Method could
// also have been another closure to return
// the closure.
def repeater(times) {
    { value -> value * times }
}

// Use explicit call() method on the return closure
// object from the repeater() method.
assert repeater(2).call('mrhaki') == 'mrhakimrhaki'

// Use implicit call() method on the return closure
// object from the repeater() method. This
// might looks strange at first...
assert repeater(2)('mrhaki') == 'mrhakimrhaki'

We can even use a closure parameter and use it in the return closure code. We rewrite the previous example and this time use a closure instead of method to define repeater:

// Extra transformer argument with default 
// closure implementation.
def repeater = { times, transformer = { it } ->
    { value -> transformer(value) * times }
}

assert repeater(2).call('mrhaki') == 'mrhakimrhaki'
assert repeater(2)('mrhaki') == 'mrhakimrhaki'

assert repeater(2) { it.toUpperCase() } ('mrhaki') == 'MRHAKIMRHAKI'
assert repeater(2, { it.reverse() })('mrhaki') == 'ikahrmikahrm'

Notice we define a transformer parameter that has a default closure that simply returns the argument of the closure, so the old assertions still work. At lines 9 and 10 we pass a closure as argument to the repeater closure using two different syntaxes.

(Code written with Groovy 2.0.4)

Groovy Goodness: Drop or Take Elements with Condition

In Groovy we can use the drop() and take() methods to get elements from a collection or String object. Since Groovy 1.8.7 we also can use the dropWhile() and takeWhile() methods and use a closure to define a condition to stop dropping or taking elements. With the dropWhile() method we drop elements or characters until the condition in the closure is true. And the takeWhile() method returns elements from a collection or characters from a String until the condition of the closure is true.

In the following example we see how we can use the methods:

def s = "Groovy Rocks!"

assert s.takeWhile { it != 'R' } == 'Groovy '
assert s.dropWhile { it != 'R' } == 'Rocks!'


def list = 0..10

assert 0..4 == list.takeWhile { it < 5 }
assert 5..10 == list.dropWhile { it < 5 }


def m = [name: 'mrhaki', loves: 'Groovy', worksAt: 'JDriven']

assert [name: 'mrhaki'] == m.takeWhile { key, value -> key.length() == 4 }
assert [loves: 'Groovy', worksAt: 'JDriven'] == m.dropWhile { it.key == 'name' }

(Code is written with Groovy 2.0.4)