Invoking web services with Spring Integration and XStream marshalling

Recently I had the opportunity to learn a bit about web services.  I had never worked with them before, but naturally my first thought was to use Spring Integration’s web services support because Spring Integration just makes everything so much simpler to do.

One of my main goals was keeping things as simple as possible.  That meant not having to get my hands too dirty converting objects to XML and XML to objects.  So I needed to find an XML marshalling solution that was just plain simple.  I didn’t have much experience with them in the past and I had tried DOM and SAX but found them too verbose.  So I looked at the ones that Spring Integration supported.  I finally settled on XStream because it’s annotation based configuration seemed so simple, and it was.

Before I go on, I should mention that I won’t be posting the full source of the project this tutorial is based on since it was for a client of mine.

Spring Integration configuration for starters

To begin, we’ll look at the Spring Integration configuration.  We’ll first register an XStream marshaller which will convert objects to XML and XML to objects.  Then I’ll define aliases to our objects as well as define which objects are annotated.  The aliases you define make it easier for the XStream marshaller to unmarshall XML responses into specific objects.  The alias or key is essentially the root element of the XML being unmarshalled.  Next the same classes are defined as a list for the annotated classes property.  Annotations that get added to elements of those classes assist XStream in making the XML output from marshalling look “prettier.”  More on that in the next section.

<beans:bean id="xstreamMarshaller" class="org.springframework.oxm.xstream.XStreamMarshaller">
	<beans:property name="aliases">
		<beans:props>
			<beans:prop key="request">com.example.Request</beans:prop>
			<beans:prop key="response">com.example.Response</beans:prop>
		</beans:props>
	</beans:property>
	<beans:property name="annotatedClasses">
		<beans:list>
			<beans:value>com.example.Request</beans:value>
			<beans:value>com.example.Response</beans:value>
		</beans:list>
	</beans:property>
</beans:bean>

<gateway id="requestGateway"
	default-request-channel="requestChannel"
	service-interface="com.example.RequestGateway"
	error-channel="errorChannel"/>

<chain input-channel="requestChannel">
	<ws:outbound-gateway uri="http://www.example.com/web-service"
		marshaller="xstreamMarshaller"/>
	
	<service-activator ref="responseServiceActivator"/>
</chain>

<chain input-channel="errorChannel" output-channel="mailChannel">
	<int-mail:header-enricher>
		<int-mail:subject value="${notification.subject}"/>
		<int-mail:to value="${notification.to}"/>
		<int-mail:from value="${notification.from}"/>
	</int-mail:header-enricher>
	
	<object-to-string-transformer/>
</chain>

<channel id="mailChannel"/>

<int-mail:outbound-channel-adapter channel="mailChannel" host="${smtp.server}"/>

Along with the XStream marshaller, I’ve defined a request gateway which will serve as the initial entry point for messages being sent to the web service.  The service interface is just that, a Java interface that defines what kind of message or more specific, what kind of message payload will be sent to the gateway.

public interface RequestGateway {

	public void invoke(Request request);
}

I’ve also defined a couple chains which simply encapsulate elements that share a common input channel but need to be invoked in specific order.  There’s the request channel which receives the messages from the request gateway, which is then sent off on the the <ws:outbound-gateway> element. That’s where the web service invocation actually takes place. Finally the error channel which I’ll use to send notification emails if an exception occurs.  When errors occur in downstream elements, they will flow up to the request gateway which will send them out on the error channel.

Annotating objects for XStream marshalling and unmarshalling

The next step is annotating the classes that will be marshalled/unmarshalled.  Let’s look at the Request and Response classes.

@RooJavaBean
@RooToString
@XStreamAlias("request")
@Component
public class Request {

	@XStreamAlias("param1")
	@Value("${request.param1}")
	private String p1;

	@XStreamAlias("param2")
	@Value("${request.param2}")
	private String p2;

	public Request() {}
}
@RooJavaBean
@RooToString
public class Response {

	@XStreamAlias("responseMap")
	private Map map;
}

As you might have guessed, I used Spring Roo for this project.  Spring Roo is just a really great tool.  What I want you to pay attention to are the @XStreamAlias annotations you see in a few places.  You see it first at the type level on the Request class and then at the member level too in both the Request and Response classes.  You might have noticed I don’t have this annotation at the type level on the Response class.  This is because I’m never marshalling the Response, I’m only ever unmarshalling the XML into a Response object and the root element “response” has already been defined as an alias for this class in the XStream marshaller in the previous section.  The @XStreamAlias annotation is what tells the marshaller what to use as the element name to make the XML look “prettier.”  So the Request object would get marshalled into something like the following.

<request>
  <param1>value</param1>
  <param2>value</param2>
</request>

Another small thing you might have noticed is that I’ve annotated the Request class with @Component and I’ve annotated each member with @Value.  The reason for this is because the values come from a properties file and the class will be instantiated as a singleton upon container initialization.  So then I can merely inject the Request instance where it’s needed.  This is good if the initial request always needs to be the same.

Without the @XStreamAlias annotation at the type level, you’d end up with a root element that looked more like <com.example.Request> which is the fully qualified name of the class.

Invoking the web service

Now that we have our XStream marshaller setup, our Spring Integration configuration complete and our object classes annotated, lets invoke the web service.

public class WebServiceInvoker {
	private RequestGateway requestGateway;
	private Request request;

	@Inject
	public void setRequestGateway(RequestGateway requestGateway) {
		this.requestGateway = requestGateway;
	}

	@Inject
	public void setRequest(Request request) {
		this.request = request;
	}

	public WebServiceInvoker() {
		requestGateway.invoke(request);
	}
}

This class is very simple.  I’m injecting the request gateway and the request instance, then I’m merely submitting the request instance to the request gateway.  The method “invoke” was defined earlier on the RequestGateway interface.

Handling the web service response

Now that we’ve made a request to the web service, we might need to handle some kind of response.  That’s where the responseServiceActivator defined in the requestChannel chain comes into use.

@Component
public class ResponseServiceActivator {

	@ServiceActivator
	public void handleResponse(Response response)
			throws RuntimeException {
		Map map = response.getMap();

		if(!ServiceUtilities.containsFaultCode(map)) {
			// handle the Response map.
		} else {
			throw new RuntimeException("Response contains a fault code.");
		}
	}
}

This is a very simple use case where you simply handle the payload of the message returned from the web service.  A method annotated with @ServiceActivator can either accept a parameter of type Message<Response> or Response in our case.  It’s just simpler to use Response directly.  In this method, I’m demonstrating how you might perform error handling if the web service you’re invoking does have the possibility of returning errors if something went wrong.  In this case, we’re throwing a runtime exception which will be thrown up the chain to the initial request gateway. However you can take it a step further and create your own exception classes for specific errors being thrown.  At that point the error will be sent to the errorChannel and emailed out.

Conclusion

So I hope I’ve covered enough of the fundamentals so that you can apply Spring Integration web services support along with XStream marshalling to your next or even current application.  The application this tutorial was based on had a few more web service requests in it. Mainly because after the initial request, I had to process the response and invoke a couple other web services based on the response. I had also implemented application specific error handling, instead of just throwing a basic runtime exception.

Btw, I think Spring Integration is the best thing since coffee!

Cheers!

About these ads

One thought on “Invoking web services with Spring Integration and XStream marshalling

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s