?? appa.htm
字號:
com.ms.com包為COM的開發(fā)定義了數(shù)量眾多的類。它支持GUID的使用——Variant(變體)和SafeArray
Automation(安全數(shù)組自動)類型——能與ActiveX控件在一個較深的層次打交道,并可控制COM異常。<br>
由于篇幅有限,這里不可能涉及所有這些主題。但我想著重強調(diào)一下COM異常的問題。根據(jù)規(guī)范,幾乎所有COM函數(shù)都會返回一個HRESULT值,它告訴我們函數(shù)調(diào)用是否成功,以及失敗的原因。但若觀察服務(wù)器和客戶代碼中的Java方法簽名,就會發(fā)現(xiàn)沒有HRESULT。相反,我們用函數(shù)返回值從一些函數(shù)那里取回數(shù)據(jù)。“虛擬機”(VM)會將Java風(fēng)格的函數(shù)調(diào)用轉(zhuǎn)換成COM風(fēng)格的函數(shù)調(diào)用,甚至包括返回參數(shù)。但假若我們在服務(wù)器里調(diào)用的一個函數(shù)在COM這一級失敗,又會在虛擬機里出現(xiàn)什么事情呢?在這種情況下,JVM會認(rèn)為HRESULT值標(biāo)志著一次失敗,并會產(chǎn)生類com.ms.com.ComFailException的一個固有Java異常。這樣一來,我們就可用Java異常控制機制來管理COM錯誤,而不是檢查函數(shù)的返回值。<br>
如欲深入了解這個包內(nèi)包含的類,請參考微軟公司的產(chǎn)品文檔。<br>
<br>
A.5.5 ActiveX/Beans集成<br>
Java/COM集成一個有趣的結(jié)果就是ActiveX/Beans的集成。也就是說,Java Bean可包含到象VB或任何一種Microsoft
Office產(chǎn)品那樣的ActiveX容器里。而一個ActiveX控件可包含到象Sun BeanBox這樣的Beans容器里。Microsoft
JVM會幫助我們考慮到所有的細(xì)節(jié)。一個ActiveX控件僅僅是一個COM服務(wù)器,它展示了預(yù)先定義好的、請求的接口。Bean只是一個特殊的Java類,它遵循特定的編程風(fēng)格。但在寫作本書的時候,這一集成仍然不能算作完美。例如,虛擬機不能將JavaBeans事件映射成為COM事件模型。若希望從ActiveX容器內(nèi)部的一個Bean里對事件加以控制,Bean必須通過低級技術(shù)攔截象鼠標(biāo)行動這類的系統(tǒng)事件,不能采用標(biāo)準(zhǔn)的JavaBeans委托事件模型。<br>
拋開這個問題不管,ActiveX/Beans集成仍然是非常有趣的。由于牽涉的概念與工具與上面討論的完全相同,所以請參閱您的Microsoft文檔,了解進一步的細(xì)節(jié)。<br>
<br>
A.5.6 固有方法與程序片的注意事項<br>
固有方法為我們帶來了安全問題的一些考慮。若您的Java代碼發(fā)出對一個固有方法的調(diào)用,就相當(dāng)于將控制權(quán)傳遞到了虛擬機“體系”的外面。固有方法擁有對操作系統(tǒng)的完全訪問權(quán)限!當(dāng)然,如果由自己編寫固有方法,這正是我們所希望的。但這對程序片來說卻是不可接受的——至少不能默許這樣做。我們不想看到從因特網(wǎng)遠(yuǎn)程服務(wù)器下載回來的一個程序片自由自在地操作文件系統(tǒng)以及機器的其他敏感區(qū)域,除非特別允許它這樣做。為了用J/Direct,RNI和COM集成防止此類情況的發(fā)生,只有受到信任(委托)的Java代碼才有權(quán)發(fā)出對固有方法的調(diào)用。根據(jù)程序片的具體使用,必須滿足不同的條件才可放行。例如,使用J/Direct的一個程序片必須擁有數(shù)字化簽名,指出自己受到完全信任。在寫作本書的時候,并不是所有這些安全機制都已實現(xiàn)(對于Microsoft
SDK for Java,beta 2版本)。所以當(dāng)新版本出現(xiàn)以后,請務(wù)必留意它的文檔說明。<br>
<br>
A.6 CORBA<br>
在大型的分布式應(yīng)用中,我們的某些要求并非前面講述的方法能夠滿足的。舉個例子來說,我們可能想同以前遺留下來的數(shù)據(jù)倉庫打交道,或者需要從一個服務(wù)器對象里獲取服務(wù),無論它的物理位置在哪里。在這些情況下,都要求某種形式的“遠(yuǎn)程過程調(diào)用”(RPC),而且可能要求與語言無關(guān)。此時,CORBA可為我們提供很大的幫助。<br>
CORBA并非一種語言特性,而是一種集成技術(shù)。它代表著一種具體的規(guī)范,各個開發(fā)商通過遵守這一規(guī)范,可設(shè)計出符合CORBA標(biāo)準(zhǔn)的集成產(chǎn)品。CORBA規(guī)范是由OMG開發(fā)出來的。這家非贏利性的機構(gòu)致力于定義一個標(biāo)準(zhǔn)框架,從而實現(xiàn)分布式、與語言無關(guān)對象的相互操作。<br>
利用CORBA,我們可實現(xiàn)對Java對象以及非Java對象的遠(yuǎn)程調(diào)用,并可與傳統(tǒng)的系統(tǒng)進行溝通——采用一種“位置透明”的形式。Java增添了連網(wǎng)支持,是一種優(yōu)秀的“面向?qū)ο蟆背绦蛟O(shè)計語言,可構(gòu)建出圖形化和非圖形化的應(yīng)用(程序)。Java和OMG對象模型存在著很好的對應(yīng)關(guān)系;例如,無論Java還是CORBA都實現(xiàn)了“接口”的概念,并且都擁有一個引用(參考)對象模型。<br>
<br>
A.6.1 CORBA基礎(chǔ)<br>
由OMG制訂的對象相互操作規(guī)范通常稱為“對象管理體系”(ObjectManagement
Architecture,OMA)。OMA定義了兩個組件:“核心對象模型”(Core Object
Model)和“OMA參考體系”(OMA Reference Model)。OMA參考體系定義了一套基層服務(wù)結(jié)構(gòu)及機制,實現(xiàn)了對象相互間進行操作的能力。OMA參考體系包括“對象請求代理”(Object
Request Broker,ORB)、“對象服務(wù)”(Object Services,也稱作CORBAservices)以及一些通用機制。<br>
ORB是對象間相互請求的一條通信總線。進行請求時,毋需關(guān)心對方的物理位置在哪里。這意味著在客戶代碼中看起來象一次方案調(diào)用的過程實際是非常復(fù)雜的一次操作。首先,必須存在與服務(wù)器對象的一條連接途徑。而且為了創(chuàng)建一個連接,ORB必須知道具體實現(xiàn)服務(wù)器的代碼存放在哪里。建好連接后,必須對方法自變量進行“匯集”。例如,將它們轉(zhuǎn)換到一個二進制流里,以便通過網(wǎng)絡(luò)傳送。必須傳遞的其他信息包括服務(wù)器的機器名稱、服務(wù)器進程以及對那個進程內(nèi)的服務(wù)器對象進行標(biāo)識的信息等等。最后,這些信息通過一種低級線路協(xié)議傳遞,信息在服務(wù)器那一端解碼,最后正式執(zhí)行調(diào)用。ORB將所有這些復(fù)雜的操作都從程序員眼前隱藏起來了,并使程序員的工作幾乎和與調(diào)用本地對象的方法一樣簡單。<br>
并沒有硬性規(guī)定應(yīng)如何實現(xiàn)ORB核心,但為了在不同開發(fā)商的ORB之間實現(xiàn)一種基本的兼容,OMG定義了一系列服務(wù),它們可通過標(biāo)準(zhǔn)接口訪問。<br>
<br>
1. CORBA接口定義語言(IDL)<br>
CORBA是面向語言的透明而設(shè)計的:一個客戶對象可調(diào)用屬于不同類的服務(wù)器對象方法,無論對方是用何種語言實現(xiàn)的。當(dāng)然,客戶對象事先必須知道由服務(wù)器對象揭示的方法名稱及簽名。這時便要用到IDL。CORBA
IDL是一種與語言無關(guān)的設(shè)計方法,可用它指定數(shù)據(jù)類型、屬性、操作、接口以及更多的東西。IDL的語法類似于C++或Java語法。下面這張表格為大家總結(jié)了三種語言一些通用概念,并展示了它們的對應(yīng)關(guān)系。<br>
<br>
CORBA IDL Java C++<br>
<br>
模塊(Module) 包(Package) 命名空間(Namespace)<br>
接口(Interface) 接口(Interface) 純抽象類(Pure abstract class)<br>
方法(Method) 方法(Method) 成員函數(shù)(Member function)<br>
<br>
繼承概念也獲得了支持——就象C++那樣,同樣使用冒號運算符。針對需要由服務(wù)器和客戶實現(xiàn)和使用的屬性、方法以及接口,程序員要寫出一個IDL描述。隨后,IDL會由一個由廠商提供的IDL/Java編譯器進行編譯,后者會讀取IDL源碼,并生成相應(yīng)的Java代碼。<br>
IDL編譯器是一個相當(dāng)有用的工具:它不僅生成與IDL等價的Java源碼,也會生成用于匯集方法自變量的代碼,并可發(fā)出遠(yuǎn)程調(diào)用。我們將這種代碼稱為“根干”(Stub
and Skeleton)代碼,它組織成多個Java源文件,而且通常屬于同一個Java包的一部分。<br>
<br>
2. 命名服務(wù)<br>
命名服務(wù)屬于CORBA基本服務(wù)之一。CORBA對象是通過一個引用訪問的。盡管引用信息用我們的眼睛來看沒什么意義,但可為引用分配由程序員定義的字串名。這一操作叫作“引用的字串化”。一個叫作“命名服務(wù)”(Naming
Service)的OMA組件專門用于執(zhí)行“字串到對象”以及“對象到字串”轉(zhuǎn)換及映射。由于命名服務(wù)扮演了服務(wù)器和客戶都能查詢和操作的一個電話本的角色,所以它作為一個獨立的進程運行。創(chuàng)建“對象到字串”映射的過程叫作“綁定一個對象”;刪除映射關(guān)系的過程叫作“取消綁定”;而讓對象引用傳遞一個字串的過程叫作“解析名稱”。<br>
比如在啟動的時候,服務(wù)器應(yīng)用可創(chuàng)建一個服務(wù)器對象,將對象同命名服務(wù)綁定起來,然后等候客戶發(fā)出請求。客戶首先獲得一個服務(wù)器引用,解析出字串名,然后通過引用發(fā)出對服務(wù)器的調(diào)用。<br>
同樣地,“命名服務(wù)”規(guī)范也屬于CORBA的一部分,但實現(xiàn)它的應(yīng)用程序是由ORB廠商(開發(fā)商)提供的。由于廠商不同,我們訪問命名服務(wù)的方式也可能有所區(qū)別。<br>
<br>
A.6.2 一個例子<br>
這兒顯示的代碼可能并不詳盡,因為不同的ORB有不同的方法來訪問CORBA服務(wù),所以無論什么例子都要取決于具體的廠商(下例使用了JavaIDL,這是Sun公司的一個免費產(chǎn)品。它配套提供了一個簡化版本的ORB、一個命名服務(wù)以及一個“IDL→Java”編譯器)。除此之外,由于Java仍處在發(fā)展初期,所以在不同的Java/CORBA產(chǎn)品里并不是包含了所有CORBA特性。<br>
我們希望實現(xiàn)一個服務(wù)器,令其在一些機器上運行,其他機器能向它查詢正確的時間。我們也希望實現(xiàn)一個客戶,令其請求正確的時間。在這種情況下,我們讓兩個程序都用Java實現(xiàn)。但在實際應(yīng)用中,往往分別采用不同的語言。<br>
<br>
1. 編寫IDL源碼<br>
第一步是為提供的服務(wù)編寫一個IDL描述。這通常是由服務(wù)器程序員完成的。隨后,程序員就可用任何語言實現(xiàn)服務(wù)器,只需那種語言里存在著一個CORBA
IDL編譯器。<br>
IDL文件已分發(fā)給客戶端的程序員,并成為兩種語言間的橋梁。<br>
下面這個例子展示了時間服務(wù)器的IDL描述情況:<br>
<br>
1031頁上程序<br>
<br>
這是對RemoteTime命名空間內(nèi)的ExactTime接口的一個聲明。該接口由單獨一個方法構(gòu)成,它以字串格式返回當(dāng)前時間。<br>
<br>
2. 創(chuàng)建根干<br>
第二步是編譯IDL,創(chuàng)建Java根干代碼。我們將利用這些代碼實現(xiàn)客戶和服務(wù)器。與JavaIDL產(chǎn)品配套提供的工具是idltojava:<br>
idltojava -fserver -fclient RemoteTime.idl<br>
其中兩個標(biāo)記告訴idltojava同時為根和干生成代碼。idltojava會生成一個Java包,它在IDL模塊、RemoteTime以及生成的Java文件置入RemoteTime子目錄后命名。_ExactTimeImplBase.java代表我們用于實現(xiàn)服務(wù)器對象的“干”;而_ExactTimeStub.java將用于客戶。在ExactTime.java中,用Java方式表示了IDL接口。此外還包含了用到的其他支持文件,例如用于簡化訪問命名服務(wù)的文件。<br>
<br>
3. 實現(xiàn)服務(wù)器和客戶<br>
大家在下面看到的是服務(wù)器端使用的代碼。服務(wù)器對象是在ExactTimeServer類里實現(xiàn)的。RemoteTimeServer這個應(yīng)用的作用是:創(chuàng)建一個服務(wù)器對象,通過ORB為其注冊,指定對象引用時采用的名稱,然后“安靜”地等候客戶發(fā)出請求。<br>
<br>
1031-1033頁程序<br>
<br>
正如大家看到的那樣,服務(wù)器對象的實現(xiàn)是非常簡單的;它是一個普通的Java類,從IDL編譯器生成的“干”代碼中繼承而來。但在與ORB以及其他CORBA服務(wù)進行聯(lián)系的時候,情況卻變得稍微有些復(fù)雜。<br>
<br>
4. 一些CORBA服務(wù)<br>
這里要簡單介紹一下JavaIDL相關(guān)代碼所做的工作(注意暫時忽略了CORBA代碼與不同廠商有關(guān)這一事實)。main()的第一行代碼用于啟動ORB。而且理所當(dāng)然,這正是服務(wù)器對象需要同它進行溝通的原因。就在ORB初始化以后,緊接著就創(chuàng)建了一個服務(wù)器對象。實際上,它正式名稱應(yīng)該是“短期服務(wù)對象”:從客戶那里接收請求,“生存時間”與創(chuàng)建它的進程是相同的。創(chuàng)建好短期服務(wù)對象后,就會通過ORB對其進行注冊。這意味著ORB已知道它的存在,可將請求轉(zhuǎn)發(fā)給它。<br>
到目前為止,我們擁有的全部東西就是一個timeServerObjRef——只有在當(dāng)前服務(wù)器進程里才有效的一個對象引用。下一步是為這個服務(wù)對象分配一個字串形式的名字。客戶會根據(jù)那個名字尋找服務(wù)對象。我們通過命名服務(wù)(Naming
Service)完成這一操作。首先,我們需要對命名服務(wù)的一個對象引用。通過調(diào)用resolve_initial_references(),可獲得對命名服務(wù)的字串式對象引用(在JavaIDL中是“NameService”),并將這個引用返回。這是對采用narrow()方法的一個特定NamingContext引用的模型。我們現(xiàn)在可開始使用命名服務(wù)了。<br>
為了將服務(wù)對象同一個字串形式的對象引用綁定在一起,我們首先創(chuàng)建一個NameComponent對象,用“ExactTime”進行初始化。“ExactTime”是我們想用于綁定服務(wù)對象的名稱字串。隨后使用rebind()方法,這是受限于對象引用的字串化引用。我們用rebind()分配一個引用——即使它已經(jīng)存在。而假若引用已經(jīng)存在,那么bind()會造成一個異常。在CORBA中,名稱由一系列NameContext構(gòu)成——這便是我們?yōu)槭裁匆靡粋€數(shù)組將名稱與對象引用綁定起來的原因。<br>
服務(wù)對象最好準(zhǔn)備好由客戶使用。此時,服務(wù)器進程會進入一種等候狀態(tài)。同樣地,由于它是一種“短期服務(wù)”,所以
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -