Introduction
Developing services and component for use in a JBI (Java Business Integration) environment can seem a little complex at first and, since the JBI (JSR-208) specification is very open-ended, it can be difficult to get started sometimes. The purpose of the ServiceMix Spring Client Toolkit (SSCT) is to allow you to get up and running quickly with either with new components or services, or maybe simply by JBI-enabling your existing Java code, so that you can use it in a JBI environment.
This Quick Start guide will help you quickly build a couple of simple components that can be hooked together, in order to illustrate how you can use JBI. All of the examples detailed below are built to work on the ServiceMix 1.0 release (see ServiceMix for more information).
It's All about Tooling
Preparing code for a JBI environment typically means that you need to be able to efficiently build code and then, make that code deployable (since this is what everyone the point of building for JBI). In order to build code for a JBI environment, ServiceMix provides some tooling projects that allow you to quickly produce JBI-compliant JARs and descriptors, without requiring you to get up to your knees in XML and Ant scripts.
The starting place is a copy of Maven 1.0.1 (this is available from Apache Maven). Once you have Maven installed, you will need to get a copy of the Maven JBI Plugin, which is available here. Simply download the maven-jbi-plugin-1.0.jar and then drop it into your $MAVEN_HOME/plugins directory to make it available for your build process.
My First Component Project
The best place to start is, of course, to create a new project with which to work. Since this Quick Start guide is intended to make it building and deploying easy, you can use the Maven JBI plugin to help simplify your work. First, create a work directory (i.e., '/work'), which is empty, and then go to that directory from a shell or command line prompt and enter the following:
You should see the Maven start-up, and then be prompted for the name of your new component. As a good starting point, please use 'myFirstComponent'. Maven will then create the required directory structure underneath the /work directory.
Now, you will need to make this project available in your favourite IDE. So if you are using Eclipse, change to the myFirstComponent directory and use Maven to create the relevant Eclipse files by running the following:
See the Apache Maven website for more information on creating the configuration files for other IDEs.
You should now be able to open the JBI project in your IDE, where you can see the basic structure of the project, as shown below:
At this point, you are ready to start working with JBI.
Understanding How JBI Works
While the JBI specification is no light document, this Quick Start guide will try to distill some of the basic ideas, so that you have the information you need to write a basic component. Basically, JBI is a way of exposing Services and Binding Components. A Service is usually something that functions as an Engine of some type, and instances of an engine each run with a configuration, e.g., a service might be a BPEL engine, or it might be a transformation engine. A Binding Component is a particular type of service, which allows you to take calls or messages from a non-JBI transport, such as JMS, or to a non-JBI transport/protocol.
The JSR is purposefully vague on some of this simply to allow the greatest range to the component developers. In this case however, you will be using the SSCT to write a simple component for integration use. To that end, there are a few basic concepts to understand:
- Services/Components have life-cycles, most commonly initialization, start and stop. There is a bit more to life-cycles, but in order to get started on building code for a JBI environment, you can start here.
- Services/Components communicate to other Services/Components via EndPoints. Therefore, in order to talk to another service, you need to refer specifically to its Service Name.
- Services/Components can have interfaces, which means a service can route a message to a different piece of code, and you can have a service that exposes more than one interface.
- All Service Names and Interface names are Qualified Names, so you should declare namespaces.
How Does this Map to the ServiceMix Spring Client Toolkit?
The SSCT is provided to try and simplify the appraoch to building for JBI and to make it easier for you to write these components, though – as with all things that hide some of technology's complexity – the SSCT also hides some of the more advanced functionality.
The SSCT itself is based on Spring and therefore, it is recommended that you first take a look at Spring if you are not already familiar, since this Quick Start guide assumes at least preliminary Spring knowledge. In addition, the SSCT works in conjunction with the Maven JBI plugin to help you build your component. Finally, in using the SSCT examples, you will be producing hard-routed components, i.e., components that will build with their destinations included, though you the guide will also show you that it isn't overly complex to change your components' desitnations.
If you are familiar with the JSR-208 specification, you should be aware of interfaces like Component/LifeCycle/Service Unit Manager etc. While you can certainly use these interfaces, the SSCT provides the following set of three, simplified interfaces to the JBI infrastructure:
ServiceLifeCycleImplementation
Which can be implemented by your code and then rely on the SSCT container to invoke the start/stop method in-line with the JBI lifecycle methods.
ServiceInterfaceImplementation
Which can be used to receieve exchanges on a given interface; your code will implement this interface and return the QName of the interface on which it wishes to receive the exchanges.
ServiceEndPointImplementation
Which can be used to receive exchanges on a given Service Name and EndPoint; your code will implement this interface and return the QName of the service and the name of the EndPoint to receive the exchanges.
Your First Component
In order to begin, you will create a very simple component that can start a Timer, and then simply create and then send a message to another component. Admittedly, not the most earth-shattering of components – but it is simple enough that you can get it built over a cup of coffee, and it requires only two pages of explanation.
Create a new package org.servicemix.tutorial under src/main/java and then, create a new class called 'TimerComponent' in order to implement the ServiceLifeCycleImplementation interface.
You should end up with a class looking much like the following:
package org.servicemix.tutorial;
import javax.jbi.JBIException;
import org.servicemix.client.ServiceContext;
import org.servicemix.client.ServiceLifeCycleImplementation;
/**
* A simple Timer based component
*
* @author <a xhref="mailto:[email protected]">Philip Dodds </a>
*/
public class TimerComponent implements ServiceLifeCycleImplementation {
/* (non-Javadoc)
* @see org.servicemix.client.ServiceLifeCycleImplementation#init(org.servicemix.client.ServiceContext)
*/
public void init(ServiceContext serviceContext) throws JBIException {
}
/* (non-Javadoc)
* @see org.servicemix.client.ServiceLifeCycleImplementation#start()
*/
public void start() throws JBIException {
}
/* (non-Javadoc)
* @see org.servicemix.client.ServiceLifeCycleImplementation#stop()
*/
public void stop() throws JBIException {
}
}
Now, you are going to create a basic Timer. The SSCT actually simplifies this for you as you are only extending the TimerTask and creating a Timer, in the init method. In the start and stop, you will basically set the timer operations to schedule the timer to run every 5000ms and to cancel it if stopped.
package org.servicemix.tutorial;
import java.util.Timer;
import java.util.TimerTask;
import javax.jbi.JBIException;
import org.servicemix.client.ServiceContext;
import org.servicemix.client.ServiceLifeCycleImplementation;
/**
* A simple Timer-based component
*
* @author <a xhref="mailto:[email protected]">Philip Dodds </a>
*/
public class TimerComponent extends TimerTask implements
ServiceLifeCycleImplementation {
private Timer timer;
private ServiceContext serviceContext;
/*
* (non-Javadoc)
*
* @see org.servicemix.client.ServiceLifeCycleImplementation#init(org.servicemix.client.ServiceContext)
*/
public void init(ServiceContext serviceContext) throws JBIException {
this.serviceContext = serviceContext;
timer = new Timer();
}
/*
* (non-Javadoc)
*
* @see org.servicemix.client.ServiceLifeCycleImplementation#start()
*/
public void start() throws JBIException {
timer.schedule(this, 5000);
}
/*
* (non-Javadoc)
*
* @see org.servicemix.client.ServiceLifeCycleImplementation#stop()
*/
public void stop() throws JBIException {
timer.cancel();
}
/*
* (non-Javadoc)
*
* @see java.util.TimerTask#run()
*/
public void run() {
}
}
NOTE: Since you extended TimerTask, you now have a run method, so you can use this run method to create a simple InOnly exchange. To do this, you can use the serviceContext helper methods.
Below, you can see how easy it is to create an InOnly exchange and how to populate the message.
NOTE: With the ServiceContext helper method, you must also refer to the name of the interface to which the message will be sent. You will see this interface mapping to a service name later in the services.xml.
/*
* (non-Javadoc)
*
* @see java.util.TimerTask#run()
*/
public void run() {
try {
InOnly inOnly = serviceContext.createInOnly(new QName(
"http:, "log"));
NormalizedMessage message = inOnly.createMessage();
message.setContent(new StreamSource(new StringReader(
"<hello>world</hello>")));
serviceContext.done(inOnly);
} catch (MessagingException e) {
e.printStackTrace();
}
}
That's it for building your first component's code. Now, you need to do the wiring for the JBI, i.e., you will need to make sure that when you publish to the interface, that it maps to a specific service name. Since you are still writing the first component, you will have to make up the name of the second component as a placeholder. However, keep this name in mind since you will be writing a second component to receive these messages shortly. To do the JBI wiring, look to the /src/main/merge/services.xml file. You should be able to prepare the file as shown below:
<services binding-component="false"
xmlns:logger="http://tempuri.org/logger">
<consumes interface-name="logger:log"
service-name="logger:myLogger" />
</services>
NOTE: The interface name is described as a consumes, which in JBI-speak means that this component will be sending its exchange to the servicename 'logger:myLogger'. You haven't written this service yet, but as you can see, it won't take you long to create this service so that you can use its services.xml to expose the service-name and interface name. The SSCT lets you work through the interface name, though you still have the ability to publish to any of the available EndPoints that are defined in the services.xml.
Next, you need to tell the Spring Component that an instance of the TimerComponent is required. This is done in the Spring configuration file found in /src/main/jbi/META-INF/jbi-spring.xml, as can be seen below:
<beans>
<!-- This is going to be where we declare the beans that we want the
SpringComponent container to build -->
<bean id="myTimer"
class="org.servicemix.tutorial.TimerComponent">
</bean>
</beans>
The final step in building the JBI component is actually creating the component, this can be done using the Maven JBI plugin by running the following command from your myFirstComponent directory:
This command will create a ZIP file in the target directory called myFirstComponent-1.0-jbi-installer.zip.
Congratulations! You have just created your first JBI component!
Creating a Component to Receive the Exchange
Of course, creating single JBI component is pretty useless, much like being the only person at the party – there is very little to do. So, the next step is for you to return to the parent directory and repeat the process above, using our Maven JBI plugin and the maven jbi:createArchetype, to create a second component, which you will call mySecondComponent.
Once you have created the project, and also the Eclipse files, you can create a new class in the package org.servicemix.tutorial called LoggerComponent. This time you will be implementing the ServiceInterfaceImplementation interface, and you will fill in the getInterface method with the name of the interface you used in building the first component, as shown below:
package org.servicemix;
import javax.jbi.messaging.MessageExchange;
import javax.xml.namespace.QName;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.servicemix.client.ServiceContext;
import org.servicemix.client.ServiceInterfaceImplementation;
/**
* A simple Logger based component
*
* @author <a xhref="mailto:[email protected]">Philip Dodds </a>
*/
public class LoggerComponent implements ServiceInterfaceImplementation {
private static final Log log = LogFactory.getLog(LoggerComponent.class
.getName());
/* (non-Javadoc)
* @see org.servicemix.client.ServiceInterfaceImplementation#getInterfaceName()
*/
public QName getInterfaceName() {
return new QName(
"http:, "notification");
}
/* (non-Javadoc)
* @see org.servicemix.client.ServiceImplementation#setServiceContext(org.servicemix.client.ServiceContext)
*/
public void setServiceContext(ServiceContext arg0) {
}
/* (non-Javadoc)
* @see org.servicemix.client.ServiceImplementation#onMessage(javax.jbi.messaging.MessageExchange)
*/
public void onMessage(MessageExchange exchange) {
log.info("I got my exchange "+exchange);
}
}
The SSCT will ensure that exchanges for this service and its interfaces will be passed to the ServiceInterfaceImplementation.
Next, you will need to set up the services.xml for this component. Since this is such a simple example, you can simply reverse the logic from the first component, so that this this component provides the interface for itself.
<!-- This is where we are able to declare the ins and outs of the Service
as it consumes and provides elements, the service-names and EndPoints
will be used to activate the JBI EndPoints, and you can use the
interface-name to determine which one you want to call and which
bean is going to receive the actual JBI exchange -->
<services binding-component="false"
xmlns:timer="http://tempuri.org/timer"
xmlns:logger="http://tempuri.org/logger">
<provides interface-name="timer:notification"
service-name="logger:write" />
</services>
Once again you need to configure the Spring container to create an instance of your bean in the src/main/jbi/META-INF/jbi-spring.xml file, shown below:
<beans>
<!-- This is going to be where we declare the beans that we want the
SpringComponent container to build -->
<bean id="myLogger"
class="org.servicemix.tutorial.LoggerComponent">
</bean>
</beans>
This now completes the writing of the receiving component's code. As with the first component, you need to build the receiving component so that it is ready for deployment using the maven jbi:generateInstaller goal onto a JBI server (in our case the wonderful ServiceMix).
Deploying Your Components onto ServiceMix
One of the key differences between the ServiceMix Spring Client Toolkit and the standard ServiceMix client libraries is that the SSCT is designed to generate standard JBI components and service units that can run in any JBI-compliant container. This means that you are able to build installable ZIP files that can be deployed onto the server itself. In this example, you are going to deploy to a stand-alone ServiceMix server, however you could deploy to a Geronimo and JBoss instance running ServiceMix embedded, as well.
To deploy your JBI components, you must first download and un-ZIP ServiceMix to your your machine.
Next, under $SERVICEMIX_HOME (the location you unzipped it), you should find an install directory. You need to copy both of the JBI installers that you created for your components into this directory. If you have been working in '/work' then these files should appear as follows:
/work/myFirstComponent/target/myFirstComponent-1.0-jbi-installer.zip and /work/mySecondComponent/target/mySecondComponent-1.0-jbi-installer.zip.
Once you have installed the new components, you can just start ServiceMix - to do so goto $SERVICE_HOME/bin and run servicemix
You should see your components deploy and then, every 5 secs you should see the logger receive the exchange from the timer component.
*Aug 19, 2005 11:13:20 AM org.servicemix.tutorial.LoggerComponent onMessage
INFO: I got my exchange org.servicemix.jbi.messaging.InOnlyImpl@15ad5c6*
There you go! You have just written your first JBI components, hooked them up, and deployed them successfully!