Accessing external web service from within Fuse ESB using soap over http
Acessing external web service using soap/http
This use case describes how to create an external Warehouse Web service and access it from FUSE ESB. It demonstrates how to
- Create the external service
- Package the required artifacts into a WAR and deploy it to either Tomcat/Jetty
- Create a service unit for accessing the service in FUSE ESB
The Warehouse service is used to determine if Items are in Stock or awaiting the arrival of Stock.
This use case uses the SOAP/HTTP protocol.

In the Logisticx demo the Warehouse Source code will be located in "warehouse/service-warehouse" and its deployable artifact will be called "warehouse.war". The CXF BC Provider for accessing the Warehouse Service from FUSE ESB is defined in the order-route/warehouse-provider-soaphttp-su service unit and it will be deployed in the "order-sa" Service assembly. The order-route project is described as part of the Content Based Routing use case.
Walkthrough
To create and access an external Web service from Fuse ESB you need to do the following:
- Create the external web service
- Create the servlet deployment descriptor (web.xml) file.
- Create the web service configuration file (ws-beans.xml).
- Build and deploy the war file on Tomcat.
- Create a CXF-BC provider service unit to setup access to the external service.
1. Create the external web service
We are not going to go into detail here about creating the actual web service as this has been described earlier at creating a web service for the order web service.
The difference here is that the web service is external to the FUSE ESB but the actual semantics of a web service are the same. It is the packaging around deployment that is different.
The full implementation of the external warehouse soap/http is in the Logisticx warehouse module in the directory service-warehouse.
So the SEI (service endpoint interface) and our implementation are setup as follows:
Example 1.0 Warehouse SEI
@WebService( targetNamespace = "http://logisticx.demo.fuse.iona.com/warehouseService/") public interface Warehouse { /** * Used to process an Order at the warehouse service. * @param order The order object being submitted by the customer * @return */ @WebMethod public abstract OrderStatus inStock(Order order); @WebMethod public abstract void updateStock(Order order); }
Here we have split up the implementation classes into having a base implementation and sub classes as we want other services to inherit these operations.
Example 1.1 Warehouse implementation
public class WarehouseBaseImpl implements Warehouse { Order ord = null; /** * Used to determine if items are in stock */ @WebMethod public OrderStatus inStock(Order order) { ord = order; OrderStatus stat = null; if (order != null) { stat = order.getStatus(); LineItem items = order.getLineItem(); if (items.getItemId() == 1002 || items.getItemId() == 1003) { stat.setStatusCode(OrderStatus.StatusCode.ORDER_INSTOCK); return stat; } else if (items.getItemId() == 1004 || items.getItemId() == 1005) { stat.setStatusCode(OrderStatus.StatusCode.ORDER_INSTOCK); return stat; } else { stat.setStatusCode(OrderStatus.StatusCode.ORDER_AWAITINGSTOCK); return stat; } } return stat; } @WebMethod public void updateStock(Order order) { } }
The CXF and ActiveMQ jars need to be added into the container classpath. Add these dependencies to your pom.xml file.
The SEI is defined with two operations "inStock" and "updateStock". These operations are used to check the availability of items in stock. The status returned can be ORDER_INSTOCK or ORDER_AWAITINGSTOCK.
service-warehouse/pom.xml: This pom file generates the wsdl using CXF's java2wsdl. It also creates the WAR file that will host the web service. The Maven Assembly Plugin is used here to create an additional JAR artifact containing just the JAX-WS objects. This artifact can then be included as a dependency in a SOAP client module's pom.xml file used for Testing.
Copy the generated wsdl file to service-warehouse/src/main/webapp/WEB-INF/wsdl
Example 1.2 pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> .... <plugin> <artifactId>maven-assembly-plugin</artifactId> <version>2.2-beta-1</version> <configuration> <descriptors> <descriptor>src/assembly/warehouse-jaxwsjar.xml</descriptor> </descriptors> <appendAssemblyId>true</appendAssemblyId> <attach>true</attach> </configuration> <executions> <execution> <id>make-assembly</id> <phase>package</phase> <goals> <goal>single</goal> </goals> </execution> </executions> </plugin> .... }
2. Create the servlet deployment descriptor (web.xml) file.
The deployment descriptor below will need modification depending on the web service stack that you will be using. We are using CXF, which offers two options for service provider configuration: a standard configuration file named "cxf-servlet.xml" that loads all internal CXF modules and another option for explicitly listing the CXF modules you wish to load. Note with the latter option you can name the file whatever you wish but to keep things simple we will keep the file named web.xml. Each stack uses its own servlet to handle the web service requests.
As we are using Maven save the web.xml file to service-warehouse/src/main/webapp/WEB-INF(Maven) directory of your project.
Example 1.3 web.xml for the warehouse service (soap/http)
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.4" mlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"> <display-name>Spring Warehouse</display-name> <description>Spring Warehouse sample application</description> <!-- - Loads the root application context of this web app at startup, - by default from "/WEB-INF/applicationContext.xml". - Note that you need to fall back to Spring's ContextLoaderServlet for - J2EE servers that do not follow the Servlet 2.4 initialization order. - - Use WebApplicationContextUtils.getWebApplicationContext(servletContext) - to access it anywhere in the web application, outside of the framework. - - The root context is the parent of all servlet-specific contexts. - This means that its beans are automatically available in these child contexts, - both for getBean(name) calls and (external) bean references. --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <context-param> <param-name>contextConfigLocation</param-name> <param-value>WEB-INF/ws-beans.xml</param-value> </context-param> <!-- - A web app can contain any number of such servlets. - Note that this web app has a shared root application context, serving as parent - of all DispatcherServlet contexts. --> <servlet> <servlet-name>CXFServlet</servlet-name> <display-name>CXFServlet</display-name> <description>Apache CXF Endpoint</description> <servlet-class> org.apache.cxf.transport.servlet.CXFServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>CXFServlet</servlet-name> <url-pattern>/services/*</url-pattern> </servlet-mapping> </web-app>
3. Create the web service configuration file (ws-beans.xml).
The configuration file will be different depending on what framework you will use. Here we are using CXF. The configuration files work in conjunction with (and take precedence over) the JSR-181 annotations on the SIB for configuration of the web service provider.
CXF uses a Spring-based configuration file. Copy the following ws-beans.xml file to your service-warehouse/src/main/webapp/WEB-INF directory for Maven.
Example 1.4 wsbeans.xml for the warehouse service (soap/http)
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jaxws="http://cxf.apache.org/jaxws" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd"> <!-- List of individual modules of CXF runtime being loaded --> <import resource="classpath:META-INF/cxf/cxf.xml" /> <import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" /> <import resource="classpath:META-INF/cxf/cxf-servlet.xml" /> <jaxws:endpoint id="WarehousePoint" implementor="#WarehouseImpl" address="/warehouse" endpointName="ware:WarehouseEndpoint" serviceName="ware:WarehouseService" xmlns:ware="http://logisticx.demo.fuse.iona.com/warehouseService/"/> <bean id="WarehouseImpl" class="com.iona.fuse.demo.logisticx.service.warehouse.WarehouseImpl"/> </beans>
4. Build and deploy the war file on Tomcat.
There are a lot of articles and tutorials about setting up tomcat so we are not going to describe that here.
Example : Glen Mazza's blog has a very good description of the steps you need to take to get Tomcat up and running.
Ensure that the JMS Broker is running before starting Tomcat (There is an embedded JMS Broker started as part of deploying and starting the Order Processing Assembly to FUSE ESB).
You have two options - you can do "mvn install" and copy the war file to the Webapps directory of tomcat or setup the tomcat-maven-plugin in your pom.xml and run "mvn tomcat:deploy". This command will first compile the service classes and package them into a WAR file before deploying.
After deployment, to make sure the web service was properly loaded by Tomcat, try to access the web service's wsdl at http://localhost:8080/warehouse/services/warehouse?wsdl
If you are getting an error message instead, check Tomcat's server logs in the $CATALINA_HOME/logs directory for more detailed information--the timestamps of the files will let you know which log files are being updated.
5. Create a CXF-BC provider service unit to setup access to the external service.
Take a look at the Content Based Router use case to setup the order-route project that this service unit will be part of.
After you have the order-route project setup - run the following maven archetype command from LOGISTICX/order-route directory.
Example 1.5 Maven Archetype command
DEMO_LOCATION\> mvn archetype:create -DarchetypeGroupId=org.apache.servicemix.tooling -DarchetypeArtifactId=servicemix-cxf-bc-service-unit -DarchetypeVersion=3.3.1.5-fuse -DgroupId=com.iona.fuse.demo.logisticx.order.warehouse -DartifactId=warehouse-provider-soaphttp-su
This creates a directory called warehouse-provider-soaphttp-su that is taken from the artifactId parameter.
It generates
- xbean.xml configuration file
- Same wsdl file
- POM File
The first three parameters to the mvn command identify which Maven archetype to use for the archetype:create goal, while the groupId and artifactId parameters identify the Maven project that is being generated.
For the Order Processing service to send a request to the external warehouse service it needs to create a CXF-BC service unit and set the cxf-bc provider in the xbean.xml file. You also need to provide the generated wsdl file in the resources directory with the xbean.xml file so that it will be on the classpath.
Renaming the Project
You need to give the project a unique name as follows:
In the warehouse-provider-soaphttp-su directory.
1. Open the pom.xml in a text editor.
2. Change the <name> attribute to <name>Order provider Service Unit</name>.
Because we ran Maven's archetype:create from the directory containing the top level pom.xml, Maven has used the groupId from the parent pom.xml for our new service unit and added a module to the parent pom.xml.
Example 1.3: Module definition
<modules> <module>order-camel-cbr-su</module> <module>warehouse-provider-soaphttp-su</module> </modules>
Updating the configuration
The configuration for the warehouse-provider-soaphttp-su will be added to the generated xbean.xml file.
LOGISTICX_DIR/order-route/warehouse-provider-soaphttp-su/src/main/resources/xbean.xml
Change the xbean.xml file to the following
Example 1.6 xbean.xml file
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns:cxfbc="http://servicemix.apache.org/cxfbc/1.0" xmlns:ware="http://logisticx.demo.fuse.iona.com/warehouseService/"> <!-- Accesses the external soap/http warehouse service --> <cxfbc:provider service="ware:WarehouseService" endpoint="WarehouseEndpoint" useJBIWrapper="false" wsdl="classpath:warehouse.wsdl" locationURI="http://localhost:8080/warehouse/services/warehouse"/> </beans>
The locationURI is important here as it specifies the location of where the warehouse service is.
Update Order-SA Service Assembly
This service unit will be part of the order-route-sa assembly.
You will need to add the following dependency to the order-sa/POM File
Example 1.7 Order-SA POM File
.... <dependency> <groupId>com.iona.fuse.demo.logisticx.order.warehouse</groupId> <artifactId>warehouse-provider-soaphttp-su</artifactId> <version>${logisticx-version}</version> </dependency> ....
This service will get invoked from the "cbrService" of the Content Based Router if an Ipod Product is ordered. It is part of the order-sa Service Assembly.
