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