本文討論如何讓用 CORBA 支持的任何語言編寫的客戶端能夠訪問 Enterprise JavaBeansTM 組件 (“EJBTM 組件”)。本文針對深入了解 JavaTM 2 Platform, Enterprise Edition ("J2EETM") 和公共對象請求代理結(jié)構(gòu)(Common Object Request Broker Architecture,CORBA)的程序員。
J2EE 技術(shù)簡化了企業(yè)應用程序,因為它將它們建立在標準、模塊化和可重用組件的基礎上,而該組件又基于 Enterprise JavaBeansTM (EJBTM) 體系結(jié)構(gòu),它也提供了完整的一組針對于那些組件的服務,并自動處理應用程序行為的許多細節(jié)。通過自動化應用程序開發(fā)的許多耗時且困難的任務,J2EE 技術(shù)使企業(yè)開發(fā)人員能夠?qū)⒅攸c放在增值上,也就是增強業(yè)務邏輯,而不是放在構(gòu)建基礎結(jié)構(gòu)上。
EJBTM 服務器端組件模型簡化了事務型、可伸縮和可移植的中間件組件的開發(fā)。Enterprise JavaBeans 服務器減少了中間件開發(fā)的復雜程度,因為它為諸如事務、安全、數(shù)據(jù)庫連接等中間件服務提供了支持。
CORBA 是一個對象管理組織(Object Management Group,OMG)標準,它是一個開放的、供應商無關的體系結(jié)構(gòu)和基礎結(jié)構(gòu),計算機應用程序可以使用它來通過網(wǎng)絡一起工作。由于使用了標準的 Internet Inter-ORB Protocol,(IIOP),因些來自任何供應商的基于 CORBA 的程序可以與來自相同或其他供應商的基于 CORBA 程序進行互操作,前一程序可以在幾乎所有的計算機、操作系統(tǒng)、編程語言和網(wǎng)絡上,后一程序可以在幾乎所有的其他計算機、操作系統(tǒng)、編程語言和網(wǎng)絡上。 要進一步學習 CORBA,請訪問 http://www.omg.org/gettingstarted/gettingstartedindex.htm。
CORBA 技術(shù)補充了 Java 平臺,因為它提供了分布式對象框架、支持此框架的服務以及與其他語言的互操作性。CORBA 技術(shù)是 Java 2 平臺的主要部分,它正用于 Enterprise JavaBeans 組件、 運行在 Internet Inter-ORB 協(xié)議上的Java 遠程方法調(diào)用 API ("Java RMI-IIOP"),以及 Java IDL API ("Java IDL")。
OMG 接口定義語言(Interface Definition Language,IDL)可用于描述一些接口,該接口由遠程對象實現(xiàn)。IDL 可用于定義接口的名稱,以及定義每個屬性和方法的名稱。一旦創(chuàng)建 IDL 文件,就可以在任何語言中,使用 IDL 編譯器來生成客戶端存根模塊 (stub) 和服務器骨架語句 (server skeleton),OMG已經(jīng)為此定義了這種語言映射的規(guī)范。要進一步了解 OMG IDL,請訪問 http://www.omg.org/gettingstarted/omg_idl.htm。
Java IDL 使得分布式 Java 應用程序能夠透明地調(diào)用遠程網(wǎng)絡服務上的操作,而該服務使用對象管理組織 (http://www.omg.org/) 定義的行業(yè)標準 OMG IDL 和 IIOP。運行在 IIOP API 上的 Java RMI 使得可以通過 javax.rmi
API 來對 CORBA 服務器和應用程序進行編程。
編寫 EJB 組件的開發(fā)人員可以遵循 Java RMI 編程模型,并將它用于他們的分布式對象模型,在該模型中,跨越所有應用程序服務器常見的所需傳輸是 Java RMI-IIOP。在異構(gòu)服務器環(huán)境中,到 CORBA 的 EJB 體系結(jié)構(gòu)的標準映射使得能夠進行下述的互操作:
- 使用來自某一供應商 ORB 的客戶端可以訪問駐留在服務器上的企業(yè) bean,而該服務器支持由另一供應商提供的 Enterprise JavaBeans 技術(shù)(“EJB 服務器”)。
- 一臺 EJB 服務器上的企業(yè) bean 可以訪問另一臺 EJB 服務器上的企業(yè) bean。
- 除了Java 編程語言之外,用某一語言編寫的 CORBA 客戶端可以訪問任何 EJB 組件,前提是要有一個從 OMG IDL 到那種編程語言的映射。
本文檔的其余部分提供了 CORBA 客戶端應用程序的例子,該應用程序訪問了企業(yè) bean 對象。在本文檔中,CORBA 客戶端就是使用 CORBA 支持的任何語言編寫的客戶端應用程序,這些編程語言包括 Java 編程語言、C++、C、Smalltalk、COBOL、Ada、Lisp 或 Python。雖然本例中的 Java 代碼特定于企業(yè) bean,但開發(fā) CORBA 的客戶端的過程是相同的,并且開發(fā)的 CORBA 客戶端可以訪問使用 Java RMI-IIOP API 創(chuàng)建的服務器。
可以在 鏈接到類似例子 中找到一些鏈接,它們指向其他實現(xiàn)了 J2EE 技術(shù)的供應商提供的類似應用程序。
開發(fā)訪問 Enterprise JavaBean 組件的 CORBA 客戶端
這是一個關于如何開發(fā) CORBA 客戶端應用程序以便訪問 EJB 組件的例子。在本例中,客戶端是用 C++ 編程語言編寫的,但客戶端可以是由 CORBA 支持的任何語言編寫的。
下面的幾節(jié)展示了 CORBA 客戶端的一般開發(fā)過程,開發(fā)完的 CORBA 客戶端可以訪問企業(yè) bean:
- 編寫 Enterprise JavaBean 組件
- 生成 CORBA IDL
- 創(chuàng)建 CORBA 客戶端
- 部署 Enterprise JavaBean 組件
- 運行客戶端可執(zhí)行文件
為了使例子變得簡單,我們采取了一些捷徑。有關構(gòu)建更加高級的解決方案的信息,請參閱 針對復雜接口的技巧。
- 在
/Java/src/ejbinterop
目錄中創(chuàng)建如下文件:Logger.java
、LoggerHome.java
、LoggerEJB.java
和LogMessage.java。
- 編譯本節(jié)編寫的文件,例如:
javac -classpath $J2EE_HOME/lib/j2ee.jar:.. *.java
這些命令在當前目錄中為所有的 .java 文件創(chuàng)建了類文件。這個命令和本文中的其他命令假定已經(jīng)正確設置了 J2EE_HOME 環(huán)境變量。使用 $J2EE_HOME 是 Unix? 操作系統(tǒng)的規(guī)定。當在 Microsoft Windows 操作環(huán)境中,請?zhí)鎿Q %J2EE_HOME%。
第 2 部分:生成 CORBA IDL
本節(jié)討論如何從 Java 類文件中生成接口定義語言(Interface Definition Language,IDL),并且假定 Java 類文件已在前一節(jié)中生成。在本例中,我們將使用
rmic
編譯器,以便將 Java 代碼映射到 IDL。IDL 提供了純聲明性的、編程語言無關的方式來指定對象的 API。- 針對 Java 類文件運行
在前面的例子中,我們包括了 .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
選項。這個選項告訴rmic
跳過具有參數(shù)或返回類型的任何方法,這里的返回類型將被映射到 CORBA 值類型。有利的方面在于它將防止我們生成許多不必要的 IDL,在 C++客戶端中,我們可能必須實現(xiàn)這些 IDL。不利的方面在于我們只能使用原始的數(shù)據(jù)類型、數(shù)組和字符串,而不能使用自己的 Java 類類型來作為參數(shù)或返回類型。 有關進一步信息,請閱讀 針對復雜接口的技巧。在 Java 類文件上運行
rmic
編譯器會生成下面的一些文件,文件所處的目錄由上面rmic
語句的 -d 選項指出: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
實現(xiàn)特定于每個應用程序服務器,因此很難開發(fā)等效設施,以便在除 Java 平臺外的平臺上繼續(xù)超時工作。一種選擇是將它們從 IDL 中刪除,但如果這樣做,那么每次改變 Java 接口,并從rmic
編譯器中重生成 IDL 文件時,就必須從 IDL 中刪除它們。
-
注意: 由于 CORBA 異常不支持繼承,因此針對 IDL 映射的 Java 語言創(chuàng)建了
Ex
類,它包含了代表實際 Java 異常的 CORBA 值類型。在這個基本的例子中,不必過多擔心異常支持。有關異常的進一步信息,請參閱http://java.sun.com/j2se/1.4.2/docs/guide/idl/jidlExceptions.html
。
- 針對 Java 類文件運行
- 使用 C++ 供應商的“IDL to C++”編譯器來編譯 IDL 文件,以便生成對應于 IDL 的 C++ 代碼。不同的供應商之間,這個過程的步驟會有區(qū)別,因此有必要參考產(chǎn)品文檔,取得針對供應商的特定步驟。
第 3 部分:創(chuàng)建 CORBA 客戶端
客戶端應用程序可以使用 CORBA 支持的任何語言編寫。下面的例子提供了針對于 C++ 客戶端的代碼,只要給予對象請求代理人( Object Request Broker,簡稱 ORB)和
LoggerHome
對象的corbaname
URL,它就會在服務器上將簡單字符串消息記錄到日志中。您必須根據(jù) C++ ORB 供應商的庫來調(diào)整include
語句,并修改注冊值工廠的代碼。本例是針對 ORBacus for C++ 4.0.5 編寫的,因此本例中的一些 C++ 代碼是特定于該產(chǎn)品的。corbaname
URL 是可閱讀的 URL 格式,它允許您訪問 CORBA 對象。它用于從特定命名上下文解析字符串化的名稱。這是 J2EE v 1.3 平臺中的新特性,它作為 CORBA 互操作命名服務(Interoperable Naming Service,簡稱 INS)的一部分。INS 是 CORBA 對象服務(CORBA Object Services,簡稱COS)命名服務的擴展,在以前版本的 J2EE 平臺中已經(jīng)交付使用。為了進一步了解 INS,請訪問 http://java.sun.com/j2se/1.4.2/docs/guide/idl/jidlNaming.html#INS。- 創(chuàng)建對象請求代理(ORB)。ORB 將對象請求服務連接到提供它們的對象。
- 注冊值工廠。
- 在命名上下文中查找
corbaname
URL 指向的LoggerHome
對象。 - 從返回給
LoggerHome
對象的對象中執(zhí)行安全的向下轉(zhuǎn)換。 - 創(chuàng)建
LoggerEJB
對象引用。 - 在日志中記錄消息。
- 告訴應用程序服務器不再使用 EJB 引用。
- 使用類似于下面的 C++ 代碼來創(chuàng)建客戶端。準確的代碼可能與 C++ 實現(xiàn)有關。這些代碼是針對于 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í)行文件。不同平臺之間,這樣的一些工具的區(qū)別甚大,因此有必要參考產(chǎn)品文檔,獲得它的說明。
第 4 部分:部署 Enterprise JavaBean 組件
- 使用滿意的應用程序服務器部署企業(yè) bean。下面的一些步驟描述了如何部署
LoggerEJB
組件,它使用了 J2EE 1.3 Reference Implementation (RI)。- 通過鍵入如下命令,從終端窗口或命令行提示中啟動 RI 應用程序:
$J2EE_HOME/bin/j2ee -verbose
- 當 J2EE 1.3 RI 指出“J2EE 啟動完成”時,鍵入如下命令,從另一終端窗口或命令提示中運行部署工具:
$J2EE_HOME/bin/deploytool
- 從部署工具中,選擇
File
->
New
->
Application。
- 在 Application File Name 字段中,輸入
Logger.ear
,以指出要在其中創(chuàng)建應用程序的文件。 - 在 Application Display Name 字段中,輸入
Logger。
- 選擇 OK 來保存設置,關閉這個對話窗口。
- 從部署工具中,選擇
File
->
New
->
Enterprise Bean。
- 如果出現(xiàn) Introduction 屏幕,選擇 Next,否則繼續(xù)。
- 在 New EnterpriseBean Wizard 中,在 Contents 框中選擇 Edit。
- 擴展 Available Files 列表,添加下面的 4 個
.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 保存設置并關閉這個對話窗口。
- 選擇 Finish.
- 從部署工具中,選擇
Tools
->
Deploy。
- 如果只運行 Java RMI-IIOP 客戶端,選擇 Return Client JAR。
- 選擇 Next。
- 在
JNDI
Name
for our LoggerEJB 字段中輸入ejbinterop/logger
。 - 選擇 Finish。
- 選擇 File -> Exit 來退出部署工具。
現(xiàn)在已經(jīng)部署了具有
LoggerEJB
組件的 Logger 應用程序,它準備接收消息。第 5 部分:運行客戶端可執(zhí)行文件
- 運行客戶端可執(zhí)行文件。運行客戶端可執(zhí)行程序的一種方法是,切換到包含可執(zhí)行客戶端文件的目錄,然后在終端窗口中輸入下面的 URL:
Client corbaname:iiop:1.2@localhost:1050#ejbinterop/logger
Client
是要運行的應用程序的名稱。corbaname
指出將從特定的命名上下文中解析字符串化的名稱。iiop:1.2
告訴 ORB 使用 IIOP 協(xié)議和 GIOP 1.2。- 要在其上查找引用的宿主計算機是
localhost
——本地計算機。為了擴展這個例子,以便在兩臺計算機上運行,請輸入計算機的 IP 地址和主機名,而不是localhost
,服務器要在該計算機上運行。 1050
是端口號,命名服務會在該端口上偵聽請求。 在 J2EE v.1.3 RI 中,默認情況下,命名服務要在其上偵聽的默認端口號是端口 1050。到目前為止,散列標記 (hash mark) 上的引用部分(Client corbaname:iiop:1.2@localhost:1050
) 是某個 URL,它返回根命名上下文。ejbinterop/logger
是要在命名上下文中解析的名稱。
如果您正在使用 J2EE 1.3 Reference Implementation,應該會看到類似于如下的一條消息,該消息是在應用程序服務器上被打印的:
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 服務器
- 停止 J2EE 服務器。為了停止服務器,可以在終端窗口或命令行提示中,輸入這條命令。
$J2EE_HOME/bin/j2ee -stop
不同的操作系統(tǒng)之間,停止運行中進程的過程是不同的,因此如果正在使用不同的服務器,可以參考系統(tǒng)文檔以取得詳細信息。
第 1 部分:編寫 Enterprise JavaBean 組件
下面的一些例子展示了企業(yè) bean 的代碼,它將從 Java RMI-IIOP 和 CORBA 客戶端接收發(fā)送給應用程序服務器的字符串日志消息。企業(yè) bean 將在服務器上把它們與當前服務器時間一起打印出來。
Logger.java
Logger.java
文件是企業(yè) bean 的遠程接口,因此,它擴展了 EJBObject
。遠程接口提供了 EJB 對象的遠程客戶端視圖,并定義了可由遠程客戶端調(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
文件擴展了 EJBHome
。EJBHome
接口必須由所有 EJB 組件的遠程 home 接口來擴展。home 接口定義了一些方法,使得遠程客戶端可以創(chuàng)建、查找和刪除 EJB 對象,以及創(chuàng)建、查找和刪除不針對 EJB 實例的 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
文件包含了會話 bean 的代碼。會話 bean 是一種企業(yè) bean,它由客戶端創(chuàng)建,并且通常只在一個客戶/服務器會話期間存在。會話 bean 執(zhí)行像計算或訪問客戶端數(shù)據(jù)庫這樣的操作。在本例中,企業(yè) bean 從客戶端接收簡單的字符串日志消息,并在服務器上打印它們。
//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
文件取得當前的日期和時間,然后創(chuàng)建格式化字串來顯示消息,并將消息打印到服務器。
//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 客戶端應用程序
使用相同的例子,可以容易地開發(fā)連接到企業(yè) bean 的 Java RMI-IIOP 客戶端,。與使用 C++ 的例子的區(qū)別在于:
- 在客戶端 CLASSPATH 中,必須包括客戶端
.jar
文件的位置,該文件是由運行需要的企業(yè) bean 的應用程序服務器創(chuàng)建的。那個.jar
文件包含了必要的客戶端存根模塊。 - 當使用 J2EE 1.3 RI 部署應用程序時,檢查 Deploy 屏幕第一頁上的 Deploytool 中的
Return Client Jar
框。
下面的代碼是 Java RMI-IIOP 版本的 LoggerEJB
組件客戶端。遵循與 C++ 客戶端例子所展示的相同步驟。當運行客戶端時,使用與 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 客戶端運行應用程序
當使用 Java RMI-IIOP 客戶端,而不是 C++ 客戶端運行示例應用程序時,請遵循這些步驟:
- 使用下面的命令,在
ejbinterop
/ 目錄中編譯 .java
文件:javac -classpath $J2EE_HOME/lib/j2ee.jar:<ejbinterop_directory> *.java
- 像 部署 Enterprise JavaBean 組件中所描述的那樣部署 Enterprise JavaBean 組件。當運行 Java RMI-IIOP 客戶應用程序時,記得在 Tools -> Deploy 頁中選擇 Return Client JAR 。 Deployment 主題中的一些命令指導您啟動 J2EE RI 或其他應用程序服務器。
- 使用類似于如下命令運行客戶應用程序:
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 正在運行的窗口中,將會看到:
Jan 31, 2002 2:27:47 PM PST: Message from a Java RMI-IIOP client
在運行客戶端的窗口中,將會看到:
Looking for: corbaname:iiop:1.2@localhost:1050#ejbinterop/logger Logging... Done
- 停止 J2EE 服務器。
超越基本應用程序
如何增強應用程序
- 開發(fā)使用值類型的例子。
為達到此目的,當運行
rmic
時刪除-noValueMethods
開關。重新運行 C++ 語言的 IDL 的映射編譯器,檢查它是否支持已經(jīng)生成的值類型。 - 在
Logger
中添加另一方法,它實際取得LogMessage
。
針對復雜接口的技巧
對于運用不同語言的客戶端和服務器之間的通信,接口是關鍵。為了在這方面獲得成功,應該考慮下面的建議:
- 避免將復雜的 Java 類,比如
java.util
中的集合,用于方法參數(shù)或返回類型。在將這些類開映射到 IDL 后,將強制您使用客戶端編程語言實現(xiàn)它們。此外,由于 Java Object Serialization 和 RMI-IIOP API 使得類的線路格式和內(nèi)部表示能夠隨時間不斷發(fā)展,因此您的 CORBA 客戶端應用程序可能在不同的 JavaTM 2 Platform, Standard Edition (J2SETM) 實現(xiàn)或版本上不兼容。
- 從 IDL 開始。
您可能想在返回類型或方法參數(shù)中使用復雜的數(shù)據(jù)結(jié)構(gòu)。在本例中,試著從 IDL 開始。在 IDL 中定義數(shù)據(jù)結(jié)構(gòu),甚至定義異常,然后將它們用在 EJB 接口中。這將可以防止逆向映射的產(chǎn)出物進入 CORBA 接口。
例如,剛開始試著在 IDL 中定義
LogMessage
類,然后在 Logger EJB 組件中,將 IDL 編譯的 Java 語言結(jié)果類用作方法參數(shù)。 - 避免重載 EJB 接口。
CORBA IDL 不支持方法重載,符合 IDL 映射規(guī)范的 Java 語言解決了這一點,其方式是創(chuàng)建 IDL 方法定義,將方法名與它的所有 IDL 參數(shù)類型組合起來。對于使用非 Java 編程語言的開發(fā)人員來說,這帶來了非常不友好的方法名。
- 考慮使用橋。
如果可用的選項仍然太有限,或者影響到想編寫的代碼,就可以考慮使用服務器端橋。在“鏈接到類似例子”一節(jié)列出了一些站點,您可以從這些站點中獲得更多有關如何構(gòu)建橋的信息。
鏈接到類似例子
實現(xiàn) J2EE 技術(shù)的幾個供應商都有一些優(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。