ServiceMix as an enterprise service bus

Use ServiceMix 2.0 as a service-oriented message routing framework

An enterprise service bus (ESB) is a centralized, logical, architectural component that operates in a distributed, heterogeneous environment to facilitate the requirements of a highly scalable, fault-tolerant, service-messaging framework. An ESB acts as an open and implementation-independent service messaging and interfacing model that isolates application code from the specifics of routing services and transport protocols, and allows substitution of service implementations as needed.

An ESB acts as a shared messaging layer for connecting applications and other services throughout an enterprise computing infrastructure. It supplements its core asynchronous messaging backbone with intelligent transformation and routing to ensure messages are passed reliably. Services participate in the ESB using either Web services messaging standards or Java Message Service (JMS). Originally defined by analysts at Gartner, ESB is increasingly seen as a core component in a service-oriented infrastructure.

In this article, I discuss the open source ESB ServiceMix and its relationship to the Java Business Integration specification.

Minimum requirements of ESB message delivery

The minimum requirements of an ESB, as a message delivery system, are often referred to by the acronym TRANS, which defines an ESB as a software entity that does the following:

  • Transforms messages from one format to another to accommodate the requirements of registered service providers.
  • Routes messages to registered services while providing quality-of-service and service-level features.
  • Augments message content with information, such as additional metadata, about the message requester. Augments the message protocol to meet service provider requirements.
  • Notifies registered message listeners about specific message requests.
  • Secures delivery of messages by enforcing authentication, authorization, nonrepudiation, confidentiality, etc.

Introducing Java Business Integration (JBI)

The Java Business Integration (JBI) specification and API defines a platform for building enterprise-class ESBs using a pluggable, service-based design. JBI builds on the TRANS foundation with normalized messages and component-based interactions.

JBI is a specification and an API for a normalized messaging service along with a component framework and management model for deploying integration services such as routing engines, rule engines, and transformation services. A JBI-based design specifies a standards-based pluggable architecture with a JVM-based runtime component called the normalized message router (NMR).

The high-level interactions of JBI can be seen in Figure 1 below.

Figure 1. High-level view of JBI. Click on thumbnail to view full-sized image.

JBI embodies a messaging model based on Web Services Description Language (WSDL) for easy mapping to Web services, HTTP, email, and JMS. JBI integrates with legacy systems, binary transports, document-oriented transports, and RPC (remote procedure call) systems.

Figure 1's binding components deal with protocol-oriented relationships and components. And service-engine components in JBI support content-based routing, orchestration, rules, transformations, custom augmentation, etc.

Normalized messages

JBI uses a "normalized" message—consisting of a payload, optional attachments, and metadata—for interaction between consumers and providers. Message normalization is the process of mapping context-specific data to a context-neutral abstraction to transport data in a standard format. All messages handled by the NMR are normalized.

A normalized message consists of three main parts:

  1. Message content, also referred to as "payload," which is an XML document that conforms to an abstract WSDL message type with no protocol encoding or formatting.
  2. Message properties or metadata that hold extra data associated with the message. This metadata can include security information, transaction-context information, component-specific information, etc. Message properties form the first part of what is referred to as the message context.
  3. Message attachments referenced by the payload, contained within a data handler used to manipulate the attachment's contents. Attachments can be non-XML data. Attachments form the second part of the message context.

Normalized message router

The JBI message exchange depends on the NMR to route message exchange objects between service consumers and providers. The NMR performs such message delivery with varying qualities of service, depending on application needs and the nature of the messages being delivered.

An NMR is not embodied by any concrete object. It is abstracted as a set of APIs, SPIs (service provider interfaces), and components. The NMR APIs include:

  • JBI Message API
  • JBI Service API
  • JBI Message Exchange Factory API
  • Service Description SPI
  • Message Exchange Patterns API
  • Endpoint Reference API

Delivery channels

A JBI delivery channel represents a bidirectional communication pipe used by binding components and service engines to transport messages across the NMR. The javax.jbi.messaging.DeliveryChannel interface forms the API contract between service consumers, service providers, and the NMR.

A service consumer uses its delivery channel to initiate service invocations, while a service provider uses its delivery channel to receive invocations. A component that functions as both consumer and provider uses the same delivery channel for both roles. Therefore implementations of DeliveryChannel must support concurrent use of a given instance from multiple threads.

Components

The JBI component framework provides a pluggable interface that allows binding components and service engines to interact with the JBI environment. The framework provides the interface to all of the JBI services.

JBI supports two kinds of components, service engines and binding components. Components interact with JBI in two ways:

  1. SPIs: Interfaces implemented by a binding or engine
  2. APIs: Interfaces exposed to bindings or engines by the framework

Service engines

Service engines are the business-logic components in a JBI system and can serve as service providers/consumers. Service engines orchestrate service consumption and requirements. Service engines can also provide services such as data transformation, sophisticated routing, and message coordination facilities.

Binding components

Binding components are used to send and receive messages across specific protocols and transports. They uncouple the JBI environment from protocol specifics by marshalling and unmarshalling messages to and from protocol-specific data formats, allowing the JBI environment to process only normalized messages.

Normalized message exchange

JBI's principal purpose is to route normalized message exchanges from one component to another. Messages are delivered in a normalized form.

Binding components must convert protocol/transport-specific messages to a normalized form. Binding components and service engines interact with the NMR via a delivery channel, which provides a bidirectional delivery mechanism for messages.

An external service consumer sends a service request across a specific protocol and transport to a binding component. The binding component converts the request to a normalized message. The binding component then creates a message packet called a message exchange (ME) and sends it across the binding component's delivery channel to the NMR for delivery to a service provider.

After receiving a message, the consuming service engine or binding component creates a normalized message, putting it into a new MessageExchange instance, and sends it to the target ServiceEndpoint instance. After accepting the ME, the ServiceEndpoint component de-normalizes the message into protocol and transport format, and sends the message along to the external service provider.

Service units

Component-specific artifacts deployed to an installed engine or binding are referred to as service units. Service units are grouped into an aggregate deployment file called a service assembly. This file includes a deployment descriptor that indicates the component into which each service unit is to be deployed.

Service units contain:

  • Metadata: JBI descriptor for services consumed/produced
  • Artifacts: Generally XML (possibly binary, whatever the target binding component or service engine needs)

Introducing ServiceMix

ServiceMix is an ESB based on JBI. Released under the Apache license, it is an open source ESB and SOA toolkit built on JBI's semantics and APIs. The toolkit is lightweight and easily embeddable, has integrated Spring support, and can run inside a client or server, as a standalone ESB provider, or as a service within another ESB. You can use ServiceMix in a Java Standard Edition or Java Enterprise Edition application server. ServiceMix is completely integrated with JBoss and Apache Geronimo and lets you deploy JBI components and services directly into Geronimo.

Figure 2 illustrates the relationships between JBI and ServiceMix.

Figure 2. JBI and ServiceMix. Click on thumbnail to view full-sized image.

ServiceMix includes a complete JBI container that supports all parts of the JBI specification including:

  • A normalized message service and router
  • JBI management beans (MBeans)
  • Ant tasks for management and installation of components
  • Full support for the JBI deployment units with hot-deployment of JBI components

ServiceMix also includes the following components and services:

  • Service components
    • Rules-based routing via the Drools rule engine
    • A client API for working with JBI components and services
    • An implementation of Web Services Notification
    • Business Process Execution Language (BPEL) support for Web Services BPEL via PXE (preboot execution environment)
    • Support for caching service invocations using a Map cache or a JCache provider
    • Support for the Java Connector Architecture
    • Timer integration via the Quartz library
    • Scripting support, allowing any Java Specification Request 223-compliant scripting engine to be used to create a component, perform a transformation, or act as an expression language
    • Transformation using Extensible Stylesheet Language Transformations
    • Schema validation of documents using the Java API for XML Processing 1.3 and XML Schema or RelaxNG
    • XSQL for working with SQL and XML via Oracle's XSQL library
  • SOAP bindings
    • Support for a SOAP stack based on the Streaming API for XML (StAX) via ActiveSOAP
    • Support for the Java API for XML-based Web Services to make a Web services client invocation or host a Java-based Web service and expose it over multiple protocols
    • Reflection to allow plain-old Java objects (POJOs) to be deployed in ServiceMix
    • SOAP with Attachments API for Java and Apache Axis support
    • Integration with POJOs via the XFire SOAP stack
    • Integration with the Apache Web Service Invocation Framework (WSIF)
  • Transport bindings
    • Email support via JavaMail
    • File-based components for writing messages to files and polling directories and sending files into the JBI
    • FTP support via the Jakarta Commons Net library
    • HTTP support for client-side and server-side processing
    • Bindings to the Jabber network via the Extensible Messaging and Presence Protocol
    • JMS support via ActiveMQ
    • RSS support via the Rome library for accessing and processing RSS feeds
    • VFS (virtual filesystem switch) via the Jakarta Commons Net library, which provides access to file systems, jar/zip/bzip2 temporary files, World Wide Web Distributed Authoring and Versioning, Samba (Common Internet File System), HTTP, HTTPS, FTP, SFTP, and others

Most of the ServiceMix initialization processes, activation processes, and message-exchange processes, involve some form of communication and/or interaction with JBI-based components. The following sections illustrate these processes within the context of a simple message-exchange scenario.

Initializing the JBI container

Before the JBI container can be used, it must be initialized by calling its init() method. This method instantiates vital system services and sets the values for the JMX (Java Management Extensions) MBeanServer, transaction manager, etc.

The snippet in Listing 1 illustrates the code needed to initialize the JBI container.

Listing 1. JBI container initialization

 protected JBIContainer jbiContainer = new JBIContainer();
jbiContainer.init();

The JBIContainer class's init() method traverses through the following steps:

  • Initialize the org.servicemix.jbi.management.ManagementContext instance and register it with the JMX MBean server. This object is the primary point of interaction for management tools, such as JMX managers.
  • Initialize the org.servicemix.jbi.container.EnvironmentContext instance and register it with the JMX MBean server. This object creates the directory structure for the install files, deployment files, components, shared libraries, service assemblies, etc.
  • Initialize the org.servicemix.jbi.framework.Registry instance. This object maintains endpoints and components.
  • Initialize the org.servicemix.jbi.nmr.Broker instance. This object manages the actual message queuing and dispatching with the help of an org.servicemix.jbi.nmr.flow.Flow object. The Flow object manages the broker's dispatch policies.
  • Initialize the org.servicemix.jbi.framework.FrameworkInstallationService implementation instance. This object installs and uninstalls archives.
  • Initialize the org.servicemix.jbi.framework.DeploymentService instance. This object deploys service assemblies and their associated service units.

Starting the JBI container

Startup for the JBI container is instigated by a simple call to the start() method on the JBIContainer instance, as illustrated in Listing 2. This process starts all embedded components and services, such as the registry, the broker, the management context, the environment context, the installation service, and the deployment service. The start process for most components and services simply involves setting a flag that designates they are in a running state and starting any associated timed tasks.

Listing 2. JBI container startup

 jbiContainer.start();

Creating the support components

Objects that serve as producers and consumers of messages in the ServiceMix framework are often referred to as support components. These objects implement the javax.jbi.component.Component interface so the JBI container and associated components can operate on them in a standard fashion. These objects generally extend some form of Support class found in the org.servicemix.components.util package, such as ComponentSupport or PojoSupport, endowed with the default behavior needed to act as a JBI component, e.g., JMX functionality.

Support components typically use an instance of javax.jbi.component.ComponentContext to retrieve a DeliveryChannel component to create and handle the actual message exchange.

Note the class/interface hierarchy for the support components in Listing 3.

Listing 3. Support-component hierarchy

 // The PojoSupport class encapsulates a simple POJO-based component that
// Provides support for standard ServiceMix-managed components
public abstract class PojoSupport
   extends org.servicemix.jbi.management.BaseLifeCycle
   implements javax.jbi.component.ComponentLifeCycle
{
…
}
// The ComponentSupport class extends PojoSupport and provides the
// functionality of a standard JBI component
public abstract class ComponentSupport
   extends org.servicemix.components.util.PojoSupport
   implements javax.jbi.component.Component
{
…
}
// The SenderComponent class will act as a producer of ServiceMix messages
public class SenderComponent
   extends org.servicemix.components.util.ComponentSupport
   implements Sender
{
…
}
// The ReceiverComponent class will act as a consumer of ServiceMix messages
public class ReceiverComponent
   extends org.servicemix.components.util.ComponentSupport
   implements org.servicemix.MessageExchangeListener, Receiver
{
…
}

Activating the support components

Before a component can be used within the ServiceMix ESB, the component must be "activated" within the context of the ServiceMix JBI container. This involves:

  • Constructing an instance of the DeliveryChannel class. This instance will then be associated with it for subsequent message exchanges. DeliveryChannel is responsible for the following:
    • Receiving messages routed to the component
    • Sending asynchronous messages
    • Sending synchronous messages
  • Registering the component with an instance of the org.servicemix.jbi.framework.ComponentRegistry class. The result of this step is an instance of the org.servicemix.jbi.framework.ComponentConnector class. This object is used internally by ServiceMix to exchange messages.
  • Register the ComponentConnector instance created by the ComponentRegistry class with an instance of the org.servicemix.jbi.container.EnvironmentContext class. The EnvironmentContext class maintains the JBI execution environment (installation path, deployment path, service-unit directory, etc.) in which the component is running.
  • Calling the component's lifecycle init() method and then its start() method.
  • Wrapping the component's ComponentConnector instance as a JMX MBean and registering it with the JBI container's org.servicemix.jbi.management.ManagementContext MBeanServer instance.

Activating components involves interacting with the org.servicemix.jbi.container.JBIContainer class via the activateComponent() method. This method takes an instance of the org.servicemix.jbi.container.ActivationSpec class, which is used to build a valid JBI component. The ActivationSpec object is an instance of one of three different Java class types that will ultimately be activated. These types are:

  1. javax.jbi.component.Component
  2. javax.jbi.component.ComponentLifeCycle
  3. org.servicemix.MessageExchangeListener: An instance of this class is wrapped within an instance of org.servicemix.components.util.PojoLifecycleAdaptor or a subclass of org.servicemix.components.util.ComponentAdaptor, such as org.servicemix.components.util.ComponentAdaptorMEListener

The snippet in Listing 4 illustrates how to activate the sender and receiver components.

Listing 4. Activating the sending and receiving components

 // Activate the sending component
String senderComponentID = "sender";
org.servicemix.jbi.container.ActivationSpec senderActivationSpec =
   new org.servicemix.jbi.container.ActivationSpec(senderComponentID,
                                                   sender);
jbiContainer.activateComponent(senderActivationSpec);
// Activate the receiving component
String receiverComponentID = "receiver";
org.servicemix.jbi.container.ActivationSpec receverActivationSpec =
   new org.servicemix.jbi.container.ActivationSpec(receiverComponentID,
                                                   receiver)
jbiContainer.activateComponent(receverActivationSpec);

Send and receive messages with the support components

Sending messages in ServiceMix involves transmitting the message through a sender support component and receiving the message through a "listening" receiver support component.

A typical sender component:

  1. Retrieves an instance of javax.jbi.messaging.DeliveryChannel from its ComponentContext
  2. Retrieves an instance of javax.jbi.messaging.MessageExchangeFactory from the DeliveryChannel instance
  3. Uses the MessageExchangeFactory instance to create an implementation of javax.jbi.messaging.MessageExchange containing the message content
  4. Transmits the MessageExchange instance to the destination via the DeliveryChannel instance

The example in Listing 5 shows how to send a String-based XML message through a sender component:

Listing 5. Send a message with a sending component

 public void sendMessage(String xml)
{
   try
   {
      ComponentContext context = getContext();
      InOnly exchange =
         context.getDeliveryChannel().
            createExchangeFactory().createInOnlyExchange();
      NormalizedMessage message = exchange.createMessage();
      message.setContent(new StringSource(xml));
      if (resolver != null)
      {
         ServiceEndpoint destination =
            resolver.resolveEndpoint(getContext(),
                                     exchange,
                                     NullEndpointFilter.getInstance());
         exchange.setEndpoint(destination);
      }
      exchange.setInMessage(message);
      // Now, send the message exchange
      context.getDeliveryChannel().send(exchange);
   }
   catch (Exception e)
   {
      e.printStackTrace();
   }
}

An interested component can subscribe to message exchanges within the ServiceMix framework through numerous approaches. One simple mechanism allows the receiving component to implement the MessageExchangeListener interface and the sending component to set the receiving component as its org.servicemix.jbi.resolver.EndpointResolver component. With this in place, ServiceMix sends all messages from the sender to the receiver. The code sample in Listing 6 illustrates this process.

Listing 6. A simple EndPointResolver-based receive process

 public class ReceiverComponent
   extends ComponentSupport
   implements MessageExchangeListener, Receiver
{
...
   // Method for the MessageExchangeListener interface
   public void onMessageExchange(MessageExchange exchange)
      throws MessagingException
   {
      NormalizedMessage inMessage = exchange.getMessage("in");
      if (inMessage == null)
      {
         throw new MessagingException("Null in message delivered!");
      }
      System.out.println(inMessage);
   }
}
// Creating the receiver and sender components and setting the receiver
// component as the EndpointResolver object in the sender component
ReceiverComponent receiver = new ReceiverComponent();
SenderComponent sender = new SenderComponent();
sender.setResolver(new ServiceNameEndpointResolver(ReceiverComponent.QNAME));

Figure 3 illustrates the send/receive sequence of a simple message exchange in ServiceMix.

Figure 3. The send/receive sequence of a simple message in ServiceMix. Click on thumbnail to view full-sized image.

Installing and starting ServiceMix on Windows

To download and install the binary distribution on a Windows system, complete the following steps:

  1. Download the ServiceMix distribution file for Windows from ServiceMix
  2. Extract the files from the zip file into a directory of your choice

To start ServiceMix, in a console window, change to the ServiceMix installation directory as follows:

 cd [servicemix_install_dir]\bin

Replace servicemix_install_dir with the directory in which ServiceMix was installed, e.g., c:\Program Files\servicemix-1.x. Then in the console window, type servicemix.

Installing and starting ServiceMix on Unix

To download and install the binary distribution on a Unix system:

  1. Download the ServiceMix distribution file for Unix. Change to the directory where ServiceMix was downloaded. Extract the files from the gzip file into a directory of your choice. For example:
     gunzip servicemix-x.x.x.tar.gz
    tar xvf servicemix-x.x.x.tar
    
  2. If the ServiceMix startup script is not executable, change its permissions. The ServiceMix script is located in the bin directory. To change the permissions, use the following examples, where [servicemix_install_dir] is the directory in which ServiceMix was installed:

     cd [servicemix_install_dir]/bin
    chmod 755 servicemix
    

To start ServiceMix, from a command shell, change to the installation directory and run the ServiceMix program: cd [servicemix_install_dir]/bin.

Replace servicemix_install_dir with the directory in which ServiceMix was installed. Then type servicemix.

Testing the installation

If ServiceMix is up and running correctly, the Window's console window or the Unix command shell displays something similar to the following line:

 [INFO] JBIContainer -- ServiceMix JBI Container 
<http://servicemix.org/> name: defaultJBI running version: null

Stopping ServiceMix

For both Windows and Unix installations, terminate ServiceMix by typing CTRL-C in the command shell or console in which it is running.

If ServiceMix was started in the background on Unix, the process can be killed, as follows:

 ps -ef|grep servicemix
kill [PID]

Replace [PID] with the actual process ID of the ServiceMix process.

Conclusion

Services using a service-oriented architecture (SOA) require an infrastructure that can connect any component or service, regardless of location, messaging protocol, and message format. An enterprise service bus (ESB) fulfills these requirements.

The JBI specification and API defines a normalized messaging service, component framework, and management model for building a standards-based and pluggable ESB. ServiceMix is a lightweight, open source ESB and SOA toolkit built on the semantics and APIs of the JBI specification and released under the Apache license. ServiceMix is easily embeddable and can run as a standalone ESB.

In this article, I discussed the mechanisms used by the ServiceMix ESB to facilitate cross-protocol messaging, message transformation, message security, service invocation, and other requirements of a service-oriented messaging infrastructure.

Jeff Hanson has more than 20 years of experience in the software industry, including working as senior engineer for the Windows OpenDoc project and as lead architect for the Route 66 framework at Novell. An author of numerous articles and books, he is currently the chief architect for eReinsure.com, building Web service frameworks and platforms for J2EE-based reinsurance systems.

Learn more about this topic

Join the discussion
Be the first to comment on this article. Our Commenting Policies