Bridging to the WebSphere JMS provider from the micro broker

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.

Advertisements

2 responses to “Bridging to the WebSphere JMS provider from the micro broker

  1. Venu Madhav Pattamatta

    Hi,

    I have created a custom MicroBroker Plugin and exported it as a Feature Project from RAD 7.5. I would like to deploy the plugin using provisioning i.e., to load and start MicroBroker automatically when Expeditor client platform starts. I have tried using install.xml in deploy directory of rcp.home but it doesn’t work. Could you suggest a better way to load and auto start my custom microbroker plugin during expeditor startup.

    Thanks and Regards,
    Venu pattamatta

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s