Configuring MQ from Oracle App Server
By Antony Reynolds on Apr 04, 2007
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
- Create the resources you want using MQ Explorer
- Register a resource provider and its classes in application.xml
- Create a resource adapter that uses the resource provider
- Deploy the resource adapter to OC4J.
- Configure the resource adapter to expose the correct resources.
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 -->
<description>MQSeries resource provider</description>
<?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" ?>
III. Add a �resourceadapter� tag to define the resource adapter and tie it back to the resource provider.
This gives us the following.
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.
<!-- non-XA Connection Factory -->
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.
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.
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.
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.
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�
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.
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 ""
- 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'
- 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'
- 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
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
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.
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.