You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 6 Next »

Introduction

Developing services and component for use in a JBI 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. The purpose of the ServiceMix Spring Client Toolkit (SSCT) is to allow you to quickly get started either with new components or services, or maybe simply JBI-enabling your existing Java code so that you can use it in a JBI environment.

This Quick Start will let you quickly get moving building a couple of simple components that we can hook together to show that we are able to use JBI. All these examples are built to work on the ServiceMix 1.0 release (see ServiceMix for more information).

Its all about Tools

Preparing to build code for a JBI environment usually means getting prepared so that you are able to efficiently build code and get deployable code out of the door (since this is what everyone is really waiting for). In order to help us get there ServiceMix provides some tooling projects that will allow us to quickly build JBI compliant JAR's and descriptors without needing to get up to our 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. You simply need to download the maven-jbi-plugin-1.0.jar and then drop it in your $MAVEN_HOME/plugins directory to make it available.

My First Component Project

The best place to start is of course to create a new project to work with, since we are all about making it easy you can use the Maven JBI plugin to help you out here, create a work directory (ie. /work) which is empty and then go to that directory in a shell or command prompt and enter:

maven jbi:createArchetype

You should see the Maven start-up and then it will ask for you the name of your new component, we can use myFirstComponent as a good starting place. It will then create the required directory structure underneath the work directory.

 __  __
|  \/  |__ _Apache__ ___
| |\/| / _` \ V / -_) ' \  ~ intelligent projects ~
|_|  |_\__,_|\_/\___|_||_|  v. 1.0.2

Enter the name for your new JBI project
myFirstComponent
build:start:

jbi:createArchetype:
    [mkdir] Created dir: C:\work\myFirstComponent\src\main\java
    [mkdir] Created dir: C:\work\myFirstComponent\src\main\test
    [mkdir] Created dir: C:\work\myFirstComponent\src\main\merge
    [mkdir] Created dir: C:\work\myFirstComponent\src\main\jbi\META-INF
    [copy] Copying 1 file to C:\work\myFirstComponent
    [copy] Copying 1 file to C:\work\myFirstComponent\src\main\jbi\META-INF
    [copy] Copying 1 file to C:\work\myFirstComponent\src\main\merge
BUILD SUCCESSFUL
Total time: 53 seconds
Finished at: Thu Aug 18 16:05:01 EDT 2005

Now we need to make this project available in our favourite IDE, so if you are using Eclipse then you can change to the myFirstComponent directory and use Maven to create the relevant Eclipse files by running:

maven eclipse

See the Apache Maven website for more information on creating the configuration files for other IDE's.

You should now be able to open the project in your IDE, and you can see the basic structure of the project shown below:

At this point we are ready to start working with JBI.

Understanding how JBI works

While the JBI specification is no light document we will try and distill some of the basic ideas down so that we can get a basic component written. Basically JBI is a way of exposing Services and Binding Components, a Service is usually something that is an Engine of some type and instances of that engine run with a configuration, this might be a BPEL engine or might be a transformation engine. While a Binding Component is a service that 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, however in order for us to be able to write a simple component we will be using our Spring Client Toolkit to help use integrate. To that end there are a few basic things you need to focus on:

  • Services/Components have life-cycles, these are basically initialization, start and stop. There is a bit more to it that that but in order to get you going we can start here.
  • Services/Components communicate to other Services/Components via EndPoints, this means that if you want to talk to another service you need to refer to its Service Name
  • Services/Components can have interfaces, this means that a service can route a message to a different peice of code, and you might want to have a service that exposes more than one interface
  • All Service Names and Interface names are Qualified Names, so we should declare namespaces for they are correct.

How does this map to the Spring Client Toolkit?

The Toolkit is there to try and simplify the appraoch to JBI and make writing these components a bit easier, though as with all things it hides some of the complexity but also hides some of the more advanced functionality.

To start with the Spring Client Toolkit is based on Spring and therefore it is probably worth first looking at what Spring is, since we will assume a little knowledge. The second thing is the the SSCT working along side the Maven JBI plugin to help you build you component. And finally in these examples we will be producing hard routed components, in other words components that will build with their destinations in, though you will see that changing the destinations isn't too complex.

If you are familiar with the JSR-208 specification you have probably heard of interfaces like Component/LifeCycle/Service Unit Manager etc, while you certainly use these the Spring Client Toolkit provides a simplified set of three interfaces to the JBI infrastructure, these are:

ServiceLifeCycleImplementation

Which can be implemented by your code and the SSCT container will 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 recieve exchanges on a given Service Name and End Point, your code will implement this interface and return the QName of the service and the name of the endpoint to receive the exchanges.

Our first Component

In order to start we will create a very simple component that is able to start a Timer and then simply create and send a message to another component. Admittedly note the most earth shattering of components though it is simple enough to get done over a cup of coffee and its going to require two pages explaining the code.

We will create a new package org.servicemix.tutorial under src/main/java and then in there create a new class called TimerComponent and implement the ServiceLifeCycleImplementation interface.

You should end up with a class looking much like this


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 href="mailto:pdodds@unity-systems.com">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 {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see org.servicemix.client.ServiceLifeCycleImplementation#start()
	 */
	public void start() throws JBIException {
		// TODO Auto-generated method stub

	}

	/* (non-Javadoc)
	 * @see org.servicemix.client.ServiceLifeCycleImplementation#stop()
	 */
	public void stop() throws JBIException {
		// TODO Auto-generated method stub

	}

}

Now we are going to create a simple Timer, this is actually made a little easier by the fact that the Spring Client Toolkit doesn't ask you to extend anything so you are extend TimerTask and create a Timer, in the init method. In the start and stop we will basically perform the timer operations to schedule it to run every 5000ms and cancel it if we stop.

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 href="mailto:pdodds@unity-systems.com">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 that since we extended TimerTask we now have a run method, so we can use this to create a simple InOnly exchange. In order to help us do this we can use the serviceContext helper methods.

Below we can see how easy it is to create an InOnly exchange and populate the message, note that with the ServiceContext helper method we also refer to the name of the interface that we will to send to, we 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://tempuri.org/logger", "log"));
		NormalizedMessage message = inOnly.createMessage();
		message.setContent(new StreamSource(new StringReader(
				"<hello>world</hello>")));
		serviceContext.done(inOnly);
	} catch (MessagingException e) {
		e.printStackTrace();
	}
}

Thats it for our first component's code, now we need to do the wiring for the JBI. This basically means we need to make sure that when we publish to the interface that maps to a service name. Since we are still writing the first component we will have to make up the name of the second component, but keep it in mind since we will write a second component to recieve these in a minute. To do the wiring we 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 that we have our interface name as a consumes, which is JBI-speak means that this component will be sending its exchange to the service-name 'logger:myLogger'. We haven't written this service yet, but as you can see it won't take us long to create this service and then we can use its services.xml to expose that service-name and interface name. The Spring Client Toolkit lets us work through the interface name, though you still have access to be able to publish to any of your available end points that you defined in the services.xml.

Next we need to tell our Spring Component that we need an instance of the TimerComponent, this is done in the spring configuration file found in /src/main/jbi/META-INF/jbi-spring.xml, as can be see 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 for our JBI component is actually creating the component, this can be done using the Maven JBI plugin, using the following command in your myFirstComponent directory:

maven jbi:generateInstaller

Which will create a ZIP file in the target directory below called myFirstComponent-1.0-jbi-installer.zip.

Congratulations you have just created your first component!

Creating a component to receive the exchange

The one problem with JBI is that a single component is pretty useless, much like being the only person at the party there is very little to do. So we can return to the parent directory and repeat the process using our Maven JBI plugin and the maven jbi:createArchetype to create a second component called aptely 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 we will implement the ServiceInterfaceImplementation interface, and we will fill in the getInterface method with the name of the interface we used in the first component.

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 href="mailto:pdodds@unity-systems.com">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://tempuri.org/timer", "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 Spring Client Toolkit will make sure that exchanges for this service and that interface will be passed to this ServiceInterfaceImplementation.

Next we need to set up the services.xml for this component, since this is such a simple example we are able to reverse the logic from the first component so this this component provides the interface on itself.

<!-- This is where we are able to declare the ins and outs of the Service
 	  as consumes and provides elements,  the service-names and endpoints
 	  will be used to activate the JBI endpoints,  and we can use the 
 	  interface-name to determine which one we want to call and also 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>

And once again we need to configure the spring container to create an instance of our 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>

And that completes the writing of a recieving component, and as with the first component we need to build this component ready for deployment using the maven jbi:generateInstaller goal to a JBI server (in our case the wonderful ServiceMix).

Deploying your Components onto ServiceMix

Once of the key differences between the Spring Client Toolkit and the standard ServiceMix client libraries is that the Spring Client Toolkit 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 into the server, in this example we are going to deploy to a stand-alone servicemix server, however you could also deploy to a Geronimo and JBoss instance running servicemix embedded.

First up you will need a copy of ServiceMix, so download and unzip this on your machine.

  • No labels