Use JBI components for integration

An introduction to Java Business Integration components

1 2 Page 2
Page 2 of 2
 

import javax.jbi.component.*;

public class Helloworld implements Component, ComponentLifeCycle {

private ComponentContext context;

private HelloworldListener listener;

public void init(ComponentContext context) throws JBIException { // Keep a reference to the given ComponentContext this.context = context; }

public void start() throws JBIException { // Create our Listener and start it listener = new HelloworldListener(context.getDeliveryChannel()); (new Thread(listener)).start();

// Register our service in the JBI environment context.activateEndpoint(QName("http://helloWorldService.com") , "HWendpoint"); }

public void stop() throws JBIException { // Just break the loop of our listener; the thread will stop listener.running= false; }

public void shutDown() throws JBIException { // Nothing }

public ComponentLifeCycle getLifeCycle() { // This object acts as the LifeCycle, so it returns itself return this; } ... }

HelloworldListener

The HelloworldListener object processes the MessageExchanges that pass through the NMR. The received messages are retrieved from the DeliveryChannel object. This listener checks that the specified operation name in MessageExchange is hello and that the type of the exchange is InOut. The listener then retrieves the "in" content, processes the message (even if, as in this example, there is no specific processing), and sets an "out" response to the MessageExchange. Then it sends the MessageExchange back to the NMR. The response is then conveyed to the consumer through the NMR:

 

import javax.jbi.messaging.*;

public class HelloworldListener implements Runnable {

private DeliveryChannel channel;

public boolean running;

/** * Constructor */ public HelloworldListener(DeliveryChannel channel) { this.channel = channel; }

/** * The listening part */ public void run() { running= true;

while(running) { // Block on the accept() method MessageExchange messageExchange = channel.accept(); // A MessageExchange is received, so process it process(messageExchange); } }

/** * Process the received messages */ private void process(MessageExchange msg) { if( new QName("hello").equals(msg.getOperation()) && msg instanceof InOut) { // We received an InOut exchange, with the "hello" operation InOut inOut = (InOut)msg;

// Read the IN message NormalizedMessage in = inOut.getInMessage(); Source content = in.getContent(); // ... Process the in-content (omitted)

// Write the response NormalizedMessage out = inOut.createMessage(); // ...Set out content (omitted) InOut.setOut(out);

// Send the response channel.send(); } } }

Bootstrap

No special operation is required during installation of this Helloworld component, so the class that implements the Bootstrap interface has nothing to do.

Package the component

Let's assume that the three component classes (Component, HelloworldListener, and Bootstrap) are archived in a helloComponent.jar file. A descriptor must be provided to help the JBI container during the installation phase. This descriptor file (jbi.xml) looks like this:

 

<jbi version="1.0" xmlns='http://java.sun.com/xml/ns/jbi' xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'>

<component type="service-engine"> <identification> <name>HelloworldComponent</name> <description>A Helloworld Component</description> </identification>

<component-class-name>hello.Helloworld</component-class-name>

<component-class-path> <path-element>helloComponent.jar</path-element> </component-class-path>

<bootstrap-class-name>hello.Bootstrap</bootstrap-class-name> <bootstrap-class-path> <path-element>helloComponent.jar</path-element>

</bootstrap-class-path>

</component>

</jbi>

The packaging of the component is a simple archive (zip or jar file) with the following structure:

- helloComponent.jar

- <META-INF> - jbi.xml

Use the Helloworld service

A component that wants to access the service provided by this Helloworld component can use the following code:

 

// Find the endpoint ServiceEndpoint ep = context.getEndpoint( new QName("http://helloWorldService.com") , "HWendpoint");

// Create the exchange MessageExchangeFactory factory = deliveryChannel().createExchangeFactory(); MessageExchange msgEx = factory.createInOutExchange(); msgEx.setOperation( new QName("hello")); msgEx.setEndpoint(ep);

// Create the message NormalizedMessage nm = msgEx.createMessage();

// Set the 'in' content - omitted nm.setContent(source); msgEx.setInMessage(nm);

// Send deliveryChannel.send(msgEx);

When the Helloworld service answers this request, the MessageExchange is sent back to the consumer. So the consumer's listener waits on the accept() method:

 

// Wait for response MessageExchange msgEx = deliveryChannel.accept();

// Process the response from Helloworld service if( msgEx.getEndpoint().equals(ep) && msg instanceof InOut) { InOut inOut = (InOut)msg; // Read the OUT message Source content = inOut.getOutMessage().getContent(); // ...process the out-content (omitted)

// Close the exchange msgEx.setStatus(ExchangeStatus.DONE); deliveryChannel.send(msgEx); }

Note: Each MessageExchange created has a unique ID. To process the response of a particular exchange, the consumer can keep the ID of the sent exchange and compare it with the ID of the received message.

The last thing to learn about components is their lifecycle management.

Install and start a JBI component

A JBI container offers administrative tools to manage components through JMX (Java Management Extensions) MBean objects.

Install a component

The MBean that manages component installation is the InstallationServiceMBean. This service creates, for each component to install, another MBean object: an InstallerMBean. In InstallationServiceMBean, call loadNewInstaller(<archiveURL>), which explodes and analyzes the archive corresponding to the given URL and returns the name of the created InstallerMBean.

Figure 11 shows how to load an Installer with the JMX API, through the Petals HTML console.

Figure 11. InstallationService::loadNewInstaller. Click on thumbnail to view full-sized image.

The InstallerMBean installs and uninstalls components with the install() and uninstall() methods. A call to install() instantiates the component's Bootstrap object, as described in the jbi.xml descriptor file. Then, the init() and unInstall() methods are called on the Bootstrap.

Finally, the Component object is instantiated, and a corresponding ComponentLifeCycleMBean object is created. The install() method returns the name of this lifecycle MBean.

Figures 12 and 13 show how to ask the container to install the component into the environment using the JMX API. The HTML console then returns the component lifecycle's MBean name.

Figure 12. Installer::install. Click on thumbnail to view full-sized image.
Figure 13. Installer::install—result. Click on thumbnail to view full-sized image.

At this point, the component is installed in a shutdown state.

Figure 14 summarizes component installation.

Figure 14. Install a component with JMX management. Click on thumbnail to view full-sized image.

Start a component

The ComponentLifeCycleMBean manages the component's lifecycle. This MBean's main methods are start(), stop(), and shutdown(). A call to start() causes start() to be called on the corresponding component.

Figure 15 shows how to start a component by interacting with its LifeCycleMBean through the Petals JMX HTML console.

Figure 15. LifeCycle::start. Click on thumbnail to view full-sized image.

If the component is started for the first time, its init() method is called before the real start.

Figure 16 shows how the JBI environment starts the component.

Figure 16. Start a component with JMX management. Click on thumbnail to view full-sized image.

To learn more about installing components, read "Getting started with Petals Service Platform."

Conclusion

From a component point of view, using JBI and communicating with the environment is quite simple. The use of WSDL for service description, XML for message payload, and the JBI specification itself promote the standardization of state-of-the-art integration.

Please note that numerous functionalities provided by the JBI environment were not discussed here, such as the WSDL definition of the provided services, synchronized or asynchronized exchanges, deployment of artifacts, and the use of binding components to access external services.

The success of JBI will depend on the plethora of proposed components, either service engines that apply some integration logic to messages or binding components that open the JBI bus to specific protocols. Providers of JBI containers must propose a pertinent set of components with their containers. Fortunately, as long as the components respect the JBI specification, they can be used on any JBI implementation.

Adrien Louis works as chief architect at EBM WebSourcing and has six years of experience working with Java EE technologies. Currently, he is working on enterprise integration solution problems. Louis is the project manager of the Petals open source project. The goal of the Petals project is to provide a distributed JBI container packaged in various integration solutions like B2B integration or business-process-based integration.

Learn more about this topic

1 2 Page 2
Page 2 of 2