Martin Gale’s blog

web 2.0, extended integration, pervasive messaging and other technical thoughts

Posts Tagged ‘lotus’

Sample composite application in Lotus Expeditor 6.2

Posted by Martin on June 22, 2009

One of the key features of Lotus Expeditor and Lotus Notes 8.5 is the Composite Applications Environment (CAE). The CAE provides a framework for integration “on the glass” of desktop applications such as native applications, terminal emulation or browser-based applications that are not otherwise easily integrated. This posting shows a very simple example of how to use the tools provided in the Lotus Expeditor 6.2 Client for Desktop to integrate together a set of disparate browser-based applications by way of illustration.

Preparing your environment

There are two possible ways to configure a composite application in the CAE — via extension points in plug-ins created using the Expeditor Toolkit or via GUI tools provided for the Expeditor Desktop Client itself. This sample uses the GUI method to create the composite application.

The GUI tooling is not installed by default with the Expeditor Desktop Client, but is supplied in the install media. You will need to install the required feature from the update site supplied with the Client inside the desktop\updates\platform folder.

Creating a new Composite Application

Once the CAE feature has been installed, you can begin creating your Composite Application using the File menu.

image

Selecting New Composite Application… will launch a modal dialog box prompting you for a filename to store your Composite Application. In this case we’ve chosen to store the Composite Application under the name Radio 1 Sample.

image

Having clicked OK we then see a blank Composite Applications page as shown below.

image

The scenario we are going to create is a very simple one whereby we take two separate web applications from different vendors and integrate data between them within a simple task flow. To begin editing the page, we follow the Actions -> Edit Application menus. We see the editing screen appear.

image

Configuring containers

The CAE works on the principle that the applications are added into the page using a set of generic containers. These containers provide a common interface around the various different desktop client technologies such that they can ultimately be wired together in a standardised fashion. Since the applications we are integrating are browser based, we will use the Browser Container shown on the Component Palette. Dragging the container onto the page creates a default configuration of the container.

image

We will modify this default configuration to reflect our application. We will use data contained within the BBC Radio 1 Album Chart to pre-populate a search in Amazon for the name of the top album. I have deliberately chosen these since they are two public sites over which I could not reasonably integrate myself in any other fashion.

We will start by configuring a container for the BBC Radio 1 web site as the source of the data. To start this process we select the Edit Component Properties option from the context menu shown below.

image

A modal dialog box then appears allowing various settings about the container. We shall first change the title and description to something more meaningful.

image

Now, we will configure the details of the starting page for the container and also define the data properties that the container will expose to the environment for composition.

image

You will see that not only have we changed the initialURL property but we have created two further properties albumArtist and albumTitle. In the case of the latter two we have ticked the Wireable box. This tells the CAE that these are data properties on this container that can be integrated (or wired) with other containers.

We now need to specify how and when albumArtist and albumTitle are populated by the container. The CAE has the notion of a landmark with an associated set of events for containers. A landmark indicates a specific logical point in the application. In the case of a web browser, we can specify either a URL or the title of the page in question. For our example we are interested specifically in the Album Chart so we shall set a landmark of the Album Chart page using its URL. We select the Landmarks tab on the dialog, then select URL as the Type of Landmark and finally click the Add Landmark button.

 

image

For our landmark we can add a set of event handlers associated with it. This tells the CAE what to do when the particular landmark is reached. For a web browser, the most common event is the Content Complete event which is fired when the web page has completed loading. In response to an event we can tell the CAE to interrogate the container to set the data in one of the Wireable properties we defined earlier. In this case we will specify the XPath within the page in the browser of the HTML element containing the data elements we are interested in. A quick and simple way of finding the XPath of an HTML node is to use the Firebug utility for Firefox.

image

Now we can specify our event handler. We will add two operations for the Content Complete event on the page to copy the values contained in the HTML into the attributes we defined earlier. We click the Add Event button and then Add Operation with Content Complete set as the Event.

image

The above Operations effectively the following:

  • When the page completes loading, publish the value held at the XPath /html/body/div/div[2]/div[2]/div[4]/div/table/tbody/tr[2]/td/table/tbody[2]/tr/td[4]/h4 into the property named albumArtist.
  • When the page completes loading, publish the value held at the XPath /html/body/div/div[2]/div[2]/div[4]/div/table/tbody/tr[2]/td/table/tbody[2]/tr/td[4]/h4 into the property named albumTitle.

Note the xpath: prefix indicating to the Browser Container that the meta-data that follows is a valid XPath string. Note that this meta-data is container specific, other containers may have different schemes.

Pressing OK on the dialog box will save the changes and present the modified container in the editor.

image

Now we need to configure a container for Amazon in the same way. We will now repeat the process above, note that you can drag your new container from the palette onto the page and attach it to a convenient point on the page (e.g. the bottom edge so the screen is split horizontally). This time, we will set the intialURL property to http://www.amazon.co.uk for the Amazon home page and a description and title to that effect. We will also do the following:

  1. Add a Wireable property called searchQuery.
  2. Create a Title landmark for the page with the title “Amazon.co.uk Music: over two million music items, including chart CDs, back-catalogue, vinyl, cassettes” (omitting the speech marks). Title landmarks are useful when the URLs can vary e.g. some sites use a URL rewriting mechanism for session affinity.
  3. Add a Content Complete event with a single Operation to Receive from the searchQuery property and put the value into the XPath //*[@id="twotabsearchtextbox"].

A snapshot of the Browser Container settings for the Amazon container is shown below.

image

Notice that in this case we choose to Receive (rather than Publish) as we will have incoming data to be plugged into the Amazon page rather than data to be propagated out as we had before. We now have two containers configured on our page.

image

Wiring the containers into a composite

We now need to wire the two containers together. Note that at this point we will no longer be talking about the specifics of how the containers give and receive data (i.e. no more talk of XPaths). This is an important feature of the CAE since it means that relatively few technical skills are required to assemble a set of containers once they have been configured. At the wiring level, the user deals only in terms of properties and wires.

image

From the context menu shown above we select the Wiring menu option. We then see the Wiring view showing the two containers we have configured.

 image

Notice how for each container we configured earlier that each Wireable property is shown on the graphical representation of the container.

What we want to do is wire the albumArtist property into the searchQuery such that when the events we configured for the container fire, the data will flow along the wire from the BBC Radio 1 Charts container into the Amazon (UK) container. We do this simply by clicking and dragging the albumArtist property and releasing it over the searchQuery property. A blue arrow appears whilst the drag/drop is in progress, once the drop is complete we see the following:

image

We complete our composite application by clicking OK on the Wiring screen, then the File -> Save and Close menu options on the editor screen to save the changes to the Composite Application. When we return to the Expeditor desktop, we now see a tab with our Composite Application contained within it.

image

Testing the application

We are now ready to test the application. To show the integration working, we simply navigate the BBC page to the album chart using the link within the page to http://www.bbc.co.uk/radio1/chart/albums.shtml and then click through on Amazon to the Music Department. We should see the following screens.

image

As you can see when we click onto the Music Department, the title of the top album in the Radio 1 chart has been extracted from the HTML and populated into the input field on the Amazon page. Our composite application is complete and working.

Posted in Snippets | Tagged: , , , , , | 1 Comment »

AES 256 encryption using Java and Lotus Expeditor 6.2

Posted by Martin on March 24, 2009

In a recent engagement, one of the requirements for the application was the ability to encrypt the payload of an MQTT message using 256 bit Advanced Encryption Standard (AES) encryption, where the key was created using a combination of a user name and a pre-shared key. This was to be accomplished using the Lotus Expeditor Device JRE profile running on a desktop PC.

I’ve captured how I did this for posterity here, it’s basically the standard Java Cryptography Architecture (JCA) so should be generally useful in other domains too. I’ve used a really simple OSGi bundle that performs the cryptography in the start() method to prove the point within the Expeditor toolkit.

Creating a the encryption key

In this scenario, I needed to construct a 256 bit key derived from a user name and pre-shared key. Java provides the SecretKeySpec class to enable the provision of application specific data within a key.

// My user name
byte[] loginId = "galem".getBytes();
// A sample pre-shared key -- this might be something like an account number
// or employee number or such like.
byte[] preSharedKey = "ACME-1234ACME-1234ACME-1234".getBytes(); 
byte[] encodedKey = new byte[loginId.length + preSharedKey.length];

System.arraycopy(loginId, 0, encodedKey, 0, loginId.length);
System.arraycopy(preSharedKey, 0, encodedKey, loginId.length, preSharedKey.length);

// The SecretKeySpec provides a mechanism for application-specific generation
// of cryptography keys for consumption by the Java Crypto classes.

// Create a key specification first, based on our key input.
SecretKey aesKey = new SecretKeySpec(encodedKey, "AES");

Encrypting the data

Now we have the key, we can now create a Crypto class to encrypt the data. I’ve output the result to the console to show a “before and after” view.

// Create a Cipher for encrypting the data using the key we created.
Cipher encryptCipher = Cipher.getInstance("AES");
// Initialize the Cipher with key and parameters
encryptCipher.init(Cipher.ENCRYPT_MODE, aesKey);

// Our cleartext
String clearString = "This is another example";
byte[] cleartext = clearString.getBytes();

System.out.println("Plain text: "+clearString);

// Encrypt the cleartext
byte[] ciphertext = encryptCipher.doFinal(cleartext);

System.out.println("Encrypted: "+new String(ciphertext));

Decrypting the data back again

Finally, to show the encrypted data can be returned to its original form, we’ll reverse the process.

// Now decrypt back again...
// Decryption cipher
Cipher decryptCipher = Cipher.getInstance("AES");
// Initialize PBE Cipher with key and parameters
decryptCipher.init(Cipher.DECRYPT_MODE, aesKey);

// Decrypt the cleartext
byte[] deciphertext = decryptCipher.doFinal(ciphertext);

System.out.println("Decrypted: "+new String(deciphertext));

Full listing

package com.ibm.issw.sample.crypto;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

import org.eclipse.core.runtime.Plugin;
import org.osgi.framework.BundleContext;

/**
 * The activator class controls the plug-in life cycle
 */
public class Activator extends Plugin {

	// The plug-in ID
	public static final String PLUGIN_ID = "com.ibm.issw.sample.crypto";

	// The shared instance
	private static Activator plugin;

	/**
	 * The constructor.
	 */
	public Activator() {
	}

	/**
	 * @see org.eclipse.core.runtime.Plugins#start(org.osgi.framework.BundleContext)
	 */
	public void start(BundleContext context) throws Exception {
		super.start(context);
		plugin = this;

		try {

		    // In this example we will just use a combination of a user name and
		    // a pre-shared key.

		    // My user name
		    byte[] loginId = "galem".getBytes();
		    // A sample pre-shared key -- this might be something like an account number
		    // or employee number or such like.
		    byte[] preSharedKey = "ACME-1234ACME-1234ACME-1234".getBytes();

		    byte[] encodedKey = new byte[loginId.length + preSharedKey.length];

		    System.arraycopy(loginId, 0, encodedKey, 0, loginId.length);
		    System.arraycopy(preSharedKey, 0, encodedKey, loginId.length, preSharedKey.length);

		    // The SecretKeySpec provides a mechanism for application-specific generation
		    // of cryptography keys for consumption by the Java Crypto classes.

		    // Create a key specification first, based on our key input.
		    SecretKey aesKey = new SecretKeySpec(encodedKey, "AES");

		    // Create a Cipher for encrypting the data using the key we created.
		    Cipher encryptCipher = Cipher.getInstance("AES");
		    // Initialize the Cipher with key and parameters
		    encryptCipher.init(Cipher.ENCRYPT_MODE, aesKey);

		    // Our cleartext
		    String clearString = "This is another example";
		    byte[] cleartext = clearString.getBytes();

		    System.out.println("Plain text: "+clearString);

		    // Encrypt the cleartext
		    byte[] ciphertext = encryptCipher.doFinal(cleartext);

		    System.out.println("Encrypted: "+new String(ciphertext));

		    // Now decrypt back again...
		    // Decryption cipher
		    Cipher decryptCipher = Cipher.getInstance("AES");
		    // Initialize PBE Cipher with key and parameters
		    decryptCipher.init(Cipher.DECRYPT_MODE, aesKey);

		    // Decrypt the cleartext
		    byte[] deciphertext = decryptCipher.doFinal(ciphertext);

		    System.out.println("Decrypted: "+new String(deciphertext));

		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * @see org.eclipse.core.runtime.Plugin#stop(org.osgi.framework.BundleContext)
	 */
	public void stop(BundleContext context) throws Exception {
		plugin = null;
		super.stop(context);
	}

	/**
	 * @return the shared instance
	 */
	public static Activator getDefault() {
		return plugin;
	}

}

Posted in Snippets | Tagged: , , , , , , | Leave a Comment »

Visualising data using MQTT and IBM Mashup Center

Posted by Martin on January 26, 2009

I’ve spoken before about how MQTT and Web 2.0 technologies can be used to extend the reach of the enterprise. When you put those pieces together, powerful possibilities emerge. We can reliably gather data from the remotest parts of the network (e.g. power stations, oil rigs, underground pipelines) and now thanks to mashup technologies rapidly put that data into the hands of users to manage their business. I’ve shown how this is possible by demonstrating how data from MQTT can be received by a messaging server and rapidly consumed into a functioning business application. I’ve uploaded a video to YouTube for posterity (hence the slightly sketchy video quality), but those inside the IBM firewall can obtain a higher quality version if they would like to see it.

Posted in Snippets | Tagged: , , , , , , , , , , , | 1 Comment »

Using the new MQTT v5 client in Expeditor 6.2

Posted by Martin on January 14, 2009

With the launch of Expeditor 6.2 comes the next generation of the MQTT client. MQTT is IBM’s specialist messaging protocol designed for use in fragile or expensive networks (e.g. mobile or satellite links) and in constrained devices such as sensors and mobile devices. This latest version (version 5 of the protocol) adds a number of features including the following:

  • Support for the point-to-point (i.e. queues) as well as the traditional pub/sub messaging paradigm.
  • Different payload types such as a textual string in addition to the basic byte array of the previous client.
  • The ability to specify whether an individual subscription is durable (i.e. survives a disconnection and continues to collect messages) or not on a per-subscription basis. In the previous incarnation, the durability of a client’s subscriptions was specified for the whole client. This could mean resources within the broker were consumed by unnecessarily durable subscriptions.
  • The ability to connect to a messaging server over SSL and using authentication credentials.
  • A variety of additional header information for messages including expiry and priority as in JMS.
  • The ability to start and stop message delivery without having to disconnect and reconnect again. This allows the application to control the flow of messages without the overhead of a full connection handshake each time.

Full details can be found in the Javadoc but I’ve included a simple sample here to get you started.

Install the MQTT v5 client into the Expeditor client runtime

In Expeditor 6.2, the MQTT v5 client is not installed by default with the base client installer. You will need to install it as an additional feature from the update site contained in desktop/updates/platform folder in the install media, even for use in the toolkit. A screen shot showing which feature is required is shown below.

image

Sample MQTT application

The following examples show a class that connects to a broker and subscribes durably for messages and a class that publishes a message. The subscriber makes use of the message delivery start/stop feature to enable message delivery only when both subscriptions are in place. You will see that I’ve included some tests that determine the type of payload of a given message as well.

Notice the different package/plug-in name for the v5 MQTT client.

import com.ibm.micro.client.MqttCallback;
import com.ibm.micro.client.MqttClient;
import com.ibm.micro.client.MqttConnectOptions;
import com.ibm.micro.client.MqttDeliveryToken;
import com.ibm.micro.client.MqttDestination;
import com.ibm.micro.client.MqttException;
import com.ibm.micro.client.MqttMessage;
import com.ibm.micro.client.MqttSubscriptionOptions;

public class MqttSubscriber implements MqttCallback {

private MqttClient mqttClient = null;
private String TOPIC_SUFFIX_ALERTS = “alerts”;
private String TOPIC_SUFFIX_DATA = “data”;
public MqttSubscriber() {
super();
}
/* MQTT Client API */
public void connectionLost(Throwable arg0) {
//
System.out.println(“Connection to the micro broker lost”);
}

public void deliveryComplete(MqttDeliveryToken arg0) {
//
}

public void deliveryFailed(MqttDeliveryToken arg0, MqttException arg1) {
//
}

public void messageArrived(MqttDestination destination, MqttMessage message) throws Exception {
System.out.println(“Message has arrived over MQTT.”);
String sourceTopic = destination.getName();
// In MQTT v5 we have different payload types.
if (message.getPayloadType() == MqttMessage.PAYLOAD_TEXT) {
String payload = message.getStringPayload();
System.out.println(“Message payload: “+payload);
} else {
// Enforce a “text only” policy.
System.err.println(“Message is not a text string.”);
}
}

public void start(String mqttUri, String name) throws MqttException {
mqttClient = new MqttClient(mqttUri, “Sub_Client”);
mqttClient.setCallback(this);
MqttConnectOptions options = new MqttConnectOptions();
// Wait until we’re ready to receive messages (overrides default)
options.setAutoStart(false);
// We don’t want our state cleaned up, we need to keep
// Durable subscriptions.
options.setPurge(false);
// Connect
mqttClient.connect(options);

MqttSubscriptionOptions subOpts = new MqttSubscriptionOptions();
subOpts.setDurable(true); // We want durable subscriptions
subOpts.setQos(2); // Once and once only delivery (same as V3 QoS).
mqttClient.subscribe(“acme/sample/”+name+”/”+TOPIC_SUFFIX_ALERTS+”/+”, subOpts);
mqttClient.subscribe(“acme/sample/”+name+”/”+TOPIC_SUFFIX_DATA+”/+”, subOpts);
// Ready to receive.
mqttClient.startListening();

System.out.println(“Connected to “+mqttUri);
}

public void stop() throws MqttException {
//
mqttClient.disconnect();
}

}

The following is the complimentary part of the sample that shows how to publish a message using the v5 client. This class is intended to be run as a simple command line utility.

import com.ibm.micro.client.MqttClient;
import com.ibm.micro.client.MqttException;
import com.ibm.micro.client.MqttMessage;
import com.ibm.micro.client.MqttTopic;

public class MqttPublisher {

public static void main(String[] args) {
try {
// Parameters: <uri> <clientid> <topic> <qos: 0,1 or 2> <string data>
MqttPublisher publisher = new MqttPublisher(args[0], args[1]);
publisher.publish(args[2], Integer.parseInt(args[3]), args[4]);
} catch (Exception ex) {
ex.printStackTrace();
}
}
private String uri = null;
private String clientId = null;
public MqttPublisher(String u, String c) {
uri = u;
clientId = c;
}

public void publish(String topic, int qos, String payload) throws MqttException {
MqttClient client = new MqttClient(“tcp://localhost:1883″, “Pub_Client”);
client.connect();
// Notice the new object model for destinations and messages
MqttTopic t = client.getTopic(topic);
// Create a string payload — v5 discriminates between payload types unlike v3.
MqttMessage message = new MqttMessage(payload);
message.setQos(qos);
t.publish(message);
client.disconnect();
}
}

Enjoy !

Posted in Snippets | Tagged: , , , , , , , , , , , | Leave a Comment »

Bridging to the WebSphere JMS provider from the micro broker

Posted by Martin on December 23, 2008

One of the key value propositions in the micro broker is its ability to connect the integration hub at the edge with an enterprise messaging server. The Bridge within the micro broker provides this capability in three flavours:

  • MQTT (v3) direct into another micro broker or Message Broker.
  • WebSphere MQ JMS – requires MQ JMS client to be packaged as a plug-in to Expeditor.
  • Third-party JMS providers using JNDI – requires the third-party JMS client to be packaged as a plug-in within Lotus Expeditor.

The third flavour above is what we use to connect the micro broker to the WebSphere JMS provider found in WAS, WESB and WPS.

image

This post describes how one configures the bridge to make use of the WebSphere JMS provider.

Note that Expeditor must be configured to use the Device Runtime Environment (DRE) J2SE JDK since the WebSphere JMS client requires a full J2SE runtime to work properly.

Creating the WebSphere JMS administered objects for JNDI programmatically

For the JNDI flavour of the bridge, a JMS Connection Factory and the target JMS Destinations must be made available using a JNDI provider. The Bridge is then configured with the appropriate JNDI keys to the administered objects. At runtime the objects are retrieved from JNDI by the Bridge using the keys provided. The JMS flavours of the micro broker both also require a “sync-queue” in order to honour once-only persistent qualities of service.

There are two approaches to creating the JMS administered objects. One is to use the WebSphere JNDI provider (JNDI over IIOP). To make use of this capability one needs to package the WebSphere JNDI client as an Expeditor plug-in. This is a good approach when Expeditor will be in close and reliable networked proximity to the WebSphere server since the creation of the JMS administered objects can be done automatically with the Messaging Destinations in WebSphere. Similarly use of a remote JNDI repository fits the JEE administrative model in that the objects can be managed independently of the application. In scenarios where the network may be unreliable (or indeed only available at certain times), an alternative approach is to create the administered objects programmatically and bind them into the built-in JNDI provider within Lotus Expeditor. This means even without a network at start-up time, the bridge can at least start, even if it cannot successfully connect straight away.

Packaging the WebSphere JMS client in Expeditor

To do this, we need to make the WebSphere JMS client available to the Lotus Expeditor runtime in the form of an Expeditor Feature.

A reduced footprint variant of the client is available as a feature pack for WAS. In order for these classes to be found by the Expeditor runtime, you will need to create a plugin in Eclipse containing the WebSphere JMS client JAR files, exporting all the interfaces (apart from javax.jms) contained in the JAR in the MANIFEST.MF for the plug-in.

There are a couple of very important points to note:

  1. You will need to make sure that the javax.jms package is NOT exported and any classes in this package are removed from the underlying JAR file. Expeditor has its own version of the JMS interfaces already exported in the platform and two plugins exporting the same interfaces cause JVM errors at runtime.
  2. Note that when you package your JMS client, the feature.xml file referencing the plug-in should have the unpack attribute set to true for the plugin containing the JMS client. In order for the interfaces contained within the underlying WebSphere JMS client JAR to be exported correctly when deployed, the JAR cannot be nested inside the plugin JAR. This is due to a limitation of how the OSGi class loader mechanism works.

Creating the administered objects

The following snippet shows how the WebSphere JMS administered objects are created and bound into the Expeditor JNDI repository.

public static final String JNDI_NAME_SIB_CONNECTION_FACTORY = "jms/SIBConnectionFactory";
public static final String JNDI_NAME_SIB_OUTBOUND_QUEUE = "jms/SIBOutQueue";
public static final String JNDI_NAME_SIB_INBOUND_QUEUE = "jms/SIBInQueue";
public static final String JNDI_NAME_SIB_SYNC_QUEUE = "jms/SIBSyncQueue";
public static final String JNDI_NAME_SIB_DEAD_LETTER_QUEUE = "jms/SIBDeadLetterQueue";

...

/**
 * Use the WebSphere JMS provider's Factory APIs to create the necessary objects
 * and bind them in JNDI.
 */
private void createAndBindSibJMSObjects() {
	try {
		// Create the ConnectionFactory
		com.ibm.websphere.sib.api.jms.JmsFactoryFactory jff = com.ibm.websphere.sib.api.jms.JmsFactoryFactory.getInstance();
		com.ibm.websphere.sib.api.jms.JmsConnectionFactory cf = jff.createConnectionFactory();

		cf.setBusName("SCA.APPLICATION.domino8Node01Cell.Bus");
		cf.setProviderEndpoints("localhost:7276:BootstrapBasicMessaging");

		// Create the request queue (messages on the outbound topic will be forwarded here)
		JmsQueue inQueue = com.ibm.websphere.sib.api.jms.JmsFactoryFactory.getInstance().createQueue(
					"PDARemoteSales.MQTT_JSONoverJMS_Export_RECEIVE_D_SIB");
		// Messages expiry after 3 minutes if not consumed.
		inQueue.setTimeToLive((long)180000);

		JmsQueue outQueue = com.ibm.websphere.sib.api.jms.JmsFactoryFactory.getInstance().createQueue(
		"PDARemoteSales.MQTT_JSONoverJMS_Export_SEND_D_SIB");
		// Messages expiry after 3 minutes if not consumed.
		outQueue.setTimeToLive((long)180000);

		JmsQueue deadLetterQueue = com.ibm.websphere.sib.api.jms.JmsFactoryFactory.getInstance().createQueue(
		"PDARemoteSales.Microbroker.DeadLetter");
		// Messages expiry after 3 minutes if not consumed.
		deadLetterQueue.setTimeToLive((long)180000);
		JmsQueue syncQueue = com.ibm.websphere.sib.api.jms.JmsFactoryFactory.getInstance().createQueue(
				"PDARemoteSales.Microbroker.SyncQueue");
		// Messages expiry after 3 minutes if not consumed.
		syncQueue.setTimeToLive((long)180000);

		try {
			InitialContext ctx = new InitialContext();
			ctx.bind(JNDI_NAME_SIB_CONNECTION_FACTORY, cf);
			ctx.bind(JNDI_NAME_SIB_INBOUND_QUEUE, inQueue);
			ctx.bind(JNDI_NAME_SIB_OUTBOUND_QUEUE, outQueue);
			ctx.bind(JNDI_NAME_SIB_SYNC_QUEUE, syncQueue);
			ctx.bind(JNDI_NAME_SIB_DEAD_LETTER_QUEUE, deadLetterQueue);

			System.out.println("All JMS SIB objects bound");
		} catch (NamingException ex) {
			System.err.println("Failed to bind JMS instances.");
			ex.printStackTrace();
		}

	} catch (JMSException e) {
		System.err.println("Failed to create JMS instances");
		e.printStackTrace();
	}

}

The first portion of the code uses the WebSphere JMS client’s Factory classes to instantiate the JMS administered objects with the latter portion binding them into Expeditor’s JNDI provider (note the Expeditor InitialContext will be used by default within an Expeditor environment).

Configuring the micro broker Bridge

The following snippet shows how the Bridge is configured using the micro broker’s administrative API. In this scenario we are bridging into WPS sending messages from a topic in the micro broker into a queue in WPS and from a queue in WPS back to a topic in the micro broker. By this point we have looked up a LocalBroker instance from the micro broker BrokerFactory service.

// Obtain a handle to the broker's bridge
Bridge bridge = broker.getBridge();

// Create a pipe definition -- this is the root of all bridge links
PipeDefinition pipe = bridge.createPipeDefinition("sibPipe");

JNDIConnectionDefinition connectionDefinition = bridge.createJNDIConnectionDefinition(pipe.getName()+"_Connection");
// Set the Initial Context to be used by the bridge to retrieve the administered objects
connectionDefinition.setInitialContext("com.ibm.pvc.jndi.provider.java.InitialContextFactory"); // uses the parameterised initial context factory i.e. XPD
connectionDefinition.setConnectionFactoryKey(JNDI_NAME_SIB_CONNECTION_FACTORY);
connectionDefinition.setDeadLetterKey(JNDI_NAME_SIB_DEAD_LETTER_QUEUE);
connectionDefinition.setSyncQKey(JNDI_NAME_SIB_SYNC_QUEUE);
connectionDefinition.setURL("none"); // Not meaningful for Expeditor JNDI but *is* still required to be set.

pipe.setConnection(connectionDefinition);

// Create an outbound flow that reads from a topic called "localoutbound" and
// puts to the remote queue.
FlowDefinition outbound = bridge.createFlowDefinition("outboundFlow");
// Set the source to be a single topic, "localoutbound"
outbound.setSources(new DestinationDefinition[] { bridge.createTopicDefinition("localoutbound")});
// Set the destination to be a queue on the remote WPS, using the reference bound in JNDI
outbound.setTarget(bridge.createJNDIDefinition(JNDI_NAME_SIB_INBOUND_QUEUE));
// Add the flow to the pipe
pipe.addOutboundFlow(outbound);

// Create an inbound flow that reads from a remote queue called "outbound" and
// puts to a topic called "localinbound"
FlowDefinition inbound = bridge.createFlowDefinition("inboundFlow");
// Set the source to be a queue on the remote WPS, using the reference bound in JNDI
inbound.setSources(new DestinationDefinition[] { bridge.createJNDIDefinition(JNDI_NAME_SIB_OUTBOUND_QUEUE)});
// Set the destination to be a topic called "localinbound" on the local broker
inbound.setTarget(bridge.createTopicDefinition("localinbound"));

// Add the flow to the pipe
pipe.addInboundFlow(inbound);

// Pipe is configured, add it to the bridge
bridge.addPipe(pipe);
// Start the pipe
bridge.startAllPipes();

The pipe is now ready for use.

Posted in Snippets | Tagged: , , , , , , , , , , , , , | 2 Comments »