Over a million developers have joined DZone.

Pattern Based Development with ServiceMix

· Integration Zone

Build APIs from SQL and NoSQL data sources in seconds. Read the Creating REST APIs white paper, brought to you in partnership with CA Technologies.

Are you still working with integration products from one of the typical large integration vendors such as IBM and Tibco and looking for a more lightweight approach? Then these two articles on Mule and Apache ServiceMix can serve as an eye-opener to the potential of Open Source ESBs. If you are already familiar with Mule or Apache ServiceMix, these articles will provide some insight in the new features of the latest versions of these Open Source ESBs and show you how to approach the design of your integration solution.

These two articles will also try to demystify the discussion between a Java Business Integration (JBI) based ESB implementation (Apache ServiceMix) and a custom developed ESB implementation (Mule). In these two articles we will implement an integration solution with both Mule and Apache ServiceMix, to show that both approaches each have their merits and that there is actually quite a bit of overlap between these two approaches.

In the first article, we discussed Mule. In this second article we’ll focus on JBI and ServiceMix, ServiceMix 3.2.1 to be more specific, which is the latest production release of the ServiceMix project.

A short introduction into JBI

To understand the architecture of ServiceMix, we will first need to discuss the JBI specification a little bit. JBI defines a standards-based architecture that can be used as the basis for Java-based integration products, in particular an ESB. Besides ServiceMix there are a couple of other Open Source ESBs that are based upon this standard, like OpenESB and Petals. Of course if you want to know more, the complete specification is available at http://jcp.org/en/jsr/detail?id=208. Even though this is a 240 page document, it’s very well written and readable.

There are a couple of key concepts in the JBI specification. There are two kinds of JBI components, the service engine (SE) and binding component (BC), which provide integration logic. BCs provide communication functionality to send messages to and from the JBI container, like for example a JMS BC, a File BC and a HTTP BC. SEs provide integration functionality that can be used to build your integration solutions, such as routing, transformation and routing logic. The BCs and SEs communicate with each other via a normalized message router (NMR). With the presence of a NMR, the BCs and SEs are decoupled and communication is done with so-called normalized messages. The communication layer between the BCs en SEs and the NMR is implemented with a delivery channel (DC). The DC is a bidirectional communication pipe that provides an API contract for BCs and SEs to be able to sent and receive messages from the NMR. An overview of these foundational concepts of JBI is provided in figure 1.

Figure 1 An overview of the important JBI concepts and their relationship.

The JBI infrastructure shown in figure 1 is exactly what Apache ServiceMix provides for you. ServiceMix provides a JBI container that implements a NMR, normalized message and DC and more important for an integration developer, it provides a lot of BCs and SEs. A couple of these BCs and SEs are shown in figure 2.

Figure 2 An overview of the Apache ServiceMix architecture, showing a number of the binding components and service engines provided out-of-the-box.

Now we have discussed the theory behind JBI and showed an overview of Apache ServiceMix in figure 2, it’s time to actually implement something. But what do we have to implement to get an integration solution running on ServiceMix? Well, we have to create service units (SUs) and a service assembly (SA). For every binding component and service engine that you want to use in your integration solution, you will have to create a service unit. The created service units can be packaged as a service assembly, which can be deployed on a JBI container such as ServiceMix. A SU is just a JAR file with a configuration file for the specific BC or SE. And a SA is also just a JAR file with a JBI deployment descriptor named jbi.xml. But let’s stop talking and implement a simple message flow for ServiceMix.

Build a ServiceMix 3.2.1 message flow

In the first article about Mule, we introduced a hello world example, showing the basics of the Mule configuration. So let’s implement the same example with ServiceMix. First we need to select the BCs and SEs we will use in the implementation of the hello world example. First, we need JMS connectivity to receive and send messages in the ServiceMix container, so we need a JMS BC.

Then we need to implement a simple Java bean, which returns the input name parameter with an injected prefix. We can implement this functionality with at least two SEs: the Bean SE and the JSR181 SE. In this example we will use the JSR181 SE, because this SE provides a nice abstraction layer from JBI and the ServiceMix container, while the Bean SE provides functionality for more advanced use cases. In figure 3 an overview is provided of the SUs that we need to create for the hello world SA.

Figure 3 An overview of the service units that we need to implement for the hello world example.

We will implement a JMS consumer with a JMS BC configuration and a HelloComponent configuration and implementation with the JSR181 SE. The configuration within ServiceMix is implemented with the Apache XBean framework, which is a sub-project of the Apache Geronimo project. The XBean framework makes it easy to define your own configuration language with out-of-the-box support for, for example, Spring. The SU configuration in ServiceMix is implemented with an xbean.xml file, which uses a set of elements and attributes specific to the BC or SE. In listing 1 the configuration for the JMS BC is shown, which uses the XBean configuration of the JMS BC.

Listing 1 JMS configuration for the simple example in ServiceMix

<beans xmlns:jms="http://servicemix.apache.org/jms/1.0"
xmlns:esb="http://esbinaction.com/simple">

<jms:consumer service="esb:simpleReceiver"
endpoint="jmsEndpoint"
targetService="esb:helloComponent"
destinationName="in-queue"
replyDestinationName="out-queue"
connectionFactory="#connectionFactory"
marshaler="#replyInOutMarshaler"/>

<bean id="replyInOutMarshaler"
class="org.apache.servicemix.jms.endpoints.DefaultConsumerMarshaler">
<property name="mep" value="http://www.w3.org/2004/08/wsdl/in-out" />
</bean>

<bean id="connectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="tcp://localhost:61616" />
</bean>
</beans>

The JMS BC configuration uses a beans root element, which refers to the Spring configuration language. As you can see the ServiceMix JMS BC namespace is declared at root level. The JMS consumer declaration, which uses the JMS BC namespace, configures most of the JMS functionality we need. The destinationName and replyDestinationName attributes tell the JMS BC to respectively listen for messages on the in-queue and sent response messages to the out-queue.

It may seem a bit strange at first sight that we also configure a response destination in a JMS consumer. This choice is related to the use of message exchange patterns (MEPs) within JBI and ServiceMix. For every message consumed by the ServiceMix container a message exchange will be created with a specific MEP. The concept of MEPs is introduced in the WSDL specification and the supported MEPs in JBI are in-out, in-only, robust-in-only and optional-in-only. The most common MEPs are of course in-out and in-only and these MEPs are also related to our choice for the JMS BC configuration.

By default the JMS consumer uses an in-only MEP, so this means that a JMS message will be consumed from a queue and sent on in the ServiceMix container. But the JSR181 hello Java bean returns a response, and for an in-only MEP there can be no response message. So we need some way to transform the in-only MEP into an in-out MEP or use an in-out MEP in the JMS consumer. An overview of this decision is shown in figure 4.

Figure 4 An overview of the choice in MEPs and use of BCs and SEs for a JMS implementation.

Obviously, in listing 1 we have chosen for the second alternative shown in figure 4. We have configured the JMS consumer to use an in-out MEP with the DefaultConsumerMarshaler and the mep property. This means that the consumed JMS message is sent on to the HelloComponent and the JMS consumer waits for a response from this Java bean. The returned message is then sent to the reply destination, which in this in example is the out-queue.

An alternative implementation would be to use the default in-only MEP in the JMS consumer and transform the message exchange to an in-out MEP with the EIP SE pipeline. The pipeline can be used to transform an in-only MEP to an in-out MEP. The response of the HelloComponent is sent to a JMS provider also configured in the EIP pipeline configuration. An example configuration of the pipeline is shown in listing 2.

Listing 2 Example of an EIP pipeline configuration

<beans xmlns:eip="http://servicemix.apache.org/eip/1.0"
xmlns:esb="http://esbinaction.com/simple">

<eip:pipeline service="esb:examplePipeline"
endpoint="routingEndpoint">
<eip:transformer>
<eip:exchange-target service="esb:helloComponent" />
</eip:transformer>
<eip:target>
<eip:exchange-target service="esb:simpleSender" />
</eip:target>
</eip:pipeline>
</beans>

Listing 2 shows a definition of a pipeline element with transformer and target child elements. The transformer element defines the in-out exchange target, in this example the HelloComponent and the target element defines the target for the response message of the in-out exchange, which will be sent as an in-only MEP. So to implement integration solutions in a JBI container such as ServiceMix, a good understanding of the MEPs is needed. But with the overview described here you will be ready to start using ServiceMix for more complex integration cases.

Notice that in listings 1 and 2 we defined service, endpoint and targetService attributes. These attributes are very important in the ServiceMix container, because they define a unique identification for a component configuration within the ServiceMix container. So the service and endpoint attributes uniquely identifies the JMS consumer and EIP pipeline components within the ServiceMix container. And to invoke a service provider within the ServiceMix container, we can define a targetService and an optional targetEndpoint value that corresponds to the service and endpoint definition of that service provider. For example, in listing 1 we defined a targetService attribute with a value of esb:helloComponent, which should correspond to the JSR181 SE hello Java bean service configuration. Note that a service definition is always namespace qualified within ServiceMix.

Now let’s look at the configuration of the JSR181 SE in listing 3 and see if the service definition matches the targetService configuration of listing 1.

Listing 3 XBean configuration of the JSR181 hello Java bean

<beans xmlns:jsr181="http://servicemix.apache.org/jsr181/1.0"
xmlns:esb="http://esbinaction.com/simple">

<jsr181:endpoint annotations="none" service="esb:helloComponent" endpoint="endpoint"
serviceInterface="esb.example.HelloIF" id="hello">
<jsr181:pojo>
<bean id="helloBean" class="esb.example.HelloBean">
<property name="prefix" value="Hello "/>
</bean>
</jsr181:pojo>
</jsr181:endpoint>
</beans>

Notice that the JSR181 SE configuration uses a different namespace as the JMS BC and EIP SE examples of listings 1 and 2. The JSR181 endpoint definition surrounding the HelloBean configuration is actually just a wrapper to expose the HelloBean within the ServiceMix container with the service and endpoint definition. The JSR181 SE uses the XFire framework to provide the functionality to serialize and deserialize XML messages to and from the Java beans. Because within the ServiceMix container every message is XML, we need some way to serialize this Java and back again. That’s exactly what the JSR181 SE provides without additional configurations.

To be complete, listing 4 shows the implementation of the HelloIF interface and the HelloBean Java class.

Listing 4 HelloBean and HelloIF which is used in the JSR181 SE configuration


public interface HelloIF {
public String hello(String name);
}

public class HelloBean {

private String prefix;

public String hello(String name) {
return prefix + name;
}

public void setPrefix(String prefix) {
this.prefix = prefix;
}
}

Now we have created the service unit configurations for the JMS BC and the JSR181 SE, the last part remaining is the SA configuration. The JBI container needs a deployment descriptor (jbi.xml) that describes the service units included in the SA. Listing 5 shows the jbi.xml configuration for the hello world SA.

Listing 5 The JBI deployment descriptor, jbi.xml, for the hello world example

<jbi xmlns="http://java.sun.com/xml/ns/jbi" version="1.0">
<service-assembly>
<identification>
<name>simple-sa</name>
</identification>
<service-unit>
<identification>
<name>simple-jms-su</name>
</identification>
<target>
<artifacts-zip>simple-jms-su.zip</artifacts-zip>
<component-name>servicemix-jms</component-name>
</target>
</service-unit>
<service-unit>
<identification>
<name>simple-jsr181-su</name>
</identification>
<target>
<artifacts-zip>simple-jsr181-su.zip</artifacts-zip>
<component-name>servicemix-jsr181</component-name>
</target>
</service-unit>
</service-assembly>
</jbi>

We have now defined all the parts of the hello world example, so can now create the SU JAR files and the SA JAR file. In the SimpleSMDZone project included in the source code of this article, An Ant build file is included which creates these JAR files. And the ServiceMix project provides Ant targets to deploy the SA to the ServiceMix container. To get the example started, you can run the start target of the build.xml Ant build file to start the ServiceMix container. Then run the deploy-simple target to deploy the hello world SA.

This example can easily be tested with a JUnit class that sends a JMS message to the in-queue queue and listens for a response message on the out-queue. A JUnit class is also provided in the SimpleSMDZone project. Now let’s look at a more complex example, the insurance broker case study which we also implemented in the first article about Mule.

Case study: an insurance broker

A new insurance company, EasyInsurance, wants to provide potential customers with a web site which can be used to get quotes from various insurance companies based on the type of insurance you want. When the website will be put online only request for travel and car insurances are available, but in the future EasyInsurance intends to also provide the same functionality for home insurance.


When an insurance request is entered via the website, the request is forwarded to insurance providers depending on the type of insurance request. The number of insurance providers should also be easily expandable. The responses from the insurance provider are shown on the website and an insurance contract can be requested from the provider. Figure 5 shows an overview of the website’s functionality to send request to insurance providers and how the responses will be sent back to the website.

Figure 5 An overview of the insurance broker case study showing the messages sent to the insurance providers depending on the insurance request type.

An added problem that we need to solve in our integration solution is that the budgetCar insurance company requires the requests to be sent in CSV format over FTP (to keep it simple we’ll use a file connector here) and the LuxuryCar insurance wants an XML file over JMS. The Resort Travel Insurance company has the requirement that all calls are done using webservices.

Pattern based design approach

Most people who have worked in integration projects are probably familiar with the Enterprise Integration Patterns (EIP) book of Gregor Hohpe and Bobby Woolf. This book shows a number of design patterns that you can use to document, describe and solve your integration challenges. In the next couple of paragraphs we’ll show how you can use the patterns described in the EIP book to describe the insurance broker case study.

Let’s first look at figure 6, which describes the request part of the case we presented.

Figure 6 This figure shows the request flow of the insurance broker integration solution described using enterprise integration patterns from the EIP book.

Let’s first look at the various patterns shown here before we explain how they work together.

Table 1. Used patterns for the request flow of the insurance case study.

Pattern
Description
Message channel[img_assist|nid=3184|title=|desc=|link=none|align=left|width=55|height=37]  A message channel allows applications to communicate with each other.
Channel Adapter[img_assist|nid=3179|title=|desc=|link=none|align=middle|width=46|height=31]  A channel adapter defines how you can connect to the messaging system (e.g. a JMS broker) so you can receive and send messages.
Content based router[img_assist|nid=3186|title=|desc=|link=none|align=middle|width=54|height=37]  As the name implies a content based router, routes messages based on the content of the message.

Recipient list
[img_assist|nid=3185|title=|desc=|link=none|align=middle|width=54|height=37]

  Sometimes you want to send a message to multiple channels at the same time. A recipient list provides in this.

Transformer
[img_assist|nid=3187|title=|desc=|link=none|align=middle|width=54|height=37]

  A transformer is used when the format of the message needs to be changed before it can be sent to a recipient or when a standard format is defined.
Message endpoint[img_assist|nid=3180|title=|desc=|link=none|align=middle|width=55|height=32]  A message endpoint defines a connection from an application to a messaging channel.

 

Now let’s see how these patterns work together to solve the request part of our insurance website. We won’t show all the front-end stuff, but we’ll start with a insurance request that is received from the EasyInsurance website.

  1. The first thing we see is that the website uses a “message endpoint” to send a message to a specific channel (a JMS queue in this case) which is managed by a broker.
  2. This queue is then read by the ESB using a JMS “channel adapter”.
  3. The message is now routed internally by the ESB. The first router is the “content based router” which picks up the message and based on the type of request, car or travel, routes it to the next component.
  4. If the message needs to be sent to multiple insurance companies a recipient list is used and before the message is actually sent it’s first transformed to the target message format using a “transformer”.
  5. The “transformer” has made sure that the message is in a format the recipient can work with, so now all that is left to do is use another “channel adaptor” to send the message to a “message channel”, and the insurance companies can use a “message endpoint” on their side to read the request from the “message channel”.

Besides the use of the Enterprise Integration Patterns, the request flow of figure 6 also shows a clear separation between the different logical boundaries of the integration solution. Of course the ESB is shown as a logical boundary, but also the message broker (the JMS provider), the website and the endpoints of the insurance companies are separated in different boundaries. Also notice that figure 6 only shows the request flow of the insurance case study solution. To keep the design clean and comprehensible it’s often better to separate the request and response flows in different design diagrams. Figure 7 shows the response of the insurance broker integration solution.

Figure 7 This figure shows the response flow of the insurance integration solution described using enterprise integration patterns from the EIP book.

The design diagram of the response flow shown in figure 7 contains a lot of the patterns that were already used in the design of the request flow, only the aggregator pattern is new here. The aggregator is used to combine the insurance response messages from the BudgetCar and LuxuryCar insurance companies into one response that can be shown on the EasyInsurance website. To be able to aggregate the response messages from the two car insurance companies, we need some kind of correlation identifier that relates that response messages to the original insurance request message. In this example we use a request identifier in the insurance request message that is also available in the insurance response message.

This introduces another important step in the design phase of an integration solution: the message design. Because Mule can also use Java objects as message payload type, we will use Java based messages to communicate between the EasyInsurance website and the JMS broker and Enterprise Service Bus. In listing 6 the elements of the 3 message types involved in this integration solution are shown.

Listing 6 An overview of the Java classes that represents the insurance requests and response messages used in the integration broker implementation.

public class CarInsuranceRequest implements Serializable {

private String requestID;
private String numberPlate;
private String carType;
private int buildYear;
private boolean companyCar;
private Date startDate;
}

public class TravelInsuranceRequest implements Serializable {

private String requestID;
private String destinationCountry;
private int numberOfPersons;
private Date startDate;
private Date endDate;
}

public class InsuranceResponse implements Serializable {
private String requestID;
private String responseID;
private String insuranceCompanyName;
private float price;
}

As can be seen in listing 6, the messages are kept really simple for this example. The important parts of the message design for the integration solution are the distinction between a CarInsuranceRequest and a TravelInsuranceRequest that’s used for content-based routing and the requestID attribute that will be used for aggregating the car insurance response messages.

Notice that so far we haven’t talked about specific tools yet. In the design we made we just described what needs to be done. We can now hand over the integration flow and message design to a developer or integration specialist who can implement it using a specific technology. In this article we’ll implement it ourselves and we’ll use ServiceMix 3.2.1 for this.

Implement the insurance broker with ServiceMix: the request part

When working with a JBI container like ServiceMix it’s a best practice to start with a SA diagram before we start with the implementation of the several BC and SE configuration files and implementation classes. With the SA diagram, consisting of the SUs, we get a good overview of what we actually need to implement. The SA diagram of the request part of the insurance broker example is shown in figure 8.

Figure 8 An overview of the SA and SUs for the request part of the insurance broker example.

There is quite a bit of work to do, as you can see in figure 8. With the numbers in the circles, the ordering of the message flow is shown. The message flow starts by consuming a message from the insurance.in queue with the JMS BC. Let’s look at the JMS BC configuration in listing 7.

Listing 7 Consume the insurance request message from the JMS queue.

<beans xmlns:jms="http://servicemix.apache.org/jms/1.0"
xmlns:esb="http://esbinaction.com/insurance">

<classpath>
<location>.</location>
<location>bcel.jar</location>
<location>jibx-bind.jar</location>
<location>jibx-extras.jar</location>
<location>jibx-run.jar</location>
<location>qdox-1.6.1.jar</location>
<location>stax-api.jar</location>
<location>wstx-asl.jar</location>
<location>xmlpull_1_1_4.jar</location>
<location>xpp3.jar</location>
</classpath>

<jms:consumer service="esb:insuranceReceiver"
endpoint="jmsEndpoint"
targetService="esb:insuranceDSLRouter"
destinationName="insurance.in"
connectionFactory="#connectionFactory"
marshaler="#InsuranceJMSMarshaler"/>

<bean id="InsuranceJMSMarshaler"
class="esb.dzone.servicemix.util.InsuranceJMSMarshaler"/>

<bean id="connectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="tcp://localhost:61616" />
</bean>

</beans>

The JMS BC configuration as shown in listing 7 is quite similar to the configuration we saw earlier in the hello world example. The main difference is that we use an in-only MEP in this implementation and the message is forwarded to a content-based router implemented with Apache Camel. We also have defined a marshaler in this configuration, because we sent a CarInsuranceRequest or TravelInsuranceRequest message to the insurance.in queue. The marshaler needs to transform these messages into an XML message, before it can be sent to the Camel content-based router. We use JiBX to transform the Java objects to XML and vice versa. Because we use JiBX in the implementation of the InsuranceJMSMarshaler, we have to include the JiBX jars on the JMS BC class path as show in listing 7. The implementation of the marshaler is shown in listing 8.

Listing 8 Implementation of the JMS marshaler that uses JiBX for XML transformation.

public class InsuranceJMSMarshaler extends DefaultConsumerMarshaler {

protected void populateMessage(Message message,
NormalizedMessage normalizedMessage) throws Exception {
if (message instanceof ObjectMessage) {
ObjectMessage objectMessage = (ObjectMessage) message;
Object payload = objectMessage.getObject();
Source source = JiBXUtil.marshalDocument(payload, "UTF-8");
normalizedMessage.setContent(source);
} else {
throw new UnsupportedOperationException("JMS message is not a ObjectMessage");
}
}
}

When a JMS ObjectMessage is consumed by the JMS BC, the Java object payload is transformed to XML with a JiBXUtil class. In the source code of this article you can find more details about the JiBX transformation and JiBXUtil class implementation.

Now let’s move on the content-based router implementation with Apache Camel. In addition to using the EIP SE, the ServiceMix project recommends to take a look at the Camel SE for more complex integration logic implementations. Apache Camel is a sub-project of the Apache ActiveMQ project and provides an implementation for a lot of the enterprise integration patterns of the Hohpe and Woolf book. Camel provides a XML based configuration and a Java domain specific language (DSL) to implement integration logic. The configuration of the Camel SE and the content-based router implementation is shown in listing 9.

Listing 9a Send the car insurance request to the two car insurance services.

<!-- camel-context.xml Camel SU configuration -->
<beans xmlns="http://www.springframework.org/schema/beans">
<camelContext id="camel" xmlns="http://activemq.apache.org/camel/schema/spring">
<package>esb.dzone.servicemix.camel</package>
</camelContext>
</beans>

Listing 9b

/ The Camel content-based router implementation
public class InsuranceRouter extends RouteBuilder {
private final static String JBI_SERVICE = "jbi:service:";
private final static String NAMESPACE = "http://esbinaction.com/insurance";
private final static String SERVICE_IN = JBI_SERVICE + NAMESPACE +
"/insuranceDSLRouter";
private final static String LUXURY_CAR_OUT = JBI_SERVICE + NAMESPACE +
"/luxuryCarSender";
private final static String BUDGET_CAR_OUT = JBI_SERVICE + NAMESPACE +
"/budgetCarSender";
private final static String TRAVEL_OUT = JBI_SERVICE + NAMESPACE +
"/travelPipeline";
private final static String FAILURE_OUT = JBI_SERVICE + NAMESPACE +
"/insuranceFailureSender";

public void configure() {
from(SERVICE_IN)
.convertBodyTo(DOMSource.class)
.choice()
.when(xpath("//ins:TravelInsuranceRequest")
.namespace("ins", "http://dzone.com/insurance"))
.to(TRAVEL_OUT)
.when(xpath("//ins:CarInsuranceRequest")
.namespace("ins", "http://dzone.com/insurance"))
.to(LUXURY_CAR_OUT, BUDGET_CAR_OUT)
.otherwise()
.to(FAILURE_OUT);
}
}

Listing 9 consists of two files, a camel-context.xml file which is used to configure the Camel SU and the InsuranceRouter Java class that implements the content-based routing logic. The camel-context.xml file defines a package that will be inspected at runtime to look for Camel classes. The Camel runtime will find the InsuranceRouter class, because it extends the RouteBuilder Camel framework class.

In the InsuranceRouter we have to implement the configure method with the content-based routing logic. First, we have to define a message channel to receive messages, the SERVICE_IN attribute, which corresponds with the targetService configuration of the JMS BC of listing 7. With this message channel definition, the routing logic is registered as a JBI service endpoint in the ServiceMix container. Then we define routing logic with the choice and when and otherwise methods. When the incoming XML message is a car insurance request it’s routed on to the budget and luxury car insurance endpoints and for a travel insurance request, the message is routed to an EIP pipeline.

Let’s first look at the budget car and luxury car insurance endpoints in listing 10. Note that this listing consists of a JMS BC configuration and a File BC configuration. The JMS BC configuration is actually part of the same xbean.xml file as shown in listing 7 as you can see in the article’s source code.

Listing 10 The JMS BC and File BC configurations for the car insurance endpoints.

<!-- JMS BC SU configuration -->
<jms:provider service="esb:luxuryCarSender"
endpoint="jmsEndpoint"
destinationName="luxurycar.send"
connectionFactory="#connectionFactory"/>

<!-- File BC SU configuration -->
<beans xmlns:file="http://servicemix.apache.org/file/1.0"
xmlns:esb="http://esbinaction.com/insurance">

<classpath>
<location>.</location>
<location>bcel.jar</location>
<location>jibx-bind.jar</location>
<location>jibx-extras.jar</location>
<location>jibx-run.jar</location>
<location>qdox-1.6.1.jar</location>
<location>stax-api.jar</location>
<location>wstx-asl.jar</location>
<location>xmlpull_1_1_4.jar</location>
<location>xpp3.jar</location>
</classpath>

<file:sender service="esb:budgetCarSender"
endpoint="fileEndpoint"
directory="file:budgetCarIn"
marshaler="#InsuranceFileMarshaler"/>

<bean id="InsuranceFileMarshaler"
class="esb.dzone.servicemix.util.InsuranceFileMarshaler"/>
</beans>

The JMS configuration is pretty standard as it just sends the message to a JMS queue named luxury.send. The File BC configuration defines a file sender, which sends the message from the content-based router to a file directory named budgetCarIn. But, because we want the message to be formatted as a CSV file, we have defined another marshaler here. The file marshaler uses JiBX to transform the XML message to a CarInsuranceRequest Java object, which is transformed to a CSV message with similar transformation logic as the Mule example implementation of the previous article. Let’s look at the file marshaler in listing 11.

Listing 11 The file marshaler implementation.

public class InsuranceFileMarshaler extends DefaultFileMarshaler {

protected void writeMessageContent(MessageExchange exchange,
NormalizedMessage message, OutputStream out, String path)
throws MessagingException {
Source src = message.getContent();
if (src == null) {
throw new NoMessageContentAvailableException(exchange);
}
try {
CarInsuranceRequest request = (CarInsuranceRequest)
JiBXUtil.unmarshalDocument(src, CarInsuranceRequest.class);
String csvMessage = getInsuranceCSV(request);
OutputStreamWriter writer = new OutputStreamWriter(out);
writer.write(csvMessage);
writer.flush();
} catch (Exception e) {
throw new MessagingException(e);
}
}

private String getInsuranceCSV(CarInsuranceRequest request) {
return new StringBuffer()
.append(request.getRequestID())
.append(",")
.append(request.getNumberPlate())
.append(",")
.append(request.getCarType())
.append(",")
.append(request.getBuildYear())
.append(",")
.append(new SimpleDateFormat().format(request.getStartDate()))
.toString();
}
}

The file marshaler just transforms the CarInsuranceRequest to a CSV message and writes it to a file with an OutputStreamWriter. This completes the car insurance request implementation, so now let’s move on to the travel insurance request handling.

Before we can send the travel insurance request to the webservice, we first have to transform the XML to the target format defined by the webservice WSDL. To reduce the lines of code in this article a bit (there’s enough code already to my opinion), we will focus on the ServiceMix configuration. Because the ServiceMix Saxon SE, which provides transformation functionality based on XSLT, requires an in-out MEP, we first have to transform the message exchange to in-out with an EIP pipeline as already explained in figure 4. And because the CXF BC, which provides webservice functionality, also requires an in-out MEP we need to define two pipelines as shown in listing 12.

Listing 12 The EIP pipeline definitions to be able to invoke the travel webservice.

<beans xmlns:eip="http://servicemix.apache.org/eip/1.0"
xmlns:esb="http://esbinaction.com/insurance"
xmlns:tri="http://dzone.com/travelInsurance">

<eip:pipeline service="esb:travelPipeline" endpoint="routingEndpoint">
<eip:transformer>
<eip:exchange-target service="esb:transformTravelRequest"/>
</eip:transformer>
<eip:target>
<eip:exchange-target service="esb:travelServicePipeline" />
</eip:target>
</eip:pipeline>

<eip:pipeline service="esb:travelServicePipeline" endpoint="routingEndpoint">
<eip:transformer>
<eip:exchange-target service="tri:TravelInsuranceServiceImplService"
operation="tri:getTravelInsurance"/>
</eip:transformer>
<eip:target>
<eip:exchange-target service="esb:insuranceSender" />
</eip:target>
</eip:pipeline>
</beans>

The first pipeline definition is invoked from the Camel content-based router implementation shown in listing 9. In the first pipeline we invoke the Saxon SE, which transforms the XML message to the webservice message format. Then the first pipeline invokes the second pipeline to invoke the webservice with an in-out MEP. So let’s quickly look at the Saxon SE configuration in listing 13.

Listing 13 The Saxon SE configuration, which transforms the XML message to the travel web service message format.

<beans xmlns:saxon="http://servicemix.apache.org/saxon/1.0"
xmlns:esb="http://esbinaction.com/insurance">

<saxon:xslt service="esb:transformTravelRequest" endpoint="xsltEndpoint"
resource="classpath:TravelRequest.xslt" />
</beans>

Well, this is a short configuration. We define the XSLT file to transform the incoming XML message and we define the Saxon JBI service endpoint names. So let’s move on to the CXF BC configuration in listing 14, which performs the travel webservice call.

Listing 14 The CXF BC configuration, which invokes the travel webservice.

<beans xmlns:cxfbc="http://servicemix.apache.org/cxfbc/1.0"
xmlns:tri="http://dzone.com/travelInsurance">

<classpath>
<location>.</location>
</classpath>

<cxfbc:provider wsdl="classpath:travelinsurance.wsdl"
locationURI="http://localhost:9090/hello"
endpoint="TravelInsuranceServiceImplPort"
service="tri:TravelInsuranceServiceImplService"/>
</beans>

With the travelinsurance.wsdl file included in the CXF BC SU, the CXF BC is able to invoke the travel webservice on the location specified with the locationURI attribute.

Well that wraps up the request part. We’ve shown you so far how we can use a content based router implemented with Apache Camel to determine the target endpoint of the insurance request message. We’ve used a recipient list to send a car insurance request to two insurance endpoints using two different transports, file and JMS, in two different formats, CSV and XML. We’ve also shown you how a travel insurance webservice can be invoked using the CXF BC, and how the response of this webservice is routed back to a JMS queue where the website is listening on. So we’ve already done a very small section of the response part, since we already routed the response from the webservice back to the queue the website is listening on.

Now let’s look at how we can implement the responses of the car insurance companies.

Implement the insurance broker with ServiceMix: the response part

As said, we already defined most of the insurance broker example configuration. Let’s first look at the remaining pieces of the response part as part of a SA diagram in figure 9.

Figure 9 An overview of the SA and SUs for the response part of the insurance broker example.

We already defined the CXF provider and pipeline configuration of the travel webservice invocation. So the only part we have to discuss for the response part is the aggregator implementation. Let’s look at the aggregator configuration in listing 15.

Listing 15 The definition of the aggregator, which aggregates two car insurance response messages in one result message.

<beans xmlns:eip="http://servicemix.apache.org/eip/1.0"
xmlns:esb="http://esbinaction.com/insurance"
xmlns:tri="http://dzone.com/travelInsurance">

<eip:split-aggregator service="esb:insuranceAggregator" endpoint="routingEndpoint">
<eip:target>
<eip:exchange-target service="esb:insuranceSender" />
</eip:target>
</eip:split-aggregator>
</beans>

This is not too difficult, isn’t it? We define the aggregator JBI service endpoint name and the target service where the aggregated message is sent. To be able to use the out-of-the-box aggregation functionality of the EIP aggregator we do have to define some message properties, such as a correlation identifier and the number of messages to be aggregated. In the JMS and file marshalers we discussed in listing 8 and 11 we can add these message properties. In listing 16 the implementation of the file marshaler is shown.

Listing 16. Overview of the file marshaler read method which adds aggregation message properties.

public class InsuranceFileMarshaler extends DefaultFileMarshaler {

public static final String FILE_NAME_PROPERTY = "org.apache.servicemix.file.name";
public static final String FILE_PATH_PROPERTY = "org.apache.servicemix.file.path";

public void readMessage(MessageExchange exchange, NormalizedMessage message,
InputStream in, String path) throws IOException, JBIException {

BufferedReader br = new BufferedReader(new InputStreamReader(in));
StringBuilder sb = new StringBuilder();
String line = null;
while ((line = br.readLine()) != null) {
sb.append(line);
}
br.close();
String csvString = sb.toString();
String[] elements = csvString.split(",");
InsuranceResponse insuranceResponse = new InsuranceResponse();
insuranceResponse.setResponseID(elements[0]);
insuranceResponse.setRequestID(elements[1]);
insuranceResponse.setInsuranceCompanyName(elements[2]);
insuranceResponse.setPrice(Float.parseFloat(elements[3]));
Source source = null;
try {
source = JiBXUtil.marshalDocument(insuranceResponse, "UTF-8");
} catch(Exception e) {
throw new JBIException(e);
}
message.setContent(source);
message.setProperty(FILE_NAME_PROPERTY, new File(path).getName());
message.setProperty(FILE_PATH_PROPERTY, path);
message.setProperty("org.apache.servicemix.eip.splitter.corrid",
insuranceResponse.getRequestID());
message.setProperty("org.apache.servicemix.eip.splitter.index", 0);
message.setProperty("org.apache.servicemix.eip.splitter.count", new Integer(2));
}
}

As shown in listing 16, the file poller first transforms the CSV message to an InsuranceResponse Java object. Then the InsuranceResponse object is transformed to an XML message with JiBX. Before the XML message is sent further on in the ServiceMix container, we add the EIP aggregator message properties. The first property is the correlation identifier, then the message index number and the number of messages to be aggregated. In the JMS marshaler we implemented similar functionality, but the index message property is set to 1.

And that’s it for the response part!

Test the insurance broker with ServiceMix

To really grasp the ServiceMix configurations shown in the insurance broker example, you can use the source code to get the example to run. We provided an Ant build script, build.xml, to make it a little bit easier for you. With the start target you can start the ServiceMix container and with the deploy-insurance target you can deploy the complete insurance broker service assembly to the ServiceMix container.

Then you can use the InsuranceTest JUnit test to send a JMS message to trigger the insurance broker message flow. With the LuxuryCarTest JUnit test you can sent the luxury car response message and there is a response.csv file available in the file SU directory to send a response for the budget car insurance company. The InsuranceTest also includes code to simulate the travel web service.

Conclusion

In this article we’ve shown how you can implement an integration case study with ServiceMix. There are quite a bit of differences between the Mule and ServiceMix insurance broker case study implementations as you can see, but the configuration also has some similarities. Both Mule and ServiceMix use Spring extensively to configure the integration logic and both ESBs use an XML based configuration style.

The main differences are related to JBI foundation of ServiceMix and the Mule specific architecture of Mule. JBI uses SUs and SAs and Mule defines everything as part of a mule-config.xml file. Another difference is the use of XML messages or normalized messages within ServiceMix (according to the JBI specification) and Java objects within Mule. Mule accepts Java objects as message payload, but ServiceMix requires the use of an XML payload. A third difference is the hotdeploy feature of ServiceMix that’s lacking in the Mule implementation. With ServiceMix you can easily deploy new versions of a SA, while ServiceMix keeps running. With Mule you will have to restart the container, before a new Mule configuration can be loaded.

We hope you enjoyed this introduction into ServiceMix 3.2.1 and the pattern based integration development approach. We hope we were able to show the functionality of Mule and ServiceMix with a small case study.

Additional resources

1. ServiceMix – http://servicemix.apache.org
2. ServiceMix 4 – http://servicemix.apache.org/SMX4/index.html
3. Enterprise Integration Patterns – http://www.enterpriseintegrationpatterns.com
4. Apache Camel – http://activemq.apache.org/camel
5. Download article source code – http://www.esbinaction.com/files/dzoneservicemix.zip


Jos Dirksen

Jos is a software architect working for Atos Origin and specializing in enterprise integration. Jos is the co-author of the upcoming Manning book “Open Source ESBs in Action” (http://www.manning.com/rademakers). He speaks frequently at Java conferences like JavaPolis, JavaZone, JavaOne and NL-JUG about Open Source enterprise integration projects like Mule, ServiceMix, jBPM and Axis2.

Tijs Rademakers

Tijs is a software architect working for Atos Origin and specializing in enterprise integration. Tijs is the co-author of the upcoming Manning book “Open Source ESBs in Action” (http://www.manning.com/rademakers). He speaks frequently at Java conferences like JavaPolis, JavaZone, JavaOne and NL-JUG about Open Source enterprise integration projects like Mule, ServiceMix, Apache Synapse and Apache Tuscany.

The Integration Zone is brought to you in partnership with CA Technologies.  Create app backends instantly with REST APIs and reactive logic using CA Live API Creator.

Topics:

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}