Loading...

Monday, November 29, 2010

Groovy Goodness: String Continuation

Groovy makes writing concise code easy,. We can use the continuation character (\) in a String to split up the definition over multiple lines.

def name ='mrhaki'

def s = "This is not a multiline\
 String, $name, but the continuation\
 character (\\) makes it more readable."
        
assert 'This is not a multiline String, mrhaki, but the continuation character (\\) makes it more readable.' == s

Thursday, November 18, 2010

Gradle Goodness: Profiling Information

If we want to know more about how much time is spent in tasks we can use the --profile command-line option. Gradle will generate a report file in the build/reports/profile directory. This report file is a HTML file with information about how much time is spent by the different tasks and processes of Gradle.
The following report file is for a Gradle project with the Groovy plugin and we invoked $ gradle --profile build:

Monday, November 15, 2010

Set the Value of a Static Property with the Java Reflection API

Recently I was working on a legacy Java project without any unit tests. Just to get started I wanted to write some unit tests, so I could understand better what was happening in the code. But the code wasn't created to be easily unit tested. Therefore I had to resort to some Reflection API code to set the value of a static property of a class that was used in the code under test. Because the property is static we must pass null as an argument for the Reflection API Field.set() method.

package com.mrhaki.java;

public class MainTest {
    @org.junit.Test
    public void main_success() {
        ...
        mockThreadLocal();
        ...
        assertEquals("mrhaki", Holder.getValue());
    }

    private void mockThreadLocal() {
        ThreadLocal mockThreadLocal = new ThreadLocal<String>();
        mockThreadLocal.set("mrhaki");

        Field threadLocalField = Holder.class.getDeclaredField("valueThreadLocal");
        threadLocalField.setAccessible(true);
        threadLocalField.set(null, mockThreadLocal);
    }
}
package com.mrhaki.java;

public class Holder {
    private static ThreadLocal<String> valueThreadLocal = new ThreadLocal<String>();

    public static String getValue() {
        return valueThreadLocal.get();
    }
}

Groovy Goodness: Use GroovyWS to Access SOAP Web Services (Part 3)

We learned in the previous posts (Part 1, Part 2) how to create a Grails SOAP web service and how to access it with GroovyWS. In this post we learn how we can apply logging interceptors to our client. The output of these logging interceptors is the XML send and received from the SOAP web service. This can be very useful for tracing the messages or for debugging.

The WSClient class of GroovyWS has a property named client of type org.apache.cxf.endpoint.Client. This is our entry point to the Apache CXF client support. We need a way to get a reference to the client property so we can apply logging interceptors for the input and output. Unfortunately the WSClient API has not a method to get a reference to the property. But we write out client code in Groovy so we can use Groovy's MetaClass support to write out own get method to return the client property.

package com.mrhaki.groovyws.client

import groovyx.net.ws.WSClient
import org.apache.cxf.interceptor.LoggingInInterceptor
import org.apache.cxf.interceptor.LoggingOutInterceptor

class BlogWSClient {

    String wsdlUrl

    def proxy

    def findAuthor(String name) {
        createProxy()
        def searchRequest = createSearchRequest(name)
        proxy.findAuthor searchRequest
    }

    private def createSearchRequest(String name) {
        def searchRequest = proxy.create('com.mrhaki.groovyws.server.SearchRequest')
        searchRequest.authorName = name
        searchRequest
    }

    private void createProxy() {
        if (!proxy) {
            WSClient.metaClass.getCxfClient = { ->
                delegate.client
            }
            proxy = new WSClient(wsdlUrl, this.class.classLoader)
            proxy.initialize()

            def cxfClient = proxy.cxfClient
            cxfClient.inInterceptors.add(new LoggingInInterceptor())
            cxfClient.outInterceptors.add(new LoggingOutInterceptor())
        }
    }

}

After this change we can run our tests again from the Gradle build file with $ gradle -q test. We can open the generated test result HTML file and look for the System.err output to see the input and output messages:

Nov 14, 2010 11:00:15 PM org.apache.cxf.interceptor.LoggingOutInterceptor$LoggingCallback onClose
INFO: Outbound Message
---------------------------
ID: 1
Address: http://localhost:8080/server/services/blog
Encoding: UTF-8
Content-Type: text/xml
Headers: {SOAPAction=[""], Accept=[*/*]}
Payload: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"><soap:Body><ns1:findAuthor xmlns:ns1="http://server.groovyws.mrhaki.com"><in0 xmlns="http://server.groovyws.mrhaki.com"><authorName>mrhaki</authorName></in0></ns1:findAuthor></soap:Body></soap:Envelope>
--------------------------------------
Nov 14, 2010 11:00:15 PM org.apache.cxf.interceptor.LoggingInInterceptor logging
INFO: Inbound Message
----------------------------
ID: 1
Response-Code: 200
Encoding: UTF-8
Content-Type: text/xml;charset=UTF-8
Headers: {content-type=[text/xml;charset=UTF-8], Date=[Sun, 14 Nov 2010 22:00:15 GMT], transfer-encoding=[chunked], Server=[Apache-Coyote/1.1]}
Payload: <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><soap:Body><ns1:findAuthorResponse xmlns:ns1="http://server.groovyws.mrhaki.com"><ns1:out><blogItems xmlns="http://server.groovyws.mrhaki.com"><BlogItem><id>2</id><text>Sample blogitem one.</text><title>Title1</title><version>0</version></BlogItem><BlogItem><id>1</id><text>Sample blogitem two.</text><title>Title2</title><version>0</version></BlogItem></blogItems><id xmlns="http://server.groovyws.mrhaki.com">1</id><name xmlns="http://server.groovyws.mrhaki.com">mrhaki</name><version xmlns="http://server.groovyws.mrhaki.com">0</version></ns1:out></ns1:findAuthorResponse></soap:Body></soap:Envelope>
--------------------------------------

Sunday, November 14, 2010

Groovy Goodness: Use GroovyWS to Access SOAP Web Services (Part 2)

In a previous post we learned how to create a SOAP web service with the XFire plugin in Grails. The generated WSDL defined that the properties of our objects could be null by default and the minimum occurence is 0. And because of this we must work with JAXBElement objects to get the real object values. In this post we change the property mapping so the properties cannot be null and have a minimum occurence of 1. And then we can change our client code and deal with the object values directly instead of via a JAXBElement object.

Grails SOAP web service

We can change the default mapping of our objects that is generated by the XFire plugin. We must add an Aegis mapping XML file to our classpath and in this file we can define the custom mapping we want to apply. The name of the file is <ClassName>.aegis.xml and must be in the same package as the class we are writing the custom mapping for. If we add the XML files to the src/java directory of our Grails application then the files will be copied to the classpath automatically.

After we have created the XML mapping files we must add an extra runtime dependency. So we change the grails-app/conf/BuildConfig.groovy file and add a dependency to Jaxen, because this is needed to make the custom mapping work.

<!-- File: src/java/com/mrhaki/groovyws/server/Author.aegis.xml -->
<mappings>
    <mapping>
        <property name="name" minOccurs="1" nillable="false"/>
        <property name="blogItems" minOccurs="1" componentType="com.mrhaki.groovyws.server.BlogItem"/>
    </mapping>
</mappings>
<!-- File: src/java/com/mrhaki/groovyws/server/BlogItem.aegis.xml -->
<mappings>
    <mapping>
        <property name="title" minOccurs="1" nillable="false"/>
        <property name="text" minOccurs="1" nillable="false"/>
    </mapping>
</mappings>
<!-- File: src/java/com/mrhaki/groovyws/server/SearchRequest.aegis.xml -->
<mappings>
    <mapping>
        <property name="authorName" minOccurs="1" nillable="false"/>
    </mapping>
</mappings>
// File: grails-app/conf/BuildConfig.groovy
grails.project.class.dir = "target/classes"
grails.project.test.class.dir = "target/test-classes"
grails.project.test.reports.dir = "target/test-reports"
grails.project.dependency.resolution = {
    inherits("global") {
    }
    log "warn"
    repositories {
        grailsPlugins()
        grailsHome()
        grailsCentral()
        mavenCentral()
    }
    dependencies {
        runtime('jaxen:jaxen:1.1.1') {
            transitive = false
        }
    }
}

We can run our Grails application with $ grails run-app and open the URL http://localhost:8080/server/services/blog?wsdl to see the changes in the generated WSDL file.

GroovyWS Client

Because the definition of our SOAP web service is changed we can also change the client code. We now no longer have use JAXBElement objects, so our code is much cleaner. We can access the object types directly. For example for the dynamic SearchRequest object we can set the authorName property directly. In our old client code we had to create a JAXBElement object to set the value.

package com.mrhaki.groovyws.client

import groovyx.net.ws.WSClient

class BlogWSClient {

    String wsdlUrl

    def proxy

    def findAuthor(String name) {
        createProxy()
        def searchRequest = createSearchRequest(name)
        proxy.findAuthor searchRequest
    }

    private def createSearchRequest(String name) {
        def searchRequest = proxy.create('com.mrhaki.groovyws.server.SearchRequest')
        searchRequest.authorName = name
        searchRequest
    }

    private void createProxy() {
        if (!proxy) {
            proxy = new WSClient(wsdlUrl, this.class.classLoader)
            proxy.initialize()
        }
    }

}
package com.mrhaki.groovyws.client

import spock.lang.Specification

class BlogWSClientSpec extends Specification {

    def client = new BlogWSClient(wsdlUrl: 'http://localhost:8080/server/services/blog?wsdl')

    def "get author with name mrhaki and two blog items"() {
        when:
        def author = client.findAuthor('mrhaki')

        then:
        'mrhaki' == author.name
        def arrayOfBlogItems = author.blogItems
        def blogItems = arrayOfBlogItems.blogItem
        2 == blogItems.size()
        'Title1' == blogItems[0].title
        'Title2' == blogItems[1].title
        'Sample blogitem one.' == blogItems[0].text
        'Sample blogitem two.' == blogItems[1].text
    }

}

In the next post we see how we can add logging interceptors to our client so we can see the input and output from the invocation of the SOAP web service.

Thursday, November 11, 2010

Groovy Goodness: Use GroovyWS to Access SOAP Web Services

With the GroovyWS module we can consume SOAP web services. Under the hood GroovyWS uses CXF to dynamically create all required classes from a WSDL file. These classes are available via the classloader in our code. So we don't need to convert a WSDL file first to source files, but the classes are generated dynamically and can be used directly in our code. This means that if we can access the WSDL for a web service we can invoke the web service without any explicit code generation.

In this blog post we first write a SOAP web service with Grails and the XFire plugin. Next we create a Gradle project with the client code to invoke and use the SOAP web service we just created. We use Spock to write a specification where we really invoke the web service client and check the results. That is a lot of Groovyness in our project!

Grails SOAP webservice

We start by creating a new Grails project and install the XFire plugin. Then we create a new Grails service, BlogService, and use the plugin to expose the service as SOAP webservice. We create one method in our service: Author findAuthor(SearchRequest search). The parameter search is of type SearchRequest and contains the property authorName, which is used to find an Author object. We define this type to show how we can dynamically create an instance with GroovyWS in the client code.

We also create two domain classes: Author and BlogItem. An Author has a one-to-many relation with BlogItem. Finally we write code in the BootStrap to create a single author with two blog items.

$ grails create-app server
$ cd server
$ grails install-plugin xfire
$ grails create-service com.mrhaki.groovyws.server.Blog
$ grails create-domain-class com.mrhaki.groovyws.server.Author
$ grails create-domain-class com.mrhaki.groovyws.server.BlogItem
// File: grails-app/services/com/mrhaki/groovyws/server/BlogService.groovy
package com.mrhaki.groovyws.server

class BlogService {

    // Make this service a SOAP web service.
    static expose = ['xfire']

    static transactional = true

    Author findAuthor(SearchRequest search) {
        Author.findByName(search.authorName)
    }

}
// File: grails-app/domain/com/mrhaki/groovyws/server/Author.groovy
package com.mrhaki.groovyws.server

class Author {

    String name

    static hasMany = [blogItems: BlogItem]

    static mapping = {
        blogItems lazy: false, sort: 'title'
    }

}
// File: grails-app/domain/com/mrhaki/groovyws/server/BlogItem.groovy
package com.mrhaki.groovyws.server

class BlogItem {

    String text
    String title

    static belongsTo = [author: Author]

    // We must use xmlTransients so belongsTo doesn't
    // cause a StackOverflowError by the XFire plugin.
    static xmlTransients = ['author']

}
// File: src/groovy/com/mrhaki/groovyws/server/SearchRequest.groovy
package com.mrhaki.groovyws.server

class SearchRequest {
    String authorName
}
// File: grails-app/conf/BootStrap.groovy
import com.mrhaki.groovyws.server.*

class BootStrap {

    def init = { servletContext ->
        def blogItem1 = new BlogItem(title: 'Title1', text: 'Sample blogitem one.')
        def blogItem2 = new BlogItem(title: 'Title2', text: 'Sample blogitem two.')
        def author = new Author(name: 'mrhaki')
        author.addToBlogItems(blogItem1)
        author.addToBlogItems(blogItem2)
        author.save()
    }

    def destroy = {
    }
}

We are ready to start our Grails application and we open the url http://localhost:8080/server/services/blog?wsdl to see the generated WSDL file. If we see the WSDL contents we know everything works.

GroovyWS client

Okay we are halfway. Now it is time to write the client code to access our Grails webservice. We create a Gradle project build file with the required dependencies. Next we create the file BlogWSClient.groovy. In this file we use GroovyWS to create the client code. And finally we create a Spock specification to invoke BlogWSClient: BlogWSClientSpec.groovy.

// File: build.gradle
apply plugin:'groovy'

repositories {
    mavenCentral()
}

dependencies {
    groovy 'org.codehaus.groovy:groovy-all:1.7.5'
    compile 'org.codehaus.groovy.modules:groovyws:0.5.2'  // GroovyWS dependency.
    testCompile 'org.spockframework:spock-core:0.4-groovy-1.7'
}
// File: src/main/groovy/com/mrhaki/groovyws/client/BlogWSClient.groovy
package com.mrhaki.groovyws.client

import groovyx.net.ws.WSClient
import javax.xml.bind.JAXBElement
import javax.xml.namespace.QName

class BlogWSClient {

    String wsdlUrl

    def proxy

    def findAuthor(String name) {
        createProxy()
        def searchRequest = createSearchRequest(name)
        invokeWebservice searchRequest
    }

    private def invokeWebservice(SearchRequest searchRequest) {
        // Invoke webservice method.
        proxy.findAuthor searchRequest
    }

    private def createSearchRequest(String name) {
        // SearchRequest class is dynamically created by GroovyWS,
        // so we must use the proxy.create() method to create a new
        // instance.
        def searchRequest = proxy.create('com.mrhaki.groovyws.server.SearchRequest')

        // The authorName property of SearchRequest can be null, so
        // we must use JAXBElement to set the value.
        searchRequest.authorName = new JAXBElement(new QName("http://server.groovyws.mrhaki.com", "authorName"), String, name)

        searchRequest
    }

    private void createProxy() {
        if (!proxy) {
            // Use GroovyWS to create a client proxy.
            proxy = new WSClient(wsdlUrl, this.class.classLoader)

            // Make sure all required classes are created and available.
            proxy.initialize()
        }
    }

}
// File: src/test/groovy/com/mrhaki/groovyws/client/BlogWSClientSpec.groovy
package com.mrhaki.groovyws.client

import spock.lang.Specification

class BlogWSClientSpec extends Specification {

    def "get author with name mrhaki"() {
        given:
        def client = new BlogWSClient(wsdlUrl: 'http://localhost:8080/server/services/blog?wsdl')

        when:
        def author = client.findAuthor('mrhaki')

        then:
        // JAXBElement is returned, so we must use 
        // the value property of this element 
        // to get the real type and value.
        'mrhaki' == author.name.value  
        def arrayOfBlogItems = author.blogItems.value
        def blogItems = arrayOfBlogItems.blogItem
        2 == blogItems.size()
        'Title1' == blogItems[0].title.value
        'Title2' == blogItems[1].title.value
        'Sample blogitem one.' == blogItems[0].text.value
        'Sample blogitem two.' == blogItems[1].text.value
   }
}

We have all the files and are ready to run the test:

$ gradle -q test

After the test has succesfully run we can open the test report HTML file. It is a good idea to take a look at the System.err output. The output shows which classes are generated by GroovyWS dynamically:

...
Nov 11, 2010 9:09:33 PM org.apache.cxf.jaxb.JAXBUtils logGeneratedClassNames
INFO: Created classes: com.mrhaki.groovyws.server.ArrayOfBlogItem, com.mrhaki.groovyws.server.Author, com.mrhaki.groovyws.server.BlogItem, com.mrhaki.groovyws.server.FindAuthor, com.mrhaki.groovyws.server.FindAuthorResponse, com.mrhaki.groovyws.server.ObjectFactory, com.mrhaki.groovyws.server.SearchRequest, com.mrhaki.groovyws.server.This$Dist$Get$2, com.mrhaki.groovyws.server.This$Dist$Get$2Response, com.mrhaki.groovyws.server.This$Dist$Invoke$2, com.mrhaki.groovyws.server.This$Dist$Invoke$2Response, com.mrhaki.groovyws.server.This$Dist$Set$2, com.mrhaki.groovyws.server.This$Dist$Set$2Response

This code shows how easy it is to invoke a SOAP web service with GroovyWS. Even if the web service has complex objects as a reponse or as input parameter. In a future post we first see how we can configure the Grails SOAP web service so we don't need to use JAXBElement objects. This makes the client code even more readable and easier to create. And we will take a look at how we can change the logging for the generated client code.

Wednesday, November 10, 2010

Gradle Goodness: Running Tests in Parallel

Once we apply the Java plugin we can run our tests with the test task. Normally each test is run sequentially, but we can also run tests in parallel. This speeds up the test task considerably especially with a lot of tests. We set the property maxParallelForks to a number greater than 1 to enable parallel tests.

We can also set the additional property forkEvery on the test task. With this property we define how many tests should run in a parallel test fork.

In the following build script we first create a lot of tests with the createTests task and then we can run them with the test task. We can pass the properties maxParallelForks and forkEvery to play around and see what happens. Of course we can also use hard coded values in our build script for the test task properties.

apply plugin: 'java'

repositories {
    mavenCentral()
}

dependencies {
    testCompile 'junit:junit:4.8.2'
}

test {
    if (project.hasProperty('maxParallelForks')) 
        maxParallelForks = project.maxParallelForks as int
    if (project.hasProperty('forkEvery')) 
        forkEvery = project.forkEvery as int
}

packages = 10
tests = 30

task createTests << {
    (0..packages).each { packageCounter ->
        def packageName = "gradletest${packageCounter}"
        (0..tests).each { classCounter ->
            def testClassName = "Gradle${classCounter}Test"
            copy {
                from 'src/templates'
                into 'src/test/java'
                expand([packageName: packageName, testClassName: testClassName])
                rename '(.*).java', packageName + '/' + testClassName + '.java'
                include 'SampleTest.java'
            }
        }
    }
}
// File: src/templates/SampleTest.java
package ${packageName};

import org.junit.Test;
import static org.junit.Assert.*;

public class ${testClassName} {

    @Test
    public void testString() throws Exception {
        Thread.sleep(200);
        assertEquals("mrhaki", "mr" + "haki");
    }
}

So first we create the tests: $ gradle createTests. And then we can experiment with different options:

$ gradle clean test
...
BUILD SUCCESSFUL

Total time: 1 mins 33.942 secs

$ gradle clean test -PmaxParallelForks=10
...
BUILD SUCCESSFUL

Total time: 36.68 secs

$ gradle clean test -PmaxParallelForks=4 -PforkEvery=25
...
BUILD SUCCESSFUL

Total time: 56.066 secs

Tuesday, November 9, 2010

Gradle Goodness: Set Java Version Compatibility

We can use the properties sourceCompatibility and targetCompatibility provided by the Java plugin to define the Java version compatibility for compiling sources. The value of these properties is a JavaVersion enum constant, a String value or a Number. If the value is a String or Number we can even leave out the 1. portion for Java 1.5 and 1.6. So we can just use 5 or '6' for example.

We can even use our own custom classes as long as we override the toString() method and return a String value that is valid as a Java version.

apply plugin: 'java'

sourceCompatibility = 1.6 // or '1.6', '6', 6, JavaVersion.VERSION_1_6, new Compatibility('Java 6')

class Compatibility {
    String version

    Compatibility(String versionValue) {
        def matcher = (versionValue =~ /Java (\d)/)
        version = matcher[0][1]
    }

    String toString() { version }
}

Monday, November 8, 2010

Gradle Goodness: Set a Project Description

We can use the description property of a Gradle project to describe the purpose of our project.

version = '1.0-bugfix'

description = """\
Simple Gradle project to show how we can
use the description property of a project.
------------------------------------------
Project version: ${version}
Gradle version: ${gradle.gradleVersion}
------------------------------------------
"""

When we invoke $ gradle projects we get to see our project description in the output.

$ gradle -q projects

Root project 'description' - Simple Gradle project to show how we can
use the description property of a project.
------------------------------------------
Project version: 1.0-bugfix
Gradle version: 0.9-rc-2
------------------------------------------

No sub-projects

To see a list of the tasks of a project, run gradle <project-path>:tasks
For example, try running gradle :tasks

Friday, November 5, 2010

Gradle Goodness: Add Filtering to ProcessResources Tasks

When we apply the Java plugin (or any dependent plugin like the Groovy plugin) we get new tasks in our project to copy resources from the source directory to the classes directory. So if we have a file app.properties in the directory src/main/resources we can run the task $ gradle processResources and the file is copied to build/classes/main/app.properties. But what if we want to apply for example some filtering while the file is copied? Or if we want to rename the file? How we can configure the processResources task?

The task itself is just an implementation of the Copy task. This means we can use all the configuration options from the Copy task. And that includes filtering and renaming the files. So we need to find all tasks in our project that copy resources and then add for example filtering to the configuration. The following build script shows how we can do this:

import org.apache.tools.ant.filters.*

apply plugin: 'java'

version = '1.0-DEVELOPMENT'

afterEvaluate {
    configure(allProcessResourcesTasks()) {
        filter(ReplaceTokens, 
               tokens: [version: project.version, gradleVersion: project.gradle.gradleVersion])
    }
}

def allProcessResourcesTasks() {
    sourceSets.all.processResourcesTaskName.collect {
        tasks[it]
    }
}

Let's create the following two files in our project directory:

# src/main/resources/app.properties
appversion=@version@
# src/test/resources/test.properties
gradleVersion=@gradleVersion@

We can now execute the build and look at the contents of the copied property files:

$ gradle build
:compileJava
:processResources
:classes
:jar
:assemble
:compileTestJava
:processTestResources
:testClasses
:test
:check
:build

BUILD SUCCESSFUL

Total time: 4.905 secs

$ cat build/classes/main/app.properties 
appversion=1.0-DEVELOPMENT
$ cat build/classes/test/test.properties 
gradleVersion=0.9-rc-2

Wednesday, November 3, 2010

Gradle Goodness: Create JAR Artifact with Test Code for Java Project

Today, during my Gradle session, someone asked how to create a JAR file with the compiled test classes and test resources. I couldn't get the task syntax right at that moment, so when I was at home I had to find out how we can create that JAR file. And it turned out to be very simple:

apply plugin: 'java'

task testJar(type: Jar) {
    classifier = 'tests'
    from sourceSets.test.classes
}

The magic is in the from method where we use sourceSets.test.classes. Because we use sourceSets.test.classes Gradle knows the task testClasses needs to be executed first before the JAR file can be created. And of course the assemble task will pick up this new task of type Jar automatically.

When we run the build we get the following output:

$ gradle assemble
:compileJava
:processResources
:classes
:jar
:compileTestJava
:processTestResources
:testClasses
:testJar
:assemble

Source Code from Gradle Session at JFall 2010 on GitHub

This morning I had a great early bird session (8 o'clock in the morning) about Gradle at JFall 2010. The source is now available on GitHub.