本文討論如何讓用 CORBA 支持的任何語言編寫的客戶端能夠訪問 Enterprise JavaBeansTM 組件 (“EJBTM 組件”)。本文針對(duì)深入了解 JavaTM 2 Platform, Enterprise Edition ("J2EETM") 和公共對(duì)象請(qǐng)求代理結(jié)構(gòu)(Common Object Request Broker Architecture,CORBA)的程序員。
J2EE 技術(shù)簡化了企業(yè)應(yīng)用程序,因?yàn)樗鼘⑺鼈兘⒃跇?biāo)準(zhǔn)、模塊化和可重用組件的基礎(chǔ)上,而該組件又基于 Enterprise JavaBeansTM (EJBTM) 體系結(jié)構(gòu),它也提供了完整的一組針對(duì)于那些組件的服務(wù),并自動(dòng)處理應(yīng)用程序行為的許多細(xì)節(jié)。通過自動(dòng)化應(yīng)用程序開發(fā)的許多耗時(shí)且困難的任務(wù),J2EE 技術(shù)使企業(yè)開發(fā)人員能夠?qū)⒅攸c(diǎn)放在增值上,也就是增強(qiáng)業(yè)務(wù)邏輯,而不是放在構(gòu)建基礎(chǔ)結(jié)構(gòu)上。
EJBTM 服務(wù)器端組件模型簡化了事務(wù)型、可伸縮和可移植的中間件組件的開發(fā)。Enterprise JavaBeans 服務(wù)器減少了中間件開發(fā)的復(fù)雜程度,因?yàn)樗鼮橹T如事務(wù)、安全、數(shù)據(jù)庫連接等中間件服務(wù)提供了支持。
CORBA 是一個(gè)對(duì)象管理組織(Object Management Group,OMG)標(biāo)準(zhǔn),它是一個(gè)開放的、供應(yīng)商無關(guān)的體系結(jié)構(gòu)和基礎(chǔ)結(jié)構(gòu),計(jì)算機(jī)應(yīng)用程序可以使用它來通過網(wǎng)絡(luò)一起工作。由于使用了標(biāo)準(zhǔn)的 Internet Inter-ORB Protocol,(IIOP),因些來自任何供應(yīng)商的基于 CORBA 的程序可以與來自相同或其他供應(yīng)商的基于 CORBA 程序進(jìn)行互操作,前一程序可以在幾乎所有的計(jì)算機(jī)、操作系統(tǒng)、編程語言和網(wǎng)絡(luò)上,后一程序可以在幾乎所有的其他計(jì)算機(jī)、操作系統(tǒng)、編程語言和網(wǎng)絡(luò)上。 要進(jìn)一步學(xué)習(xí) CORBA,請(qǐng)?jiān)L問 http://www.omg.org/gettingstarted/gettingstartedindex.htm。
CORBA 技術(shù)補(bǔ)充了 Java 平臺(tái),因?yàn)樗峁┝朔植际綄?duì)象框架、支持此框架的服務(wù)以及與其他語言的互操作性。CORBA 技術(shù)是 Java 2 平臺(tái)的主要部分,它正用于 Enterprise JavaBeans 組件、 運(yùn)行在 Internet Inter-ORB 協(xié)議上的Java 遠(yuǎn)程方法調(diào)用 API ("Java RMI-IIOP"),以及 Java IDL API ("Java IDL")。
OMG 接口定義語言(Interface Definition Language,IDL)可用于描述一些接口,該接口由遠(yuǎn)程對(duì)象實(shí)現(xiàn)。IDL 可用于定義接口的名稱,以及定義每個(gè)屬性和方法的名稱。一旦創(chuàng)建 IDL 文件,就可以在任何語言中,使用 IDL 編譯器來生成客戶端存根模塊 (stub) 和服務(wù)器骨架語句 (server skeleton),OMG已經(jīng)為此定義了這種語言映射的規(guī)范。要進(jìn)一步了解 OMG IDL,請(qǐng)?jiān)L問 http://www.omg.org/gettingstarted/omg_idl.htm。
Java IDL 使得分布式 Java 應(yīng)用程序能夠透明地調(diào)用遠(yuǎn)程網(wǎng)絡(luò)服務(wù)上的操作,而該服務(wù)使用對(duì)象管理組織 (http://www.omg.org/) 定義的行業(yè)標(biāo)準(zhǔn) OMG IDL 和 IIOP。運(yùn)行在 IIOP API 上的 Java RMI 使得可以通過 javax.rmi
API 來對(duì) CORBA 服務(wù)器和應(yīng)用程序進(jìn)行編程。
編寫 EJB 組件的開發(fā)人員可以遵循 Java RMI 編程模型,并將它用于他們的分布式對(duì)象模型,在該模型中,跨越所有應(yīng)用程序服務(wù)器常見的所需傳輸是 Java RMI-IIOP。在異構(gòu)服務(wù)器環(huán)境中,到 CORBA 的 EJB 體系結(jié)構(gòu)的標(biāo)準(zhǔn)映射使得能夠進(jìn)行下述的互操作:
- 使用來自某一供應(yīng)商 ORB 的客戶端可以訪問駐留在服務(wù)器上的企業(yè) bean,而該服務(wù)器支持由另一供應(yīng)商提供的 Enterprise JavaBeans 技術(shù)(“EJB 服務(wù)器”)。
- 一臺(tái) EJB 服務(wù)器上的企業(yè) bean 可以訪問另一臺(tái) EJB 服務(wù)器上的企業(yè) bean。
- 除了Java 編程語言之外,用某一語言編寫的 CORBA 客戶端可以訪問任何 EJB 組件,前提是要有一個(gè)從 OMG IDL 到那種編程語言的映射。
本文檔的其余部分提供了 CORBA 客戶端應(yīng)用程序的例子,該應(yīng)用程序訪問了企業(yè) bean 對(duì)象。在本文檔中,CORBA 客戶端就是使用 CORBA 支持的任何語言編寫的客戶端應(yīng)用程序,這些編程語言包括 Java 編程語言、C++、C、Smalltalk、COBOL、Ada、Lisp 或 Python。雖然本例中的 Java 代碼特定于企業(yè) bean,但開發(fā) CORBA 的客戶端的過程是相同的,并且開發(fā)的 CORBA 客戶端可以訪問使用 Java RMI-IIOP API 創(chuàng)建的服務(wù)器。
可以在 鏈接到類似例子 中找到一些鏈接,它們指向其他實(shí)現(xiàn)了 J2EE 技術(shù)的供應(yīng)商提供的類似應(yīng)用程序。
開發(fā)訪問 Enterprise JavaBean 組件的 CORBA 客戶端
這是一個(gè)關(guān)于如何開發(fā) CORBA 客戶端應(yīng)用程序以便訪問 EJB 組件的例子。在本例中,客戶端是用 C++ 編程語言編寫的,但客戶端可以是由 CORBA 支持的任何語言編寫的。
下面的幾節(jié)展示了 CORBA 客戶端的一般開發(fā)過程,開發(fā)完的 CORBA 客戶端可以訪問企業(yè) bean:
- 編寫 Enterprise JavaBean 組件
- 生成 CORBA IDL
- 創(chuàng)建 CORBA 客戶端
- 部署 Enterprise JavaBean 組件
- 運(yùn)行客戶端可執(zhí)行文件
為了使例子變得簡單,我們采取了一些捷徑。有關(guān)構(gòu)建更加高級(jí)的解決方案的信息,請(qǐng)參閱 針對(duì)復(fù)雜接口的技巧。
- 在
/Java/src/ejbinterop
目錄中創(chuàng)建如下文件:Logger.java
、LoggerHome.java
、LoggerEJB.java
和LogMessage.java。
- 編譯本節(jié)編寫的文件,例如:
javac -classpath $J2EE_HOME/lib/j2ee.jar:.. *.java
這些命令在當(dāng)前目錄中為所有的 .java 文件創(chuàng)建了類文件。這個(gè)命令和本文中的其他命令假定已經(jīng)正確設(shè)置了 J2EE_HOME 環(huán)境變量。使用 $J2EE_HOME 是 Unix? 操作系統(tǒng)的規(guī)定。當(dāng)在 Microsoft Windows 操作環(huán)境中,請(qǐng)?zhí)鎿Q %J2EE_HOME%。
第 2 部分:生成 CORBA IDL
本節(jié)討論如何從 Java 類文件中生成接口定義語言(Interface Definition Language,IDL),并且假定 Java 類文件已在前一節(jié)中生成。在本例中,我們將使用
rmic
編譯器,以便將 Java 代碼映射到 IDL。IDL 提供了純聲明性的、編程語言無關(guān)的方式來指定對(duì)象的 API。- 針對(duì) Java 類文件運(yùn)行
在前面的例子中,我們包括了 .jar 文件和rmic
編譯器,該 Java 類文件已在前一步驟中生成,其命令如下:rmic -idl -noValueMethods -classpath $J2EE_HOME/lib/j2ee.jar:<path_to_ejbinterop_dir> -d <path_to_where_idl_files_should_be_generated> ejbinterop.Logger ejbinterop.LoggerHome
ejbinterop
文件的目錄,.jar 文件中包含有javax.ejb
包的定義。如果您正在使用 JavaTM 2 Platform, Enterprise Edition (J2EETM), version 1.3 Reference Implementation (RI),那么.jar
文件就位于$J2EE_HOME/lib/j2ee.jar
。在上面的
rmic
命令行中,我們推薦了一種捷徑——使用noValueMethods
選項(xiàng)。這個(gè)選項(xiàng)告訴rmic
跳過具有參數(shù)或返回類型的任何方法,這里的返回類型將被映射到 CORBA 值類型。有利的方面在于它將防止我們生成許多不必要的 IDL,在 C++客戶端中,我們可能必須實(shí)現(xiàn)這些 IDL。不利的方面在于我們只能使用原始的數(shù)據(jù)類型、數(shù)組和字符串,而不能使用自己的 Java 類類型來作為參數(shù)或返回類型。 有關(guān)進(jìn)一步信息,請(qǐng)閱讀 針對(duì)復(fù)雜接口的技巧。在 Java 類文件上運(yùn)行
rmic
編譯器會(huì)生成下面的一些文件,文件所處的目錄由上面rmic
語句的 -d 選項(xiàng)指出:java/lang/Ex.idl
java/lang/Exception.idl
java/lang/Object.idl
java/lang/Throwable.idl
java/lang/ThrowableEx.idl
javax/ejb/CreateEx.idl
javax/ejb/CreateException.idl
javax/ejb/EJBHome.idl
javax/ejb/EJBMetaData.idl
javax/ejb/EJBObject.idl
javax/ejb/Handle.idl
javax/ejb/HomeHandle.idl
javax/ejb/RemoveEx.idl
javax/ejb/RemoveException.idl
ejbinterop/Logger.idl
ejbinterop/LoggerHome.idl
- 注意:許多生成文件包含了只能在 Java 編程環(huán)境中使用的 API 。 例如,目前
EJBMetaData
實(shí)現(xiàn)特定于每個(gè)應(yīng)用程序服務(wù)器,因此很難開發(fā)等效設(shè)施,以便在除 Java 平臺(tái)外的平臺(tái)上繼續(xù)超時(shí)工作。一種選擇是將它們從 IDL 中刪除,但如果這樣做,那么每次改變 Java 接口,并從rmic
編譯器中重生成 IDL 文件時(shí),就必須從 IDL 中刪除它們。
-
注意: 由于 CORBA 異常不支持繼承,因此針對(duì) IDL 映射的 Java 語言創(chuàng)建了
Ex
類,它包含了代表實(shí)際 Java 異常的 CORBA 值類型。在這個(gè)基本的例子中,不必過多擔(dān)心異常支持。有關(guān)異常的進(jìn)一步信息,請(qǐng)參閱http://java.sun.com/j2se/1.4.2/docs/guide/idl/jidlExceptions.html
。
- 針對(duì) Java 類文件運(yùn)行
- 使用 C++ 供應(yīng)商的“IDL to C++”編譯器來編譯 IDL 文件,以便生成對(duì)應(yīng)于 IDL 的 C++ 代碼。不同的供應(yīng)商之間,這個(gè)過程的步驟會(huì)有區(qū)別,因此有必要參考產(chǎn)品文檔,取得針對(duì)供應(yīng)商的特定步驟。
第 3 部分:創(chuàng)建 CORBA 客戶端
客戶端應(yīng)用程序可以使用 CORBA 支持的任何語言編寫。下面的例子提供了針對(duì)于 C++ 客戶端的代碼,只要給予對(duì)象請(qǐng)求代理人( Object Request Broker,簡稱 ORB)和
LoggerHome
對(duì)象的corbaname
URL,它就會(huì)在服務(wù)器上將簡單字符串消息記錄到日志中。您必須根據(jù) C++ ORB 供應(yīng)商的庫來調(diào)整include
語句,并修改注冊(cè)值工廠的代碼。本例是針對(duì) ORBacus for C++ 4.0.5 編寫的,因此本例中的一些 C++ 代碼是特定于該產(chǎn)品的。corbaname
URL 是可閱讀的 URL 格式,它允許您訪問 CORBA 對(duì)象。它用于從特定命名上下文解析字符串化的名稱。這是 J2EE v 1.3 平臺(tái)中的新特性,它作為 CORBA 互操作命名服務(wù)(Interoperable Naming Service,簡稱 INS)的一部分。INS 是 CORBA 對(duì)象服務(wù)(CORBA Object Services,簡稱COS)命名服務(wù)的擴(kuò)展,在以前版本的 J2EE 平臺(tái)中已經(jīng)交付使用。為了進(jìn)一步了解 INS,請(qǐng)?jiān)L問 http://java.sun.com/j2se/1.4.2/docs/guide/idl/jidlNaming.html#INS。- 創(chuàng)建對(duì)象請(qǐng)求代理(ORB)。ORB 將對(duì)象請(qǐng)求服務(wù)連接到提供它們的對(duì)象。
- 注冊(cè)值工廠。
- 在命名上下文中查找
corbaname
URL 指向的LoggerHome
對(duì)象。 - 從返回給
LoggerHome
對(duì)象的對(duì)象中執(zhí)行安全的向下轉(zhuǎn)換。 - 創(chuàng)建
LoggerEJB
對(duì)象引用。 - 在日志中記錄消息。
- 告訴應(yīng)用程序服務(wù)器不再使用 EJB 引用。
- 使用類似于下面的 C++ 代碼來創(chuàng)建客戶端。準(zhǔn)確的代碼可能與 C++ 實(shí)現(xiàn)有關(guān)。這些代碼是針對(duì)于 ORBacus for C++ 4.0.5 編寫的,因此本例中的一些 C++ 代碼可能特定于該產(chǎn)品。
//Code Example: Client.cpp #include <fstream.h> // C++ ORB Vendor specific include files // These are from C++ ORBacus 4.0.5 #include <OB/CORBA.h> #include <OB/OBORB.h> // Include files generated from our IDL #include <java/lang/Exception.h> #include <java/lang/Throwable.h> #include <javax/ejb/CreateException.h> #include <javax/ejb/RemoveException.h> #include <ejbinterop/Logger.h> #include <ejbinterop/LoggerHome.h> /** * Given an ORB and a corbaname URL for a LoggerHome * object, logs a simple string message on the server. */ void run(CORBA::ORB_ptr orb, const char* logger_home_url) { cout << "Looking for: " << logger_home_url << endl; // Look up the LoggerHome object in the naming context // pointed to by the corbaname URL CORBA::Object_var home_obj = orb->string_to_object(logger_home_url); // Perform a safe downcast ejbinterop::LoggerHome_var home = ejbinterop::LoggerHome::_narrow(home_obj.in()); assert(!CORBA::is_nil(home)); // Create a Logger EJB reference ejbinterop::Logger_var logger = home->create(); CORBA::WStringValue_var msg = new CORBA::WStringValue((const CORBA::WChar*)L"Message from a C++ client"); cout << "Logging..." << endl; // Log our message logger->logString(msg); // Tell the application server we won't use this // EJB reference any more logger->remove(); cout << "Done" << endl; } /** * Simple main method that checks arguments, creates an * ORB, and handles exceptions. */ int main(int argc, char* argv[]) { int exit_code = 0; CORBA::ORB_var orb; try { // Check the arguments if (argc != 2) { cerr << "Usage: Client <corbaname URL of LoggerHome>" << endl; return 1; } // Create an ORB orb = CORBA::ORB_init(argc, argv); // Register value factories // NOTE: This is overkill for the example since we'll never // get these exceptions. Also, the _OB_id method is a // proprietary feature of ORBacus C++ generated code. CORBA::ValueFactory factory = new java::lang::Throwable_init; orb -> register_value_factory(java::lang::Throwable::_OB_id(), factory); factory -> _remove_ref(); factory = new java::lang::Exception_init; orb -> register_value_factory(java::lang::Exception::_OB_id(), factory); factory -> _remove_ref(); factory = new javax::ejb::CreateException_init; orb -> register_value_factory(javax::ejb::CreateException::_OB_id(), factory); factory -> _remove_ref(); factory = new javax::ejb::RemoveException_init; orb -> register_value_factory(javax::ejb::RemoveException::_OB_id(), factory); factory -> _remove_ref(); // Perform the work run(orb, argv[1]); } catch(const CORBA::Exception& ex) { // Handle any CORBA related exceptions cerr << ex._to_string() << endl; exit_code = 1; } // Release any ORB resources if (!CORBA::is_nil(orb)) { try { orb -> destroy(); } catch(const CORBA::Exception& ex) { cerr << ex._to_string() << endl; exit_code = 1; } } return exit_code; }
- 使用 C++ 編譯器來編譯所有的 C++ 文件,包括 Client.cpp 文件,創(chuàng)建客戶端可執(zhí)行文件。不同平臺(tái)之間,這樣的一些工具的區(qū)別甚大,因此有必要參考產(chǎn)品文檔,獲得它的說明。
第 4 部分:部署 Enterprise JavaBean 組件
- 使用滿意的應(yīng)用程序服務(wù)器部署企業(yè) bean。下面的一些步驟描述了如何部署
LoggerEJB
組件,它使用了 J2EE 1.3 Reference Implementation (RI)。- 通過鍵入如下命令,從終端窗口或命令行提示中啟動(dòng) RI 應(yīng)用程序:
$J2EE_HOME/bin/j2ee -verbose
- 當(dāng) J2EE 1.3 RI 指出“J2EE 啟動(dòng)完成”時(shí),鍵入如下命令,從另一終端窗口或命令提示中運(yùn)行部署工具:
$J2EE_HOME/bin/deploytool
- 從部署工具中,選擇
File
->
New
->
Application。
- 在 Application File Name 字段中,輸入
Logger.ear
,以指出要在其中創(chuàng)建應(yīng)用程序的文件。 - 在 Application Display Name 字段中,輸入
Logger。
- 選擇 OK 來保存設(shè)置,關(guān)閉這個(gè)對(duì)話窗口。
- 從部署工具中,選擇
File
->
New
->
Enterprise Bean。
- 如果出現(xiàn) Introduction 屏幕,選擇 Next,否則繼續(xù)。
- 在 New EnterpriseBean Wizard 中,在 Contents 框中選擇 Edit。
- 擴(kuò)展 Available Files 列表,添加下面的 4 個(gè)
.class
文件,它們來自ejbinterop
包:Logger.class
、LoggerHome.class
、LoggerEJB.class
和LogMessage.class
。選擇 OK,然后選擇 Next。 - 選擇
Stateless
Session
Bean
Type。
- 選擇
ejbinterop.LoggerEJB
用于Enterprise
Bean
Class
。 - 選擇
ejbinterop.LoggerHome
用于Remote
Home
Interface
。 - 選擇
ejbinterop.Logger
用于Remote
Interface
。 - 選擇 Next 按扭,直到看到
Security
Settings
頁。 - 選擇
Deployment
Settings
按扭。 - 選擇
Support
Client
Choice
. - 選擇 OK 保存設(shè)置并關(guān)閉這個(gè)對(duì)話窗口。
- 選擇 Finish.
- 從部署工具中,選擇
Tools
->
Deploy。
- 如果只運(yùn)行 Java RMI-IIOP 客戶端,選擇 Return Client JAR。
- 選擇 Next。
- 在
JNDI
Name
for our LoggerEJB 字段中輸入ejbinterop/logger
。 - 選擇 Finish。
- 選擇 File -> Exit 來退出部署工具。
現(xiàn)在已經(jīng)部署了具有
LoggerEJB
組件的 Logger 應(yīng)用程序,它準(zhǔn)備接收消息。第 5 部分:運(yùn)行客戶端可執(zhí)行文件
- 運(yùn)行客戶端可執(zhí)行文件。運(yùn)行客戶端可執(zhí)行程序的一種方法是,切換到包含可執(zhí)行客戶端文件的目錄,然后在終端窗口中輸入下面的 URL:
Client corbaname:iiop:1.2@localhost:1050#ejbinterop/logger
Client
是要運(yùn)行的應(yīng)用程序的名稱。corbaname
指出將從特定的命名上下文中解析字符串化的名稱。iiop:1.2
告訴 ORB 使用 IIOP 協(xié)議和 GIOP 1.2。- 要在其上查找引用的宿主計(jì)算機(jī)是
localhost
——本地計(jì)算機(jī)。為了擴(kuò)展這個(gè)例子,以便在兩臺(tái)計(jì)算機(jī)上運(yùn)行,請(qǐng)輸入計(jì)算機(jī)的 IP 地址和主機(jī)名,而不是localhost
,服務(wù)器要在該計(jì)算機(jī)上運(yùn)行。 1050
是端口號(hào),命名服務(wù)會(huì)在該端口上偵聽請(qǐng)求。 在 J2EE v.1.3 RI 中,默認(rèn)情況下,命名服務(wù)要在其上偵聽的默認(rèn)端口號(hào)是端口 1050。到目前為止,散列標(biāo)記 (hash mark) 上的引用部分(Client corbaname:iiop:1.2@localhost:1050
) 是某個(gè) URL,它返回根命名上下文。ejbinterop/logger
是要在命名上下文中解析的名稱。
如果您正在使用 J2EE 1.3 Reference Implementation,應(yīng)該會(huì)看到類似于如下的一條消息,該消息是在應(yīng)用程序服務(wù)器上被打印的:
Sep 21, 2001 3:33:07 PM PDT: Message from a C++ client
ejbinterop/ logger
is the name to be resolved from the Naming Service.第 6 部分:停止 J2EE 服務(wù)器
- 停止 J2EE 服務(wù)器。為了停止服務(wù)器,可以在終端窗口或命令行提示中,輸入這條命令。
$J2EE_HOME/bin/j2ee -stop
不同的操作系統(tǒng)之間,停止運(yùn)行中進(jìn)程的過程是不同的,因此如果正在使用不同的服務(wù)器,可以參考系統(tǒng)文檔以取得詳細(xì)信息。
第 1 部分:編寫 Enterprise JavaBean 組件
下面的一些例子展示了企業(yè) bean 的代碼,它將從 Java RMI-IIOP 和 CORBA 客戶端接收發(fā)送給應(yīng)用程序服務(wù)器的字符串日志消息。企業(yè) bean 將在服務(wù)器上把它們與當(dāng)前服務(wù)器時(shí)間一起打印出來。
Logger.java
Logger.java
文件是企業(yè) bean 的遠(yuǎn)程接口,因此,它擴(kuò)展了 EJBObject
。遠(yuǎn)程接口提供了 EJB 對(duì)象的遠(yuǎn)程客戶端視圖,并定義了可由遠(yuǎn)程客戶端調(diào)用的 business 方法。
//Code Example 1: Logger.java package ejbinterop; import javax.ejb.EJBObject; import java.rmi.RemoteException; /** * Accepts simple String log messages and prints * them on the server. */ public interface Logger extends EJBObject { /** * Logs the given message on the server with * the current server time. */ void logString(String message) throws RemoteException; }
LoggerHome.java
LoggerHome.java
文件擴(kuò)展了 EJBHome
。EJBHome
接口必須由所有 EJB 組件的遠(yuǎn)程 home 接口來擴(kuò)展。home 接口定義了一些方法,使得遠(yuǎn)程客戶端可以創(chuàng)建、查找和刪除 EJB 對(duì)象,以及創(chuàng)建、查找和刪除不針對(duì) EJB 實(shí)例的 home business 方法。
//Code Example 2: LoggerHome.java package ejbinterop; import java.rmi.RemoteException; import javax.ejb.EJBHome; import javax.ejb.CreateException; public interface LoggerHome extends EJBHome { Logger create() throws RemoteException, CreateException; }
LoggerEJB.java
LoggerEJB.java
文件包含了會(huì)話 bean 的代碼。會(huì)話 bean 是一種企業(yè) bean,它由客戶端創(chuàng)建,并且通常只在一個(gè)客戶/服務(wù)器會(huì)話期間存在。會(huì)話 bean 執(zhí)行像計(jì)算或訪問客戶端數(shù)據(jù)庫這樣的操作。在本例中,企業(yè) bean 從客戶端接收簡單的字符串日志消息,并在服務(wù)器上打印它們。
//LoggerEJB.java package ejbinterop; import javax.ejb.*; import java.util.*; import java.rmi.*; import java.io.*; /** * Accepts simple String log messages and prints * them on the server. */ public class LoggerEJB implements SessionBean { public LoggerEJB() {} public void ejbCreate() {} public void ejbRemove() {} public void ejbActivate() {} public void ejbPassivate() {} public void setSessionContext(SessionContext sc) {} /** * Logs the given message on the server with * the current server time. */ public void logString(String message) { LogMessage msg = new LogMessage(message); System.out.println(msg); } }
LogMessage.java
LogMessage.java
文件取得當(dāng)前的日期和時(shí)間,然后創(chuàng)建格式化字串來顯示消息,并將消息打印到服務(wù)器。
//LogMessage.java package ejbinterop; import java.io.Serializable; import java.util.Date; import java.text.*; /** * Simple message class that handles pretty * printing of log messages. */ public class LogMessage implements Serializable { private String message; private long datetime; /** * Constructor taking the message. This will * take the current date and time. */ public LogMessage(String msg) { message = msg; datetime = (new Date()).getTime(); } /** * Creates a formatted String showing the message. */ public String toString() { StringBuffer sbuf = new StringBuffer(); DateFormat dformat = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.LONG); FieldPosition fpos = new FieldPosition(DateFormat.DATE_FIELD); dformat.format(new Date(datetime), sbuf, fpos); sbuf.append(": "); sbuf.append(message); return sbuf.toString(); } }
創(chuàng)建 Java RMI-IIOP 客戶端應(yīng)用程序
使用相同的例子,可以容易地開發(fā)連接到企業(yè) bean 的 Java RMI-IIOP 客戶端,。與使用 C++ 的例子的區(qū)別在于:
- 在客戶端 CLASSPATH 中,必須包括客戶端
.jar
文件的位置,該文件是由運(yùn)行需要的企業(yè) bean 的應(yīng)用程序服務(wù)器創(chuàng)建的。那個(gè).jar
文件包含了必要的客戶端存根模塊。 - 當(dāng)使用 J2EE 1.3 RI 部署應(yīng)用程序時(shí),檢查 Deploy 屏幕第一頁上的 Deploytool 中的
Return Client Jar
框。
下面的代碼是 Java RMI-IIOP 版本的 LoggerEJB
組件客戶端。遵循與 C++ 客戶端例子所展示的相同步驟。當(dāng)運(yùn)行客戶端時(shí),使用與 C++ 例子中相同的 URL。
//Code Example: LogClient.java package ejbinterop; import java.rmi.RemoteException; import javax.rmi.*; import java.io.*; import javax.naming.*; import javax.ejb.*; /** * Simple Java RMI-IIOP client that uses an EJB component. */ public class LogClient { /** * Given a corbaname URL for a LoggerHome, * log a simple String message on the server. */ public static void run(String loggerHomeURL) throws CreateException, RemoveException, RemoteException, NamingException { System.out.println("Looking for: " + loggerHomeURL); // Create an InitialContext. This will use the // CosNaming provider we will specify at runtime. InitialContext ic = new InitialContext(); // Lookup the LoggerHome in the naming context // pointed to by the corbaname URL Object homeObj = ic.lookup(loggerHomeURL); // Perform a safe downcast LoggerHome home = (LoggerHome)PortableRemoteObject.narrow(homeObj, LoggerHome.class); // Create a Logger EJB reference Logger logger = home.create(); System.out.println("Logging..."); // Log our message logger.logString("Message from a Java RMI-IIOP client"); // Tell the application server we won't use this // EJB reference anymore logger.remove(); System.out.println("Done"); } /** * Simple main method to check arguments and handle * exceptions. */ public static void main(String args[]) { try { if (args.length != 1) { System.out.println("Args: corbaname URL of LoggerHome"); System.exit(1); } LogClient.run(args[0]); } catch (Throwable t) { t.printStackTrace(); System.exit(1); } } }
使用 Java RMI-IIOP 客戶端運(yùn)行應(yīng)用程序
當(dāng)使用 Java RMI-IIOP 客戶端,而不是 C++ 客戶端運(yùn)行示例應(yīng)用程序時(shí),請(qǐng)遵循這些步驟:
- 使用下面的命令,在
ejbinterop
/ 目錄中編譯 .java
文件:javac -classpath $J2EE_HOME/lib/j2ee.jar:<ejbinterop_directory> *.java
- 像 部署 Enterprise JavaBean 組件中所描述的那樣部署 Enterprise JavaBean 組件。當(dāng)運(yùn)行 Java RMI-IIOP 客戶應(yīng)用程序時(shí),記得在 Tools -> Deploy 頁中選擇 Return Client JAR 。 Deployment 主題中的一些命令指導(dǎo)您啟動(dòng) J2EE RI 或其他應(yīng)用程序服務(wù)器。
- 使用類似于如下命令運(yùn)行客戶應(yīng)用程序:
java -classpath $J2EE_HOME/lib/j2ee.jar: <path to LoggerClient.jar>/LoggerClient.jar: <directory_above_ejbinterop>:<ejbinterop_directory> ejbinterop.LogClient corbaname:iiop:1.2@localhost:1050#ejbinterop/logger
在 J2EE RI 正在運(yùn)行的窗口中,將會(huì)看到:
Jan 31, 2002 2:27:47 PM PST: Message from a Java RMI-IIOP client
在運(yùn)行客戶端的窗口中,將會(huì)看到:
Looking for: corbaname:iiop:1.2@localhost:1050#ejbinterop/logger Logging... Done
- 停止 J2EE 服務(wù)器。
超越基本應(yīng)用程序
如何增強(qiáng)應(yīng)用程序
- 開發(fā)使用值類型的例子。
為達(dá)到此目的,當(dāng)運(yùn)行
rmic
時(shí)刪除-noValueMethods
開關(guān)。重新運(yùn)行 C++ 語言的 IDL 的映射編譯器,檢查它是否支持已經(jīng)生成的值類型。 - 在
Logger
中添加另一方法,它實(shí)際取得LogMessage
。
針對(duì)復(fù)雜接口的技巧
對(duì)于運(yùn)用不同語言的客戶端和服務(wù)器之間的通信,接口是關(guān)鍵。為了在這方面獲得成功,應(yīng)該考慮下面的建議:
- 避免將復(fù)雜的 Java 類,比如
java.util
中的集合,用于方法參數(shù)或返回類型。在將這些類開映射到 IDL 后,將強(qiáng)制您使用客戶端編程語言實(shí)現(xiàn)它們。此外,由于 Java Object Serialization 和 RMI-IIOP API 使得類的線路格式和內(nèi)部表示能夠隨時(shí)間不斷發(fā)展,因此您的 CORBA 客戶端應(yīng)用程序可能在不同的 JavaTM 2 Platform, Standard Edition (J2SETM) 實(shí)現(xiàn)或版本上不兼容。
- 從 IDL 開始。
您可能想在返回類型或方法參數(shù)中使用復(fù)雜的數(shù)據(jù)結(jié)構(gòu)。在本例中,試著從 IDL 開始。在 IDL 中定義數(shù)據(jù)結(jié)構(gòu),甚至定義異常,然后將它們用在 EJB 接口中。這將可以防止逆向映射的產(chǎn)出物進(jìn)入 CORBA 接口。
例如,剛開始試著在 IDL 中定義
LogMessage
類,然后在 Logger EJB 組件中,將 IDL 編譯的 Java 語言結(jié)果類用作方法參數(shù)。 - 避免重載 EJB 接口。
CORBA IDL 不支持方法重載,符合 IDL 映射規(guī)范的 Java 語言解決了這一點(diǎn),其方式是創(chuàng)建 IDL 方法定義,將方法名與它的所有 IDL 參數(shù)類型組合起來。對(duì)于使用非 Java 編程語言的開發(fā)人員來說,這帶來了非常不友好的方法名。
- 考慮使用橋。
如果可用的選項(xiàng)仍然太有限,或者影響到想編寫的代碼,就可以考慮使用服務(wù)器端橋。在“鏈接到類似例子”一節(jié)列出了一些站點(diǎn),您可以從這些站點(diǎn)中獲得更多有關(guān)如何構(gòu)建橋的信息。
鏈接到類似例子
實(shí)現(xiàn) J2EE 技術(shù)的幾個(gè)供應(yīng)商都有一些優(yōu)秀的例子和技巧,用于集成 CORBA 和 Enterprise JavaBeans 技術(shù):
- IONA - EJB-CORBA and CORBA-EJB Interoperability 位于 http://www.iona.com/whitepapers/CORBA-EJBInteropWPV02-00.pdf。
- BEA - EJB-to-CORBA/Java Simpapp Sample Application 位于 http://edocs.bea.com/wle/wle50/interop/ejbcorba.htm。
- Borland - Sevens steps to build a VisiBroker C++ CORBA Client for an EJB Server 位于 http://www.borland.com/devsupport/appserver/faq/ejbcpp/ejb_cpp.html。