Thursday, 10 December 2009

Make your Spring project Groovy


I know there's already an example in the Spring documentation (http://static.springsource.org/spring/docs/2.0.8/reference/dynamic-language.html) of using dynamic languages and having the Spring container instantiate, configure and dependency inject the resulting objects but after trying the example using Maven and STS there's a couple of extra points worth writing down.

So, the first thing I did was to create a new Maven project just using the quickstart archetype. At this point I added the Groovy nature to the newly created project (right click > Groovy > Add Grovy Nature) and added Groovy as a dependency in the POM


<dependency>
<groupId>org.codehaus.groovy</groupId>
<artifactId>groovy</artifactId>
<version>${groovy.version}</version>
</dependency>


Next I created the Java interface, Groovy script that implements it and a Spring application context to configure my bean. Now at this point you have 2 options:

Option 1
Add the GMaven plugin to your POM to compile your Groovy scripts and configure them as just plain beans in the Spring context

<plugin>
<groupId>org.codehaus.groovy.maven</groupId>
<artifactId>gmaven-plugin</artifactId>
<version>1.0-rc-5</version>
<executions>
<execution>
<goals>
<goal>generateStubs</goal>
<goal>compile</goal>
<goal>generateTestStubs</goal>
<goal>testCompile</goal>
</goals>
<configuration>
<sources>
<fileset>
<directory>${project.build.sourceDirectory}</directory>
<includes>
<include>**/*.groovy</include>
</includes>
<directory>${project.build.testDirectory}</directory>
<includes>
<include>**/*.groovy</include>
</includes>
</fileset>
</sources>
</configuration>
</execution>
</executions>
</plugin>


<bean id="messenger" class="org.rhart.GroovyMessenger">
<property name="message" value="Groovy In Spring Works!" />
</bean>


Option 2
Include *.groovy files as resources to be exported as part of the build and use the lang namespace within the Spring context

<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
<include>**/*.xsl</include>
<include>**/*.groovy</include>
</includes>
</resource>
</resources>


<lang:groovy id="messenger" script-source="classpath:org/rhar/GroovyMessenger.groovy">
<lang:property name="message" value="Groovy In Spring Works!"></lang:property>
</lang:groovy>


You can find the complete Maven based eclipse project here

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

Thursday, 4 June 2009

Spring Web Services - Deploying to WAS 6.1


If like me you've ever tried to deploy a Spring web service, that auto generates the WSDL, to WebSphere Application Server you've probably encoutered the same WSDLException that I have:
Caused by: WSDLException: faultCode=CONFIGURATION_ERROR: No Java extensionType found to represent a '{http://www.w3.org/2001/XMLSchema}schema' element in the context of a 'javax.wsdl.Types'.:
at javax.wsdl.extensions.ExtensionRegistry.createExtension(Unknown Source)
at org.springframework.ws.wsdl.wsdl11.provider.InliningXsdSchemaTypesProvider.addTypes(InliningXsdSchemaTypesProvider.java:102)
at org.springframework.ws.wsdl.wsdl11.ProviderBasedWsdl4jDefinition.afterPropertiesSet(ProviderBasedWsdl4jDefinition.java:233)
at org.springframework.ws.wsdl.wsdl11.DefaultWsdl11Definition.afterPropertiesSet(DefaultWsdl11Definition.java:170)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1369)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1335)

This is basically down to IBM's JDK shipping with old versions of WSDL4J, Xalan and Xerces and also has other side effects detailed in the following posts:
http://jira.springframework.org/browse/SWS-35
http://forum.springsource.org/archive/index.php/t-26464.html
http://forum.springsource.org/showthread.php?t=53734

There seem to be many suggestions on how to solve this problem from setting environment variables to copying the correct version of the jars to lib/ext directory of the
WAS install but the best solution I've come across is to put the correct jars in the WEB-INF/lib directory of the web application and change the classloader mode to PARENT_LAST and WAR classloader policy to APPLICATION in the EAR's deployment descriptor.


One thing to note is that changing these settings just at the EAR level is not sufficient, you need to change them at the WAR level. This has the effect of telling your web application to locate classes using the WAR classloader first (WEB-INF/lib), if it cant find them then delegate to the EAR classloader and finally to the WASext classloader until they are found.

Search This Blog