top
Loading...
編寫Enterprisebean的客戶端(下)
P>

使用bean的句柄:

句柄是用來引用enterprise bean的另一種方法。句柄相當于bean的一個較長的指針。你可以從remote接口獲得句柄。一旦你擁有了句柄,就可以將它寫入到文件或其它的持久存貯器里面。便于以后可以重新得到句柄,用它來重新建立enterprise bean的引用。

但是,你只能用remote接口的句柄來重新建立bean的引用。你不能用句柄來創建bean本身。如果另一個進程刪除了bean,或者系統崩潰或關閉,刪除了bean的實例,則當應用程序試圖用句柄重新建立對bean的引用時會拋出異常。

當你不確定bean的實例是否依然存在的時候,你可以不用remote接口的句柄。而是保存bean的home接口的句柄,在以后要用的時候再通過調用create方法或finder方法重新創建bean對象。

在客戶創建了bean的實例以后,就能夠用getHandle()方法來獲得實例的句柄。一旦擁有的句柄,就能夠將它寫到文件里面去。在以后的時間,客戶可以讀這個文件,將讀出來的對象轉化為句柄類型。然后,就可以在句柄上調用的getEJBObject方法來獲得bean的引用。最后再將getEJBObject方法返回的值轉化為合適的類型。

使用句柄來引用一個Bean

Import java.io;

Import javax.ejb.Handle;

……

Cart cart;

……

cart = home.create(cartHolderName,creditcartNumber,expirationDate);

//在cart對象上調用getHander方法來獲得它的句柄。

CartHander=cart.getHandler();

//將hander寫到文件中去。

FileOutputStream f = new FileOutputStream(“carthandle.ser”);

ObjectOutputStream o = new ObjectOutputStream(f);

o.writeObject(myHandle);

o.flush();

o.close();

……

//在以后的某個時間,可以從文件中讀出handle

FileInputStream fi = new FileInputStream(“carthandle.ser”);

ObjectInputSteam oi = new ObjectInputStream(fi);

//從文件中讀出對象并將它轉化為Hander類型。

CartHanle = (Handle)oi.readObject();

Oi.close;

……

//使用handle來引用bean的實例

try{

Object ref = context.lookup(“cart”);

Cart cart1 = (Cart)javax.rmi.PortableRemoteObject.narrow(ref,Cart.class);

……

}catch(RemoteException e){

……

}

……

當用完會話bean的句柄以后,客戶將使用javax.ejb.EJBHome.remove(Handle handle)方法來刪除句柄。

二、管理事務:

客戶程序能夠管理它自己的事務,而不是讓enterprise bean或者是容器來管理。客戶管理自己事務的時,就好象會話bean管理它自己的事務一樣。

當客戶管理自己的事務的時候,需要自己來描述事務的分界線。這也就是說,它必須明確的開始一個事務和終止(提交或回滾)一個事務。

客戶使用javax.transaction.UserTransaction接口來管理它自己的事務。它必須首先用JNDI來獲得UserTransaction接口的引用。一旦有了UserTranscation的上下文,就可以用UserTransaction.begin()方法來開始一個事務(后面用UserTranscation.commit()方法提交或Usertransction.rollback()方法回滾這個事務)。這之間客戶做有關的查詢和更新操作。

如下代碼演示了客戶如何實現管理它自己的事務。客戶管理的屬于協議的那部分用粗體顯示:

客戶管理事務:

import javax.naming.initialContext;

import javax.transcation.UserTransaction;

……

public class clientTransaction{

public static void main(String[] argv){

UserTranscation ut=null;

InitialContext initContext = new InitialContext();

……

ut = (UserTransaction)initContext.lookup(“java:comp/UserTranscation”);

//開始一個事務

ut.begin();

//做事務工作。

……

ut.commit(); //or ut.rollback();

}

}

三、獲得enterprise bean的信息:

enterprise bean的信息是一個指向metadata引用。客戶使用enterprise bean的home接口的getMetaData()方法能夠獲得bean的metadata信息。

GetMetaData()方法經常被開發環境和build工具所使用,因為它們需要知道enterprise bean的相關信息,例如哪些鏈接到一起的bean已經被安裝。腳本客戶也需要獲得bean的metadata信息。

一旦客戶重新得到home接口的引用。就能夠在home接口上調用getEJBMetaData()方法。然后,客戶就可以通過調用EJBMetaData接口上的方法來取得如下信息。

用EJBMetaData.getEJBHome()方法獲得bean的EJBHome接口。

用EJBMetaData.getHomeInterfaecClass()方法來獲得home接口類的對象。包括其接口,類,域和方法。

用EJBMetaData.getRemoteInterfaceClass()方法來獲得remote接口類的對象。包括所有的類信息。

用EJBMetaData.getPrimaryKeyClass()方法來獲得bean的主鍵類對象。

不管是會話bean還是實體bean。可用EJBMetaData.isSession()方法來判斷。

用EJBMetaData.isStatelessSession()來判斷會話bean是否有狀態還是無狀態的。

四、JNDI的支持:

EJB規范定義了定位home接口的API。JNDI是在其它的服務(CORBA的命名服務,LDAP/X.500,flat files,目錄服務)上面實現的。下圖解釋了不同的實現選擇。典型的,EJB服務提供者選擇一個特定的JNDI實現。

這個技術實現了JNDI底層的與客戶無關性。客戶只需要使用JNDI的API就可以了。

五、EJB到CORBA的映射:

EJB和CORBA之間有許多的聯系。有三點很重要:

用ORB實現EJB容器/服務。

將原有系統放到EJB中間層的綜合能力。

從非java組件的客戶,訪問EJB的能力。

EJB規范目前只涉及到這三個方面。

CORBA是實現EJB下層組織的很適合而且很自然的平臺。CORBA提供了所有的EJB規范與CORBA核心規范或者與CORBA核心服務之間的相關的東西。

持分布式:CORBA核心和CORBA命名服務

支持事務:CORBA對象的事務服務

支持安全:CORBA的安全規范,包括IIOP-over-SSL

另外:CORBA允許非JAVA組件與應用程序的結合。這些組件可以是原來的系統或程序,將它們插入到不同的客戶中去。后端系統能夠很容易的用OTS和任何能夠與IDL映射的程序設計語言結合在一起。這需要容器提供OTS和IIOP的APIs。

EJB規范允許非JAVA客戶訪問enterprise bean,也提供了EJB到CORBA的映射。EJB/CORBA映射的目的是:

支持用任何CORBA支持的程序設計語言編寫的客戶端和基于CORBA的EJB服務上的enterprise bean的結合。

使客戶程序在相同的事務處理中與CORBA對象或者enterprise bean相結合。

支持在涉及到不同代理商提供的多個客戶端在基于CORBA的EJB服務器上運行時的分布式事務。

映射是基于java-to-IDL映射的。其規范包括了如下幾個方面:分布式關系的映射,命名約定的映射,事務處理的映射,安全的映射。下面的部分,我們將解釋每一個映射。因為映射用了新的IDL特性,這些特性在OMG的Object-by-Value規范中介紹。與其它語言的結合需要與CORBA2.3ORB規范兼容。

分布式的映射:

enterprise bean有兩個可以遠程訪問的接口:remote接口和home接口。IDL規范中有這樣的JAVA/IDL到這些接口的映射。EJB規范中定義的基類也是以同樣的方式映射到IDL中的。

例如:讓我們看看下面的IDL接口,這是ATM那個例子。是一個enterprise 會話bean。有一個方法在accounts之間轉帳。也可以拋出資金不足的異常。通過JAVA/IDL映射其home接口和remote接口。我們得到如下的IDL接口:

Module transaction{

Module ejb{

Valuetype InsufficientFundsException: ::java::lang::Exception{};

Exception InsufficientFundsEx{

::transcation::ejb::InsufficientFundsException value;

};

interface Atm: ::javax::ejb::EJBObject{

void transfer(in string arg[], in string arg1, in float arg2)

raise(::transaction::ejb::InsufficientFundsEx);

};

interface AtmHome: ::javax.:ejb::EJBHome{

::transaction::ejb::Atm create{}

raise(::javax::ejb::CreateEx);

};

};

};

命名映射:

基于CORBA的EJB運行時環境如果要想讓所有的CORBA客戶都能夠訪問enterprise bean,就必須使用CORBA命名服務來發布enterprise bean的home接口。運行時能夠直接使用CORBA的命名服務,或者通過JNDI及其到CORBA命名服務的標準映射來間接的使用。

JNDI命名用一個字符串表示成如下形式:“directory1/directory2/…/directotyN/objectName”。CORBA的命名服務將名字定義成一系列的名字組件:

Typedef string Istring;

Struct NameComponet{

Istring id;

Istring kind;

};

typedef sequence $#@60;NameCompoent$#@62; Name;

每一個由”/”分開的JNDI字符串名字都被映射成一個名字組件。最左邊的組件就是CORBA命名服務名字的第一個入口。

JNDI字符串名字與一些命名上下文有關。我們把這樣的上下文叫做JNDI根部上下文。JNDI根部上下文相當于CORBA的命名服務的初始化上下文。CORBA命名服務的名字與CORBA的初始化上下文有關。

通過在ORB的虛擬對象上面調用resolv_initial_reference(“NameService”),CORBA應用程序能夠得到初始的CORBA命名服務的上下文。CORBA命名服務并沒有指定如何組織命名上下文,這樣,根上下文的概念就不起作用了。ORB的初始化通過resolve_initial_reference()來決定上下文。

例如:一個C++的客戶端能夠定位我們的ATM會話bean的home接口。這個ATM bean已經用JNDI字符串“transaction/corbaEjb/atm”注冊。首先,我們得到初始的命名上下文。

oject_ptr obj = orb-$#@62;resolve_initial_references(“NameService”);

NameContext initialNameContext = NameingContext.narrow(obj);

if (initialNameingContext == NULL) {

cerr $#@60;$#@60;”Could not initial naming context” $#@60;$#@60;endl;

exit(1);

}

然后,我們產生了一個CORBA命名服務的名字并且根據上面所說的對它進行初始化。

Name name = new Name(1);

name[0].id=”atm”;

name[0].kind=””;

現在我們解決了初始化命名服務的名字問題。假定我們成功的進行了初始化,我們也有了enterprise bean名字域上的上下文。我們將CORBA對象范圍縮小到所需要的類型,并且,確信這樣的縮小是成功的。

Object_ptr obj=initialNamingContext-$#@62;resolve(name);

AtmSessionHome_ptr atmSessionHome = AtmSessionHome.narrow(obj);

if (atmSessionHome == NULL){

cerr$#@60;$#@60;”Could not narrow to ATMSessionHome” $#@60;$#@60;endl;

exit(1);

}

事務處理的映射:

基于CORBA的enterprise bean運行時環境需要使CORBA的客戶端參加到涉及enterprise bean的事務處理中來,就必須使用CORBA的OTS(Object Transaction Service)來進行事務控制。

當enterprise bean配置好之后,能夠根據不同的事務服務方針進行安裝。方針是定義在配置描述器中的。

事務性的enterprise bean有如下的定義規則:CORBA客戶通過IDL接口產生的stub來調用enterprise bean的remote接口和home接口。如果涉及到事務處理,它使用CORBA OTS提供的接口。

例如:一個C++的客戶能夠調用ATM會話bean:

try{

//obtain transaction current

Object_ptr obj = orb-$#@62;resolve_initial_reference(“Current”);

Current current = Current.narrow(obj);

if(current==NULL){

cerr$#@60;$#@60;”Could not resolve current ”$#@60;$#@60;endl;

exit(1);

}

//execute transaction

try{

current-$#@62;begin();

atmSession-$#@62;transfer(“checking”,”saving”,100.00);

current-$#@62;commit(0);

}catch(…){

current-$#@62;rollback();

}

}catch(…){

……

}

安全的映射:

EJB規范的安全方面主要考慮的是控制enterprise bean的訪問權限。CORBA規定了一些方法來定義標識符,包括如下的方面:

Plain IIOP(簡單的IIOP方式):CORBA的主要接口在1998年早期并沒有被接受。主要的接口用來確定客戶的標識。但是,CORBA安全服務的作者卻實現了不同的途徑:GIOP。GIOP規范包括了一個叫服務上下文的組件,其實是一個元素為值對的數組。其標識符是CORBA的long型的,值是十進制的序列。服務上下文的入口可以用來標識調用者。

Secure IIOP(可靠的IIOP方式):CORBA的安全規范為身份定義了一個不透明的數據類型。身份的實際類型是由所選擇的安全機制所決定的。例如:GSS Kerberos,SPKM,或者CSI-ECMA。

IIOP over SSL:SSL(加密套接字協議層)用X.509來來證明服務器或者是客戶的身份。當服務器需要客戶的身份驗證的時候,服務器使用這個證書作為客戶的身份驗證。

作者:http://www.zhujiangroad.com
來源:http://www.zhujiangroad.com
北斗有巢氏 有巢氏北斗