• No results found

Configuring the ServiceMix example implementation

In document Open-Source ESBs in Action (Page 133-138)

Setting up the Mule and ServiceMix environments

3.4 Inaugurate the ServiceMix environment

3.4.2 Configuring the ServiceMix example implementation

In figure 3.9 you saw that we must read an XML file from the file system, and then put that XML message on a JMS queue for further processing. Another part of the example is listening on this queue and forwarding the message to our custom trans- former component.

In the transformer component we use JiBX to transform the incoming message to a Java object, alter a value, and transform it back to XML. In the final step, we put the message on a JMS queue and bridge it to the file system. Figure 3.10 shows the exam- ple implementation in the context of the JBI architecture.

As you can see in figure 3.10, we have two binding components, which handle the communication from outside the container, and we have one service engine, which runs our own custom component that implements transformation functionality. In chapter 2 we defined a service unit as an artifact that can be deployed inside a JBI

component. In this example implementation, we deploy four JBI services inside the

JMS component—two consumers and two providers. We deploy two services inside the File component: a file sender and a file poller. Finally, we deploy one bean ser- vice into the servicemix-bean service engine.

Let’s see how we’re going to implement all this. Before we dive into the XML configu- ration, check out our custom Java component in listing 3.21, which we deploy to the servicemix-bean service engine.

public class SimpleTransformerBean

implements MessageExchangeListener { private static Log log = LogFactory.getLog( SimpleTransformerBean.class);

@Resource private DeliveryChannel channel;

@Resource private ComponentContext compContext;

public void onMessageExchange(MessageExchange exchange) throws MessagingException {

try {

if (exchange.getStatus() != ExchangeStatus.ACTIVE) return;

Person person = (Person) JiBXUtil .unMarshalDocument(exchange.getMessage("in") .getContent(), Person.class);

log.info("received person " + person.getFirstName() + " " + person.getLastName());

Listing 3.21 Bean implementation that defines transformation and routing logic Figure 3.10 The binding components and service engines used in the implementation of our example

Injects channel and component resources

B

Transforms XML to Person object

person.setFirstName("John");

exchange.setStatus(ExchangeStatus.DONE); channel.send(exchange);

ServiceEndpoint targetEndpoint = compContext .getEndpoint(new QName( "http://opensourceesb/chapter3/", "JMSProviderService"), "outQueueWriter"); MessageExchange exch = channel.createExchangeFactory(targetEndpoint) .createInOnlyExchange(); NormalizedMessage normalizedMsg = exch.createMessage(); normalizedMsg.setContent(

JiBXUtil.marshalDocument(person, "UTF-8")); exch.setMessage(normalizedMsg, "in");

channel.send(exch); } catch (Exception e) {

log.error("JBI bean exception", e); throw new MessagingException(

"Error transforming object to or from XML"); }

} }

A number of interesting things are going on in listing 3.21. You can see that the SimpleTransformerBean implements the MessageExchangeListener interface. This interface defines that this class is able to receive message exchanges. The next thing you see is that the resources we need in this class are inserted by the ServiceMix con- tainer

B

. In this case, we inject the DeliveryChannel, which we use to send and receive messages, and the ComponentContext, which we can use to search for regis- tered JBI endpoints.

When we receive a message, we first check to see if it’s part of an active exchange, since we only need to process active JBI message exchanges. We then start to process the message with JiBX to transform it to a Java object

C

. After that, we finish the cur- rent exchange, because we are done processing. To finish the current in-only message exchange, the channel,send(exchange) is executed with a status of done. Then we do a lookup

D

for the target endpoint of the transformed message, which will be a

JMS queue defined in listing 3.23.

The last step is to create a new JBI message exchange

E

to send an XML message, transformed with JiBX, to the target destination.

Before we dive into the configuration of the ServiceMix JBI components we use in this example, let’s quickly look at the JiBX configuration in listing 3.22, which shows how to map the incoming XML to a Java object.

<binding>

<mapping name="person"

class="esb.chapter3.Person">

<value name="customer-number" field="customerNumber"/> Listing 3.22 JiBX mapping illustrating how to map between XML and Java

Retrieves the target endpoint

D

Creates a new message exchange

E

<value name="first-name" field="firstName"/> <value name="last-name" field="lastName"/> <value name="street" field="street"/> <value name="city" field="city"/> <value name="state" field="state"/> <value name="zip" field="zip"/> <value name="phone" field="phone"/> </mapping>

</binding>

Listing 3.22 shows a basic mapping that transforms a simple XML message to the esb.chapter3.Person Java class. We don’t show the Person class, since this is just a

POJO with a getter and setter for all the fields specified in the mapping file. As we’ve mentioned before, we need to run the binding compiler before we can use this JiBX

mapping configuration at runtime. All this is done automatically for you when you use the supplied Ant build file in the servicemix/resources/chapter3 directory from the servicemix-workspace to deploy this example to ServiceMix at the end of this section.

Now that the programming part is out of the way, the main thing missing is the configuration of the three JBI components. Let’s start with the JMS consumers and providers. ServiceMix already starts up an ActiveMQ broker in its default configura- tion, so we don’t have to start a separate JMS broker instance. We only have to config- ure the JMS consumers and providers and connect to this broker. We can do this by creating an ActiveMQConnectionFactory, and since the ServiceMix configuration already is based on Spring, this is easy to do:

<bean id="connectionFactory"

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

In this configuration, we define a connection to the ActiveMQ broker instance. This code is added to the service unit configuration, which we deploy to the servicemix-jms binding component. Listing 3.23 shows how we reference the ActiveMQConnection- Factory. <beans xmlns:jms="http://servicemix.apache.org/jms/1.0" xmlns:esb="http://opensourceesb/chapter3/"> <jms:consumer service="esb:JMSConsumerService" endpoint="inQueueReader" targetService="esb:beanService" targetEndpoint="endpoint" destinationName="inQueue" connectionFactory="#connectionFactory" /> <jms:consumer service="esb:JMSConsumerService" endpoint="inQueueReader2" targetService="esb:fileSender" targetEndpoint="endpoint" Listing 3.23 ServiceMix JMS configuration

Targets JBI service for consumed message

destinationName="outQueue" connectionFactory="#connectionFactory"/> <jms:provider service="esb:JMSProviderService" endpoint="inQueueWriter" destinationName="inQueue" connectionFactory="#connectionFactory" /> <jms:provider service="esb:JMSProviderService" endpoint="outQueueWriter" destinationName="outQueue" connectionFactory="#connectionFactory" /> <bean id="connectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory"> <property name="brokerURL" value="tcp://localhost:61616" /> </bean>

</beans>

We see two different types of JMS endpoints defined here: consumer endpoints and provider endpoints. A consumer endpoint listens on a specific JMS input queue

C

, and when a message is received, it invokes the specified target service, like, for exam- ple, the bean service

B

. A provider sends a message to a queue

D

using the ActiveMQ

connection factory

E

defined at the bottom of the JMS service unit configuration. Table 3.2 shows the properties for a JMS endpoint.

In listing 3.23 we have two providers that send messages to the inQueue and outQueue queues, and two consumers that listen to those queues and forward the messages to the osesb:beanService JBI service and the osesb:fileSender JBI service.

The final items we consider for this scenario are the configuration of the service unit for the bean component and the configuration of the service unit for the file component. The file component is a simple configuration, as shown in listing 3.24.

<beans xmlns="http://xbean.org/schemas/spring/1.0" xmlns:file="http://servicemix.apache.org/file/1.0" xmlns:esb="http://opensourceesb/chapter3/"> Table 3.2 The ServiceMix JMS endpoint attributes

Attribute Description

service The name of the ser vice this endpoint will be registered on. endpoint The name of the endpoint this ser vice can be reached on.

targetService If a message is received on the queue, it’s sent to the ser vice registered on this name.

targetEndpoint The name of the endpoint we send the message to.

destinationName The name of the queue a consumer listens to or a provider sends to.

Listing 3.24 File endpoints configuration for the ServiceMix example

Defines the consumer queue name

C

Defines the provider queue name

D

References the connection factory

<file:sender service="esb:fileSender" endpoint="endpoint" directory="chapter3/out"/> <file:poller service="esb:filePoller" endpoint="simpleToJMSPoller" targetService="esb:JMSProviderService" targetEndpoint="inQueueWriter" file="chapter3/in" period="2000"/> </beans>

Listing 3.24 is pretty much self-explanatory. We have a file poller that listens on the chapter3/in directory

C

, and a sender that sends the received messages to the chapter3/out directory

B

.

The final JBI component that we have to configure is the servicemix-bean (its Java code appears in listing 3.21):

<beans xmlns:bean="http://servicemix.apache.org/bean/1.0" xmlns:esb="http://opensourceesb/chapter3/"> <bean:endpoint service="esb:beanService" endpoint="endpoint" bean="#SimpleTransformer"/> <bean id="SimpleTransformer" class="esb.chapter3.SimpleTransformerBean"/> </beans>

Here we define a JBI service bean by configuring the name and endpoint of the ser- vice and the implementation class. The #SimpleTransformer reference tells Service- Mix to look up the component in the Spring context.

The final step is packaging all these service units into a service assembly and deploying it to the ServiceMix container.

In document Open-Source ESBs in Action (Page 133-138)