Appendix 1 : Code for JNDI Web Service implementation
Listing 1 MQData class implementation

package article.examples;

import java.io.Serializable;

public class MQData implements Serializable
{
private String queueName;
private String queueMgrName;
private String factoryQmgrName;
private int bindingtype;
private String channel;
private String ldappath;
private String connection;

public MQData()
{
queueMgrName = null;
queueName = null;
factoryQmgrName = null;
channel = null;
ldappath = null;
connection = null;

//Default is binding
// client is 1
bindingtype = 0;
}

public String getQueueMgrName()
{
return queueMgrName;
}

public String getQueueName()
{
return queueName;
}

public void setQueueMgrName(String queueMgrName)
{
this.queueMgrName = queueMgrName;
}

public void setQueueName(String queueName)
{
this.queueName = queueName;
}

public String getFactoryQmgrName()
{
return factoryQmgrName;
}

public void setFactoryQmgrName(String thefactoryqmgrName)
{
factoryQmgrName = thefactoryqmgrName;
}


public int getBindingtype() {
return bindingtype;
}


public String getChannel() {
return channel;
}


public void setBindingtype(int bindingtype) {
this.bindingtype = bindingtype;
}


public void setChannel(String channel) {
this.channel = channel;
}

/**
* Returns the ldappath.
* @return String
*/
public String getLdappath() {
return ldappath;
}

/**
* Sets the ldappath.
* @param ldappath The ldappath to set
*/
public void setLdappath(String ldappath) {
this.ldappath = ldappath;
}

/**
* Returns the connection.
* @return String
*/
public String getConnection() {
return connection;
}

/**
* Sets the connection.
* @param connection The connection to set
*/
public void setConnection(String connection) {
this.connection = connection;
}
}

Listing 2 JNDILookUpUtils class implementation

package article.examples;

/**
* @author Didier Le Tien
*
* This class includes all the method needed to format the incoming request
* into an JNDILookUp compliant format
*
*/

import java.io.IOException;
import java.util.Hashtable;
import java.util.Properties;
import java.util.Vector;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.naming.directory.InitialDirContext;
import javax.naming.spi.InitialContextFactory;

import com.ibm.jvm.io.FileInputStream;
import com.ibm.mq.jms.*;

public class JNDILookUpUtils {

public static MQData getQueue(String ldapq, String icf, String url)
throws NamingException
{
Hashtable env = new Hashtable();

env.put(Context.INITIAL_CONTEXT_FACTORY, icf);
env.put(Context.PROVIDER_URL, url);
InitialDirContext ctx = new InitialDirContext(env);

MQData queueinfo = new MQData();


MQQueue queueref = (MQQueue)ctx.lookup(ldapq);

queueinfo.setQueueName(queueref.getBaseQueueName());
queueinfo.setQueueMgrName(queueref.getBaseQueueManagerName());
queueinfo.setFactoryQmgrName(null);
queueinfo.setConnection(null);

return queueinfo;
}

public static MQData getQueueMgr(String qcf, String icf, String url)
throws NamingException
{

Hashtable env = new Hashtable();


env.put(Context.INITIAL_CONTEXT_FACTORY, icf);
env.put(Context.PROVIDER_URL, url);
InitialDirContext ctx = new InitialDirContext(env);

MQData qmgrinfo = new MQData();

MQQueueConnectionFactory factory =
(MQQueueConnectionFactory)ctx.lookup(qcf);

qmgrinfo.setFactoryQmgrName(factory.getQueueManager());
qmgrinfo.setQueueName(null);
qmgrinfo.setQueueMgrName(null);

qmgrinfo.setBindingtype(factory.getTransportType());

// If we have a client connection)
if (qmgrinfo.getBindingtype() == 1){
String temphost = factory.getHostName();
Integer port = new Integer (factory.getPort());

qmgrinfo.setConnection(temphost + "(" + port.toString() + ")");
qmgrinfo.setChannel(factory.getChannel());
}
return qmgrinfo;
}
}

Listing 3 ServiceQueueString class implementation

package article.examples;

import java.util.*;

/**
* @author Boris Lublinsky
*
* Modified by Didier Le Tien to handle consumer side
* and Queue Manager information
*/



public class ServiceQueueString {

// Method used for converting service name to queue name

public static String generateQueueString(String ServiceName, String cf, int mode){

String postpath = "/Queue";
String consumerprepath = "/Consumers/";
String managerpostpath = "/queueManager";
String producerprepath = "/Producers/";
StringBuffer fn = null;

// mode = 0 Service request
// mode = 1 Consumer request
// mode = 2 Consumer queue manager
// mode = 3 Service queue manager
switch (mode) {
case 0 :
fn = new
StringBuffer().append(producerprepath).append(ServiceName).append(postpath);
break;
case 1 :
fn = new StringBuffer().append(consumerprepath)
.append(ServiceName).append(postpath);
break;
case 2 :
fn = new StringBuffer().append(consumerprepath)
.append(ServiceName).append(managerpostpath);
break;
case 3 :
fn = new StringBuffer().append(producerprepath)
.append(ServiceName).append(managerpostpath);
break;
}

// The format of returned String depends on the JNDILookUp used

// Websphere JNDILookUp

if(cf.equalsIgnoreCase("com.ibm.websphere.naming.WsnInitialContextFactory")){
return fn.toString();
}

// File based JNDILookUp
if(cf.equalsIgnoreCase("com.sun.jndi.fscontext.RefFSContextFactory")){
StringTokenizer st = new StringTokenizer(fn.toString(),"/");
StringBuffer fs = new StringBuffer();
boolean delim = false;
while (st.hasMoreTokens()){
if(delim)
fs.append("\\\\");
else
delim = true;
fs.append(st.nextToken());
}
return fs.toString();
}

// LDAP based JNDILookUp

if(cf.equalsIgnoreCase("com.sun.jndi.ldap.LdapCtxFactory")){
StringTokenizer st = new StringTokenizer(fn.toString(),"/");
Vector tn = new Vector();
while (st.hasMoreTokens())
tn.add(st.nextToken());
StringBuffer fs = new StringBuffer();
boolean delim = false;
for(int i = tn.size(); i > 0; i --){
if(delim)
fs.append(",");
else
delim = true;
fs.append("cn = ").append((String)tn.elementAt(i-1));
}
return fs.toString();
}
return null;
}
}

Listing 4 JNDIBean class implementation

package article.examples;

/**
* Bean implementation class for Enterprise Bean: JNDI
*/
import javax.naming.NamingException;
import javax.naming.directory.InitialDirContext;

/**
* Bean implementation class for Enterprise Bean: JNDI
*/
public class JNDIBean implements javax.ejb.SessionBean {
private javax.ejb.SessionContext mySessionCtx;
private String icf;
private String url;

/**
* getSessionContext
*/
public javax.ejb.SessionContext getSessionContext() {
return mySessionCtx;
}
/**
* setSessionContext
*/
public void setSessionContext(javax.ejb.SessionContext ctx) {
mySessionCtx = ctx;
}
/**
* ejbCreate
*/
public void ejbCreate() throws javax.ejb.CreateException {
getProperties();
}
/**
* ejbActivate
*/
public void ejbActivate() {
}
/**
* ejbPassivate
*/
public void ejbPassivate() {
}
/**
* ejbRemove
*/
public void ejbRemove() {
}

/**
* Returns the icf.
* @return String
*/
public String getIcf() {
return icf;
}

/**
* Returns the url.
* @return String
*/
public String getUrl() {
return url;
}

// Retrieve the properties to initiate the JNDI connection
public void getProperties (){

String lookupicf = "icf";
String lookupurl = "url";

try {
InitialDirContext wsctx = new InitialDirContext();

// Lookup the object into the ejb-jar.xml file
icf = (String)wsctx.lookup("java:comp/env/" +lookupicf);
url = (String)wsctx.lookup("java:comp/env/" +lookupurl);

System.out.println(icf + " " + url);
}
catch (NamingException namEx) {
System.out.println(namEx.getMessage());
}
}

// Main method to achieve lookup for the Queue
private MQData lookupQ (String ldapq, String icf, String url)
throws NamingException
{
MQData reqinfo = new MQData();

// LookUp a service input queue
reqinfo = JNDILookUpUtils.getQueue(ldapq, icf,url);

return reqinfo;
}

// Method to retrieve the Service
public MQData ServiceLookUp (String destination) {
MQData reqinfo = new MQData();

try {
MQData temp;

//Format the entry
String ldapname =
ServiceQueueString.generateQueueString(destination,getIcf(), 0);
reqinfo = lookupQ(ldapname, getIcf(), getUrl());
reqinfo.setLdappath(ldapname);

ldapname =
ServiceQueueString.generateQueueString(destination,getIcf(),
3);

// Populate the queue manager field
temp = JNDILookUpUtils.getQueueMgr(ldapname, getIcf(), getUrl());

if(temp.getBindingtype() == 0) {
reqinfo.setBindingtype(0);
reqinfo.setFactoryQmgrName(temp.getFactoryQmgrName());
}
else {
reqinfo.setChannel(temp.getChannel());
reqinfo.setConnection(temp.getConnection());
reqinfo.setBindingtype(1);
reqinfo.setFactoryQmgrName(temp.getFactoryQmgrName());
}
}
catch (NamingException namex) {
System.out.println(namex.getMessage());
return null;
}

return reqinfo;
}

// Method to retrieve the Service
public MQData ConsumerLookUp (String destination) {
MQData reqinfo = new MQData();

try {
MQData temp;

//Format the entry
String ldapname =
ServiceQueueString.generateQueueString(destination,getIcf(), 1);

System.out.println(ldapname);

ldapname =
ServiceQueueString.generateQueueString(destination,getIcf(),
2);

reqinfo = lookupQ(ldapname, getIcf(), getUrl());
reqinfo.setLdappath(ldapname);

// Populate the queue manager field
temp = JNDILookUpUtils.getQueueMgr(ldapname, getIcf(), getUrl());

if(temp.getBindingtype() == 0) {
reqinfo.setBindingtype(0);
reqinfo.setFactoryQmgrName(temp.getFactoryQmgrName());
}
else {
reqinfo.setChannel(temp.getChannel());
reqinfo.setConnection(temp.getConnection());
reqinfo.setBindingtype(1);
reqinfo.setFactoryQmgrName(temp.getFactoryQmgrName());
}
}
catch (NamingException namex) {
System.out.println(namex.getMessage());
return null;
}

return reqinfo;
}
}

Listing 5 JNDI Service Configuration class

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE ejb-jar PUBLIC "-//Sun Microsystems, Inc.

//DTD Enterprise JavaBeans 2.0//EN" "http://java.sun.com/dtd/ejb-jar_2_0.dtd">
<ejb-jar id="ejb-jar_ID">
<display-name>WSArticle</display-name>
<enterprise-beans>
<session id="JNDILookUp">
<ejb-name>JNDILookUp</ejb-name>
<home>article.webservice.JNDILookUpHome</home>
<remote>article.webservice.JNDILookUp</remote>
<ejb-class>article.webservice.JNDILookUpBean</ejb-class>
<session-type>Stateless</session-type>
<transaction-type>Bean</transaction-type>

<!-- Setup the properties for the icf and the url to use -->
<env-entry>
<env-entry-name>icf</env-entry-name>
<env-entry-type>java.lang.String</env-entry-type>
<env-entry-value>com.sun.jndi.ldap.LdapCtxFactory</env-entry-value>
</env-entry>
<env-entry>
<env-entry-name>url</env-entry-name>
<env-entry-type>java.lang.String</env-entry-type>
<env-entry-value>
ldap://sch1h008.cna.com/o=cna,cn=localhost</env-entry-value>
</env-entry>
</session>
</enterprise-beans>
</ejb-jar>

Listing 6 MQData.xsd

<?xml version="1.0" encoding="UTF-8"?>
<schema attributeFormDefault="qualified"
elementFormDefault="unqualified"
targetNamespace="http://webservice.article/"
xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:xsd1="http://webservice.article/">
<complexType name="MQData">
<all>
<element name="connection" nillable="true" type="string"/>
<element name="ldappath" nillable="true" type="string"/>
<element name="factoryQmgrName" nillable="true" type="string"/>
<element name="queueMgrName" nillable="true" type="string"/>
<element name="channel" nillable="true" type="string"/>
<element name="queueName" nillable="true" type="string"/>
<element name="bindingtype" type="int"/>
</all>
</complexType>
</schema>

Listing 7 JNDILookUpService.wsdl

<?xml version="1.0" encoding="UTF-8"?>
<definitions name="JNDILookUpService"
targetNamespace="http://webservice.article.wsdl/JNDILookUpService/"
xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:binding="http://webservice.article.wsdl/JNDILookUpBinding/"
xmlns:soap=http://schemas.xmlsoap.org/wsdl/soap/
xmlns:tns="http://webservice.article.wsdl/JNDILookUpService/">
<import location="JNDILookUpBinding.wsdl"
namespace="http://webservice.article.wsdl/JNDILookUpBinding/"/>
<service name="JNDILookUpService">
<port binding="binding:JNDILookUpBinding" name="JNDILookUpPort">
<soap:address location="http://localhost:9080/ArticleWeb/servlet/rpcrouter"/>
</port>
</service>
</definitions>

Listing 8 JNDILookUpBinding.wsdl

<?xml version="1.0" encoding="UTF-8"?>
<definitions name="JNDILookUpBinding"
targetNamespace="http://webservice.article.wsdl/JNDILookUpBinding/"
xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:interface="http://webservice.article.wsdl/JNDILookUp/"
xmlns:soap=http://schemas.xmlsoap.org/wsdl/soap/
xmlns:tns="http://webservice.article.wsdl/JNDILookUpBinding/"/>
<import location="JNDILookUp.wsdl"
namespace="http://webservice.article.wsdl/JNDILookUp/">
<binding name="JNDILookUpBinding" type="interface:JNDILookUp">
<soap:binding style="rpc"
transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="ServiceLookUp">
<soap:operation soapAction="" style="rpc"/>
<input name="ServiceLookUpRequest">
<soap:body
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="http://tempuri.org/article.webservice.JNDILookUp"
parts="destination" use="encoded"/>
</input>
<output name="ServiceLookUpResponse">
<soap:body
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="http://tempuri.org/article.webservice.JNDILookUp"
use="encoded"/>
</output>
</operation>
<operation name="ConsumerLookUp">
<soap:operation soapAction="" style="rpc"/>
<input name="ConsumerLookUpRequest">
<soap:body
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="http://tempuri.org/article.webservice.JNDILookUp"
parts="destination" use="encoded"/>
</input>
<output name="ConsumerLookUpResponse">
<soap:body
encodingStyle="http://schemas.xmlsoap.org/soap/encoding/"
namespace="http://tempuri.org/article.webservice.JNDILookUp"
use="encoded"/>
</output>
</operation>
</binding>
</definitions>

Listing 9 JNDILookUp.wsdl

<?xml version="1.0" encoding="UTF-8"?>
<definitions name="JNDILookUp"
targetNamespace="http://webservice.article.wsdl/JNDILookUp/"
xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:tns="http://webservice.article.wsdl/JNDILookUp/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsd1="http://webservice.article/">
<import location="MQData.xsd" namespace="http://webservice.article/"/>
<message name="ServiceLookUpRequest">
<part name="destination" type="xsd:string"/>
</message>
<message name="ServiceLookUpResponse">
<part name="result" type="xsd1:MQData"/>
</message>
<message name="ConsumerLookUpRequest">
<part name="destination" type="xsd:string"/>
</message>
<message name="ConsumerLookUpResponse">
<part name="result" type="xsd1:MQData"/>
</message>
<portType name="JNDILookUp">
<operation name="ServiceLookUp" parameterOrder="destination">
<input message="tns:ServiceLookUpRequest" name="ServiceLookUpRequest"/>
<output message="tns:ServiceLookUpResponse" name="ServiceLookUpResponse"/>
</operation>
<operation name="ConsumerLookUp" parameterOrder="destination">
<input message="tns:ConsumerLookUpRequest" name="ConsumerLookUpRequest"/>
<output message="tns:ConsumerLookUpResponse" name="ConsumerLookUpResponse"/>
</operation>
</portType>
</definitions>

Appendix 2 : Code for the .Net client implementation.
Listing 10 JNDIProxy class implementation

Using System;
using Application.JNDILookUpService;

namespace test
{
/// <summary>
/// The JNDI Proxy class is provide functionalities to retrieve information from
/// the LDAP directory. Result are cached in order to optimize performances.
/// In order to use the object a URL and a InitialConextFactory have to be specified
/// (LDAP is the default)
/// </summary>
public class JNDIProxy
{
private static JNDICache cache;
private static Application.JNDILookUpService.JNDILookUpService lookup;
private static string consumername;

// JNDIProxy Constructor
public JNDIProxy()
{
if (cache == null)
cache = new JNDICache();

if (lookup == null)
lookup = new Application.JNDILookUpService.JNDILookUpService();

// Setting the JNDI URL from the configuration file
lookup.Url = CfConfigurationSettings.getLookupURL();
consumername = CfConfigurationSettings.getConsumerName();
}

// Retrieve the queue for the service information
public ObjectInformation CfServiceLookUp(string servicename)
{
ObjectInformation qinf;

qinf = cache.CheckEntry(servicename);

// if no entry is found in the cache then do a lookup
if (qinf == null)
{
try
{
qinf = new ObjectInformation();
qinf.SetMQData(lookup.ServiceLookUp(servicename));
}
catch (System.Net.WebException webEx)
{
// Throw the exception back to the caller
throw new LookUpRepositoryConnectionFailedException("Cannot connect
to the repository", webEx) ;
}

if (qinf != null)
cache.PutEntry(servicename,qinf);
else
return null;
}

return qinf;
}

// Retrieve the queue for the consumer information
public ObjectInformation CfConsumerLookUp(string consumerentry)
{
ObjectInformation qinf;

qinf = cache.CheckEntry(consumerentry);

// if no entry is found in the cache then do a lookup
if (qinf == null)
{
try
{
qinf = new ObjectInformation();
qinf.SetMQData(lookup.ConsumerLookUp(consumerentry));
}
catch (System.Net.WebException webEx)
{
// Throw the exception back to the caller
throw new LookUpRepositoryConnectionFailedException("Cannot connect
to the repository", webEx) ;
}

if (qinf != null)
cache.PutEntry(consumerentry,qinf);
else
return null;
}

return qinf;
}

}
}

Listing 11 JNDICache class implementation

using System;
using System.Collections;

namespace test
{
/// <summary>
/// The JNDICache object maintain the references of the previous service invocation
/// Each time a lookup is requested, the JNDIProxy object first checked if a Service
/// entry hasn't been already registered in the cache
///
/// As applications are dealing with alias queues only, they should not be affected
/// by any changes at the physical queue level; therefore they is no need to refresh
the
/// information stored in the hashtable
/// </summary>
public class JNDICache
{
private static Hashtable jndientries;

public JNDICache()
{
if (jndientries == null)
jndientries = new Hashtable();
}

public ObjectInformation CheckEntry(string ldapentry)
{
ObjectInformation data;

// check if the entry already exist
if (jndientries.ContainsKey(ldapentry))
{
data = (ObjectInformation)jndientries[ldapentry];

// If the object is older than 3 hours then refresh it
if ((DateTime.Now.Hour - data.GetAge().Hour) > 3)
{
//Remove the object from the Hashtable
jndientries.Remove(ldapentry);
return null;
}
}
else
data = null;

return data;
}

public void PutEntry(string ldapentry, ObjectInformation data) 
{
try
{
// Lock the hashtable during the writing operation
lock(jndientries.SyncRoot)
{
// Setup the date for future update
data.SetAge(DateTime.Now);

jndientries.Add(ldapentry, data);
}
}
catch (ArgumentException argEx)
{
// Throw the exception back to the caller
throw argEx;
}
}
}
}

Listing 12 RFH2 header class

using System;
using System.Text;
using System.Collections;

namespace com.cna.util.jms
{
/// <summary>
/// This class implements RFH2 header of the JMSMessage,
/// supporting all the functionality,
/// required for storage, parsing and stringifying the header.
/// </summary>
public class RFH2
{
// Fields, defined in RFH2 header

public int version = 0;
public int rfhlen = 0;
public int encoding = 0;
public int charSet = 0;
public string format = null;
public int flags = 0;
public int valueCCID = 0;
public string type = null;
public Hashtable jmsProperties = null;
public Hashtable customProperties = null;

// Constructing new RFH2 header. By default populate all
// of the required fields
public RFH2()
{
version = 2;
rfhlen = 36;
encoding = 273;
charSet = 1208;
format = "MQSTR ";
flags = 0;
valueCCID = 1208;
type = "text";
jmsProperties = null;
customProperties = null;
}

// Static helper method, converting 4
// consecutive bytes to integer

public static int bytesToInt(byte[]bytes, int sindex)
{
int val = bytes[sindex + 3] + ((bytes[sindex + 2] +
(bytes[sindex + 1] + bytes[sindex] << 4) << 4) << 4);
return val;
}

// Static helper method, converting integer to 4
// consecutive bytes

public static void intToBytes(int val, byte[]bytes,
int sindex){
bytes[sindex + 3] = Convert.ToByte(val & 0xff);
val = val / 256;
bytes[sindex + 2] = Convert.ToByte(val & 0xff);
val = val / 256;
bytes[sindex + 1] = Convert.ToByte(val & 0xff);
val = val / 256;
bytes[sindex] = Convert.ToByte(val & 0xff);
}

// Helper method, adjusting the length of the RFH2
// folder. Every folder inside RFH2 has
// to have a length, dividable by 4

private int folderLength(ref string folder)
{
int fLen = folder.Length;
int rem = fLen & 0x3;
if(rem != 0)
{
int pad = 4-rem;
for(int i = 0;i < pad;i++)
folder += " ";
fLen += pad;
}
return fLen;
}

// Given payload, build the complete message,
// including current RFH2

public byte[] toByte(string payload)
{
int payloadLen = 0;
rfhlen = 36; // Standard length of the RFH2 header
if(payload != null)
payloadLen = payload.Length;
int blen = payloadLen;

// Build MCD Folder. MCD folder is always present
string mcdFolder = "<mcd><Msd>" + "jms_" +
type + "</Msd></mcd>";
int mcdLen = folderLength(ref mcdFolder);
rfhlen += (mcdLen + 4);

// Build JMS Folder
string jmsFolder = null;
int jmsLen = 0;

// But only if required
if(jmsProperties != null)
{
jmsFolder = "<jms>";
IDictionaryEnumerator enumerator =
jmsProperties.GetEnumerator();
while ( enumerator.MoveNext() )
jmsFolder += "<" + enumerator.Key + ">" +
enumerator.Value +"</" + enumerator.Key + ">";
jmsFolder += "</jms>";
jmsLen = folderLength(ref jmsFolder);
rfhlen += (jmsLen + 4);
}

// Build USR Folder
string usrFolder = null;
int usrLen = 0;

// But only if required
if(customProperties != null)
{
usrFolder = "<usr>";
IDictionaryEnumerator enumerator =
customProperties.GetEnumerator();
while ( enumerator.MoveNext() )
usrFolder += "<" + enumerator.Key + ">" +
enumerator.Value +"</" + enumerator.Key + ">";
usrFolder += "</usr>";
usrLen = folderLength(ref usrFolder);
rfhlen += (usrLen + 4);
}
blen += rfhlen;
byte[] bytes = new byte[blen];

// Stringify RFH2 header
Encoding.UTF8.GetBytes("RFH ",0,4,bytes,0);
intToBytes(version,bytes,4);
intToBytes(rfhlen,bytes,8);
intToBytes(encoding,bytes,12);
intToBytes(charSet,bytes,16);
int flen = format.Length;
while(flen < 8)
format += " ";
Encoding.UTF8.GetBytes(format,0,8,bytes,20);
intToBytes(flags,bytes,28);
intToBytes(valueCCID,bytes,32);

// Stringify MCD folder
int sf = 36;
intToBytes(mcdLen,bytes,sf);
sf += 4;
Encoding.UTF8.GetBytes(mcdFolder,0,mcdLen,bytes,sf);
sf += mcdLen;

// Stringify JMS folder
if(jmsLen > 0)
{
intToBytes(jmsLen,bytes,sf);
sf += 4;
Encoding.UTF8.GetBytes(jmsFolder,0,
jmsLen,bytes,sf);
sf += jmsLen;
}

// Stringify USR folder
if(usrLen > 0)
{
intToBytes(usrLen,bytes,sf);
sf += 4;
Encoding.UTF8.GetBytes(usrFolder,0,
usrLen,bytes,sf);
}

// Stringify Payload
if(payloadLen > 0)
Encoding.UTF8.GetBytes(payload,0,payloadLen,
bytes,rfhlen);
return bytes;
}
}

}

Listing 13 Implementation of JMSMessage

using System;
using System.Text;
using System.Collections;
using IBM.WMQ;

namespace com.cna.util.jms
{
/// <summary>
/// This class wraps MQMessage class (provided by IBM)
/// to implement basic functionality of JMS Message.
/// Usage of this class simplifies interoperability with
/// MQ/JMS messaging by abstracting out usage of RFH2
/// header in IBMs implementation of JMS.
/// </summary>
public class JMSMessage:MQMessage
{

static private string[] hexv = {"0","1","2",
"3","4","5","6","7","8","9","a","b","c","d","e","f"};
RFH2 header = null;
string payload = null;
bool parsed = false;

// Constructor. Invokes the constructor of the base class
public JMSMessage():base()
{
CharacterSet = 437;
// UTF8 Encoding = 785;
}

// Getting message payload
public string getPayload()
{
if(!parsed)
parseMessage();
return payload;
}

// Setting message payload
public void setPayload(string data)
{
payload = data;
serialize();
}

// Setting custom property by name. Custom properties
// are placed in the USR folder of the RFH2. For now we
// are allowing only string properties
private void setProperty(string name, string val)
{

if(header == null)
header = new RFH2();
if(header.customProperties == null)
header.customProperties = new Hashtable();
try
{
header.customProperties.Add(name,val);
}
catch(ArgumentException e)
{
// This is necessary, because Microsoft
// implementation of the hashtable throws an
// exception in the case of duplicate key
header.customProperties.Remove(name);
header.customProperties.Add(name,val);
}
serialize();
}

// Getting custom property by name. Custom properties
// are placed in the USR folder of the RFH2. For now we
// are allowing only string properties
public string getProperty(string name)
{
if(!parsed)
parseMessage();
if((header == null) || (header.customProperties == null))
return null;
string prop = null;
try
{
prop =(string)header.customProperties[name];
}
catch(Exception e){}
return prop;
}

// Setting JMS correlation ID as string
public void setJMSCorrelationID(string id)
{
int idLength = id.Length;
byte[] bytes = new byte[24];
System.Text.Encoding.UTF8.GetBytes
(id,0,idLength,bytes,0);
CorrelationId = bytes;
setJMSProperty("Cid",id);
}

// This is a helper method, converting bytes to string
// as hexadecimal values. It is used for converting
// correlation ID and message ID
static public string bytesToHexString(byte[] bytes)
{
int blen = bytes.Length;
string sval = "";
for(int i = 0; i < blen; i++)
{
int val = Convert.ToInt32(bytes[i]);
int lower = val & 0xf;
int higher = val / 16;
sval += (hexv[higher] + hexv[lower]);
}
return sval;
}

// Setting JMS correlation ID as bytes
public void setJMSCorrelationID(byte[] bytes)
{
string id = "ID:" +
JMSMessage.bytesToHexString(bytes);
CorrelationId = bytes;
setJMSProperty("Cid",id);
}

// Getting JMS correlation ID as bytes
public byte[] getJMSCorrelationIDasBytes()
{
return CorrelationId;
}

// Getting JMS correlation ID as string
public string getJMSCorrelationIDasString()
{
string cid = null;
if(!parsed)
parseMessage();
if((header != null) && (header.jmsProperties != null))
{
try
{
cid =
(string)header.jmsProperties["Cid"];
}
catch(Exception e){};
}
if(cid == null)
cid = "ID:" +
JMSMessage.bytesToHexString(CorrelationId);
return cid;
}

// Getting Message ID as bytes
public byte[] getJMSMessageIDasBytes()
{
return MessageId;
}

// Getting Message ID as string
public string getJMSMessageIDasString()
{
return "ID:" +
JMSMessage.bytesToHexString(MessageId);
}

// Setting Message Delivery mode
public void setJMSDeliveryMode(int persistence)
{

// Make sure that it is a valid value.
// Defaulted to non persistent
if((persistence != MQC.MQPER_PERSISTENT) &&
(persistence != MQC.MQPER_PERSISTENCE_AS_Q_DEF))
persistence = MQC.MQPER_NOT_PERSISTENT;
Persistence = persistence;
setJMSProperty("Dlv",Convert.ToString(persistence));
}

// Getting Message Delivery mode
public int getJMSDeliveryMode()
{
if(!parsed)
parseMessage();
string exp = null;
if((header != null) && (header.jmsProperties != null))
{
try
{
exp =
(string)header.jmsProperties["Dlv"];
}
catch(Exception){}
}
if(exp != null)
return Convert.ToInt32(exp);
return Persistence;
}

// Setting Message Expiration
public void setJMSExpiration(int time)
{
setJMSProperty("Exp",Convert.ToString(time));
Expiry = time;
}

// Getting Message Expiration
public int getJMSExpiration()
{
return Expiry;
}

// Setting Message Reply To
public void setJMSReplyTo(MQQueue queue)
{
string qname = queue.Name.Trim();
int length = qname.Length;
char[] chars = qname.ToCharArray();
int es = 0;
for(; es < length; es++)
if(chars[es] == '\0')
break;
qname = new string(chars,0,es);
ReplyToQueueName = qname;
string qmname = ReplyToQueueManagerName.Trim();
length = qmname.Length;
chars = qmname.ToCharArray();
es = 0;
for(; es < length; es++)
if(chars[es] == '\0')
break;
qmname = new string(chars,0,es);
string jmsProp = "queue://" + qmname + "/" + qname;
setJMSProperty("Rto",jmsProp);
}

// Getting Message Reply To
public MQQueue getJMSReplyTo()
{
string qname = ReplyToQueueName;
return new
MQQueue(null,qname,MQC.MQOO_OUTPUT,null,null,null);
}

// Setting Message Reply To Queue Manager. This is
// MQ specific extension required for support of
// request reply in the clustered environment
public void setReplyToQM(string qmname)
{
string qname = ReplyToQueueName;
ReplyToQueueManagerName = qmname;
string jmsProp = "queue://" + qmname + "/" + qname;
setJMSProperty("Rto",jmsProp);
}

// Setting JMS property by name. JMS properties are placed
// in the JMS folder of the RFH2.
private void setJMSProperty(string name, string val)
{
if(header == null)
header = new RFH2();
if(header.jmsProperties == null)
header.jmsProperties = new Hashtable();
try
{
header.jmsProperties.Add(name,val);
}
catch(ArgumentException e)
{
// This is necessary, because Microsoft
// implementation of the hashtable throws
// an exception in the case of duplicate key
header.jmsProperties.Remove(name);
header.jmsProperties.Add(name,val);
}
serialize();
}

// Serializing JMS message to send it over MQ
private void serialize()
{
ClearMessage();
if(header != null)
{
Format = MQC.MQFMT_RF_HEADER_2;
// Format RFH2
byte[] bytes = header.toByte(payload);
WriteBytes(bytes);
}
else
{
Format = MQC.MQFMT_STRING;
// Format String
int plen = payload.Length;
byte[] bytes = new byte[plen];
System.Text.Encoding.UTF8.GetBytes
(payload,0,plen,bytes,0);
WriteBytes(bytes);
}
}

// Parse MQ message to populate JMS message
private void parseMessage()
{
if(parsed)
return;
byte[] inMessage = GetBuffer();
int message_len = inMessage.GetLength(0);
int message_start = 0;
string rfhh =
System.Text.Encoding.UTF8.GetString(inMessage,0,4);
if(rfhh.Equals("RFH "))
{
/* We have RFH header, process it */ 

header = new RFH2();
header.version = RFH2.bytesToInt(inMessage,4);
header.rfhlen = RFH2.bytesToInt(inMessage,8);
header.encoding =
RFH2.bytesToInt(inMessage,12);
header.charSet = RFH2.bytesToInt(inMessage,16);
header.format = System.Text.Encoding.UTF8.
GetString(inMessage,20,8);
header.flags = RFH2.bytesToInt(inMessage,28);
header.valueCCID =
RFH2.bytesToInt(inMessage,32);
header.type = null;
message_start = header.rfhlen;
message_len -= message_start;
string RFHfolders = System.Text.Encoding.UTF8.
GetString(inMessage,36,header.rfhlen-36);
string delimStr = "<>";
char [] delimiters = delimStr.ToCharArray();
string[] tokens =
RFHfolders.Split(delimiters,100);
int ntokens = tokens.GetLength(0);
for(int i = 0; i < ntokens; i++)
{
string tk = tokens[i].Trim();
if(tk.Equals("mcd"))
{
i = parseMCDfolder
(tokens,i+1,ntokens, header);
continue;
}
if(tk.Equals("jms"))
{
i = parseJMSfolder
(tokens,i+1,ntokens, header);
continue;
}
if(tk.Equals("usr"))
{
i = parseUSRfolder
(tokens,i+1,ntokens,header);
continue;
}
}
}
payload = System.Text.Encoding.UTF8.
GetString(inMessage, message_start, message_len);
parsed = true;
}

// Parsing content of the MCD folder
private int parseMCDfolder(string[] tokens,int sindex,
int findex, RFH2 header){

int cindex = sindex;
String type = "none";
for(bool done = false;(cindex < findex) && (!done);
cindex++){
string tk = tokens[cindex].Trim();
if(tk.Equals("/mcd"))
{
header.type = type;
return cindex;
}
if(tk.Equals("Msd"))
{
for(cindex++; cindex < findex; cindex++)
{
tk = tokens[cindex].Trim();
if(tk.Length <= 0)
continue;
if(tk.Equals("/mcd"))
{
header.type = type;
return cindex;
}
if(tk.Equals("/Msd"))
{
break;
}
if(tk.Equals("jms_none"))
{
type = "none";
done = true;
break;
}
if(tk.Equals("jms_text"))
{
type = "text";
done = true;
break;
}
if(tk.Equals("jms_bytes"))
{
type = "bytes";
done = true;
break;
}
if(tk.Equals("jms_map"))
{
type = "map";
done = true;
break;
}
if(tk.Equals("jms_stream"))
{
type = "stream";
done = true;
break;
}
if(tk.Equals("jms_object"))
{
type = "object";
done = true;
break;
}
}
}
}
header.type = type;
for(;cindex < findex;cindex++)
{
string tk = tokens[cindex].Trim();
if(tk.Equals("/mcd"))
{
break;
}
}
return cindex;
}
// Parsing content of the JMS folder
private int parseJMSfolder(string[] tokens,int sindex,
int findex, RFH2 header){

header.jmsProperties = new Hashtable();

int cindex = sindex;
string name = null;
string val = null;
for(;cindex < findex; cindex++)
{
string tk = tokens[cindex].Trim();
if(tk.Length <= 0)
continue;
if(tk.Equals("/jms"))
return cindex;
name = tk;
for(cindex++;cindex < findex;cindex ++)
{
tk = tokens[cindex].Trim();
if(tk.Length <= 0)
continue;
if(tk.Equals("/" + name))
{
if(val != null)
{
header.jmsProperties.Add(name,val);
}
name = null;
val = null;
break;
}
if(val == null)
val = tk;
}
}
return cindex;
}

// Parsing content of the USR folder
private int parseUSRfolder(string[] tokens,int sindex,
int findex,RFH2 header){

header.customProperties = new Hashtable();
int cindex = sindex;
string name = null;
string val = null;
for(;cindex < findex; cindex++)
{
string tk = tokens[cindex].Trim();
if(tk.Equals("/usr"))
return cindex;
if(tk.Length <= 0)
continue;
name = tk;
for(cindex++;cindex < findex;cindex ++)
{
tk = tokens[cindex].Trim();
if(tk.Length <= 0)
continue;
if(tk.Equals("/" + name))
{
if(val != null)
header.customProperties.Add(name,val);
name = null;
val = null;
break;
}
if(val == null)
val = tk;
}
}
return cindex;
}
}
}

Listing 14 RequestProcessor class

using System;

namespace com.cna.util.jms
{
/// <summary>
/// This class provides support for MQ-based communications.
/// Two currently supported communication models are:
/// - synchronous request/reply
/// - fire-and-forget messages
/// </summary>
public class RequestProcessor
{
private MessageSender sender = null;
private static bool initialized = false;
private static string qmname = null;
private static string channel = null;
private static string constr = null;
private static JNDIProxy locator = null;
private static ConfigurationParameters param = null;

// This is factory method, creating a new RequestProcessor
public static RequestProcessor getRequestProcessor
(string producer){
// Initialize, if necessary
if(!initialized)
startUp();
if(!initialized)
throw new Exception
("Initialization of RequestProcessor failed");

// Get producer queue. We are using JNDI Web Service
// for getting queue name based on the producer name
MQData mqdata;
try
{
mqdata = locator.ProducerLookUp(producer);
}
catch (Exception e)
{
Console.WriteLine
("Error communicating to Web Service " + e);
throw new Exception
("Cannot resolve consumer queue");
}
string pqname = mqdata.queueName;
return new RequestProcessor(pqname);
}

// This is a bootstrapping method for all of the code
private static void startUp()
{
// First get configuration parameters
if(param == null)
param =
ConfigurationParameters.getParameters();
if((param == null) || (param.wsURL == null) ||
(param.name == null))
{
param = null;
return;
}
if(param.recieverThreads <= 0)
param.recieverThreads = 5;

// Now get our MQ environment. We are using JNDI Web
// Service to get information about queue manager and
// reply queue to use, based on our name.
locator = new JNDIProxy(param.wsURL);
string qname = null;
try
{
MQData mqdata =
locator.ConsumerLookUp(param.name);
channel = mqdata.channel;
constr = mqdata.connection;
qmname = mqdata.factoryQmgrName;
qname = mqdata.queueName;
}
catch (Exception e){
Console.WriteLine
("Error communicating to Web Service " + e);
}

// Start Recievers
MessageReciever.startRecievers
(qmname,qname,channel,constr,param.recieverThreads);
if(MessageReciever.isRunning())
initialized = true;
return;
}

// Dissalow direct creation
private RequestProcessor(string qname)
{
sender =
new MessageSender(qmname,channel,constr,qname);
}

// This is request reply communications
public string requestReply(string message, int timeout)
{
if((sender != null) && sender.isInitialized())
return
sender.sendMessage(message,true,timeout);
throw new Exception
("Error initializing MQ environment");
}

// This is fire-and-forget communications
public void fireAndForget(string message)
{
if((sender != null) && sender.isInitialized())
{
sender.sendMessage(message,false,0);
return;
}
throw new Exception
("Error initializing MQ environment");
}
}
}

Listing 15 Sample configuration file

<?xml version="1.0" encoding="utf-8" ?>
<ConfigurationParameters>
<wsURL>http://vivendi:9080/JNDI/servlet/rpcrouter</wsURL>
<name>helloconsumer</name>
<recieverThreads>10</recieverThreads>
</ConfigurationParameters>

Listing 16 ConfigurationParameters class

using System;
using System.Xml.Serialization;
using System.Xml;
using System.IO;

namespace com.cna.util
{
/// <summary>
/// This class is a container for the configuration parameters.
/// </summary>
public class ConfigurationParameters
{
public string wsURL = null;
public string name = null;
public int recieverThreads = 0;

private static XmlSerializer serializer =
new XmlSerializer(typeof(ConfigurationParameters));
private static ConfigurationParameters myParameters = null;

// Singleton support
public static ConfigurationParameters getParameters()
{
if(myParameters == null)
{
string fileName =
AppDomain.CurrentDomain.BaseDirectory + "Config.config";
XmlTextReader reader =
new XmlTextReader(fileName);
myParameters = deserialize(reader);
}
return myParameters;
}

// Deserialize from XML
public static ConfigurationParameters deserialize
(XmlReader reader){
ConfigurationParameters cp =
(ConfigurationParameters)serializer.Deserialize(reader);
return cp;
}
}
}

Listing 17 MessageSender class

using System;
using IBM.WMQ;
using com.cna.util;

namespace com.cna.util.jms
{
/// <summary>
/// This class is responcible for sending an MQ message.
/// </summary>
public class MessageSender
{

private MQQueueManager qm = null;
private MQQueue outputq = null;
private MQPutMessageOptions pmo = null;
private bool initialized = false;

// Constructor. Initializes MQ environment, based on
// the queue manager's name, channel name, connection
// string and queue name. If a server binding is used,
// channel and connection string can be nulls. For
// client connection all parameters have to be specified.
public MessageSender(string qmname,string channel,
string constr,string qname)
{
try
{
// Attempt to connect to the MQ queue manager
qm = new MQQueueManager(qmname,channel,constr);
// Attempt to open the request input queue
outputq = qm.AccessQueue(qname, MQC.MQOO_OUTPUT);
// Set options for outgoinging messages
pmo = new MQPutMessageOptions();
pmo.Options =
pmo.Options | MQC.MQPMO_SYNCPOINT;
initialized = true;
}
catch(Exception e)
{
System.Console.WriteLine
("Exception Setting up MQ Environment" + e);
}
}
// Check, whether initialization was successful.
public bool isInitialized()
{
return initialized;
}

// Actually send outgoing message
public string sendMessage(string message, bool reply, int timeout){
JMSMessage PutMsg = new JMSMessage();
// Make sure that for request/reply message is
// non persistent and will expire in 30 min

if(reply)
{
PutMsg.setJMSDeliveryMode(MQC.MQPER_NOT_PERSISTENT);
PutMsg.setJMSExpiration(18000);
PutMsg.setJMSReplyTo(MessageReciever.replyTo());
}

// Send it
PutMsg.setPayload(message);
outputq.Put(PutMsg, pmo);
System.Console.WriteLine
(" Sending a message " + message);
// If fire and forget return
if(!reply)
{
qm.Commit();
return null;
}
// Get the ID of the sent message
string mid = PutMsg.getJMSMessageIDasString();

// Create data retriever
DataRetriever dr = new DataRetriever();

// Get Correlator
Correlator correlator = Correlator.getCorrelator();

// Add ourselves to the waiting list
correlator.addElement(mid,dr);

// Commit send
qm.Commit();

// Wait for the reply
return (string)dr.getReply(timeout);
}
}
}

Listing 18 MessageReciever class

using System;
using System.Threading;
using IBM.WMQ;
using com.cna.util;

namespace com.cna.util.jms
{
/// <summary>
/// This class is responsible for reading of MQ messages. It runs
/// in its own thread (s)(readMessages method), reading all of
/// the messages for the given queue/queue manager pair and
/// processing them. The above method is in infinite loop, while
/// the thread is not terminated. We are running a pool of this
/// class instances in order to provide required throughput
/// </summary>
public class MessageReciever
{
// private variables for the class
private static bool recRunning = false;
private static MessageReciever[] readers = null;
private static Thread[] threads = null;
private static MQQueue repq = null;
private static int nThreads = 0;

// Private variables for every instance
private MQQueueManager qm = null;
private MQQueue inputq = null;
private MQGetMessageOptions gmo = null;
private bool initialized = false;
private bool terminated = false;
private string mqname = null;
private string mqmname = null;
private string mchannel = null;
private string mconstr = null;
private Correlator correlator = null;

// This is a bootstrapping method for the message readers
public static void startRecievers(string qmname,
string qname, string channel,string constr,int reqThreads)
{

// Check whether we are already initialized
if(recRunning)
return;

// Create global arrays
readers = new MessageReciever[reqThreads];
threads = new Thread[reqThreads];
for(int i = 0; i < reqThreads; i++)
{
// Create a reader object
MessageReciever reader =
new MessageReciever
(qmname,channel, constr, qname);
if(!reader.isInitialized())
continue;

// Do only if the object was created
// successfully
readers[nThreads] = reader;

// Create a thread
Thread et = new
Thread(new ThreadStart(reader.readMessages));
threads[nThreads] = et;
nThreads ++;

// Start the thread
et.Start();
}
if(nThreads > 0)

// Mark initialized
recRunning = true;
}

// Checking whether recievers are running
public static bool isRunning()
{
return recRunning;
}

// This is a clean-up method for the message readers

public static void stopRecievers()
{
if(!recRunning)
return;
for(int i = 0; i < nThreads; i++)
{
// Send terminate command
readers[i].terminate();

// Wait, till the execution is complete
threads[i].Join();
}
}

// Get our reply to queue
public static MQQueue replyTo(){
return MessageReciever.repq;
}

// Initialize for a given queue manager, queue pair.
// Disallow creation
private MessageReciever(string qmName, string channel,
string constr, string qname)
{
mqname = qname;
mqmname = qmName;
mchannel = channel;
mconstr = constr;
try
{
// Set options for incoming messages. Specify
// timeout so that we can
// Check for the termination
gmo = new MQGetMessageOptions();
gmo.Options = gmo.Options | MQC.MQGMO_WAIT | MQC.MQGMO_CONVERT;
gmo.WaitInterval = 1000;

// Get Correlator
correlator = Correlator.getCorrelator();

initialized = true;
}
catch(Exception e)
{
System.Console.WriteLine
("Exception Setting up MQ Environment for reciever" + e);
}
}

// Check, whether initialization was successful.
private bool isInitialized()
{
return initialized;
}

// Set termination flag.
private void terminate()
{
terminated = true;
}

// Read Incoming messages
private void readMessages()
{
// Attempt to connect to the MQ queue manager. This
// has to be a part of a particular thread execution
// because queue manager reference is not sharable
// between threads
qm = new MQQueueManager(mqmname,mchannel,mconstr);

// Attempt to open the request input queue.
inputq = qm.AccessQueue
(mqname, MQC.MQOO_INPUT_SHARED);
repq = inputq;

// Loop while not terminated
while(!terminated)
{
JMSMessage GetMsg = new JMSMessage();
bool gotMsg = false;
try
{
inputq.Get(GetMsg, gmo);
gotMsg = true;
}
catch (MQException e)
{
// If we just got no message in the
// timeout interval - continue reading
if (e.Reason ==
MQC.MQRC_NO_MSG_AVAILABLE)
continue;

// The exception was something other than
// a timeout
System.Console.WriteLine
("Exception reading a message" + e);
}

// continue if there is no message
if(!gotMsg)
continue;

// Is anyone waiting for this message?
string cid =
GetMsg.getJMSCorrelationIDasString();
DataRetriever dr =
(DataRetriever)correlator.getElement(cid);
if(dr == null){
System.Console.WriteLine
("Got orphant message with the ID" + cid);
continue;
}

// Invoke requester

dr.setReply(GetMsg.getPayload());
}
}
}
}

Listing 19 DataRetriever class

using System;
using System.Threading;

namespace com.cna.util
{
/// <summary>
/// This class is responsible for synchronizing between message
/// sender (sending the request) and message recieverr
/// ( retrieveing result). Message sender invokes method
/// getReply, which support the wait (with the time interval) for
/// reciever to populate the result field. The reciever is using
/// setResult method to set the result value and release sender
/// </summary>
public class DataRetriever
{
private object reply;

// Constructor
public DataRetriever()
{
reply = null;
}

// This method allows to synchronize request with the
// reply, returning:
// null, if reply was not received within the specified
// timeout
// reply object
// It is called by the requester

public Object getReply(int timeout)
{
lock(this)
{
try
{
Monitor.Wait(this,timeout);
}
catch(Exception e)
{
Console.WriteLine
("Exception wailting for reply" + e);
}
}
return reply;
}

// This method allows to synchronize request with the
// reply. It stores the result and releases requester
// thread.
// It is called by the reciever

public void setReply(object reply)
{
lock(this)
{
this.reply = reply;
Monitor.Pulse(this);
}
}
}
}

Listing 20 Correlator class

using System;
using System.Collections;

namespace com.cna.util
{
/// <summary>
/// This class is a thread save wrapper for the hashtable class,
/// used for matching requests and replies. Matching is assumed
/// on the message ID of the request and correlation ID of
/// the reply
/// </summary>

public class Correlator
{
private Hashtable threads;
private static Correlator myCorrelator = null;

// Disallow direct creation

private Correlator()
{
threads = new Hashtable();
}

// Singleton support
public static Correlator getCorrelator()
{
if(myCorrelator == null)
myCorrelator = new Correlator();
return myCorrelator;
}

// Adding elemnt to the table
public void addElement(string key, object kvalue)
{
lock(this)
{
threads.Add(key,kvalue);
}
}

// Getting elemnt from the table
public Object getElement(string key)
{

object result;
lock(this)
{
result = threads[key];
threads.Remove(key);
}
return result;
}
}
}

Appendix 3 : Code for the J2EE - based provider implementation.
Listing 21 J2EE Provider bean implementation

\package article.example;

import javax.jms.JMSException;
import javax.jms.TextMessage;
import javax.naming.NamingException;
import javax.naming.directory.InitialDirContext;
import java.util.Hashtable;
import javax.jms.*;
import javax.naming.InitialContext;
import javax.naming.directory.InitialDirContext;

/**
* Bean implementation class for Enterprise Bean: Provider
*/
public class ProviderBean
implements javax.ejb.MessageDrivenBean, javax.jms.MessageListener {
private javax.ejb.MessageDrivenContext fMessageDrivenCtx;
/**
* getMessageDrivenContext
*/
public javax.ejb.MessageDrivenContext getMessageDrivenContext() {
return fMessageDrivenCtx;
}
/**
* setMessageDrivenContext
*/
public void setMessageDrivenContext(javax.ejb.MessageDrivenContext ctx) {
fMessageDrivenCtx = ctx;
}
/**
* ejbCreate
*/
public void ejbCreate() {
}

/**
* onMessage
*/
public void onMessage(javax.jms.Message msg) {

if (msg instanceof TextMessage) {

try {
TextMessage txtmsg = (TextMessage) msg;
Queue replyq;

String msgback = "Hello " + txtmsg.getText();


replyq = (Queue)txtmsg.getJMSReplyTo();

sendReply(msgback, replyq, msg.getJMSMessageID());

System.out.println(msgback);
}
catch (JMSException jmsEx) {
System.out.println(jmsEx.getMessage());
}
}

}

/**
* ejbRemove
*/
public void ejbRemove() {
}

private void sendReply(String data, Queue dest, String correlID) {

Hashtable env = new Hashtable();

String providerURL = "ldap://sch1h008.cna.com/o=cna, cn=localhost";
String InitialContextFactory = "com.sun.jndi.ldap.LdapCtxFactory";
String qcf = "cn=queueManager,cn=helloproducer,cn=Producers";
QueueConnectionFactory factory;
QueueConnection connection;
QueueSession session;
QueueSender sender;
Tex