SOAP Service with WebLogic 12c and Camel

I recently acknowledged that I need to expand on my skills. Not only for business reasons, but also to keep me interested in Integration development. I decided that I wanted to focus on Apache Camel first and coming from the Oracle world I thought it would be fun to get a little experience on using Apache Camel with WebLogic. Most of this, first post, isn't WebLogic specific in any way so most of the information in this post should work in pretty much any servlet container. Later on I want to experiment with using WebLogic JMS queues and so on. So stay tuned for more posts in the future.

For my first endeavor I wanted to try and replicate something simple from Oracle Service Bus. So I decided to try to expose a simple SOAP service using Camel to handle the request and response. After searching a bit around I decided to go ahead and use camel-spring-ws for implementing the SOAP endpoint.

My full source is available on GitHub here

In this post I will try to highlight the things that I had trouble with. But this won't be a full tutorial on how to get this working. Think of it more like a collection of notes from my endeavor.

Maven Configuration

To build everything with Maven I used the following dependencies

<dependencies>
<dependency>
<artifactId>camel-core</artifactId>
<groupId>org.apache.camel</groupId>
<version>2.18.0</version>
</dependency>
<dependency>
<artifactId>camel-spring-ws</artifactId>
<groupId>org.apache.camel</groupId>
<version>2.18.0</version>
</dependency>
<dependency>
<artifactId>camel-jaxb</artifactId>
<groupId>org.apache.camel</groupId>
<version>2.18.0</version>
</dependency>
</dependencies>

To enable jaxb generation of java classes from my schemas I needed to add the following plugin

<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>jaxb2-maven-plugin</artifactId>
<version>1.6</version>
<executions>
<execution>
<id>xjc</id>
<goals>
<goal>xjc</goal>
</goals>
</execution>
</executions>
<configuration>
<schemaDirectory>${project.basedir}/src/main/resources/</schemaDirectory>
<outputDirectory>${project.basedir}/src/main/java</outputDirectory>
<clearOutputDir>false</clearOutputDir>
</configuration>
</plugin>

Spring WS Configuration

First thing I needed to do was to get Spring WS to expose my service. This was actually pretty easy to do. In my web.xml file I added the following

<web-app version="2.4" xmlns="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>Camel and Spring WS</display-name>

<servlet>
<servlet-name>spring-ws</servlet-name>
<servlet-class>org.springframework.ws.transport.http.MessageDispatcherServlet</servlet-class>
<init-param>
<param-name>transformWsdlLocations</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>spring-ws</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>

This adds the Spring WS MessageDispatcherServlet to my web application. To configure this I needed another xml file called spring-ws-servlet.xml with the following content.

<?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:camel="http://camel.apache.org/schema/spring"
 xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://camel.apache.org/schema/spring
http://camel.apache.org/schema/spring/camel-spring.xsd">
<bean id="weather" class="org.springframework.ws.wsdl.wsdl11.DefaultWsdl11Definition">
<property name="schema">
<bean id="xsd" class="org.springframework.xml.xsd.SimpleXsdSchema">
<property name="xsd" value="WEB-INF/classes/weather.xsd"/>
</bean>
</property>
<property name="portTypeName" value="weather"/>
<property name="locationUri" value="/weather"/>
</bean>
</beans>

This tells Spring WS to expose my service using the weather.xsd schema. A WSDL file is now available at http://localhost:7001/WEBLOGICCONTEXTROOT/weather/weather.wsdl 

NB! Both of these files should be placed in src/main/webapp/WEB-INF/

Camel Configuration

Now I wanted to have my exposed service pass on the payload to Camel for processing. It turns out that all I needed was to add a few sections to the spring-ws-servlet.xml file we created a minute ago. I added the following sections

<camel:camelContext id="camelContext">
<camel:routeBuilder ref="weatherRoute"/>
</camel:camelContext>
<bean id="weatherRoute" class="dk.moerks.weather.routes.WeatherRoute"/>

<bean id="endpointMapping" class="org.apache.camel.component.spring.ws.bean.CamelEndpointMapping" />

The first adds a Route to Camel and the second simply allows camel to map endpoints to the spring-ws services. After this it is now possible in my Route to reference my Spring WS service.

Camel Route

As seen above I added a Route to Camel called weatherRoute which I implemented in the java class WeatherRoute shown in the following.

package dk.moerks.weather.routes;

import dk.moerks.weather.processors.WeatherProcessor;
import dk.moerks.weather.schemas.WeatherRequest;
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.model.dataformat.JaxbDataFormat;

public class WeatherRoute extends RouteBuilder{
public void configure() throws Exception {
JaxbDataFormat jaxb = new JaxbDataFormat();
jaxb.setContextPath(WeatherRequest.class.getPackage().getName());

WeatherProcessor weatherProcessor = new WeatherProcessor();

from("spring-ws:rootqname:{http://moerks.dk/soapws/schemas}WeatherRequest?endpointMapping=#endpointMapping")
.unmarshal(jaxb)
.process(weatherProcessor)
.marshal(jaxb);
}
}

This is a simple Camel route that gets the requests from my Spring WS service where the Root Element Name is {http://moerks.dk/soapws/schemas}WeatherRequest. It then unmarshals the request using jaxb and passes it along to a Camel Processor. The result from that Processor is then marshalled using jaxb and passed back to the requesting client.

That is basically it! Of course I wrote a few more files to tie it all together and implemented a stupid Processor, but all of that is available on Github here