【譯】使用Java編寫Oracle Tuxedo應用

來源:Programming an Oracle Tuxedo Application Using Javahtml

Oracle Tuxedo Java編程介紹

簡介

Oracle Tuxedo服務可使用純java來編寫。使用java實現的服務的功能和其餘Tuxedo服務實現是同樣的。你可使用客戶端或者Tuxedo服務器經過ATMI接口來調用Tuxedo Java Server(TMJSVASVR)對外提供的服務;你也在java實現的服務中經過TJATMI接口來調用Tuxedo server提供的服務。java

另外,你可使用任何類型的Tuxedo客戶端調用java實現的服務,好比本地客戶端,/WS客戶端和Jolt客戶端。web

可使用TJATMI接口、JATMI類型緩衝、POLO java對象等主流Java技術來實現Tuxedo服務。sql

編程方針

  • Java服務類,實現Java服務,須要繼承TuxedoJavaServer類;Java服務類應該有一個默認的構造函數
  • Java服務類中的Java方法會被向外提供成Java服務,應該聲明爲public, 並將TPSVCINFO接口做爲惟一的輸入參數
  • Java服務類應該實現tpsvrinit()方法,在Tuxedo Java服務啓動時會被調用
  • Java服務類應該實現tpsvrdone()方法,在Tuxedo Java服務關閉時會被調用
  • Java服務可使用Tuxedo Java ATMI接口(例如tpcall,tpbegin等)
  • Java服務可使用tpreturn向客戶端返回結果,或者經過拋出異常退出

Tuxedo Java 服務器線程與Java類實例模型

  • Tuxedo Java服務使用傳統的Tuxedo多線程模型,必須運行在多線程模式下
  • 一旦啓動,Tuxedo Java服務爲每個定義在配置文件中的類建立一個全局對象(實例),處理Java服務時工做線程共享全局對象(實例)

Tudexo Java服務器 tpsvrinit()/tpsvrdone()處理

tpsvrinit()處理:
用戶須要實現tpsvrinit()方法。因爲該方法會在服務啓動時調用,最好在該方法中完成類的初始化。若是一個類的tpsvrinit()方法失敗,用戶日誌中會報告一條警告信息,Java服務會繼續執行。數據庫

tpsvrdone()處理:
用戶須要實現tpsvrinit()方法。該方法在服務關閉時調用,推薦將類範圍的清理工做放入這個方法中。編程

Tuxedo Java服務器tpreturn()處理

Java服務的tpreturn()並不會當即結束Java服務方法的執行,而是向Tuxedo Java服務器返回一個結果。數組

Java 服務的tpreturn()的行爲與現有Tuxedo系統的tpreturn()行爲不一樣:服務器

  • 當現有Tuxedo系統調用tpreturn()時,流控制自動轉向Tuxedo
  • 當Java服務調用tpreturn()時,tpreturn()以後的語句依舊會被執行。用戶必須保證tpreturn()是Java服務中最後一條執行的語句。若是不是,建議在tpreturn()以後加上return;不然tpreturn()不會自動將流控制轉向Tuxedo系統

注意:不建議在Java服務中前面沒有tpreturn()時使用return。這種用法會使Java服務器返回rcode爲0的TPFAIL到相關的客戶端。多線程

Tuxedo Java服務器異常處理

  • Java服務執行期間能夠拋出任何的異常而後退出Java服務。這種狀況下Java服務器會返回TPFAIL到其客戶端,其中rcode設置爲0
  • 全部的異常信息會記錄在$APPDIR/stderr文件中。

編程環境

更新UBB配置文件

你須要配置一個路徑,經過該路徑Tuxdeo Java服務器能夠找到CLOPT中Java實現的服務的配置文件。
因爲ATMI Java服務器是一個多線程服務器,你還須要指名線程分配的限制。能夠查看Defining the Server Dispatch Threads一章獲取更多關於多線程服務配置的信息。oracle

清單2-1 顯示了ATMI Java服務器的UBB配置文件示例:

清單2-1

conf*SERVERS
TMJAVASVR SRVGRP=TJSVRGRP SRVID=3
CLOPT="-- -c /home/oracle/app/javaserver/TJSconfig.xml"
MINDISPATCHTHREADS=2 MAXDISPATCHTHREADS=3

注意:UBBCONFIG中爲Java服務器指明的MAXDISPATCHTHREADS最小值爲2。

參見

  • Setting Up an Oracle Tuxedo Application
  • UBBCONFIG(5) in the File Formats, Data Descriptions, MIBs, and System Processes Reference

ATMI Java Server 用戶接口

TuxedoJavaServer

TuxedoJavaServer是一個抽象類,全部用戶定義的實現服務的類都應該繼承它。

表3-1 TuxedoJavaServer接口

函數 描述
tpsvrinit 抽象方法,子類實現時作一些初始化的工做
tpsvrdone 抽象方法,子類實現時作一些清理工做
getTuxAppContext 用來取回當前鏈接的Tuxedo應用Java上下文

Oracle Tuxedo Java上下文

爲了獲取Oracle Tuxedo Java Server提供的TJATMI原始功能,你須要獲取一個TuxAppContext對象,該對象實現了全部的TJATMI功能
由於服務類繼承自TuxedoJavaServer,你能夠在服務中調用getTuxAppContext()方法獲取上下文對象。然而,你不能在tpsvrinit()中或其TuxAppContext,由於此時TuxAppContext沒有準備好。若是你在tpsvrinit()中嘗試獲取TuxAppContexttpsvrinit()會出錯並拋出異常。

Tuxedo Java 應用中的TJATMI功能

TJATMI是原生功能的集合,提供客戶端和服務器端的通訊功能,好比調用服務,開始和結束事務,獲取到數據源的鏈接,日誌等等。更多信息參考Java Server Javadoc.

表3-2 TJATMI功能

名字 操做
tpcall 用於在請求/應答通訊中同步調用Oracle Tuxedo服務
tpreturn 用於在Tuxedo Java Server中設置返回值
tpbegin 開始事務
tpcommit 提交當前事務
tpabort 終止當前事務
tpgetlev 檢查事務是否正在執行
getConnection 獲取到已配置的數據源的鏈接
userlog 在Tuxedo用戶日誌文件中打印日誌

注意:在tpreturn結束執行後服務依舊在運行。推薦把tpreturn做爲服務中最後執行的語句。

Tuxedo Java應用的類型緩衝

ATMI Java server 重用了Oracle WebLogic Tuxedo Connector TypedBuffers 做爲相應的Oracle Tuxedo類型緩衝。消息經過類型緩衝傳入 server 。ATMI Java server提供的類型緩衝見表3-3:

表3-3 類型緩衝

緩衝類型 描述
TypedString 數據是以null字符做爲結束的字符數組時使用。Oracle Tuxedo 等價類型:STRING
TypedCArray 數據是未定義字符數組(字節數組),任一字節都有多是null。Oracle Tuxedo等價類型:CARRAY
TypedFML 數據自定義時使用。每一個數據域攜帶本身的標識,事件數,有可能有長度指示器。Oracle Tuxedo等價類型:FML
TypedFML32 相似於TypedFML可是容許更大的字符範圍和域,更大的緩衝。Oracle Tuxedo等價類型:FML32
TypedXML 數據是基於XML的消息。Oracle Tuxedo等價類型:XML
TypedView 應用使用Java結構,使用視圖描述文件來定義緩衝結構。Oracle Tuxedo等價類型:VIEW
TypedView32 相似於View,容許更大的字符範圍、域、緩衝。Oracle Tuxedo等價類型:VIEW32

更多關於類型緩衝的信息,參見"weblogic.wtc.jatmi"

類型緩衝支持的限制

  • TypedFML32Fldid()/Fname()嵌套在另外一個TypedFML32中時沒法工做。爲了應對這種狀況,你可使用fieldtable類傳輸name/id。
  • 目前weblogic.wtc.gwt.XmlViewCnv/XmlFmlCnv類沒法使用。

獲取/設置服務信息

使用TPSVCINFO類經過客戶端獲取/設置服務信息

表3-4 Getter函數

函數 描述
getServiceData 用來返回Oracle Tuxedo客戶端發送過來的服務數據
getServiceFlags 用來返回客戶端發送過來的服務標識
getServiceName 用來返回調用的服務名
getAppKey 獲取程序認證客戶端密鑰
getClientID 獲取客戶端標識符

使用TuxATMIReply從服務請求中獲取迴應數據和元數據

表3-5 用於迴應的Getter函數

函數 描述
getReplyBuffer 返回從服務返回的類型緩衝(多是null)
gettpurcode 返回從服務返回的tpurcode

異常

你須要捕獲服務中JATMI原語拋出的異常,好比tpcall()。JATMI可能拋出兩種類型的異常:

  • TuxATMITPException:該異常拋出代表TJATMI出錯
  • TuxATMITPReplyException:若是服務出錯(TPESVCFAIL或者TPSVCERROR)該異常拋出,用戶數據關聯到異常中。

跟蹤

你還須要導出TMTRACE=atmi:ulog,正如你使用傳統ATMI那樣。TJATMI API跟蹤信息被寫入ULOG。


在Oracle Tuxedo Java Server 中實現服務

典型過程

  1. 定義一個繼承自 TuxedoJavaServer的類
  2. 提供一個默認的構造函數
  3. 實現tpsvrinit()tpsvrdone()方法
  4. 實現服務方法,該方法應該使用TPSVCINFO做爲惟一的參數

    • 使用getTuxAppContext()獲取TuxAppContext對象
    • 使用TPSVCINFO.getServiceData()TPSVCINFO對象中獲取客戶端請求數據
    • 若是配置了數據源,使用TuxAppContext.getConnection()方法獲取到數據源的鏈接
    • 完成商業邏輯,好比使用TuxAppContext.tpcall()調用其餘服務,操縱數據庫等
    • 分配新的類型緩衝,把應答數據放入類型緩衝中
    • 調用TuxAppContext.tpreturn()將應答數據返回客戶端

實例:沒有事務的Java服務實現

以下實例是實現TOUPPER服務的簡單示例。

定義Java類

清單4-1

javaimport weblogic.wtc.jatmi.TypedBuffer;
import weblogic.wtc.jatmi.TypedString;
import com.oracle.tuxedo.tjatmi.*;
public class MyTuxedoJavaServer extends TuxedoJavaServer {
    public MyTuxedoJavaServer()
    {
        return;
    }

    public int tpsvrinit() throws TuxException
    {
        System.out.println("MyTuxedoJavaServer.tpsvrinit()");
        return 0;
    }

    public void tpsvrdone()
    {
        System.out.println("MyTuxedoJavaServer.tpsvrdone()");
        return;
    }

    public void JAVATOUPPER(TPSVCINFO rqst) throws TuxException {
        TypedBuffer svcData;
        TuxAppContext myAppCtxt = null;
        TuxATMIReply myTuxReply = null;
        TypedBuffer replyTb = null;

        /* Get TuxAppContext first */
        myAppCtxt = getTuxAppContext();

        svcData = rqst.getServiceData();
        TypedString TbString = (TypedString)svcData;
        myAppCtxt.userlog("Handling in JAVATOUPPER()");
        myAppCtxt.userlog("Received string is:" + TbString.toString());
        String newStr = TbString.toString();
        newStr = newStr.toUpperCase();
        TypedString replyTbString = new TypedString(newStr);
        /* Return new string to client */
        myAppCtxt.tpreturn(TPSUCCESS, 0, replyTbString, 0);
    }

    public void JAVATOUPPERFORWARD(TPSVCINFO rqst) throws TuxException {
        TypedBuffer svcData;
        TuxAppContext myAppCtxt = null;
        TuxATMIReply myTuxReply = null;
        TypedBuffer replyTb = null;
        long flags = TPSIGRSTRT;
        /* Get TuxAppContext first */
        myAppCtxt = getTuxAppContext();
        svcData = rqst.getServiceData();
        TypedString TbString = (TypedString)svcData;

        myAppCtxt.userlog("Handling in JAVATOUPPERFORWARD()");
        myAppCtxt.userlog("Received string is:" + TbString.toString());
        /* Call another service "TOUPPER" which may be implemented by another Tuxedo Server */
        try {
            myTuxReply = myAppCtxt.tpcall("TOUPPER", svcData, flags);
            /* If success, get reply buffer */
            replyTb = myTuxReply.getReplyBuffer();
            TypedString replyTbStr = (TypedString)replyTb;
            myAppCtxt.userlog("Replied string from TOUPPER:" + replyTbStr.toString());
            /* Return the replied buffer to client */
            myAppCtxt.tpreturn(TPSUCCESS, 0, replyTb, 0);
        } catch (TuxATMITPReplyException tre) {
            myAppCtxt.userlog("TuxATMITPReplyException:" + tre);
            myAppCtxt.tpreturn(TPFAIL, 0, null, 0);
        } catch (TuxATMITPException te) {
            myAppCtxt.userlog("TuxATMITPException:" + te);
            myAppCtxt.tpreturn(TPFAIL, 0, null, 0);
        }
    }
}

建立Java Server配置文件

清單4-2顯示了配置示例,將MyTuxedoJavaServer.JAVATOUPPER()方法導出成Tuxedo 服務JAVATOUPPER,將MyTuxedoJavaServer.JAVATOUPPERFORWARD()方法導出成Tuxedo 服務JAVATOUPPERFORWARD

清單4-2

xml<?xml version="1.0" encoding="UTF-8"?>
<TJSconfig>
    <TuxedoServerClasses>
        <TuxedoServerClass name="MyTuxedoJavaServer"> </TuxedoServerClass>
    </TuxedoServerClasses>
</TJSconfig>

更新UBB配置文件

清單4-3 UBB配置文件

config*GROUPS
TJSVRGRP LMID=simple GRPNO=2
*SERVERS
TMJAVASVR SRVGRP= TJSVRGRP SRVID=4 CLOPT="-- -c TJSconfig.xml"
MINDISPATCHTHREADS=2 MAXDISPATCHTHREADS=2

實例:帶有事務的Java Service實現

清單4-4給出了一個示例,實現WRITEDB_SVCTRN_COMMIT服務,該服務將用戶請求字符串插入表TUXJ_TRAN_TEST中。

定義Java類

清單4-4

javaimport weblogic.wtc.jatmi.TypedBuffer;
import weblogic.wtc.jatmi.TypedString;
import com.oracle.tuxedo.tjatmi.*;
import java.sql.SQLException;
/* MyTuxedoTransactionServer is user defined class */
public class MyTuxedoTransactionServer extends TuxedoJavaServer{
    public MyTuxedoTransactionServer ()
    {
        return;
    }

    public int tpsvrinit() throws TuxException
    {
        System.out.println("In MyTuxedoTransactionServer.tpsvrinit()");
        return 0;
    }

    public void tpsvrdone()
    {
        System.out.println("In MyTuxedoTransactionServer.tpsvrdone()");
        return;
    }

    public void WRITEDB_SVCTRN_COMMIT(TPSVCINFO rqst) throws TuxException {
        TuxAppContext myAppCtxt;
        TypedBuffer rplyBuf = null;
        String strType = "STRING";
        String ulogMsg;
        TypedString rqstMsg;
        Connection connDB = null;
        Statement stmtDB = null;
        String stmtSQL;
        int trnLvl, trnStrtInSVC;
        int trnRtn;
        int rc = TPSUCCESS;
        rqstMsg = (TypedString)rqst.getServiceData();
        myAppCtxt = getTuxAppContext();
        myAppCtxt.userlog("JAVA-INFO: Request Message Is \"" + rqstMsg.toString() + "\"");
        rplyBuf = new TypedString("This Is a Simple Transaction Test from Tuxedo Java Service");
        long trnFlags = 0;
        try {
            trnStrtInSVC = 0;
            trnLvl = myAppCtxt.tpgetlev();
            if (0 == trnLvl) {
                long trnTime = 6000;
                myAppCtxt.userlog("JAVA-INFO: Start a transaction...");
                trnRtn = myAppCtxt.tpbegin(trnTime, trnFlags);
                myAppCtxt.userlog("JAVA-INFO: tpbegin return " + trnRtn);
                trnStrtInSVC = 1;
            }
            connDB = myAppCtxt.getConnection();
            if (null != connDB) {
                myAppCtxt.userlog("JAVA-INFO: Get connection: (" + connDB.toString() + ").");
            }
            stmtDB = connDB.createStatement();
            if (null != stmtDB) {
                myAppCtxt.userlog("JAVA-INFO: Create statement: (" + stmtDB.toString() + ").");
            }
            stmtSQL = "INSERT INTO TUXJ_TRAN_TEST VALUES ('" + rqstMsg.toString() + "')";
            myAppCtxt.userlog("JAVA-INFO: Start to execute sql (" + stmtSQL + ")...");
            stmtDB.execute(stmtSQL);
            myAppCtxt.userlog("JAVA-INFO: End to execute sql (" + stmtSQL +
").");
            if (1 == trnStrtInSVC) {
                myAppCtxt.userlog("JAVA-INFO: tpcommit current transaction...");
                trnRtn = myAppCtxt.tpcommit(trnFlags);
                myAppCtxt.userlog("JAVA-INFO: tpcommit return " + trnRtn);
                trnStrtInSVC = 0;
                if (-1 == trnRtn ) {
                    rc = TPFAIL;
                }
            }
        } catch (TuxATMIRMException e) {
            String errMsg = "ERROR: TuxATMIRMException: (" + e.getMessage() + ").";
            myAppCtxt.userlog("JAVA-ERROR: " + errMsg);
            rc = TPFAIL;
        } catch (TuxATMITPException e) {
            String errMsg = "ERROR: TuxATMITPException: (" + e.getMessage() + ").";
            myAppCtxt.userlog("JAVA-ERROR: " + errMsg);
            rc = TPFAIL;
        } catch (SQLException e) {
            String errMsg = "ERROR: SQLException: (" + e.getMessage() + ").";
            myAppCtxt.userlog("JAVA-ERROR: " + errMsg);
            rc = TPFAIL;
        } catch (Exception e) {
            String errMsg = "ERROR: Exception: (" + e.getMessage() + ").";
            myAppCtxt.userlog("JAVA-ERROR: " + errMsg);
            rc = TPFAIL;
        } catch (Throwable e) {
            String errMsg = "ERROR: Throwable: (" + e.getMessage() + ").";
            myAppCtxt.userlog("JAVA-ERROR: " + errMsg);
            rc = TPFAIL;
        } finally {
            if (null != stmtDB) {
                try {
                    stmtDB.close();
                } catch (SQLException e) {}
            }
        }
        myAppCtxt.tpreturn(rc, 0, rplyBuf, 0);
    }
}

建立Java 服務配置文件

表4-5

xml<?xml version="1.0" encoding="UTF-8"?>
<TJSconfig>
    <ClassPaths>
    <ClassPath>/home/oracle/app/oracle/product/11.2.0/dbhome_2/ucp/lib/ucp.jar
    </ClassPath>
    <ClassPath>/home/oracle/app/oracle/product/11.2.0/dbhome_2/jdbc/lib/ojdbc6.jar</ClassPath>
    </ClassPaths>

    <DataSources>
    <DataSource name="oracle">
    <DriverClass>oracle.jdbc.xa.client.OracleXADataSource</DriverClass>
    <JdbcDriverParams>
    <ConnectionUrl>jdbc:oracle:thin:@//10.182.54.144:1521/javaorcl</ConnectionUrl>
    </JdbcDriverParams>
    </DataSource>
    </DataSources>

    <TuxedoServerClasses>
    <TuxedoServerClass name=" MyTuxedoTransactionServer">
    </TuxedoServerClass>
    </TuxedoServerClasses>
</TJSconfig>

更新UBB配置文件

清單4-6

config*GROUPS
ORASVRGRP LMID=simple GRPNO=1
OPENINFO="Oracle_XA:Oracle_XA+Acc=P/scott/triger+SesTm=120+MaxCur=5+LogDir=.+SqlNet=javaorcl"
TMSNAME=TMSORA TMSCOUNT=2
*SERVERS
TMJAVASVR SRVGRP=ORASVRGRP SRVID=3
    CLOPT="-- -c TJSconfig.xml"
    MINDISPATCHTHREADS=2 MAXDISPATCHTHREADS=4
相關文章
相關標籤/搜索