Last week I attended the SpringOne Congress in Antwerp. Just one or two days before the congress I wanted to create a proof of concept for a client connecting to a webservice. I have been using the proxy way (spring-remote), but I did not really like the way this works. Therefore I was looking for something else. I stumbled upon the Spring Webservices project. I did try this out before, but not for clients. I started working and it did not look very complicated. I must admit I needed the help from Arjen Poutsma himself to make it work, but now I have a very light weight solution. I like the approach very much, therefore I will briefly describe the solution I have created. You can of course find the sources online as well. Check the google code subversion repo for gridshore.

Overview of application

  • Build application using maven2
  • Web application build using spring webmvc
  • Webservice client created using spring-ws
  • Mapping between objects and xml using jaxb2 and spring-oxm

Maven 2 for building

This time not much details about the maven2 part. There are some things interesting though. Most important part is the creation of the jaxb generated classes using the maven2 jaxb2 plugin.

Using spring-webmv for web project

I do not think it is really interesting to talk a long time about this. There can be found a lot (better) resources online. I used the spring webmvc project to make the client i18n compatible, used the form controllers from spring to help with the error messages and validation stuff. For the webservices part the most interesting thing starts in the file service-applicationcontext.xml. This spring configurtion file contains the webservice client, the converters for jaxb (using generics to abstract the technique marshalling technique).

Webservice client created using spring-ws

Let’s start by having a look at the configuration:

<bean id="congressRegistrationDAO"
    class="nl.gridshore.samples.springws.integration.wsclient.impl.CongressRegistrationGateway">
  <property name="defaultUri" value="${cr.endpoint}" />
  <property name="marshaller" ref="marshaller"/>
  <property name="unmarshaller" ref="unmarshaller"/>
  <constructor-arg index="0" ref="congressRegistrationRequestConverter"/>
  <constructor-arg index="1" ref="congressRegistrationResponseConverter"/>
</bean>
<bean id="marshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
  <property name="contextPath" value="nl.gridshore.samples.jaxb"/>
</bean>
<bean id="unmarshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
  <property name="contextPath" value="nl.gridshore.samples.jaxb"/>
</bean>

This configured class is the class that knows how to connect to the webservice. It uses a few values and classes to do it’s work. The defaultUri is used to find the endpoint to connect to (we obtain it from a property file). Since we use JAXB2 to marshall and unmarshall the request we need the marshaller and unmarshaller. These (un)marshallers are provided by spring-ws as well. Actually they are provided by spring-oxm. The interface for the marshaller is the same as for the unmarshaller. The only thing you need to provide is the package where the jaxb files are generatd in. The other two references are converters used to convert the application specific components to JAXB2 components. More on this later as well. So the most important class is the Gateway class. Let’s have a look at that now.

package nl.gridshore.samples.springws.integration.wsclient.impl;

import nl.gridshore.samples.springws.domain.RegistrationDetails;
import nl.gridshore.samples.springws.integration.converter.Converter;
import nl.gridshore.samples.springws.integration.wsclient.CongressRegistrationDAO;

import org.springframework.ws.client.core.support.WebServiceGatewaySupport;
import org.springframework.ws.soap.client.core.SoapActionCallback;

public class CongressRegistrationGateway extends WebServiceGatewaySupport implements CongressRegistrationDAO {
  private final Converter requestConverter;
  private final Converter responseConverter;
	
  public CongressRegistrationGateway(Converter requestConverter,  
      Converter responseConverter) {
    this.requestConverter = requestConverter;
    this.responseConverter = responseConverter;
  }
	
  public String registerForCongress(final RegistrationDetails registrationDetails) {
    Object request = requestConverter.convert(registrationDetails);
    Object response = getWebServiceTemplate().marshalSendAndReceive(request);
    return responseConverter.convert(response);
  }
}

This is it, really. I show you the complete class, but in the end the most important works takes place in one line. That’s the one in bold. Here we use the special webServiceTemplate class and ask it to marshall our request object and send it as a soap message to the configured endpoint. Ofcourse you can do a lot more, but for most situations this is all it takes. Do not forget to extend the WebServiceGatewaySupport class.

Mapping between objects and xml using jaxb2 and spring-oxm

Not much to tell here as well. I keep saying this, but that’s because it is true. We have configured the marshaller and the unmarshaller which are provided by spring-oxm. We also call the right method from the template adapter called marshalSendAndReceive. I did create an interface and some implementations that enable the gateway to be ignorand to the type of marshalling and unmarshalling we use. This is my first try to do something with generics. There can be a better way, if you know one, please let me know as well :-). Let’s start with the generic interface.

public interface Converter {
  public E convert(T toBeConverted);
}

So we have an interface specifying we have a object as a parameter and an object as a return type. Then there is a method called convert that uses these generic types. At the moment I have two concrete implementations for creating the JAXB request and handling the JAXB Response. One of them is presented below.

public class CongressRegistrationResponseConverter implements Converter {
  public String convert(CongressRegistrationResponse toBeConverted) {
    String response = toBeConverted.getRegistrationCode();
      return response;
  }
}

As you can see we now have a concrete implementation for the generic interface. The returned object is a String and the parameter is a JAXB object called CongressRegistrationResponse. Now look back at the gateway code, check that there is no jaxb reference in that code.

Again check out the code at google code subversion repo for gridshore. You can already find the code for a server implementation there as well. The next blog will deal with the server. I am also working on a sample about the Rule engine called Drools. so stay tuned.

Creating a webservice client using Spring-ws and maven2