November 15, 2010

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) {
        def searchRequest = createSearchRequest(name)
        proxy.findAuthor searchRequest

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

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

            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>