Tuesday 8 December 2009

Spring Integration - GatewayProxyFacadeBean


Spring Integration has a great piece of functionality that allows you to hide and totally de-couple the integration infrastructure of your solution from the calling application code without the calling code being dependant on the Spring Integration API. This functionality is called GatewayProxyFacadeBean. The following example will demonstrate how to use GatewayProxyFacadeBean, but in essence we will be creating a Java Interface that can be injected into any bean that needs to use the service and GatewayProxyFacadeBean will automatically generate a proxy for that interface and deal with invoking the Spring Integration API for us. Sound easy?? Well it is!

The context of this example is calling the tempconvert web service supplied by W3Schools (http://www.w3schools.com/webservices/tempconvert.asmx) to convert a temperature from fahrenheit to celsius.

First thing I did was to create my Spring Integration config that deals with calling the web service. For this example the actual configuration is not important but here it is anyway:


<chain input-channel="temperatureConversionRequest" output-channel="temperatureConversionResponse">

<transformer ref="temperatureConversionTransformer" method="transformRequest" />

<ws:header-enricher>
<ws:soap-action value="http://tempuri.org/FahrenheitToCelsius" />
</ws:header-enricher>

<ws:outbound-gateway uri="http://www.w3schools.com/webservices/tempconvert.asmx" />

<transformer ref="temperatureConversionTransformer" method="transformResponse" />

</chain>

<channel id="temperatureConversionResponse" />


Basically I'm expecting a decimal as the payload of a message delivered to the temperatureConversionRequest channel. Then transforming the message using a custom transformer to the format expected by the web service, enriching the header of the message with the relevant SOAP action (ws-addressing), calling the web service and finally parsing the response to a decimal to be put on the temperatureConversionResponse channel.

The next thing I did was define the java interface which looks like this:

public interface TemperatureConversionService {
BigDecimal convertFahrenheitToCelsius(BigDecimal request);
}


Now to add the GatewayProxyFacadeBean configuration to my Spring Integration config. This is the bridge between the calling Java code and my Spring Integration messaging infrastructure. GatewayProxyFacadeBean will create a proxy implementing the interface we just defined and handle all the calling of the Spring Integration API and conversion of Java objects to Spring Integration messages. Essentially it will create a Spring Integration message using the input parameter as the payload and put that message on the defined request channel. As we have also defined a reply channel it will wait for the return message to appear on that channel and extract the payload of the message to be the return of the method call.

<gateway id="temperatureConversionService" service-interface="org.rhart.TemperatureConversionService"
default-request-channel="temperatureConversionRequest default-reply-channel="temperatureConversionResponse" />


And that's it! In order to see this work and to understand what will be required on the calling Java code side I have a unit test with the interface injected which makes a call to the convertFahrenheitToCelsius method. As you can see below there are no Spring Integration dependencies and if I desired could easily plug in a different implementation without any affect to the calling code.

public class TemperatureConversionTests {

@Autowired
TemperatureConversionService temperatureConversionService;

@Test
public void testUsingGatewayProxyFactoryBean() {

BigDecimal conversion = temperatureConversionService.convertFahrenheitToCelsius(new BigDecimal("90.0"));

Assert.assertEquals(new BigDecimal("32.2222222222222"), conversion);

}

}


In my opinion this is a great little piece of functionality that hides all the messaging infrastructure from any calling client and leaves the client totally de-coupled. Using the messagingTemplate direct is not exactly difficult either but this is much more elegant and removes any dependency from the Spring Integration API.

The attached zip file contains the Eclipse based Maven project in it's entirety gatewayProxyFactoryBeanDemo

1 comment:

Search This Blog