Configuring MQ from Oracle App Server

Registering MQ Series as a Standalone Resource Provider in OC4J


I have just been fighting to get MQ Series working with OC4J as a stand alone resource provider with the minimum of effort and in the most easy to understand way.  Thought I would share with you the results of my travails.


To summarise you



  1. Create the resources you want using MQ Explorer

  2. Register a resource provider and its classes in application.xml

  3. Create a resource adapter that uses the resource provider

  4. Deploy the resource adapter to OC4J.

  5. Configure the resource adapter to expose the correct resources.

Scenario


A standalone resource provider is available to all applications in the application server and so is an attractive way to install something as generic as IBM MQ Series.  I decided to use the file based JNDI interface into MQ Series and registered a ConnectionFactory and a Queue into the JNDI namespace using Websphere MQ Explorer.


1. Creating the MQ Resources


Using Websphere MQ Explorer I create a file based JNDI naming tree and bound into it the following



  • A Queue (called �MQQ�) mapped onto the default queue.

  • A Queue (called �RouterLogQ�) mapped onto a new queue I created called  AS_Router_LOGQ

  • A ConnectionFactory (called �MQCF�) mapped onto a ConnectionFactory.

The names obviously don�t matter but I intended to set up a JMS Router job to transfer messages from an Oracle queue to an IBM queue and each router job must have a log queue in both the source and target messaging systems, hence the creation of the queue AS_Router_LOGQ which I exposed through JNDI as RouterLogQ.


2. Registering the Resource Provider


This is simplicity itself.  Declare the IBM resource provider in %ORACLE_HOME%/j2ee/home/config/application.xml.


<!-- MQ Series resource Provider -->


<resource-provider class="com.evermind.server.deployment.ContextScanningResourceProvider"


   name="mqjmsrp">


  <description>MQSeries resource provider</description>


  <property name="java.naming.factory.initial"


            value="com.sun.jndi.fscontext.RefFSContextFactory">


  </property>


  <property name="java.naming.provider.url"


            value="file:C:/JNDI">


  </property>


</resource-provider>


 <?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /><o:p></o:p>


This declaration tells OC4J that it is using a resource provider that exposes resources through a JNDI naming context (class "com.evermind.server.deployment.ContextScanningResourceProvider").  The resource provider is called "mqjmsrp" (an arbitrary name that is referenced from the resource adapter). The exact details of the JNDI context are provided by identifying the class of the initial naming context (com.sun.jndi.fscontext.RefFSContextFactory).  Finally we identify the file location which is the root of the MQ JNDI tree (using �java.naming.providor.url� property).


If we were to use a different JNDI naming context class then we may need different property parameters, such a port number and host name.


The final step to registering the provider is to add the MQ libraries to the classpath in %ORACLE_HOME%/j2ee/home/config/application.xml.  The easiest way to do this is to point to the value of the %MQ_JAVA_LIB_PATH% environment variable that is set when you install MQ.


<!-- MQ Series classes -->


<library path="C:\Program Files\IBM\Websphere MQ\Java\lib"/>


When you insert this make sure it is last in your list of library paths as it does contain the same classes as some OC4J libraries.  You will be warned that these classes are being ignored when OC4J starts up.  Don�t worry about that � trust me.


3. Create & deploy Resource Adapter


To create a resource adapter I used Oracle JDeveloper.  Unfortunately JDeveloper has rather basic facilties for supporting creation of resource adapters.  I followed the following steps to create the resource adapter.


I. Create an empty JDeveloper project and add appropriate libraries


This will provide us the structure in which to work.  After creating the empty project add the standard J2EE librarie and create two new librarie from the following jar files



  • GJRA Library from %J2EE_HOME%/connectors/OracleASjms/OracleASjms/gjra.jar file

  • JCA Connectors library from %J2EE_HOME%/lib/connector.jar

By adding these libraries JDeveloper will be able to verify that classes referenced in the ra.xml file actually exist, thus checking that your file has the correct values in it.


II. Add a �new� ra.xml resource adapter descriptor file to the project by using the J2EE deployment descriptor wizard in JDeveloper.


This creates the resource descriptor file.  So far so good.  Many of the descriptors in JDeveloper have smart property editors that make sure you put the right elements in the right order, no such joy with resource adapter descriptors.  So we need to build the remainder of the descriptor by hand.


Fill in the vendor details, EIS type and resource adapter version (provided in the template for the ra.xml file), which are all in our control and add a display name.


<?xml version="1.0" encoding="windows-1252" ?>


<connector xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"


           xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/connector_1_5.xsd"


           xmlns="http://java.sun.com/xml/ns/j2ee" version="1.5">


  <display-name>MQjms</display-name>


  <vendor-name>Oracle Corporation</vendor-name>


  <eis-type>MQ JMS</eis-type>


  <resourceadapter-version>1.0</resourceadapter-version>


</connector>


III. Add a �resourceadapter� tag to define the resource adapter and tie it back to the resource provider.


This gives us the following.


<resourceadapter>


  <resourceadapter-class>oracle.j2ee.ra.jms.generic.JMSResourceAdapter</resourceadapter-class>


  <config-property>


    <config-property-name>lookupMethod</config-property-name>


    <config-property-type>java.lang.String</config-property-type>


    <config-property-value>resourceProvider</config-property-value>


  </config-property>


  <config-property>


    <config-property-name>resourceProviderName</config-property-name>


    <config-property-type>java.lang.String</config-property-type>


    <config-property-value>mqjmsrp</config-property-value>


  </config-property>


<resourceadapter>


The resource adapter needs a class to define it.  This class is provided by the oracle.j2ee.ra.jms.generic.JMSResourceAdapter class which provides a generic JMS resource adapter wrapper.  This class, together with the other classes used in this entry are shipped as part of the OracleASjms adapter in OC4J.


The resource adapter class needs to be configured.  We need to identify the external service provider and this is done by identifying the provider as a resourceProvider (using the lookupMethod property) and then identifying which resource provider (using the resourceProviderName property).  I have pointed it to the MQ Series resource provider we defined earlier, the resourceProviderName in the ra.xml pointing to the resource provider (�mqjmsrp�) defined in application.xml.


IV. Configure an outbound resource ConnectorFactory


JCA 1.5 introduced the idea of inbound and outbound resources.  Outbound adapters are the original way of working, we make calls outbound from the resource adapter to the resource (remember resources are called EISs in JCA speak).  Inbound adapters are new in JCA 1.5 and work on the Hollywood principal, don�t call us we�ll call you.


Lets define an outbound resource adapter using the �outbound-resourceadapter� element.  We then need to declare the connection factories within the resource adapter.  We do this within the �connection-definition� element.


<outbound-resourceadapter>


  <!-- non-XA Connection Factory -->


  <connection-definition>


    <managedconnectionfactory-class>oracle.j2ee.ra.jms.generic.ManagedConnectionFactoryImpl</managedconnectionfactory-class>


    <config-property>


      <config-property-name>jndiLocation</config-property-name>


      <config-property-type>java.lang.String</config-property-type>


      <config-property-value>MQCF</config-property-value>


    </config-property>


    <connectionfactory-interface>javax.jms.ConnectionFactory</connectionfactory-interface>


    <connectionfactory-impl-class>oracle.j2ee.ra.jms.generic.ConnectionFactoryWrapper</connectionfactory-impl-class>


    <connection-interface>javax.jms.Connection</connection-interface>


    <connection-impl-class>oracle.j2ee.ra.jms.generic.ConnectionWrapper</connection-impl-class>


  </connection-definition>


</outbound-resourceadapter>


Here we have declared a managed connection factory (managed means that it can be managed by the container, in our case OC4J).  We need to provide a managed connection factory class which we identify (again using the classes provided in the OracleASjms adapter) .


We then configure the managed connection factory by identifying the JNDI location in the MQ JNDI space where a ConnectionFactory has been registered.  In this case �MQCF�.


Having located the real ConnectionFactory we need to tell the adapter what classes it implements.  We do this with the �connection-factory-interface� element which tells us that this is really a JMS ConnectionFactory.  We provide a generic wrapper for this to provide the implementation class �ConnectionFactoryWrapper� (in the �connectionfactory-impl-class� tag).


Finally we tell the adapter that a ConnectionFactory class generates JMS �Connection�s (with the �connection-interface� element) and that we have provided a wrapper for this (identified by the �connection-impl-class� element) of a ConnectionWrapper class.


All this fuss allows the container to manage pools of connections itself, giving us greater control over how OC4J manages the integration with MQ.


V. Add other ConnectionFactory definitions.


We can have multiple connection factories in an outbound resource adapter definition.  The table below summarises the connection factories supported by the generic JMS adapter.














































<connection-factory-interface>
javax.jms


<managedconnection
factory-class>
oracle.j2ee.ra.jms.generic


<connectionfactory-impl-class>
oracle.j2ee.ra.jms.generic


<connection-interface
>
javax.jms


<connection-impl-class>
oracle.j2ee.ra.jms.generic


Connection­Factory


Managed­Connection­Factory­Impl


Connection­Factory­Wrapper


Connection


Connection­Wrapper


XA­Connection­Factory


Managed­XA­Connection­Factory­Impl


XA­Connection­Factory­Wrapper


XA­Connection


XA­Connection­Wrapper


Queue­Connection­Factory


Managed­­Queue­Connection­Factory­Impl


Queue­Connection­Factory­Wrapper


Queue­Connection


Queue­Connection­Wrapper


XA­Queue­Connection­Factory


Managed­XA­Queue­Connection­Factory­Impl


XA­Queue­Connection­Factory­Wrapper


XA­Queue­Connection


XA­Queue­Connection­Wrapper


Topic­Connection­Factory


Managed­­Topic­Connection­Factory­Impl


Topic­Connection­Factory­Wrapper


Topic­Connection


Topic­Connection­Wrapper


XA­Topic­Connection­Factory


Managed­XA­Topic­Connection­Factory­Impl


XA­Topic­Connection­Factory­Wrapper


XA­Topic­Connection


XA­Topic­Connection­Wrapper


VI. Declare the type of transaction support for the outbound-resourceadapter


We need to tell the container the type of transaction support provided by this adapter.  The choices are XATransaction, LocalTransaction and NoTransaction.  In this case we declare the resource adapter to support XA transactions by adding a suitable �transaction-support� element after all connection factory definitions.


<transaction-support>XATransaction</transaction-support>


If the resource provider only supports �LocalTransaction� then OC4J can still enlist the resource in XA transactions, but only if no other non-XA resources are involved.


VII. Add authentication and re-authentication elements for the outbound resource adapter


The container must be told about the authentication requirements of the resource.  In this case we identify support for basic password authentication only.


<authentication-mechanism>


  <authentication-mechanism-type>BasicPassword</authentication-mechanism-type>


  <credential-interface>javax.resource.spi.security.PasswordCredential</credential-interface>


</authentication-mechanism>


<reauthentication-support>false</reauthentication-support>


We also say that reauthentication is not supported.


VIII. Declare placeholders for queues


So far we have identified what connection factories look like.  We now tell the container what Queues and/or Topics look like.  To do this we use the �adminobject� element.  Here we identify the type of objects to be found (using the �adminobject-interface� element) and also their wrapper implementation (using the �adminobject-class� element).


Finally we identify the source location for these objects (in this Queues) by having a �resourceProviderName� property that we point at the MQ JMS resource provider.


This then provides a description of what a queue looks like.  We will see later how this becomes a prototype for accessing MQ Series Queue objects from OC4J.


<adminobject>


  <adminobject-interface>javax.jms.Queue</adminobject-interface>


  <adminobject-class>oracle.j2ee.ra.jms.generic.AdminObjectQueueImpl</adminobject-class>


  <config-property>


    <config-property-name>resourceProviderName</config-property-name>


    <config-property-type>java.lang.String</config-property-type>


    <config-property-value>mqjmsrp</config-property-value>


  </config-property>


</adminobject>


The same configuration can be used for Topics by replacing references to Queue with references to Topic.


IX. Create Resource Adapter Deployment Profile


We have now finished with the ra.xml file and can proceed to package up the resource adapter for deployment to OC4J.  To do this we create a new RAR file deployment profile within JDeveloper (I called mine �MQjms�).  The name of the deployment profile by default will be the name of the RAR file and the resulting resource adapter.


Explicitly add the GJRA jar file (%J2EE_HOME%/connectors/OracleASjms/OracleASjms/gjra.jar) to the list of contributors.  We are now ready to deploy the resource adapter archive (rar) file.


4. Deploy the MQ Resource Adapter to OC4J


We can deploy the rar file direct from JDeveloper or by using the EM console in App Server.  If we deploy through JDeveloper then it will be deployed with default settings (i.e. nothing will be configured unless we have provided an �oc4j-ra.xml� file in the deployment).  If we deploy through EM then we will be given the opportunity to configure the resource adapter at deployment time.


To get to the deployment screen on EM



  • Logon to EM

  • Select Applications tab

  • Select �Standalone Resource Adapters� view from the dropdown

  • Click deploy�

Note that if deploying from JDeveloper the adapter will be called by the name of the depoloyment profile, if deploying from EM you can choose a name.


If we decide not to configure the resource adapter we can always do so later.  So lets leave it until later.


5. Configure the MQ Resource Adapter on OC4J


At this point we have created a description of MQ Series resources potentially available to an OC4J application but we have not actually configured any resources, so lets go ahead and do that.


I. Create a ConnectionFactory


Lets start by creating a ConnectionFactory using EM.



  • Logon to EM

  • Select Applications tab

  • Select �Standalone Resource Adapters� view from the dropdown

  • Select �Connection Factories� tab

  • Select �create�

A drop down list of the different types of connection factory available (the ones you registered in the ra.xml file) will appear.  Select the type that you want and you will then be asked to provide the OC4J �JNDI Location� of this factory.  This location is relative to the name of the resource adapter (�MQjms� in my case).


This screen will also show the �jndiLocation� of the resource in the MQ JNDI namespace (relative to the root context of the MQ JNDI namespace.


I created a connection factory at location �IBMMQjms/ConnectionFactory�.  Although you can use arbitrary names it is a good idea to group all resources in a single adapter under a single tree so that you know where your resources are coming from.


II. Create Queues


There is no need to declare individual queue objects.  We can just map the MQ JNDI namespace onto the OC4J namespace and let applications look up any Queue in the MQ namespace.  To do this use the �Administered Objects� tab in EM and select �create�.  Select the type of object you want to map into the OC4J namespace.  Then enter the JNDI location where you want the IBM MQ Series queues defined in the MQ JNDI to appear.


I entered a value of �IBMMQjms/Queues�.  The first part tells me (not OC4J) that this is an IBM MQ namespace, Queues tells me that I can access queue objects here.  Individual queues in the MQ namespace (for example Queue at location �MQQ�) can be looked up by appending the IBM JNDI location to the OC4J prefix, in this case IBM �MQQ� will appear at �IBMMQjms/Queues/MQQ�


Completed!


We have now finished configuring everything.  So lets summarise what we did.



  • Set up the objects we wanted in IBM MQ Series


    • Connection Factory �MQCF�

    • Queue �MQQ�

  • Created a Resource Provider �mqjmsrp� that provides access to the IBM JNDI name space.

  • Created a Resource Adapter �MQjms� that describes what MQ objects look like to OC4J.

  • Mapped objects in the MQ JNDI namespace into the OC4J namespace


    • Connection Factory �MQCF� mapped to �IBMMQjms/ConnectionFactory�

    • Queue �MQQ� mapped to �IBMMQjms/Queues/MQQ� � note that any other queues in the MQ JNDI namespace can be accessed in a similar way with no more configuration on the OC4J side.

Testing It


To test the configuration I created several servlets.



  • ListerServlet (�/list�) that displays the JNDI namespace.  Use this to verify that you can see your connection factories and queue template directories.


    • Sample Output

JNDI Root ""


/jmsrouter_ejb_TimerHandlerBeanLocal(TimerHandlerBean_LocalHomeProxy_1nca7p1)


/admin_ejb_MBeanServerEjb(MBeanServerEjb_RemoteHomeProxy_1me2j7)



/IBMMQjms(javax.naming.Context)


/IBMMQjms/Queues(oracle.j2ee.ra.jms.generic.AdminObjectQueueImpl)


/IBMMQjms/ConnectionFactory(oracle.j2ee.ra.jms.generic.ConnectionFactoryWrapper)



  • PosterServlet (�/send�) that submits a message onto a queue using a ConnectionFactory (�/send?CF=IBMMQjms/ConnectionFactory&Q=IBMMQjms/Queues/MQQ�)


    • Sample Output

Sent message 'Hello at Wed Apr 04 09:53:20 BST 2007'


'JMSCorrelationID'=null


'JMSDeliveryMode'=2


'JMSDestination'=oracle.j2ee.ra.jms.generic.AdminObjectQueueImpl[queue://QM_workstationxp/default]


'JMSExpiration'=0


'JMSMessageID'=ID:414d5120514d5f776f726b737461746909251146200b2802


'JMSPriority'=4


'JMSRedelivered'=false


'JMSReplyTo'=null


'JMSTimestamp'=1175676800062


'JMSType'=null


'JMS_IBM_PutDate'='20070404'(java.lang.String)


'JMSXAppID'='JDeveloperjdkbinjava.exe'(java.lang.String)


'JMS_IBM_PutApplType'='11'(java.lang.Integer)


'JMSXUserID'='oracle      '(java.lang.String)


'JMS_IBM_PutTime'='08532006'(java.lang.String)


'JMSXDeliveryCount'='0'(java.lang.Integer)



  • ReaderServlet (�/reader�) that reads a message from a queue using a ConnectionFactory (�/send?CF=IBMMQjms/ConnectionFactory&Q=IBMMQjms/Queues/MQQ�)


    • Sample Output

Received message 'Hello at Wed Apr 04 09:53:20 BST 2007'


'JMSCorrelationID'=null


'JMSDeliveryMode'=2


'JMSDestination'=oracle.j2ee.ra.jms.generic.AdminObjectQueueImpl[queue://QM_workstationxp/default]


'JMSExpiration'=0


'JMSMessageID'=ID:414d5120514d5f776f726b737461746909251146200b2802


'JMSPriority'=4


'JMSRedelivered'=false


'JMSReplyTo'=null


'JMSTimestamp'=1175676800062


'JMSType'=null


'JMS_IBM_PutDate'='20070404'(java.lang.String)


'JMSXAppID'='JDeveloperjdkbinjava.exe'(java.lang.String)


'JMS_IBM_Format'='MQSTR   '(java.lang.String)


'JMS_IBM_PutApplType'='11'(java.lang.Integer)


'JMS_IBM_MsgType'='8'(java.lang.Integer)


'JMSXUserID'='oracle      '(java.lang.String)


'JMS_IBM_PutTime'='08532006'(java.lang.String)


'JMSXDeliveryCount'='1'(java.lang.Integer)



  • EnvironmentServlet (�/printenv� that displays the environment as seen from within the Java Virtual machine (useful for checking that you can see the directory with IBM MQ Series native libraries)


    • Sample Output

Java Environment


Absolute Default Directory C:OC4Jbin.


Canonical Default Directory C:OC4Jbin


Available Processors 1



MQ_JAVA_LIB_PATH C:Program FilesIBMWebSphere MQJavalib



lib C:Program FilesIBMWebSphere MQtoolslib


MQ_JAVA_DATA_PATH C:Program FilesIBMWebSphere MQ



MQ_JAVA_INSTALL_PATH C:Program FilesIBMWebSphere MQJava



Path C:Program FilesIBMWebSphere MQJavalib;C:WINDOWSsystem32;C:WINDOWS;C:WINDOWSSystem32Wbem;C:Program FilesIBMWebSphere MQbin;C:Program FilesIBMWebSphere MQtoolsc\samplesbin


Sample Files


I have uploaded the following files.



  • ra.xml Resource adapter file for MQ series.

  • MQjms.rar (includes ra.xml file) MQ Series Resource Adapter.  Deploy this and configure it to point to your own MQ resources.

  • WebTester.ear Sample JMS Test application.  Deploy this to access the Servlets listed above.

What�s Left?


I haven�t covered the inbound use of JMS as a MessageListener.  Maybe I will cover that in another post.  In the meantime enjoy using MQ Series from within OC4J.

Comments:

Antony, It seems that you are missing oc4j-ra.xml file for your example. I am using your post as well as the examples from Oracle and IBM to connect MQ server on one box and OC4J on a different one. The connection info (host, port, channel name, queue manager, queue name) should go to this XML config file. Igor.

Posted by Igor on June 12, 2007 at 10:04 AM MDT #

Hi, thanks for the post, help a lot. Now i'm trying to setup an MDB but the OC4J gives "Operation failed with error: Destination and Connection mismatch for MessageDrivenBean MessageDrivenEJBBean: they must either both be Topic or both be Queue" MDB Conf. @MessageDriven(activationConfig = { @ActivationConfigProperty(propertyName = "connectionFactoryJndiName", propertyValue ="IBMMQjms/ConnectionFactory"), @ActivationConfigProperty(propertyName = "destinationName", propertyValue ="IBMMQjms/Queues/sisns00.jms.OrderedInboundQueue"), @ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue")}) This CF and Q works fine on Sample JMS Test application that you provide. Can you help me? Many thanks Nuno Borges

Posted by Nuno Borges on August 13, 2007 at 01:59 AM MDT #

Hi, I read your exmaple and others by Oracle which try to explain now to connect to MQ. Nont of these examples work , either some config is missing or the example is incomplete. I have MQ running on machine A, oc4j standlone on Machine B. The question is what config do i need to do in oc4j and in my ear file hosted on oc4j so I can reach the MQ queue on Machine A. To date I have not found a working exmaple on any site. Oracles own exmaple assumes MQ is on the same machine as oc4j - however, I want to connect to MQ running on a totally different machine but on the same network so its reachable.

Posted by ash patel on October 27, 2007 at 03:11 AM MDT #

The assumption I have made in my configuration is that I am accessing MQ through the file based JNDI providor and as such how to access MQ resources is not a problem to be solved in OC4J but one to be solved in MQ configuration. The assumption in all the Oracle examples is that you have at least MQ client installed on the machine running OC4J. If you only have MQ client then there is no XA support and so you have to use last resource commit to make MQ transactions participate in a distributed transaction. Whether MQ client is used or MQ server then the setup and mapping of the JNDI space is crucial to the setup working. Hope this clarifies. Antony

Posted by Antony Reynolds on October 27, 2007 at 09:04 AM MDT #

I deployed the MYjms.rar and this went ok. Im trying to see the src code in the ear file so I can see how you send and recive messages from the queue setup (IBMMQjms/Queues/MQQ). Could you please also upload the src code for the java code in the ear file ? Thanks.

Posted by ash patel on October 31, 2007 at 10:49 AM MDT #

I was going through Oracles example on using MQ with Oc4j and its v old. I can not get theirs to work . Yours made a lot more sense. You say on the blog that you havent covered the inbound use of JMS as a MessageListener but you in the ear file/demo code, you have an example that picks up messages ? isnt this the inbound queue stuff or do you mean usign ejb message driven beans to pick up the messages async from the queue ?

Posted by ash patel on October 31, 2007 at 10:52 AM MDT #

The example just receives directly off a queue although the same JNDI location for the queue could be bound to a MDB, I just didn't do this in the sample.

Antony

Posted by Antony Reynolds on December 05, 2007 at 12:27 AM MST #

Hi Antony, Thanks for sharing this information, I could create a working adaptor for BEA WLS JMS using this. However, I have a query. We need to define the Resource Provider in %ORACLE_HOME%/j2ee/home/config/application.xml.file. In case when my oc4j is coming up if the WLS server is down then it fails to get a connection and doesn't come up. Is there any way to prevent this? Something like loose coupling with the WLS JMS? Thanks, Amit

Posted by AMit on July 17, 2008 at 09:07 PM MDT #

HOw to implement XA transactions in OC4J for Webpshere MQ

Posted by Meetgaurav on September 11, 2008 at 09:39 PM MDT #

Post a Comment:
Comments are closed for this entry.
About

Musings on Fusion Middleware and SOA Picture of Antony Antony works with customers across the US and Canada in implementing SOA and other Fusion Middleware solutions. Antony is the co-author of the SOA Suite 11g Developers Cookbook, the SOA Suite 11g Developers Guide and the SOA Suite Developers Guide.

Search

Archives
« April 2014
SunMonTueWedThuFriSat
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
Today