Monday 18 August 2008

Consuming WCF Web Service Using Groovy Client

Last month, I developed some simple web services using WCF and consumed it using various web service frameworks in Java. Now I have implemented the web service client using GroovyWS, which is an add-on module to Groovy. It uses CXF under the hood.

To add the GroovyWS library, I simply copied its JAR file groovy-all-1.5.6.jar into the Groovy's lib directory (it can either go in {groovy.home}/lib or {user.home}/.groovy/lib according to the groovy-starter.conf file). Then run the following script from Groovy Console:

import groovyx.net.ws.WSClient
def proxy = new WSClient("http://localhost/PromoService.svc?wsdl", 
                this.class.classLoader)
        
def keywords = proxy.GetKeywordsFromMySpace("http://someurl/somepage.htm")
if(keywords!=null) {
    if (proxy.HasPromo(keywords)) {
        def promo = proxy.GetFirstPromo(keywords)
        println "Promo: ${promo?.promoName?.getValue()}, ${promo?.promoDateTime}"
    }
}
gives the result:
BindingInfo = [BindingInfo http://schemas.xmlsoap.org/wsdl/soap/]
o = SOAPBinding ({http://schemas.xmlsoap.org/wsdl/soap/}binding):
required=null
transportURI=http://schemas.xmlsoap.org/soap/http
Promo: Batman The Dark Knight, 2008-07-30T10:00:00

That's all!

I then re-did it using Eclipse 3.4 with Groovy Plug-in to create the Groovy project by following the instructions from the same web site. Then I added the JAR files into the dependency:

  • ant.jar from Apache Ant 1.7.0 - this is needed by GroovyWS but not included in its distribution
  • groovy-all-1.5.6.jar
The Groovy code for the test client is very simple:
package svdemo

import groovyx.net.ws.WSClient

/**
 * @author ROMENL
 *
 */
public class Program{

 /**
  * @param args
  */
 public static void main(def args){
  def proxy = new WSClient("http://localhost/PromoService.svc?wsdl", 
    Program.class.classLoader)
  
  def keywords = proxy.GetKeywordsFromMySpace("http://someurl/somepage.htm")
  if(keywords!=null) {
   if (proxy.HasPromo(keywords)) {
    def promo = proxy.GetFirstPromo(keywords)
    println "Promo: ${promo?.promoName?.getValue()}, ${promo?.promoDateTime}"
   }
  }
 }
}
Compiling then running the program yielded:
18/08/2008 12:19:33 PM org.apache.cxf.endpoint.dynamic.DynamicClientFactory outputDebug
INFO: Created classes: org.tempuri.GetFirstPromo, org.tempuri.GetFirstPromoResponse, org.tempuri.GetKeywordsFromMySpace, org.tempuri.GetKeywordsFromMySpaceResponse, org.tempuri.HasPromo, org.tempuri.HasPromoResponse, org.tempuri.ObjectFactory, com.microsoft.schemas._2003._10.serialization.ObjectFactory, org.datacontract.schemas._2004._07.svdemo.ObjectFactory, org.datacontract.schemas._2004._07.svdemo.PromoInfo
BindingInfo = [BindingInfo http://schemas.xmlsoap.org/wsdl/soap/]
o = SOAPBinding ({http://schemas.xmlsoap.org/wsdl/soap/}binding):
required=null
transportURI=http://schemas.xmlsoap.org/soap/http
Promo: Batman The Dark Knight, 2008-07-30T10:00:00

Much of the output was produced by CXF. Only the last line was produced by the test program. As you can see, the major difference between the Groovy version and the Java version using CXF is that in Java, you will use the wsdl2java tool to generate the Java client proxy and the data contract classes up front; but in Groovy, all that is automatic when you run the script. This makes the Groovy code very simple and small. However, the downside of this is that the IDE (Eclipse) cannot know the methods and members of the class up front. Therefore, there is no code-completion (intellisense) support for the business methods. Since I heavily rely on code-completion of the IDEs, this is a big disadvantage about dynamic languages for me (I do not memorise all the class members and methods names, and I do not read all the API docs either. I usually try to figure out the methods I need by looking at their names).

There are a couple of things I had to do for my code to run without errors:

  1. I had to upgrade my JRE used by Eclipse to a 1.6.0_u10rc. Eclipse automatically addes a bunch of JARs from the JRE, including the resources.jar, which includes the JAXB classes. In an earlier version of my JRE (1.6.0_u2) the JAXB was version 2.0, but the CXF bundled in GroovyWS 0.3.1 requires v2.1. However, if you are not using Eclipse (e.g. using the Groovy Console directly), this step is not required
  2. The CXF bundled with GroovyWS 0.3.1 had problem generating the code from WSDL - it complained about a namespace "doesnt contain ObjectFactory.class or jaxb.index". It turned out to be a CXF bug and had been fixed in CXF 2.1.1, thanks to a post by Bernie. After I replaced the org/apache/cxf branch of the groovyws-all-0.3.1.jar using the contents in cxf-2.1.1.jar, it was smooth sailing.

Related Posts:

2 comments:

Anonymous said...

Hello,

This is Sayli. I am consuming the service that is hosted by me at some url using our own product. But I am not able to get the proper o/p. I get it as “null”. The service is properly running in Soap UI 3.0. May I know the reason why?

Thanks & Regards,
~ Sayli

Anonymous said...

As far as I can see WSClient is not included in groovy-all-1.5.6.jar. Can not see how you got this working with the given libs.