Saturday, May 14, 2016

Java Integration with Oracle Tuxedo using JCA Adapter

Today's article is about integrating Tuxedo based system with J2EE using Application Server. I think this article will helpful if you are looking to integrate tuxedo system with J2EE application. So, let us begin this integration.

For this article I have used Jboss EAP/AS as a application server, Orcale Tuxedo Adapter and Java based web application. I assume that you guys have basic knowledge of JBoss AS configuration, java web based application and JCA and have some basic idea about Tuxedo System.

Now, you have to setup the environment so we can start the development.
Download Jboss Application Server(6.xxx) or Jboss EAP(6.xxx) from official Redhat
Download Tuxedo JCA connector from Oracle official site. You can have introductory knowledge by referring Data sheet pdf file.

Ref. Oracle


Note, we will have imaginary Tuxedo system because configuring Tuxedo system is tedious job and again its one big topic. You can have basic understanding from  Data Sheet of Oracle Tuxedo document. I think this will help you guys to get basic knowledge of Tuxedo.

Ref. Oracle
I think this is sufficient to have basic knowledge of Tuxedo and Tuxedo Adapter based on JCA provided by Oracle.

Now, after environment  is ready please check Jboss server should be up and functioning without any failure. You can check Jboss server admin console by typing in your browser http://127.0.0.1:9990. It will ask for username and password. You provide whatever you have given at the time of user creation with Jboss.

Jboss Configuration :
Once server is up and running, we need to do some configuration changes in Jboss AS as per below which is required to deploy the Tuxedo JCA Adapter in server,

  1. Need to disable archive-validation in $JbossAS\standalone\configuration\standalone.xml
      2. Need to add resource-adapters entry in $JbossAS\standalone\configuration\standalone.xml
      
....        <subsystem xmlns="urn:jboss:domain:pojo:1.0"/>
        <subsystem xmlns="urn:jboss:domain:remoting:1.1">
            <connector name="remoting-connector" socket-binding="remoting" security-realm="ApplicationRealm"/>
        </subsystem>
        <subsystem xmlns="urn:jboss:domain:resource-adapters:1.0">
            <resource-adapters>
                <resource-adapter>
                    <archive>com.oracle.tuxedo.TuxedoAdapter.rar</archive>
                    <transaction-support>LocalTransaction</transaction-support>
                    <config-property name="traceLevel">80000</config-property>
                    <config-property name="xaAffinity">true</config-property>
                    <config-property name="dmconfig">
                       $JbossAS/standalone/configuration/dmconfig.xml
                    </config-property>
                    <connection-definitions>
                        <connection-definition class-name="javax.resource.cci.ConnectionFactory" jndi-name="java:tuxedo/Connection" enabled="true" use-java-context="true" pool-name="Connection" use-ccm="true">
                            <pool>
                                <min-pool-size>0</min-pool-size>
                                <max-pool-size>10</max-pool-size>
                                <prefill>false</prefill>
                                <use-strict-min>false</use-strict-min>
                                <flush-strategy>FailingConnectionOnly</flush-strategy>
                            </pool>
                            <security>
                                <application/>
                            </security>
                        </connection-definition>
                    </connection-definitions>
                </resource-adapter>
            </resource-adapters>
        </subsystem>
        <subsystem xmlns="urn:jboss:domain:sar:1.0"/>
        <subsystem xmlns="urn:jboss:domain:security:1.1">
     .....
In this we have to note that we have exposed JNDI context with name java:tuxedo/Connection for Tuxedo Adapter in Jboss container. The same will be used to  create a connection object to do transaction with Tuxedo system.

Tuxedo JCA Adapter Configuration:
We are done with Jboss AS configuration. Now we will do Tuxedo Adapter internal configuration to connect real Tuxedo based system. Tuxedo JCA adapter is bundled as a rar file like com.oracle.tuxedo.TuxedoAdapter.rar. Follow below configuration with Tuxedo Adapter

1) Remove dmconfig.xml fle from adapter .rar file and placed it into $JbossAS\standalone\configuration. Later we will modify it for connection and transaction. Below files and jar files are the part of the adapter.
 

Also, we need to remove all the files from META-INF dir except ra.xml and MANIFEST.MF. Later we will update the ra.xml file as per our requirement.




2) Copy all the jar files which is available inside adapter into your web app from where we will get the connection from JNDI and do the programming to send data to Tuxedo system.

3) Modification in dmconfig.xml as per below. It varies as per your requirement. This file contains Tuxedo system related configuration. Configuration like, local access point, remote access point, session profile, session, exposed services by Tuxedo System. I'm not going to explain more about this file, you can learn it from official oracle web site. But for reference you can refer this site. This is the key file which is used by tuxedo adapter to establish connection and trigger the request based on exposed services by Tuxedo System.
dmconfig.xml :

<?xml version="1.0" encoding="UTF-8"?>
<TuxedoConnector>
<!-- Local Access point from where Tuxedo System is being called,
Your server IP and your server IP needs to be configured at Tuxedo System
as remote access point
-->
<LocalAccessPoint name="local_acc_point">
<AccessPointId>local_acc_point_id</AccessPointId>
<NetworkAddress>//localhost:8080</NetworkAddress>
</LocalAccessPoint>
<!-- 
Remote Tuxedo System IP along with port
-->
<RemoteAccessPoint name="remote_acc_point">
<AccessPointId>remote_acc_point_id</AccessPointId>
<NetworkAddress>//remote.tuxedo.system.host.endpoint:port</NetworkAddress>
</RemoteAccessPoint>
<!-- 
Basic configuration to establish session with Tuxedo System.
-->
<SessionProfile name="profile_1">
<Security>NONE</Security>
<BlockTime>30000</BlockTime>
<Interoperate>false</Interoperate>
<ConnectionPolicy>ON_DEMAND</ConnectionPolicy>
<ACLPolicy>local</ACLPolicy>
<CredentialPolicy>local</CredentialPolicy>
<RetryInterval>60</RetryInterval>
<MaxRetries>1000</MaxRetries>
<CompressionLimit>1000000</CompressionLimit>
<KeepAlive>100000</KeepAlive>
<KeepAliveWait>200000</KeepAliveWait>
</SessionProfile>
<!-- 
This session will be used by Tuxedo Adapter for transaction by
using session profile and remote/loca access point.
-->
<Session name="session_1">
<LocalAccessPointName>local_acc_point</LocalAccessPointName>
<RemoteAccessPointName>remote_acc_point</RemoteAccessPointName>
<ProfileName>profile_1</ProfileName>
</Session>
<Import name="TOUPPER">
    <RemoteName>TOUPPER</RemoteName>
    <SessionName>session_1</SessionName>
    <LoadBalancing>RoundRobin</LoadBalancing>
  </Import>
  <Import name="ECHO">
    <RemoteName>ECHO</RemoteName>
    <SessionName>session_1</SessionName>
    <LoadBalancing>RoundRobin</LoadBalancing>
  </Import>
   <!-- More than one  Import will be configured here as per the Tuxedo services exposed -->
  <Import name="Service_Name_1">
    <RemoteName>Service_Name_1</RemoteName>
    <SessionName>session_1</SessionName>
    <LoadBalancing>RoundRobin</LoadBalancing>
  </Import>
  <Import name="Service_Name_2">
    <RemoteName>Service_Name_2</RemoteName>
    <SessionName>session_1</SessionName>
    <LoadBalancing>RoundRobin</LoadBalancing>
  </Import>
</TuxedoConnector>


4)
Need to modify the Adapter's ra.xml as I did. Here, we have to make sure the dmconfig.xml file should be correctly placed and correctly configured in this file.This configuration is used internally by Tuxedo Adapter. You can read more about this file from here.
ra.xml :
<?xml version="1.0" encoding="UTF-8"?>
<connector xmlns="http://java.sun.com/xml/ns/j2ee"
    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"
    version="1.5">
<display-name>Tuxedo JCA Adapter</display-name>
<vendor-name>Oracle</vendor-name>
<eis-type>Tuxedo</eis-type>
<resourceadapter-version>11gR1(11.1.1.2.1)</resourceadapter-version>
<license>
<description>Tuxedo SALT license</description>
<license-required>false</license-required>
</license>
<resourceadapter>
<resourceadapter-class>com.oracle.tuxedo.adapter.TuxedoResourceAdapter</resourceadapter-class>
<config-property>
<config-property-name>debugConfig</config-property-name>
<config-property-type>java.lang.Boolean</config-property-type>
<config-property-value>true</config-property-value>
</config-property>
<config-property>
<config-property-name>traceLevel</config-property-name>
<config-property-type>java.lang.String</config-property-type>
<config-property-value>100000</config-property-value>
</config-property>
<config-property>
<config-property-name>xaAffinity</config-property-name>
<config-property-type>java.lang.String</config-property-type>
<config-property-value>true</config-property-value>
</config-property>
<config-property>
<config-property-name>dmconfig</config-property-name>
<config-property-type>java.lang.String</config-property-type>
<config-property-value>$JbossAS/standalone/configuration/dmconfig.xml</config-property-value>
</config-property>
<outbound-resourceadapter>
<connection-definition>
<managedconnectionfactory-class>com.oracle.tuxedo.adapter.spi.TuxedoManagedConnectionFactory</managedconnectionfactory-class>
<connectionfactory-interface>javax.resource.cci.ConnectionFactory</connectionfactory-interface>
<connectionfactory-impl-class>com.oracle.tuxedo.adapter.cci.TuxedoConnectionFactory</connectionfactory-impl-class>
<connection-interface>javax.resource.cci.Connection</connection-interface>
<connection-impl-class>com.oracle.tuxedo.adapter.cci.TuxedoJCAConnection</connection-impl-class>
</connection-definition>
<transaction-support>LocalTransaction</transaction-support>
<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>
</outbound-resourceadapter>
</resourceadapter>
</connector>


We almost completed configuration related things for this integration. So, let's do some programming now.

Application Programming:
Create one web application say it test-tuxedo-connector. Create one jsp and one servlet. From servlet create one service class from where we will prepare tuxedo request and will establish a connection with Tuxedo system and post our request to Tuxedo system. Let's move step by step.

1) Create a jsp-servlet based web app. Include a jars file in web-inf/lib directory from adapter.rar file which I explained earlier.Add this jars in the classpath of your web app.

2) I assume that you have already read about Tuxedo based system and aware with .FML file(Field Mapping List). Basically in this file all the fields and services are defined. This file is similar like wdl and xsd file for SOAP based web services. This is the mapping file in which fields are defined which are used in Tuxedo system along with data type. I have used below test.fml file in this example.


3) Need to create java class in which all the fields are mapped with respect to test.fml. Going to say this class as TuxedoFmlTable.java. In this class we have to create unique integer value for each of the field defined in test.fml. We are going to create one utility class which creates unique numeric value by using test.fml.

public class TuxedoFmlFieldsCreater extends weblogic.wtc.jatmi.DynamicFldTbl{
static final String USER_FML_TABLE_FILE = "<file_location_of_fml_file>\\test.fml";
public TuxedoFmlFieldsCreater() {
super(USER_FML_TABLE_FILE, true);
}
public static void main(String[] args) {
TuxedoFieldTable bf = new TuxedoFieldTable();
String[] list = bf.getFldNames();
for (int i = 0; i < list.length; i++ )
System.out.println("FieldName = [" + list[i] + "], FieldId = [" + bf.name_to_Fldid(list[i]) + "]");

System.out.println("Total entries = " + list.length);
}
}

Output of above class file.

TuxedoFmlTable.java

import java.util.Hashtable;
import weblogic.wtc.jatmi.FldTbl;

public class TuxedoFmlTable implements FldTbl{
Hashtable<String, Integer> nameToFieldTable;
Hashtable<Integer, String> fieldToNameTable;

public final static int TST_DATE = 167772161;
public final static int TST_TIME = 167772162;
public final static int TST_MSGNAME = 167772163;
public final static int TST_CONTEXTID = 33554436;
public final static int TST_USERID = 167772165;
public final static int TST_ERRORNUM = 33554438;
public final static int TST_STATUSTEXT = 167772167;
public final static int TST_STATUSFLAG = 167772168;

public TuxedoFmlTable(){
if(nameToFieldTable == null || nameToFieldTable.isEmpty()){
nameToFieldTable = new Hashtable<String, Integer>(9, 0.75f);

nameToFieldTable.put("TST_DATE", TST_DATE);
nameToFieldTable.put("TST_TIME", TST_TIME);
nameToFieldTable.put("TST_MSGNAME", TST_MSGNAME);
nameToFieldTable.put("TST_CONTEXTID", TST_CONTEXTID);
nameToFieldTable.put("TST_USERID", TST_USERID);
nameToFieldTable.put("TST_ERRORNUM", TST_ERRORNUM);
nameToFieldTable.put("TST_STATUSTEXT", TST_STATUSTEXT);
nameToFieldTable.put("TST_STATUSFLAG", TST_STATUSFLAG);
}

if(fieldToNameTable == null || fieldToNameTable.isEmpty()){
fieldToNameTable = new Hashtable<Integer, String>(9, 0.75f);

fieldToNameTable.put(TST_DATE, "TST_DATE");
fieldToNameTable.put(TST_TIME, "TST_TIME");
fieldToNameTable.put(TST_MSGNAME, "TST_MSGNAME");
fieldToNameTable.put(TST_CONTEXTID, "TST_CONTEXTID");
fieldToNameTable.put(TST_USERID, "TST_USERID");
fieldToNameTable.put(TST_ERRORNUM, "TST_ERRORNUM");
fieldToNameTable.put(TST_STATUSTEXT, "TST_STATUSTEXT");
fieldToNameTable.put(TST_STATUSFLAG, "TST_STATUSFLAG");
}
}

@Override
public String Fldid_to_name(int fldId) {
return ((String) fieldToNameTable.get(new Integer(fldId)));
}

@Override
public String[] getFldNames() {
String[] fieldNames = {
"TST_DATE","TST_TIME","TST_MSGNAME","TST_CONTEXTID",
"TST_USERID","TST_ERRORNUM","TST_STATUSTEXT","TST_STATUSFLAG"
};
return fieldNames;
}

@Override
public int name_to_Fldid(String fieldName) {
Integer fldId = nameToFieldTable.get(new String(fieldName));
if (fldId == null) {
return (-1);
} else {
return (fldId.intValue());
}
}
}


4) We have created all the basic class which is required to created FML32 object which is going to send by our web app to tuxedo system via adapter. I assume that you have created web apps in which you have created one servelt and jsp page from where you will trigger the request and which will be served by servlet. Here in below class I will explain to create an tuxedo connection object through JNDI lookup from in Jboss server. We have already deploy the adapter in $JbossAS\standalone\deployments and hope its successfully deployed. We have already exposed java:tuxedo/Connection.

Full implementation of the main class where we are creating connection and posting data to tuxedo system via adapter.

TuxedoExecutor.java

import java.util.Map;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.resource.cci.Connection;
import javax.resource.cci.ConnectionFactory;
import javax.resource.cci.Interaction;
import javax.resource.cci.InteractionSpec;
import weblogic.wtc.jatmi.TypedFML32;
import com.oracle.tuxedo.adapter.cci.TuxedoFML32Record;
import com.oracle.tuxedo.adapter.cci.TuxedoInteractionSpec;

public class TuxedoExecutor {
private static Context contextObj = null;
private static ConnectionFactory conFactoryObj = null;
private static TuxedoFmlTable fmlTable = null;

private void createTuxedoConnectionFactory() throws NamingException, Exception {
try {
if(contextObj == null)
contextObj = new InitialContext();
if(conFactoryObj == null)
conFactoryObj = (ConnectionFactory) contextObj.lookup("java:tuxedo/Connection");
} catch (NamingException ne) {
throw ne;
} catch (Exception e) {
throw e;
}
}

public Connection getTuxedoConnection() throws Exception{
Connection connection = null;
try {
if(conFactoryObj == null)
createTuxedoConnectionFactory();
connection = conFactoryObj.getConnection();
} catch (Exception e) {
throw e;
}
return connection;
}

public void postDataToTuxedoSystem(Map<String, String> paramMap) throws Exception{
Connection tuxConObj = null;
Interaction tuxInteraction = null;
TuxedoInteractionSpec tuxInterSpec = null;
try {
if(fmlTable == null)
fmlTable = new TuxedoFmlTable();
tuxConObj = getTuxedoConnection(); 
tuxInteraction = tuxConObj.createInteraction();
tuxInterSpec = new TuxedoInteractionSpec();
tuxInterSpec.setFunctionName("");
tuxInterSpec.setInteractionVerb(InteractionSpec.SYNC_SEND_RECEIVE);
TypedFML32 inFml32 = new TypedFML32(fmlTable);
//Setting key-value in inFml32 object
inFml32.Fchg(fmlTable.name_to_Fldid("TST_DATE"), new Short((short)0), paramMap.get("TST_DATE").trim());
inFml32.Fchg(fmlTable.name_to_Fldid("TST_TIME"), new Short((short)0), paramMap.get("TST_TIME").trim());
inFml32.Fchg(fmlTable.name_to_Fldid("TST_MSGNAME"), new Short((short)0), paramMap.get("TST_MSGNAME").trim());
inFml32.Fchg(fmlTable.name_to_Fldid("TST_CONTEXTID"), new Short((short)0), paramMap.get("TST_CONTEXTID").trim());
inFml32.Fchg(fmlTable.name_to_Fldid("TST_USERID"), new Short((short)0), paramMap.get("TST_USERID").trim());
inFml32.Fchg(fmlTable.name_to_Fldid("TST_ERRORNUM"), new Short((short)0), paramMap.get("TST_ERRORNUM").trim());
//inFml32.Fchg(fmlTable.name_to_Fldid("TST_STATUSTEXT"), new Short((short)0), paramMap.get("TST_STATUSTEXT").trim());
//inFml32.Fchg(fmlTable.name_to_Fldid("TST_STATUSFLAG"), new Short((short)0), paramMap.get("TST_STATUSFLAG").trim());

TuxedoFML32Record inRecord = new TuxedoFML32Record(inFml32);
TypedFML32 outFml32 = new TypedFML32(fmlTable);
TuxedoFML32Record outRecord = new TuxedoFML32Record(outFml32);
//This will execute our requet to Tuxedo system via adapter
tuxInteraction.execute(tuxInterSpec, inRecord, outRecord);
if(outRecord.getTperrno() == 0){
System.out.println("Transaction Successful.");
//Fetching details from the outRecord
TypedFML32 fml32 = outRecord.getFML32();
String statusText = (String) fml32.Fget(fmlTable.name_to_Fldid("TST_STATUSTEXT"), new Short((short)0));
String statusFlag = (String) fml32.Fget(fmlTable.name_to_Fldid("TST_STATUSFLAG"), new Short((short)0));
} else {
System.out.println("Some problem occurred during the transaction.");
System.out.println("Tperrno : " + outRecord.getTperrno());
System.out.println("Tpurcode : " + outRecord.getTpurcode());
System.out.println("Tperrordetail : " + outRecord.getTperrordetail());
}
} catch (Exception e) {
throw e;
}
finally {
if(tuxInteraction != null)
tuxInteraction.close();
if(tuxConObj != null)
tuxConObj.close();
}
}
}


We are done now. Once you are ready with all this than please deploy your web application in the same directory where we have deployed the adapter. Our application should be deployed successfully. Now you trigger the request and observe the log in your system as well as in Tuxedo system which you wish to connect.

Please don't forget to give your input to make this article more helpful.

Cheers,
Ashish Mishra

4 comments:

  1. In Tuxedo Adapter Connection settings, how do you copy the jar files to Jboss? Do we need to deploy .rar file in to JBoss. Please explain

    ReplyDelete
    Replies
    1. Hi Karthik,

      Please refer my blog related to creating a shared module in Jboss EAP.

      http://akmishra30.blogspot.sg/2016/03/create-common-module-in-jboss-as7xeap6x.html

      I think this will help you to clarify your question. If still you have any confusion than please comment or reply.

      Thank You..!!

      Delete
  2. hi Ashish, I am using Teiid designer in JBoss, which offers some set of JCA's but not for Tuxedo. Can we integrate Tuxedo with Teiid?

    ReplyDelete