WebService using Spring Integration
Article to show WebService call ( SOAP ) using Spring Integration . It uses Gateway , Channel and Router
What you will need
1. Schema or WSDL to generate the Marshaller and UnMarshaller Objects .
2. Java Interface to Call WebService
3. Bean configuration defining gateway , channel , router etc
4. Java Transformer
Generation of Marshaller and UnMarshaller
Marshaller and a UnMarshaller are basically Java representation of the Request and Response , these can be generated by xjc utility on schema (or) wsimport on WSDL. If you don't have the schema , it can be generated by the xml using many tools like http://www.freeformatter.com/ Here is example of generating them from schema using ant ( uses xjc )
<?xml version = "1.0" encoding = "UTF-8"?>
<project name = "mywsproject"
default = "generate">
<property file = "build.properties"/>
<fileset id = "tools"
dir = "tools">
<include name = "**/*.jar"/>
</fileset>
<taskdef name = "xjc" classname = "com.sun.tools.xjc.XJCTask">
<classpath>
<fileset refid = "tools"/>
</classpath>
</taskdef>
<target name = "generate">
<xjc schema = "src/main/xml/country.xsd"
destdir = "src/main/java"
package = "com.my.services.model"/>
</target>
</project>
WSDL will have the schema and "wsimport" utility will generate the Classes for Marshaling and Un-Marshaling ( details of the wsimport utility can be found here http://ajaxrocks.blogspot.com/2013/08/jax-ws-call-ws-using-maven.html) . If you are generating using the WSDL there will be the WebService and PortType classes , delete them after generation .
Java Interface to Call WebService
Interface to call the webservice , it uses the generated classes . My case the class is GetCountryRequest and GetCountryResponse
package com.my.services.api;
import javax.xml.bind.annotation.XmlElement;
import io.spring.guides.gs_producing_web_service.GetCountryRequest;
import io.spring.guides.gs_producing_web_service.GetCountryResponse;
public interface MyService {
GetCountryResponse countryRequest(GetCountryRequest request);
}
Stuff to Configure ( full xml shown below )
Gateway
Specify's the interface and map the method to the header
<int:gateway id="myService" service-interface="com.my.services.api.MyService" default-request-channel="myService_routingChannel"> <int:method name="countryRequest"> <int:header name="REQUEST_TYPE" value="countryRequest" /> </int:method> </int:gateway>
Publish-Subscribe Channel
Specify the Channel to map this way we can map the header value to the channel<int:publish-subscribe-channel id="myService_routingChannel" />
Header-Value Router
Route the call based on the header value to the chain<int:header-value-router input-channel="myService_routingChannel" header-name="REQUEST_TYPE"> <int:mapping value="countryRequest" channel="myService_countryRequestChannel" /> </int:header-value-router> <int:channel id="myService_countryRequestChannel" />
Chain
Service-Activation - transformer and the method to be called in the java class
Soap-Action ( ws:header-enricher ) - soap-action to be called ( you will find this in the wsdl ). Example this one is commented out as soap-action is empty . You need to provide this otherwise
outbound-gateway - WebService end point with message-sender and unmarshaller
<int:chain input-channel="myService_countryRequestChannel" output-channel="myService_countryRequestOutputChannel" > <int:service-activator ref="MyWSTransformer" method="countryRequestSOAPRequest" /> <!-- <ws:header-enricher> <ws:soap-action value="" /> </ws:header-enricher> --> <ws:outbound-gateway uri="http://localhost:8080/ws" message-sender="MY.SOAP-MessageSender" unmarshaller="myrequestJAXBUnMarshaller"/> </int:chain>
Outbound gateway
Configure the outbound gateway <ws:outbound-gateway
uri="${my.purchase.url}"
message-sender="MY.SOAP-MessageSender" unmarshaller="mypurchaseJAXBUnMarshaller"/>
</int:chain>
Authentication can also be added using
<beans:bean id = "org.apache.commons.httpclient.Credentials-Service"
class = "org.apache.commons.httpclient.UsernamePasswordCredentials"
c:userName = "${userName}"
c:password = "${password}"/>
and specify the ref as credentials-ref in the ws:outbound-gateway
Full XML
<?xml version = "1.0" encoding = "UTF-8"?>
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns:int="http://www.springframework.org/schema/integration"
xmlns:http="http://www.springframework.org/schema/integration/http"
xmlns:ws="http://www.springframework.org/schema/integration/ws"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:si-xml="http://www.springframework.org/schema/integration/xml"
xmlns:oxm = "http://www.springframework.org/schema/oxm"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
http://www.springframework.org/schema/integration/http http://www.springframework.org/schema/integration/http/spring-integration-http.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/integration/ws http://www.springframework.org/schema/integration/ws/spring-integration-ws.xsd
http://www.springframework.org/schema/integration/xml http://www.springframework.org/schema/integration/xml/spring-integration-xml.xsd
http://www.springframework.org/schema/oxm http://www.springframework.org/schema/oxm/spring-oxm.xsd">
<!-- <beans:bean id="myManager"
class="com.my.services.manager.MyServiceImpl" >
<beans:property name="myService" ref="myService" />
</beans:bean>
-->
<beans:bean id="MyWSTransformer"
class="com.my.services.transformer.MyWSTransformer" />
<beans:bean id="MY.SOAP-MessageSender"
class="org.springframework.ws.transport.http.HttpComponentsMessageSender">
<beans:property name="connectionTimeout" value="3000" />
<beans:property name="readTimeout" value="5000" />
</beans:bean>
<int:publish-subscribe-channel id="myService_routingChannel" />
<int:gateway id="myService" service-interface="com.my.services.api.MyService"
default-request-channel="myService_routingChannel">
<int:method name="countryRequest">
<int:header name="REQUEST_TYPE" value="countryRequest" />
</int:method>
</int:gateway>
<int:header-value-router input-channel="myService_routingChannel" header-name="REQUEST_TYPE">
<int:mapping value="countryRequest" channel="myService_countryRequestChannel" />
</int:header-value-router>
<int:channel id="myService_countryRequestChannel" />
<int:chain input-channel="myService_countryRequestChannel"
output-channel="myService_countryRequestOutputChannel" >
<int:service-activator ref="MyWSTransformer"
method="countryRequestSOAPRequest" />
<!-- <ws:header-enricher>
<ws:soap-action value="" />
</ws:header-enricher> -->
<ws:outbound-gateway
uri="http://localhost:8080/ws"
message-sender="MY.SOAP-MessageSender" unmarshaller="myrequestJAXBUnMarshaller"/>
</int:chain>
<si-xml:unmarshalling-transformer id="countryRequestUnmarshaller"
input-channel="myService_countryRequestOutputChannel"
unmarshaller="myrequestJAXBUnMarshaller" />
<oxm:jaxb2-marshaller id = "myrequestJAXBUnMarshaller">
<oxm:class-to-be-bound name = "io.spring.guides.gs_producing_web_service.GetCountryResponse"/>
<oxm:class-to-be-bound name = "io.spring.guides.gs_producing_web_service.Country"/>
<oxm:class-to-be-bound name = "io.spring.guides.gs_producing_web_service.Currency"/>
<!-- <oxm:class-to-be-bound name = "io.spring.guides.gs_producing_web_service.GetCountryRequest"/> -->
</oxm:jaxb2-marshaller>
</beans:beans>
Java Transformer
Transformer has the method that makes the SOAP Request call , its clear if you look at the requestXML string.
GetCountryRequest is already marshaled and available as a input parameter .
GetCountryRequest is already marshaled and available as a input parameter .
package com.my.services.transformer;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.integration.annotation.Header;
import org.springframework.stereotype.Component;
import io.spring.guides.gs_producing_web_service.GetCountryRequest;
@Component
public class MyWSTransformer {
static private final Logger logger = LoggerFactory.getLogger(MyWSTransformer.class);
public static String countryRequestSOAPRequest(GetCountryRequest request)
{
logger.info("Calling MyWSTransformer with GetCountryRequest " +request.getName());
String requestXml =" <gs:getCountryRequest xmlns:gs=\"http://spring.io/guides/gs-producing-web-service\">"+
" <gs:name>"+request.getName()+"</gs:name> "+
" </gs:getCountryRequest>";
return requestXml;
}
}
2 comments:
Hi, I did check the code and looks like stubs are generated? If my interpretation is correct then it is not spring integration.
Yes , Stubs are generated and you can use wsimport or utlitity from your IDE
Post a Comment