corba核心規範(轉)

post0發表於2007-08-11
corba核心規範(轉)[@more@]

核心規範

當前最新版本是3.0,是在2002年8月整理釋出的。CCM的3.0規範也已經發布。 CORBA規範3.0終於出來了,也許是不能再拖了吧。比較奇怪的是3.0規範的編號是2002年6月份的(02-06-33),但是規範是在7月份才整理出來的。在CORBA3.0規範中去掉了 MiniCORBA和實時CORBA。 OMG組織的網站上有一個頁面介紹在3.0規範將要增加的內容,我將其翻譯過來,大家可以點這兒檢視。因為新版本規範在不斷推出,所以裡面的內容可能會與現在的實際情況有點兒差異。

語言對映

規定IDL語言到Ada、C、C++、JAVA、COBOL、SmallTalk、Lisp、Python和CORBA指令碼語言的對映,以及JAVA到IDL的反對映等。

物件服務

共有17個物件服務:命名服務、事件服務、時間服務、物件事務服務、安全服務、收集服務、併發服務、特性服務、持久物件服務、生命週期服務、交易物件服務、外表化服務、關係服務、查詢服務、通知服務、許可服務、增強時間檢視。

通用設施

主要包括國際化和時間、移動代理。

行業標準

主要有商業、金融、生命科學研究、製造業、電信、交通、醫療保健等。

規則與自由

----為何選擇 CORBA 和 Java 技術?

歡迎光臨有關 Java 和 CORBA 技術的這一定期欄目。此第一期將概述 Java 和 CORBA 技術,並幫助您決定如何最有效地讓它們為您工作。以後的欄目將提供 Java 和 CORBA 程式設計的內行指導和程式碼。

在 1855 年,時年 26 歲的 Joshua Chamberlain 是 Bowdoin 大學的修辭學教授,在一次演講中講述了規則與自由之間的關係,以及二者之間失衡帶來的危害。沒有自由的規則是專制,而沒有規則的自由是混亂。

公司資訊系統部門的管理可能會形成過度的規則或過度的自由。規則過度的一個例子是隻適用於一個廠商的管理指令,這樣您的系統在擴充套件時,或在與潛在的公司合作伙伴整合時就會有問題。如果自由過多,個人或者開發小組就會根據他們來選擇技術,這樣,如果這些技術高手遇到他們“生疏的”優先認股權這樣的話題時,擴充套件或整合又會變得很困難。開發人員可能會受業務環境不斷變化的影響。

努力實現環境平衡

多種環境因素在決定我們的系統必須遵守的的規則。存在於一個業務環境中的系統應有足夠長的壽命,以為公司和客戶創造價值。持續為一個組織創造長期價值的系統必須能夠應付經常的變化。合併、併購、新的管理和市場力量在改變系統的環境,以及透過使用該系統完成業務過程的使用者的需求。變化是一個常數,必須將它新增到評估方程式中。當然,我們無法預知未來,但我們可以分析趨勢並努力設計我們的系統,使之能夠接受大量潛在的變化或系統擴充套件,同時對組織產生的影響又可以儘可能小。

為了做出正確的決策和評估,我們需要理解支配著環境的規則,以及我們的應用程式在該環境中應具有的自由。要理解的最重要的規則是,我們的系統處在不斷髮展的組織中,無論是在公司、政府還是教育組織中,都是業務問題支配技術問題。許多體系結構和平臺評估都將主要問題漏掉了。他們通常會將兩項或多項技術並排放在一起,然後比較技術特性列表。在完成的時候,大多數參與者會達成一致,因為他們不願與評估小組中嗓門最大、最強硬、勢力最大的派別爭吵。顯然,這不是作出選擇的最有效方法。

確定關鍵業務問題

將業務問題轉換為對組織需要的實際評估意味著應該著重考慮以下問題:

· 組織內的技術力量

· 不抑制程式設計師的開發環境

· 不對應用程式構成限制的執行時環境

· 執行時環境和開發環境的許可證問題和法律問題(可以說是規則的規則)

· 可找到有經驗的開發人員

· 能找到收費合理、有見地的諮詢服務公司

· 對組織的客戶的影響

· 對廠商或技術合作夥伴的影響

· 組織的文化和策略

· 組織的上級管理聯盟

· “大亨們”是否在討論併購或合併

· 誰是決策者

這些業務問題通常比其他問題(比如採用每個會話一個執行緒的併發模型還是每個請求一個執行緒的併發模型)更重要。您可以走進老闆的辦公室,向他發表足可以充斥一次軟體研討會的技術觀點,但是除非您強調了組織的需要,否則您的觀點將顯得非常空洞。

走近 CORBA

現在讓我們用 CORBA 來解決這些問題。CORBA 是一種開放的行業標準,它由參加“物件管理組織 (OMG)”的 600 多家公司支援。這些公司包括硬體或軟體公司、電信公司、金融公司、大學、醫藥研究所和政府機構。OMG 並不實現它們自己的規範;它們依靠廠商的實現,這些實現有助於將竟爭導向到功能、效能、價格和令人鼓舞的質量這些方面。OMG 本身是一個充滿生機的、活躍的組織,它的許多官員在各種會議上撰寫文章並發表演講。只要留心觀察,您就會發現,他們總在關注將會對他們的組織及您的組織造成影響的各種變化。

除上述優勢外,CORBA 還提供了高度的互動操作性。這保證了在不同的 CORBA 產品基礎之上構建的分散式物件可以相互通訊。因此,大型組織不需要讓所有開發工作都使用同一 CORBA 產品。OMG 一直都在辛勤工作,以期透過加強 CORBA 規範來提供更高階別的可移植性。要知道,當廠商分化它們的產品以及開發人員新增限制時,他們往往會忘記原始碼的可移植性這回事。應當指出,可移植性比以前的版本中有了實質性的提高,並且隨著因特網互操作性協議 (IIOP) 形成強大的使用者集團和眾多聯盟,可移植性將越來越好。

我們很快變會轉入 Java 技術的討論,但我們首先應將語言看作一個整體。資訊系統有一個確定的規則,那就是不確定性本身。Java 程式語言可能是今天的語言,但誰知道下一種更好的語言哪一天會使它暗然失色呢?應當知道,就在此時此刻,有人正在他們的車庫裡加緊編寫一種更好的語言。因此, CORBA 的語言無關性有助於您長期遵守資訊系統環境中的這一法則。CORBA 支援一種經典的、穩定的物件模型,此模型將繼續步入未來。它一直在憑藉最新的語言不斷髮展,並將繼續向極好的新語言(如 Python)擴充套件。

Java 程式語言及其他

此環境中可確定的另一點是它的複雜性,這是我們所不願看到的,Java 技術正好可以派上用場。它能很好地滿足需要,因為它的簡單性將有助於使開發免於陷入底層的複雜性中。Java 語言在許多方面隱藏了一些基本的細節,但就整體而言,Java 技術改善從分析、設計到執行的整個過程。

在分析和設計階段要儘可能統一和明確地表示您的系統和設計模式,這一點極為重要。“統一建模語言 (UML)”事實上已成為表述系統設計的標準語言。UML 的開發是協作方面的一個極好的故事。UML 的標準化過程也相當引人注意。UML 的標準化是透過 OMG 來實現的。OMG 認識到需要一種標準建模語言,以跨語言和環境表示分散式物件模型。Java 物件模型與 CORBA 物件模型幾乎完全相同,從而很容易將您的 UML 設計對映到一種實現,同時也很容易將 UML 圖對映到“Interface Definition Language (IDL)-to-Java 語言”實現。

經過分析和設計階段的物件將有一些介面,這些介面定義其他元件將如何訪問您的服務。現在需要將那些介面轉換為一種實現語言。Java 技術同樣使這一步很容易實現。“IDL-to-Java 語言”對映相當直接。Java 語言和 IDL 分別提供一個介面關鍵字,這個關鍵字有助於說明用每種語言表示的資料型別之間的緊密關係。Java 技術提供一種從 Java 介面到 IDL 的反向對映。不管選擇哪個方向,您都應該用 IDL 表示您的介面;這使您能夠使用所有其他語言與 IDL 之間的對映,併為您提供了為了在以後具有更大自由而必需的語言無關性。

體系結構案例

除了設計之外,系統的體系結構也很重要。許多系統體系結構問題涉及對現有系統(資料庫、舊有系統、可用物件或可能用其他語言編寫的應用程式)的包含。Java 和 CORBA 語言使得可以(而不是禁止)將這些強有力的系統帶給更多的使用者。這是一種解放 -- 許多系統可能許多年來都在發揮著作用。實際上,當完成將這些系統帶入新世紀的所有 Y2K 以前的工作以後,在今後幾年它們可能還將存在。由於其編譯後的位元組碼結構,Java 語言將使您很容易建立和分發可移植的物件,而 CORBA 允許您將這些物件與您計算環境的其餘部分進行連線和整合。

我並非想用 Java 和 CORBA 技術來排斥 Java 語言的遠端方法呼叫、Enterprise JavaBeans 技術、 Microsoft 的 DCOM 甚至 DCE。Java 和 CORBA 語言最自由的方面是,OMG 正在加緊工作,以確保 CORBA 物件能夠與大量的物件互動。當然,這些連線中有些較難實現,並且最終可能會很脆弱。請記住,這些型別的連線常常是因體系結構、成本、時間或業務等原因而建立的。

Joshua Chamberlain,帶著對規則與自由的見解,在他在 Bowdoin 大學的演講過後七年加入北方軍隊。他功勳卓著,並證明是一位有力的領導者,所以格蘭特將軍選擇讓他接受北弗吉尼亞軍隊的正式投降。他向投降計程車兵行行軍禮以示尊敬的行動,是恢復被四年內戰破壞的破碎混亂的聯邦系統的新基礎中的第一塊基石。理解規則和自由的平衡為任何型別的組織中的參與者提供了一個清晰的影像,使他們能夠清楚地理解他們所面對的系統和要避免的混亂之間的相互影響。

小結

異構系統環境中的互連和通訊應該是我們的目標。我們要選擇使用的規則應該允許自由地將現有的系統與新系統一起使用以滿足組織的需要。在這個變化的世界中,當變化被強加給您的組織時,這些規則應該提供最大的靈活性。這些規則提供了一個限制我們的自由的操作範圍,這樣就不易陷入盲目開發的境況。

 

謝謝您耐著性子讀完了本文。我不是修飾學教授,我只是一個程式設計師,所以在下一期我們將開始討論一個簡單的示例 -- 使用 Java 技術實現 CORBA 客戶機和伺服器。

 

探索CORBA技術的應用領域---- 一個簡單的CORBA/Java示例

首  頁 CORBA文章 CORBA規範 CORBA實現 CORBA應用 相關技術 CORBA論壇

(本文摘自IBM developerWorks)

Dave Bartlett

顧問、撰稿人兼講師

2000 年 7 月

內容:

IDL 介面

IDL 編譯器

伺服器

客戶機

結論

6 月份,我們談過您為什麼要使用 CORBA 和 Java 技術。本月,我要透過一個可用的簡單示例,讓您開始探索 CORBA 技術的許多領域。不過,別忘了我們的目標是,建立這樣一種分散式應用程式:使駐留在一臺計算機上的客戶機能向執行於另一臺計算機上的服務發出請求。我們不想為諸如硬體或作業系統軟體等細節問題操心,而只是想讓這種服務能響應客戶機的請求。

IDL 介面

全部 CORBA 結構是從一個介面開始的,理解介面的最佳方法就是想像我的汽車,對,我的汽車。雖然您不熟悉它,但如果我對您說:“開上我的車,帶些三明治回來當午餐”,恐怕您就不會懷疑自己能不能駕駛我的汽車。您可能想知道它停在哪裡,以及開它是否安全,但是您會確信開我的車與開您的車差別不大。這是因為,在各種汽車當中,人與汽車之間的介面已高度標準化了。我的轎車和您的跑車之間可能會有一些差異,但汽車的油門踏板、剎車和方向盤的安裝都是標準的,您一定能輕鬆快速上路。

因為 CORBA 與語言無關,所以它依靠一種介面定義語言 (IDL),來表達客戶機如何向實現介面的服務發出請求。我們的介面就是一個方法:add()。這個方法將取兩個數(兩個 IDL 的 long 型數)並返回這兩個數之和。下面是我們的介面計算程式:

清單 1. calcsimpl.idl

module corbasem { module gen { module calcsimpl { interface calculator { long add(in long x, in long y); }; }; };};

這個介面中的 IDL 關鍵字有:module、interface、long 和 in。IDL 使用關鍵字 module 來建立名稱空間,並且此關鍵字準確地對映為 Java 關鍵字 package。執行 IDL-to-Java 編譯器時,生成的 Java 檔案將會存到名為 calcsimpl 的子目錄中。IDL 關鍵字 interface 完美地對映為 Java 介面,並代表一種抽象型別,因為兩者都只定義您與物件通訊的方式,而不涉及物件的實現。IDL 關鍵字 long 是一種基本的整數型別,它至少對映為一個 4 位元組的型別,這種型別在 Java 程式碼中就是 int。

想一想執行遠端方法呼叫的機制,您就會發現定義引數傳遞的方向(客戶機到伺服器、伺服器到客戶機或者雙向傳遞)是多麼的有意義。在 IDL 操作中,這些方向用 in、out 和 inout 關鍵字來宣告,每個引數都必須宣告方向,以便使物件請求代理程式 (ORB) 知道該引數的去向。這會影響到為傳送而進行的引數打包、引數解包以及記憶體管理。ORB 對引數瞭解得越多,它的效率就越高。關鍵字 in 表明 long x 和 long y 是從客戶機傳遞到伺服器。

圖 1. 參與 CORBA 請求的各個部分

IDL 編譯器

需要 IDL 編譯器嗎?您可能已經有了 ORB 供應商和 IDL-to-Java 編譯器。但如果還沒有,您從哪裡獲取呢?這裡有好多,而且有些還可以免費下載。我推薦 Object Oriented Concepts, Inc. 的 Orbacus ORB。如果不將其用於商業目的,它還可以免費下載,而且完全符合 CORBA 2.3 規範。另外一個可試用 60 天的編譯器是 Inprise 的 Visibroker,也完全符合 CORBA 2.3 規範並且可下載。如想獲得這兩種產品,請參閱參考資料。

介面定義以後,必須在 ORB 供應商提供的 IDL-to-Java 編譯器上執行。IDL 編譯器是一種精巧的實用程式,它生成 IDL 的 stub 和 skeleton 以及其它支援檔案。生成的這些原始檔,大部分將增強 CORBA 標準中定義的特定 IDL 型別的打包功能。編譯器將生成大部分網路探測 (plumbing),這在分散式系統中非常重要。在最基本的級別中,IDL-to-Java 編譯器只是一個按 CORBA 2.3 規範的定義來實現從 IDL 到 Java 語言對映的程式。手動生成這些程式碼既枯燥又費時,還容易出錯;IDL-to- Java 編譯器會處理這一切,所以您就不用操心啦;同時,它會用一定的規則約束您,並強制您執行封裝。IDL-to-Java 編譯器將把 CORBA -land 規則強加給您的系統。

輸入下面的命令,從 Orbacus 執行 IDL-to-Java 編譯器,把所有生成的檔案都放在 CLASSPATH 的輸出目錄下。

清單 2. 呼叫 IDL-to-Java 編譯器

jidl --output-dir c:\_workcorbasem calculator.idl

生成了什麼呢?這個命令生成了構建實現所需要的全部 Java 原始檔。IDL-to-Java 編譯器可確保所定義的介面遵守 CORBA 規範的規則。

圖 2. IDL-to-Java 編譯器檔案生成

下面是這些檔案:

· calculator.java - 這個檔案叫標記介面檔案。CORBA 規範指出這個檔案必須擴充套件 IDLEntity,並且與 IDL 介面同名。這個檔案提供型別標記,從而使這個介面能用於其它介面的方法宣告。

· calculatorOperations.java - 這個檔案內含 Java 公共介面 -- calculatorOperations。規範指出,這個檔案應該與具有 Operations 字尾的 IDL 介面同名,並且這個檔案內含此介面對映的操作標記。上面定義的標記介面 (calculator.java) 可擴充套件這個介面。

· calculatorHelper.java - 設計 helper 類的目的是,讓所需要的許多內務處理功能脫離我們的介面,但又隨時可用到實現過程中。幫助程式檔案含有重要的靜態 narrow 方法,這種方法使 org.omg.CORBA.Object 收縮為一種更具體的型別的物件引用;在這種情況下,將是一個計算程式型別。

· calculatorHolder.java - holder 類是一個專門化類,是為了需要透過引用來傳遞引數的任意資料型別而生成的。這個示例中將不使用 holder 類,但我們將會在以後的欄目中經常見到它。

· calculatorPOA.java - skeleton 類為 CORBA 功能提供了請求-響應探測的一大部分。生成 calculatorPOA.java,是因為預設方式下的實現是基於繼承的,如果我們選擇基於委託的實現方式,輸出就會不一樣。這些主題將在以後的欄目中詳細介紹。

· _calculatorStub.java - 顧名思義,這是一個 stub 類。您的客戶機將需要這個類來進行工作。

 

伺服器

現在生成的檔案必須在伺服器上開始工作,用這個伺服器實現我們的介面。所幸的是,大部分探測是適合我們的要求的,但別高興得太早 -- 還有許多工作要做;就是說,所有這些檔案都必須用在正確的地方。

讓我們從 add() 方法的實現開始。

清單 3. SimpleCalcSvr.java -- add() 方法

SimpleCalcServant extends calculatorPOA { public int add(int x, int y) { return x + y; }}

請注意,我們的實現類擴充套件了已生成的類 calculatorPOA。從客戶機發來一個請求時,該請求透過 ORB 進入 skeleton, skeleton 最終將呼叫 SimpleCalcServant,來完成請求並啟動響應。我們的介面很簡單,所以我們的實現也很簡單。

伺服器其餘部分的實現,涉及如何圍繞這個介面實現來設定 CORBA 體系結構,由於可移植性和靈活性方面的原因,許多這些呼叫要按 CORBA 規範執行。

我們需要完成的第一項任務是,詳細說明要使用哪一個 ORB,然後予以初始化。下面的程式碼處理此任務:

清單 4. SimpleCalcSvr.java -- 初始化 ORB

java.util.Properties props = System.getProperties(); props.put("org.omg.CORBA.ORBClass", "com.ooc.CORBA.ORG"); props.put("org.omg.CORBA.ORBSingletonClass", "com.ooc.CORBA.ORBSingleton"); org.omg.CORBA.ORB orb = null; // 初始化 ORB orb = org.omg.CORBA.ORB.init(args, props);

初始化 ORB 時,需要準確地告訴它哪一個類將用作 ORBClass,哪一個類將用作 ORBSingleton 類。我們的實現將不考慮這些,但所有相關的探測則都將考慮這些。正如我前面所說的,這種情況下,我使用的是 Object Oriented Concepts, Inc. 的 Orbacus ORB,而 OOC 類在那兩個 props.put() 呼叫中已給出。一旦填入了屬性,props 就只作為一個引數傳遞給 ORB.init() 方法。實際情況可能不是這樣;如果我們要把這個伺服器移到另一個 ORB,不希望為伺服器重新編碼。所以,在理想情況下,我們寧願改變一個配置檔案,使之指向另一個 ORB 類,然後直接重新啟動。

現在,ORB 已經到位並已初始化,並且實現也已經到位,只是尚未建立,此時,需要為實現建立一個完善的生存地點,而這可不像聽起來那麼容易,在一個分散式環境中,各個實現要求的環境可能略有不同。可以賦予實現許多特徵。實現既可以是單執行緒的,也可以是多執行緒的;既可以是具有高度可伸縮性的物件池,也可以是單元素。這許多不同的伺服器特徵已產生了可移植物件介面卡 (POA)。POA 使我們可以建立完善的環境,供我們的實現在其中駐留。所有符合 2.3 規範的 ORB 都會有一個根 POA,所有其它 POA 都是從根 POA 建立的。在這個簡單示例中,我已將實現專用的程式碼分解為它自己的方法 runcalc()。

為實現建立一個環境將是我們的第一項任務,所以必須設定一個 POA。本來,CORBA 伺服器使用基本物件介面卡 (BOA),但是每個供應商的 BOA 都不一樣,在最新版本的 CORBA 規範中,POA 已完全取代了 BOA。

清單 5. SimpleCalcSvr.java -- 設定 POA

// 從始終存在的 rootPOA // 設定可移植物件介面卡 org.omg.PortableServer.POA rootPOA = org.omg.PortableServer.POAHelper.narrow( orb.resolve_initial_references("RootPOA")); org.omg.PortableServer.POAManager manager = rootPOA.the_POAManager();

從標題和定義可以看出,這是一個簡單的示例。使用根 POA 而不建立新的 POA,將使事情變得簡單。POA 管理器是一種封裝了 POA 處理狀態的物件,所以,我們使用 POA 管理器,將發給 servant 的請求排隊。

還需要例項化實現:

清單 6. SimpleCalcSvr.java -- 例項化實現

// 建立計算程式介面的 servant SimpleCalcServant calcSvt = new SimpleCalcServant(); calculator calc = calcSvt._this(orb);

按照 CORBA 2.3 規範,所有 skeleton 均提供一個 _this() 方法,該方法使 servant 能得到目標 CORBA 物件的物件引用,servant 正是用目標 CORBA 物件來與這些請求相關聯的。

完成實現的例項化以後,就必須把機制放到適當的位置,以便客戶機能夠找到它們。有許多不同的方法和服務可用來找到滿足介面請求的物件。 CORBA Service 定義 Naming Service 和 Trader Services,來專門幫助客戶機查詢物件,以處理請求。也可以透過方法呼叫來傳遞物件。

在這個示例中,我們將使用所有方法中最直截了當的一種 — 將物件引用寫入一個檔案,該檔案將由客戶機選取。對於所有的 ORB 來說,建立一個物件引用的字串表示,或者反過來,建立由字串到物件的引用,都是必備的功能。

清單 7. SimpleCalcSvr.java -- 編寫物件引用

// 將物件引用寫入一個檔案 PrintWriter refstr = new PrintWriter ( new FileWriter("calcref.ior")); refstr.println(orb.object_to_string(calc)); refstr.close();

最後要做的一件事,就是啟用 POA,使客戶機請求開始排隊,並強制伺服器輸入其事件迴圈,以接收這些傳入的請求。

清單 8. SimpleCalcSvr.java -- 啟用 POA

// 使實現成為可用 manager.activate(); System.out.println("SimpleCalcSvr is running!"); orb.run();

客戶機

如果您考慮一下正在發生的事件的機制,就會明白客戶機和伺服器實際上正是互為映像的。客戶機將所有的引數打包以建立一個請求,然後以它自己的方式來傳送這個請求。伺服器只是將請求中的引數解包,執行運算,將返回值和輸出引數打包,然後向客戶機發迴響應。客戶機則將返回值和輸出引數解包,然後繼續處理。這樣,客戶機打包什麼,伺服器就解包什麼,反之亦然。

這意味著您將會看到客戶機和伺服器具有相似的結構。客戶機還必須建立並初始化一個 ORB。它可以是我們正在使用的 ORB,也可以是另一個供應商提供的 ORB;但是,不能是任意的 ORB,而應該是支援 IIOP 的 ORB,IIOP 是由物件管理集團 (OMG) 定義的、基於 TCP/IP 的互操作性協議。如果您的 ORB 比較舊,那麼請小心,它可能無法與其它 ORB 通話。

首先,我們以相同的方式建立 ORB,就像建立伺服器一樣。

清單 9. SimpleCalcClient.java -- 初始化 ORB

java.util.Properties props = System.getProperties(); props.put("org.omg.CORBA.ORBClass", "com.ooc.CORBA.ORG"); props.put("org.omg.CORBA.ORBSingletonClass", "com.ooc.CORBA.ORBSingleton"); org.omg.CORBA.ORB orb = null; // 初始化 ORB orb = ORB.init(args, props);

看起來眼熟?應該是這樣,它看起來與伺服器完全一樣。現在,客戶機已經連線到了一個 ORB 之上,但我們的目標是呼叫一個服務,而這個服務是在系統中別的地方提供的,需要找到能響應請求的物件。在這個示例中,這意味著要從建立於伺服器上的檔案中獲取一個物件引用。為了找到計算程式伺服器,需要取得儲存在這個檔案中的物件引用的字串版本,然後把它轉換成物件引用,透過這個物件引用就可以進行呼叫了。

清單 10. SimpleCalcClient.java -- 獲取物件引用

System.out.println("Getting reference from string..."); BufferedReader in = new BufferedReader( new FileReader("calcref.ior") ; String ior = in.readLine(); in.close(); calculator calc = calculatorHelper.narrow( orb.string_to_object(ior));

請注意,這裡使用了由 IDL-to-Java 編譯器生成的 calculatorHelper 類。calcref.ior 檔案含有一個物件引用,而不是含有計算程式引用。calculatorHelper 類有一個 narrow 方法,可用來將抽象型別集中到特定的計算程式型別。

仔細看一看計算程式 calc,它表示計算機空間中另外某個地方的一個伺服器。最後必須做的一件事,就是呼叫 calc 上的方法 add()。

清單 11. SimpleCalcClient.java -- 呼叫 add()

System.out.println( calc.add(2,3) ;

結論

已經討論了很多內容,不過請想一想,都學到了什麼。我們的客戶機與伺服器是完全隔離的,客戶機不知道伺服器在什麼樣的硬體上執行,使用的是什麼作業系統,它是用什麼語言編寫的,它是不是多執行緒的,還有,它位於何處 — 是在隔壁,還是距離半個地球之遙。它只知道一點,即如果它呼叫 calc 中的 add(),就會得到可以指望的響應。

提供服務的情形全都是這樣,電話或電力公司也是如此。當您拿起電話的時候,您所期望的是聽到拔號音,然後您的呼叫能暢通連線,您並不在乎電話是透過光纜傳輸的還是透過衛星轉發的,同樣的情況在資訊產業中也正在成為現實。多虧有了 OMG 和這個基本結構,我們才得以加進這個既簡單而又非常有說服力的例子。

接觸CORBA內幕:IOR、GIOP和IIOP

(本文摘自IBM developerWorks)

Dave Bartlett

顧問、作家和講師

2000 年 8 月

內容:

網路

IOR

存根

打包:GIOP 和 CDR

IIOP

結束語

 

7 月,我們建立了一個簡單示例 -- SimpleCalc。這個示例不值得多說;它是單一方法 add(),接受兩個 IDL long 型變數,返回一個 long 型變數。講授與學習 CORBA 的一個難題是:已知它是基於分佈的客戶機和伺服器,從一開始它就變得很複雜。必須立即與網路打交道。所以,讓我們現在就來談談網路。

網路

如果將話題深入一點,將發現許多都值得探討,但又很簡單。我們簡單的計算器伺服器設計成被遠端呼叫,CORBA 專門確保讓我們不必擔心客戶機環境和伺服器環境之間的差異。客戶機對伺服器的遠端呼叫是根據遠端過程呼叫 (RPC) 協議生成的,該協議自 20 世紀 80 年代就存在。RPC 是由各種通訊模型經過多年測試得到的結果 -- 這是已經在產品環境中測試過的可靠且真實的技術。我們現在使用的 CORBA 模型就基於該模型。

圖 1. 網路

可互操作物件引用 (IOR)

讓我們跟蹤方法呼叫。客戶機必須首先獲得計算器的例項。它透過使用 calculatorHelper.java narrow() 方法來達到這一目的。ior 是可互操作物件引用 (IOR) 的字串表示,是從檔案 calcref.ior 中檢索到的。這個檔案是由伺服器寫的,以便客戶機可以定位並連線到它。對 orb string_to_object() 的方法呼叫只取得 ior 字串,並將它轉換成物件引用。以下是客戶機中的程式碼,SimpleCalcClient.java:

calculator calc = calculatorHelper.narrow(orb.string_to_object(ior));System.out.println("Calling into the server");System.out.println( calc.add(2,3) ;

IOR 中有什麼?IOR 是一個資料結構,它提供了關於型別、協議支援和可用 ORB 服務的資訊。ORB 建立、使用並維護該 IOR。許多 ORB 供應商提供了一個實用程式來窺視 IOR 的內部。OOC (Object Oriented Concepts, Inc.) 的 Orbacus 附帶 IORDump.exe,如果您使用 Visibroker,它為您提供了 PrintIOR.exe。也有一些網站為您分析 IOR;可在 Xerox Parc 站點上找到我使用的一個實用程式。因為正在使用 Orbacus,我將對在 SimpleCalc 示例中建立的 IOR 執行 IORDump。得到以下輸出:

C:\_workcorbasem\_sourcescalcsimpl>iordump -f calcref.iorIOR #1:byteorder: big endiantype_id: IDL:corbasem/gen/calcsimpl/calculator:1.0IIOP profile #1:iiop_version: 1.2host: 192.168.0.10port: 4545object_key: (36)171 172 171 49 57 54 49 48 "1/2 1/4 1/2 9610" 48 53 56 49 54 0 95 82 "05816._R"111 111 116 80 79 65 0 0 "ootPOA.."202 254 186 190 57 71 200 248 ".?.9G.." 0 0 0 0 "...."Native char codeset: "ISO 8859-1:1987; Latin Alphabet No. 1"Char conversion codesets: "X/Open UTF-8; UCS Transformation Format 8 (UTF-" "ISO 646:1991 IRV (International Reference Version)"Native wchar codeset: "ISO/IEC 10646-1:1993; UTF-16, UCS Transformation Format 16-bit form"Wchar conversion codesets: "ISO/IEC 10646-1:1993; UCS-2, Level 1" "ISO 8859-1:1987; Latin Alphabet No. 1" "X/Open UTF-8; UCS Transformation Format 8 (UTF-" "ISO 646:1991 IRV (International Reference Version)"

IOR 中嵌入的是 type_id、IIOP 版本、主機地址和埠號,以及物件鍵。type_id 字串是介面型別,眾所周知,它是資源庫標識格式。基本上,資源庫標識是介面唯一的標識。這個標識可以是 DCE UUID 格式(COM 程式設計師比較熟悉它)或者是您指定的本地格式。 IIOP 版本將幫助 IOR 閱讀器(通常是 ORB)正確瞭解 IOR 是哪種格式,因為 OMG 總是改進規範,每個版本的閱讀方法都與以前版本略有不同 。主機地址和埠號將讓我們接觸到與期望的物件通訊的 ORB。物件鍵和許多其它資料都是按特定於服務的資訊的 OMG 標準構建的。這是幫助 OTB 支援伺服器的特定於服務的資料。例如,這些專用 IOR 元件可以編碼 ORB 型別和版本,或者幫助支援 OMG 安全服務的 ORB 實現。以上大多數資訊指定了字元程式碼集轉換,這樣客戶機和伺服器就能夠互相理解。

如果透過 Xerox Parc IOR 語法分析器執行 IOR,將得到以下輸出:

IIOP_ParseCDR: byte order BigEndian, repository id, 1 profile_IIOP_ParseCDR: profile 1 is 124 bytes, tag 0 (INTERNET), BigEndian byte order (iiop.c:parse_IIOP_Profile): bo=BigEndian, version =1.2, hostname=192.168.165.142, port =4545, object_key=<...1961005816._rootpoa......9g......>(iiop.c: parse_IIOP_Profile): encoded object key is <(iiop.c:parse_IIOP_Profile)non-native cinfo is object key is ; no trustworthy most-specific-type info; unrecognized ORB; reachable with IIOP 1.2 at host "192.168.165.142", port 4545

IOR 中最主要的部分是幫助客戶機連線到伺服器的那些部分。可以在 Xerox Parc IOR 閱讀器的輸出中看到這些部分。但是,其它許多資訊是 Orbacus 專有的,其它 IOR 閱讀器不能解釋它。這些專用部分是作為附加到 IOR 的資料序列出現的,並且只有構建 IOR 的 ORB 才懂得這些資料。

存根

現在,我們知道 IOR 帶來了什麼功能。IOR 的目的就是使客戶機能夠連線到伺服器,以便它能夠完成方法呼叫。客戶機必須用 Add 方法將 IOR 轉換成它可以呼叫的實際物件。這是透過使用從 IDL 編譯器中生成的兩個 Java 檔案來完成的。客戶機將首先使用 calculatorHelper 物件將 IOR 的範圍縮小到 _calculatorStub 代理物件。

以下是 Orbacus 附帶的 jidl 編譯器生成的 narrow() 方法:

public static calculator narrow(org.omg.CORBA.Object _ob_v) { if(_ob_v != null) { try { return (calculator)_ob_v; } catch(ClassCastException ex) { } if(_ob_v._is_a(id())) { org.omg.CORBA.portable.ObjectImpl _ob_impl; _calculatorStub _ob_stub = new _calculatorStub(); _ob_impl = (org.omg.CORBA.portable.ObjectImpl)_ob_v; _ob_stub._set_delegate(_ob_impl._get_delegate()); return _ob_stub; } throw new org.omg.CORBA.BAD_PARAM(); } return null;}

可以看到,它最主要的任務是建立一個新的 _calculatorStub 物件。_calculatorStub 充當駐留在伺服器上的實際計算器物件的代理物件。如果您不瞭解代理模式,我將非常樂意向您介紹“四人組”Design Patterns 一書。實際上,代理模式無非是建立一個代表或充當另一個實際物件的替身的物件,另一個物件將最終將呼叫或執行服務。代理模式是一種重要且常用的模式。在所有分散式設計中都會用到它。我敢打賭,您肯定用過這種模式,只不過從沒有稱您的設計為代理模式。

一旦建立了 _calculatorStub,它就代表客戶機的計算器介面。add 方法在伺服器中實現,而該伺服器在 IOR 中定義的地址上的電腦空間中執行。至此,這就所呼叫的 add() 方法。這裡,需要注意兩點:首先,我們必須以 _calculatorStub 的形式呼叫 add 方法。其次,請注意客戶機將中斷直到呼叫返回,就像其它同步方法呼叫一樣。這是一種請求響應協議,它模仿單程式應用程式。程式設計客戶機,然後使用該請求響應協議執行客戶機就像用庫和 API 呼叫建立的常用程式設計開發環境一樣普通自然。這並不表示您不能使用非同步呼叫;您當然可以生成那種型別的呼叫。我將在以後的專欄文章中討論那些話題。

打包:GIOP 和 CDR

至此,在體系結構中,我們已成功欺騙了客戶機,使它相信服務與它在一起。但事實併為如此,並且在以後幾步中,我們必須將資料和方法呼叫鑄造成一種形式,它允許在網路上繼續該呼叫,並且可以在另一端使用該呼叫。這並不是無關重要的,且這種模型已經問世好幾年了。您也許已經多次見過 OSI 模型了,在圖 2 中,您將看到 OSI 模型,旁邊就是 OMG 所使用的模型。

圖 2. OSI 的結構 vs. GIOP 協議堆疊

客戶機呼叫介面操作時,它必須將運算元據(in 和 inout 引數)傳送到伺服器。此時的困難在於將資料轉換成公共格式,這樣伺服器抽取運算元據時不會誤解或錯誤對齊資料。因為伺服器可以是任意數量不同的平臺,我們應該預計到客戶機和伺服器之間的體系結構差異。CORBA 透過嚴格定義如何將資料轉換或打包成公共格式來處理這種問題。然後在連線的另一端重新組成或解包資料。這是透過用最基本的結構表示資料來完成的,最基本的結構就是位元組流,也就是八位元流。

CORBA 規範將八位元流定義成“一種抽象表示法,通常對應於要透過 IPC 機制或網路傳輸來傳送到另一個程式或另一臺機器的記憶體緩衝區”。IDL 八位元準確對映成 Java 位元組。它們都是 8 位值,客戶機或伺服器都不打包這種值。將這些引數轉換成八位元序列的根本目的是產生用於資訊交換的基本結構。

現在,我們應當窺視 _calculatorStub 生成的程式碼的內部資訊。請記住這不是由我編寫的 -- 它是由 Orbacus 附帶的 IDL-到-Java 編譯器 jidl 生成的。

【發表回覆】【進入論壇此帖】【關閉】

yuxq 回覆於:2003-09-17 18:49:03

//// IDL:corbasem/gen/calcsimpl/calculator/add:1.0//public int add(int _ob_a0, int _ob_a1) { System.out.println("Inside _calculatorStub.add()"); while(true) { if(!this._is_local()) { org.omg.CORBA.portable.OutputStream out = null; org.omg.CORBA.portable.InputStream in = null; try { out = _request("add", true); out.write_long(_ob_a0); out.write_long(_ob_a1); in = _invoke(out); int _ob_r = in.read_long(); return _ob_r; } catch(org.omg.CORBA.portable.RemarshalException _ob_ex) { continue; } catch(org.omg.CORBA.portable.ApplicationException _ob_aex) { final String _ob_id = _ob_aex.getId(); in = _ob_aex.getInputStream(); throw new org.omg.CORBA.UNKNOWN("Unexpected User Exception: " + _ob_id); } finally { _releaseReply(in); } } else { org.omg.CORBA.portable.ServantObject _ob_so = _servant_preinvoke("add", _ob_opsClass); if(_ob_so == null) continue; calculatorOperations _ob_self = (calculatorOperations)_ob_so.servant; try { return _ob_self.add(_ob_a0, _ob_a1); } finally { _servant_postinvoke(_ob_so); } } }}

要注意的部分是包含 _request()、write_long() 呼叫,和 _invoke() 及隨後的 read_long()。對 _request() 的呼叫使用要呼叫的方法名稱,和顯示是否需要響應的布林 (boolean) 值。它返回 CORBA 規範指定的 org.omg.CORBA.portable.OutputStream 物件。對於可移植性,這是必要的,因為 Java 經常被下載,並且依賴於它執行的機器上的公共庫。對於 ORB 是這樣,對於 IO 也是這樣。因此,CORBA 規範為 Java 語言定義了比其它語言更廣泛的可移植型別集合。

通用 ORB 間協議 (GIOP)

通用 ORB 間協議 (GIOP) 用來為這個由不同計算機及其各種體系結構組成的凌亂世界中傳送訊息定義結構和格式。如果使用 GIOP 的結構和格式,並將它們應用於 TCP/IP,那麼就得到 IIOP。GIOP 有兩個版本:1.0 和 1.1。這就意味著我們的訊息根據其符合的 GIOP 版本可能有不同的格式。

至此,我們必須看一下 GIOP 以瞭解請求在變成正確格式化的 CORBA 請求時所要經歷的操作。儘管我們將仔細研究請求,響應只是請求的映象影像。如果您知道請求的工作原理,那麼您就能瞭解響應。

GIOP 請求訊息分成三部分:GIOP 訊息頭、GIOP 請求頭和請求主體。GIOP 訊息頭表示這就是一條 GIOP 訊息。它包含 GIOP 版本、訊息型別、訊息大小,然後根據您是使用 1.0、1.1 還是 1.2,包含位元組次序 (GIOP 1.0) 或一個位標誌欄位,該欄位包括位元組次序以及一些保留位標誌。GIOP 1.1 新增了對訊息儲存碎片的支援,GIOP 1.2 新增了雙向通訊支援。更新的版本都是向下相容的。

公共資料表示 (CDR)

公共資料表示 (CDR) 是 CORBA 呼叫中將使用的資料型別的正式對映。客戶機生成請求時,它不必知道請求要傳送到什麼地方,或者哪一臺伺服器將響應該請求。CORBA(作為規範)和 GIOP(作為規範的一部分,定義訊息結構和傳送)被設計成允許實現一個介面的可能的多種不同伺服器之一來響應請求。規範必須定義如何打包操作中的資料,這樣所有可能的伺服器都可以抽取引數並呼叫遠端操作,並且資料轉換不會產生多義性。這種轉換問題的典型示例就是指標。客戶機中的指標對於在另一臺機器上執行另一個程式的伺服器意味著什麼?毫無意義。或者,變數如何在使用不同定址方案(大尾數法,小尾數法)的機器間傳送?這些資料型別必須轉換成伺服器能夠理解並使用的流。顯然,CORBA 規範在公共資料表示方面是十分詳細的。這是我們不必涉足的細節層次,但如果您想要了解詳細資訊,請閱讀規範或 Ruh、Herron 和 Klinkeron 合著的 IIOP Complete 一書。

一旦包裝了所有資料,就將使用 IOR 中的資訊來建立連線。您可以區別 IOR 的結構,通常必須使用 TCP 作為傳送機制。但是,也可以使用其它傳送(再次提醒,請參閱 CORBA 規範以獲取詳細資訊)。ORB 守護程式負責查詢 IOR 指定的物件實現,以及建立客戶機和伺服器之間的連線。一旦建立了連線,GIOP 將定義一組由客戶機用於請求或伺服器用於響應的訊息。客戶機將傳送訊息型別 Request、 LocateRequest、CancelRequest、Fragment 和 MessageError。伺服器可以傳送訊息型別 Reply、 LocateReply、CloseConnection、Fragment 和 MessageError。

如果我們扯開 GIOP 訊息,它看上去就像:

0x47 0x49 0x4f 0x50 -> GIOP, the key0x01 0x00 -> GIOP_version0x00 -> Byte order (big endian)0x00 -> Message type (Request message)0x00 0x00 0x00 0x2c -> Message size (44)0x00 0x00 0x00 0x00 -> Service context0x00 0x00 0x00 0x01 -> Request ID0x01 -> Response expected0x00 0x00 0x00 0x24 -> Object key length in octets (36)0xab 0xac 0xab 0x31 0x39 0x36 0x31 0x300x30 0x35 0x38 0x31 0x36 0x00 0x5f 0x520x6f 0x6f 0x74 0x50 0x4f 0x41 0x00 0x000xca 0xfe 0xba 0xbe 0x39 0x47 0xc8 0xf80x00 0x00 0x00 0x00 -> Object key defined by vendor0x00 0x00 0x00 0x04 -> Operation name length (4 octets long)0x61 0x64 0x64 0x00 -> Value of operation name ("add")0x20 -> Padding bytes to align next value

您應該瞭解大概情況了。這種訊息流是高度結構化的。它也必須是,為了客戶機可以建立伺服器可以轉換成實現的訊息 -- 不管實現如何執行,或在哪裡執行。伺服器也必須為在響應客戶機時使用的返回值和引數執行相同操作。此訊息格式在 OMG 成就中非常重要,因為它可以實現可移植性和互操作性目標。這種可移植性將給予您我們在第一篇專欄文章中談到的自由。您無需關心硬體、資料庫或程式語言。只要關心您的資訊就行了。

IIOP

我們還沒有徹底結束。GIOP 是 CORBA 方法呼叫的核心部分。GIOP 不基於任何特別的網路協議,如 IPX 或 TCP/IP。為了確保互操作性,OMG 必須將 GIOP 定義在所有供應商都支援的特定傳輸之上。如果有詳細和簡潔的訊息規範,則不會提供互操作性,因為所有供應商使用不同的傳送機制來實現這個互操作性。因此,OMG 在最廣泛使用的通訊傳輸平臺 -- TCP/IP 上標準化 GIOP。GIOP 加 TCP/IP 等於 IIOP!就這麼簡單。

需要使用已釋出物件服務的客戶機將使用 IOR 中的值來啟動與物件的連線。我們已經繞了一個圈子,又回到了 IOR。IOR 對於 IIOP 是至關重要的,任何要對某個物件呼叫方法的客戶機都要將“請求”訊息傳送到 IOR 中詳細說明的主機和埠地址。在主機上,伺服器程式在請求進入時會偵聽埠,並將那些訊息傳送到物件。這就要求伺服器主動偵聽請求。

生活有陰陽兩面,每件事都有缺點,互操作性和 IIOP 也不例外。OMG 推出和執行了 IIOP,對比 ORB 供應商它們自己的伺服器上實現此功能,並且沒有伺服器方可移植性的年代,這是一大改進。但如果要求伺服器是位置無關的,我們應該做什麼?如果主機和埠值嵌入 IOR 中,每當您將物件從一個伺服器移到另一個伺服器,以均衡負載時,這個問題就會突然出現。可喜的是這個問題已經解決了;但又有一條壞訊息,每家供應商的解決方法都不同。

結束語

現在,將負載均衡話題留到將來討論。如果您在幾年前有 CORBA“經驗”(也就是說在一段時期內),而現在從事另一項研究,我相信您將感到驚喜。CORBA 規範已經獲得很大進步,可以確保您為一個 ORB 編寫的伺服器程式碼可以移植到執行另一個 ORB 的另一臺伺服器上。解決方案非常簡單,並且以經典的協議為基礎。客戶機和伺服器間的標準交換語法基於某些 OMG 詳細說明的需求。OMG 透過使用網路定址協議 (IIOP) 獨立於訊息傳遞協議 (GIOP),為其規範建立了更多功能。這也確保隨著資訊工業的變動(的確發展很快),CORBA 仍能跟上它的步伐。我最喜歡的是,對於我們剛討論的關於如何使之成功完成的 CORBA 物件呼叫,我不必編寫程式碼!在 ORB 中和用 IDL 標準化介面的功能中已經概括了網路測量和打包的詳細資訊。

OMG 介面定義語言

----定義分散式服務的能力

(本文摘自IBM developerWorks)

Dave Bartlett

顧問、作家和講師

2000 年 9 月

內容:

IDL 基本型別

使用者定義的型別

常數定義

使用者異常

陣列、序列、字串

名稱和作用域

介面

結束語

 

一切都要從介面定義語言 (IDL) 開始。當我們採用 RPC 或 COM 技術以及 CORBA 技術來編寫分散式系統時都需要它。在各種情況下,介面定義語言提供了將物件的介面與其實現分離的能力。IDL 提供了抽象,它提供了將事務與其具體實現分離的概念。它還為我們提供了一套通用的資料型別使得我們可以使用它們來定義更為複雜的型別。我們將採用所有這些資料型別來定義分散式服務的功能。IDL 的另一個好處是它剝離了程式語言和硬體的依賴性。本文探討了 OMG IDL 的內建型別和關鍵字。

IDL 是一種規範語言。它允許我們從實現中剝離物件的規範(如何與它互動)。這是一個約定:“客戶機女士,如果您要呼叫這個方法,請傳送這些引數,然後我,伺服器先生,將把這個字串陣列返回給您。”使用這個介面的客戶機程式設計師不知道介面背後的實現細節。

OMG IDL 看上去很像 C 語言。這就很容易將這兩種語言以及它們的關鍵字做比較。但是,這種相似性只流於表面。每種語言的目的是完全不同的。我們在討論這種語言時,您已經記住 OMG IDL 的目的是定義介面和精簡分佈物件的過程。

IDL 基本型別

OMG 介面定義語言有一些看上去應該很熟悉的基本型別。以下就是這些內建型別的表:

表 1. IDL 基本型別

型別 範圍 最小大小(以位為單位)

short -215 到 215-1 16

unsigned short 0 到 216-1 16

long -231 到 231-1 32

unsigned long 0 到 232-1 32

long long -263 到 263-1 64

unsigned long long 0 到 264-1 64

float IEEE 單精度 32

double IEEE 雙精度 64

long double IEEE 雙位元組擴充套件浮點數 15 位指數,64 位帶符號小數

char ISO Latin-1 8

wchar 從任何寬字符集編碼寬字元,如 Unicode 依賴於實現

string ISO Latin-1,除了 ASCII NUL 以外 可變化

Boolean TRUE 或 FALSE 未指定

octet 0 到 255 8

any 自己描述的資料型別,可表示任何 IDL 型別 可變化

整數型別

OMG IDL 的整數型別非常簡單。雖然它沒有提供 int 型別,但它不會受到 int 在不同平臺上的取值範圍不同所帶來的多義性的困擾。然而,IDL 確實提供幾種整數型別,2 位元組 (short)、4 位元組 (long) 和 8 位元組 (long long) 的整數型別。

所有這些整數型別都有相應的無符號數型別。這對於 Java 程式又產生了問題,因為 Java 程式語言不支援無符號數型別。儘管這不是 OMG IDL 的特性,它還是在 Java-to-IDL 的對映中建立了一種獨有的局面,我們將在下個月的專欄文章中討論 Java-to- IDL 的對映。但在此之前,您已經考慮如何將 IDL 中的 unsigned short 對映成一種 Java 型別。使用 Java short 還是 Java int?它們各自的利弊是什麼?這些是語言對映的作者必須努力解決的問題,並且這是一個很好的練習,可以幫助您為閱讀下一篇專欄文章做好準備。

浮點型別

OMG IDL 浮點數型別 float、double 和 long double 遵循 IEEE 754-1985 二進位制浮點數算術的標準。目前,long double 用於巨大數字,您也許會發現您的特殊語言對映還不支援這種型別。

char 和 wchar

我們都使用相同的術語,字符集就是字母或其它構成單詞的字元以及其它本機語言或計算機語言的基本單元的集合。編碼字符集(或程式碼集)是一組明確的規則,它建立了字符集和集合的每個字元與其位表示法之間的一一對應關係。

處理 char 時,必須記住 OMG IDL 必須分兩個層次處理字符集。首先必須明確規定從哪個字符集生成 IDL 定義。詞法約定(表示 IDL 檔案的關鍵字、註釋和文字的字元記號)規定 ISO 8859.1 字符集表示 IDL 檔案中的字元。是的,連 IDL 都必須有一個標準字符集,它將構建在這個字符集上。ISO 464 定義了空字元(null)和其它圖形字元。

接著,OMG 必須處理從一個計算機系統到另一個計算機系統之間的字元傳輸。這意味著可能涉及到從一個字元程式碼集到另一個字元程式碼集的轉換,這取決於語言繫結。在上個月的專欄文章中,我們對 Orbacus Object Reference 執行了 IORDump 操作,並且發現了以下資訊:

Native char codeset: "ISO 8859-1:1987; Latin Alphabet No. 1"Char conversion codesets: "X/Open UTF-8; UCS Transformation Format 8 (UTF-" "ISO 646:1991 IRV (International Reference Version)"Native wchar codeset: "ISO/IEC 10646-1:1993; UTF-16, UCS Transformation Format 16-bit form"Wchar conversion codesets: "ISO/IEC 10646-1:1993; UCS-2, Level 1" "ISO 8859-1:1987; Latin Alphabet No. 1" "X/Open UTF-8; UCS Transformation Format 8 (UTF-" "ISO 646:1991 IRV (International Reference Version)"

可以看到,IOR 可以包含程式碼集資訊,以在轉換時協調首選程式碼集和可用程式碼集。

解決了所有問題後,您應該知道 OMG IDL char 是一個 8 位變數,可以用兩種方法表示一個字元。首先,它可以從面向位元組的程式碼集編碼單位元組字元,其次,當在陣列中使用時,它可以從多位元組字符集(如 Unicode),編碼任何多位元組字元。

Wchar 只允許大於 8 個位元組的程式碼集。規範不支援特殊的程式碼集。它允許每個客戶機和伺服器使用本機的程式碼集,然後指定如何轉換字元和字串,以便在使用不同程式碼集的環境之間進行傳輸。

Boolean

這裡沒有什麼可以多說的 -- Boolean 值只能是 TRUE 或 FALSE。

Octet

octet 是 8 位型別。因為保證了 octet 在地址空間之間傳送時不會有任何表示更改,因此這就使它變成了一種非常重要的型別。這就表示您可以傳送二進位制資料,並且知道當將它打包時,它的形式仍然相同。其它每種 IDL 型別在傳輸時都有表示變化。例如,根據 IOR 程式碼集資訊的指示,char 陣列會經歷程式碼集轉換。而 octet 陣列卻不會。

any 型別

IDL any 是一種包含任何資料型別的結構。該型別可以是 char 或 long long 或 string 或另一種 any,或者是已經建立的一種型別,如 Address。any 容器由型別碼和值組成。型別碼描述 any 的值部分中的內容是什麼。

如果您擁有 C++ 經驗,則可以將 any 看作是自我描述的資料型別,它類似於 void *,但更安全。如果有 Visual Basic 經驗,可以將 any 看作類似於 variant。當我們討論 IDL-to-Java 對映時,any 型別的結構和它如何對使用者定義的型別產生作用將變得一目瞭然。

使用者定義的型別

基本型別是必不可少的;它們為介面定義提供了構件塊。OMG IDL 為您提供了定義您自己的型別的能力,這可以幫助減少複雜程度並且讓您可以根據基本型別組成更精巧的資料型別。這些複雜的型別可以是列舉、結構和聯合,或者您可以使用 typedef 來建立型別的新名稱。

命名的型別

應該使用 typedef 建立新的型別名稱,這將幫助解釋介面或儲存輸入。

例如,您也許想在方法 PresentWeather(..., in float Pressure, ...) 中傳送氣壓值。如果在該方法中使用 typedef float 語句,這將使該方法更具可讀性。

typedef float AtmosPressure;

在 C++ 中,typedef 關鍵字表示型別定義,實際上別名也許是更為精確的術語。對於 OMG IDL,也許是這樣,也許不是,這取決於其所對映到的實現語言。CORBA 規範不保證 short 的兩種 typedef 是相容的和可互換的。

在文體上,應注意不要為現有型別建立別名。您應該嘗試建立不同概念的型別,它將為您的 IDL 新增可讀性和可擴充套件性。最好是明確定義一次邏輯型別,然後在整個介面中不斷使用該定義。

列舉

OMG IDL 列舉是將名稱附加到數字的一種方法,從而讀取程式碼的人就可以瞭解到更多的含義。OMG IDL 版的列舉看上去象 C++ 版本的列舉。

enum CloudCover{cloudy, sunny};

CloudCover 現在就成為可以在 IDL 中使用的一種新型別。由於在一個列舉中可以有最多 232 個標識,OMG IDL 保證列舉被對映到至少 32 位的型別。規範中沒有規定標識的有序數值,但它規定了將保持順序。因此,不能假設 cloudy 永遠擁有序數值 0 -- 某些語言對映可能將 1 賦值給它。但可以確保 cloudy 小於 sunny。

如果認為 IDL 的目的是定義跨各種系統的介面,那麼不指定序數值是明智的。您只將值傳送到伺服器。即, "cloudy"。在伺服器空間中,cloudy 可以由 0、1 或如何實現語言規定的值表示。某些實現語言不允許您控制序數值,而 C++ 允許。OMG IDL 不允許空的列舉。

結構

struct 關鍵字提供了將一組變數集中到一個結構的方法。一旦建立了,struct 表示可以在整個介面定義中被使用的新型別。

struct Date { short month; short day; long year;};

定義 struct 時,要確保所建立的型別是可讀的。不要在不同的名稱空間中建立幾個不同的同名結構,這隻會使 IDL 的使用者搞糊塗。

識別聯合

OMG CORBA 規範將 IDL 聯合描述成 C 聯合型別和 switch 語句的混合物。IDL 識別聯合必須有一個型別標記欄位用於確定在當前例項中使用哪個聯合成員。像 C++ 一樣,一次只能有一個聯合成員是活動的,並且可以從其識別名稱來確定該成員。

enum PressureScale{customary,metric};union BarometricPressure switch (PressureScale) { case customary : float Inches; case metric : default: short CCs;};

在以上示例中,如果識別名稱是 metric,或者使用了不能識別的識別名稱值,那麼 short CCs 就是活動的。如果識別名稱是 customary,那麼 float 成員 Inches 是活動的。聯合成員可以是任何型別,包括使用者定義的複雜型別。識別名稱型別必須是整數型別(short、long、long long 等,以及 char、boolean 或 enumeraton)。

常數定義

在 IDL 中定義常數的語法和語意與 C++ 一樣。常數可以是整數、字元、浮點數、字串、Boolean、octet 或列舉型,但不能是 any 型別或使用者定義的型別。這裡有一些例子:

const float MeanDensityEarth = 5.522; // g/cm^3const float knot = 1.1508; // miles per hourconst char NUL = '';

可以用十進位制、十六進位制或八進位制記數法定義整數常數:

const long ARRAY_MAX_SIZE = 10000;const long HEX_NUM = 0xff;

對於指數和小數,浮點字元使用常用的 C++ 約定:

const double SPEED_OF_LIGHT = 2.997925E8;const double AVOGADRO = 6.0222E26;

字元和字串常數支援標準換碼序列:

const char TAB = ' ';const char NEWLINE = ' ';

只要沒有混合的型別表示式,就可以在常數說明中使用算術運算子。

使用者異常

IDL 允許建立異常來指出錯誤條件。IDL 使用者異常類似於一個結構,在這個結構中,異常可以包含所選型別的任意多錯誤資訊。最終是從方法中使用異常。這裡有一個例子:

exception DIVIDE_BY_ZERO { string err;};interface someIface { long div(in long x, in long y) raises(DIVIDE_BY_ZERO);};

異常將建立名稱空間 -- 因此,異常中的成員名必須是唯一的。異常不能當作使用者定義型別的資料成員使用。OMG IDL 中沒有異常繼承。

陣列、序列和字串

每次只傳送一個元素是可以的,但我們通常有一個列表或向量或矩陣的資訊要在客戶機和伺服器之間來回傳送。陣列幾乎是所有程式語言所共有的型別,但一種語言的陣列與另一種語言的陣列實現通常是不同的。OMG IDL 開發者面臨的挑戰是建立一組陣列型別,它可以輕易地被對映到實現語言中。這種需求產生了 IDL array 和 sequence。string 型別是一種特殊的序列,它允許語言使用它們的字串庫和最佳化。

陣列

OMG IDL 有任意元素型別的多維固定大小的陣列。所有陣列都必須是有界的。陣列非常適合於與擁有固定數量元素的列表一起使用,而這些元素通常都是存在的。例如:

// bounded and unbounded array examplestypedef long shares[1000];typedef string spreadsheet[100][100];struct ofArrays { long anArray[1000];};// unbounded arrays NOT ALLOWED// typedef long orders[];

必須指定陣列維數,並且它們必須為正的整型常量來表示。IDL 不支援在 C 和 C++ 中的開放陣列,這是因為沒有指標支援。必須出現 typedef 關鍵字,除非指定的陣列是結構的一部分。

在許多例項中,CORBA 規範所沒有提及的內容與它提及的內容是一樣重要的。規範不以任何方式、形態或形式指定陣列下標編排方法。這表示從一種實現語言到另一種實現語言的陣列下標可以是不同的,這樣您不能假定將陣列下標從客戶機傳送到伺服器時,伺服器會調整並指向正確的陣列元素。某些語言的陣列下標從 0 開始,而其它的則是從 1 開始。

序列

在開發介面定義時,會大量使用序列。如果正在處理資料陣列,其中許多值相同,那麼序列就可以提供靈活性。

序列是變長向量,它有兩個特徵:元素的最大大小,在編譯時確定,可以是無限的;長度,在執行時確定。序列可以包含所有型別的元素,不管是基本型別還是使用者定義的型別。

序列可以是有界的,也可以是無界的。例如:

// bounded and unbounded sequence examplestypedef sequence Unbounded;typedef sequence Bounded;

一個無限序列可以擁有任意多個元素,只會受到平臺記憶體大小的限制。有限序列則有邊界限制。這兩種序列都可以不包含元素、使用者定義的型別,但可以包含其它序列。

string 和 wstring

string 等價於 char 的序列,而 wstring 表示 wchar 的序列。作為 C 和 C++ 的折衷, OMG IDL string 和 wstring 可以包含任何字元,除空字元以外。char 或 wchar 約定確定了型別為 string 的元素大小由 8 個位元組表示,wstring 型別的元素大小是 16 個位元組或更多。

IDL 中的字串很特殊,然而在大多數語言中字串都很特殊。許多語言都用庫和特殊最佳化來處理字串處理。透過將字串歸到它自己的型別,OMG 允許語言對映使用特殊最佳化,這些最佳化不會與通用序列一起處理。

名稱和作用域

所有 OMG IDL 標識都是區分大小寫的。這意味著將把兩個只有字元大小寫不同的標識看作是彼此的重新定義。應該注意根據區分大小寫的語言,所有的定義引用必須與定義的大小寫相同。

IDL 作用域規則非常易於掌握。整個 OMG IDL 內容和透過前處理器偽指令傳入的所有檔案共同組成了命名作用域。任何未出現在某個作用域中的定義都是全域性作用域的一部分 -- 只有一個全域性作用域。在全域性作用域中,以下定義組成了作用域:module、interface、struct、 union、operation 和 exception。

module 關鍵字用於建立名稱空間;這是其唯一目的。您定義的模組將建立一個邏輯組,模組的自由使用防止了全域性名稱空間的汙染。根或全域性空間被認為是空的,檔案掃描中每次遇到模組關鍵字時,字串 "::" 和其標識都會附加到當前根的名稱後面。這就可以透過包括其它名稱作用域來引用其它模組中的型別,如以下示例中的 Pennsylvania::river。

一個標識可以在一個作用域中定義一次,但可以在巢狀作用域中重新定義。下例將解釋這些要點:

module States { // error: redefinition // typedef sequence states; module Pennsylvania { typedef string river; interface Capital { void visitGovernor(); }; }; module NewYork { interface Capital { void visitGovernor(); }; interface Pennsylvania { void visit(); }; }; module NewJersey { typedef Pennsylvania::river NJRiver; // Error // typedef string Pennsylvania; interface Capital { void visitGovernor(); }; };};

每個內部模組(Pennsylvania、New York 和 New Jersey)都有一個介面 Capital 和一個操作 visitGovernor()。但它們並不相互牽連,因為它們在各自的模組中。當我們嘗試在模組 States 中建立一個同名序列時,遇到了一個重新定義 'State' 的問題。重新定義 Pennsylvania 發生在已經將它介紹為 New Jersey 中 'NJRiver' 的作用域解析標識之後。請注意,我們在帶有介面 Pennsylvania 的 New York 模組中沒有發生錯誤,因為透過某些作用域解析標識介紹外部 Pennsylvania 模組。

介面

現在該定義介面了,它是我們學習 OMG 介面定義語言的首要原因。有一個好方法來理解 IDL 介面:它指定了服務實現和使用它的客戶機之間的軟體約定。讓我們開始定義介面吧,這將運用我們所學到的 IDL 知識。由於這一切都與通訊有關,就讓我們看一些定義 Listener 和 Speaker 的 IDL。Listener 必須連線到 Speaker,然後 Speaker 將訊息傳送給 Listener。這是一個回撥的例子。

// Thrown by server when the client passes// an invalid connection id to the serverexception InvalidConnectionIdException{ long invalidId;};// This is the callback interface that// the client has to implement in order// to listen to a talker.interface Listener{ // Called by the server to dispatch messages on the client void listen(in string message); // Called by the server when the connection // with the client is successfully opened void engage(in string person); // Called by the server when the connection with the client is closed void disengage(in string person);};// interface on the server sideinterface Speaker{ // Called by the client to open a new connection // Returned long is the connection ID long register(in Listener client, in string listenerName); // Makes the server broadcast the message to all clients void speak(in long connectionId, in string message) raises(InvalidConnectionIdException); // Called by the client to sever the communication void unregister(in long connectionId) raises(InvalidConnectionIdException);};

使用這個定義,我們定義了兩個新的 CORBA 介面型別:Listener 和 Speaker。每個介面都有一些方法,它們將由連線的另一端使用。客戶機將透過獲取對實現 Speaker 介面的伺服器物件的初始物件引用來啟動連線。這個物件引用可以傳送給客戶機,或者可以從命名服務中檢索到這個引用。最重要的是,客戶機首先聯絡 Speaker。接著,客戶機(即 Listener,因為它實現 Listener 介面)必須註冊到 Speaker,並將引用傳給 Listener 介面。這就使它們可以從 Speaker 處接收到訊息。

要注意的一點是在 register 方法中 Listener 介面被當作一個型別使用。介面名稱變成了型別,可以當作引數傳送。看上去就像在傳送 Listener 物件,但實際是一個物件引用。這是提供位置透明性的 CORBA 模型的另一個示例。

有一點值得注意,每個物件引用 (IOR) 僅指向一個介面。每個介面都披露一個或多個分散式物件的詳細資訊。我說“一個或多個”是因為可以有幾千個物件實現分散式系統中的同一個介面。在這個示例中,Speaker 可以將訊息傳送到幾千個 Listeners。因而在某種程度上,IDL 介面對應於類定義,CORBA 物件對應於類例項。

結束語

對於 OMG IDL,我只是介紹了其的皮毛。顯而易見,OMG IDL 提供了一組內容豐富的內建型別和關鍵字,它們可以用來為與分散式系統中的物件的互動建立嚴密的描述。由於這種語言類似於 C 語言,您應該瞭解所有使 C 語言變得如此成功的描述功能。所有 OMG 服務定義都是用 IDL 編寫的,證明 OMG IDL 的強大功能。所有垂直市場標準化努力(Financial、CORBAMed 等)都是用 IDL 編寫的,這證明了其靈活性。

學習正確和有效地使用 OMG IDL 是您開始學習 CORBA 和編寫優秀的分散式系統的良好起點。每件事都從 IDL 開始,如果您在專案開始時正確運用了 IDL,那麼您成功的機會會成倍增長。

IDL-to-Java的對映(1):

怎樣將離散的構件介面定義轉換為 Java 元素

(本文摘自IBM developerWorks)

Dave Bartlett

顧問,作家,講師

2000年10月

內容:

前提

IDL-to-Java 庫

基本資料型別

holder 類

結論

這篇文章開始闡述 IDL-to-Java 的對映。這個月的專欄介紹基本的資料型別、結構和資料傳遞。下個月我們將會介紹更加複雜的型別。語言對映並非無足輕重,COBRA 規範中有很大一部分闡述的就是多語言對映。

COBRA 規範詳細說明了介面定義語言(IDL)並詳細說明了 IDL 到幾種程式語言的對映,如 C,C++,ADA,COBOL, Lisp,Smalltalk 和 Java。IDL 的優勢在於它完整而詳細描述了介面及操作引數。 IDL 介面提供了開發使用介面操作的 Client 和實現介面的 Server 所需要的資訊。當然,Client 和 Server 並沒有在介面中編寫,IDL 只是一種純粹的描述性語言。 Client 和 Server 用完全意義上的程式語言來編寫。IDL 語言對映應該為介面定義提供一致的、可移植的構架。那麼這些對映的介面就可以在 Server 端實現,或者像其它方法一樣由 Client 端呼叫。對於使用的每一種程式語言來說,都需要有一種對映來方便的轉換已定義的 IDL 概念。 IDL 概念到 Client 語言結構的對映取決於程式語言的結構和能力。例如,一個 IDL 異常(exception)在不提供 exception 的語言中可能被對映為結構(structure),而在提供 exception 的語言中就可以直接對映為 exception。每種語言的特性和效率必須與之相適應。

IDL 到程式語言對映的前提

所有的語言對映都有近似的結構。它們必須定義語言中的表達方法:

· 所有的 IDL 基本資料型別

· 所有的 IDL 結構資料型別

· IDL 中定義的常量

· IDL 中定義的物件引用

· 對操作的呼叫,包括傳遞引數和接收結果

· 異常,包括當操作產生異常時的處理和訪問異常引數的方法

· 屬性訪問

· ORB 定義的運算子號,如動態呼叫介面,物件介面卡等等。

一個完整的語言對映允許程式設計師以對於某種特定程式語言來說很便捷的方式來訪問所有的 ORB 功能。為了支援原始碼的可移植性,所有的 ORB 實現都要支援某種語言的同一對映。

MotherIDL

在本文中將使用一個叫做 MotherIDL 的檔案-- motheridl.idl。以上要求這一 IDL 檔案都可以做到,它的目的就是示意並檢驗部分對映。你最好先瀏覽它一下,這樣我們逐步講述的時候你就會對它比較熟悉了。

為了檢驗對映,你需要一個 IDL-to-Java 的編譯器。每個 CORBA ORB 都至少帶有一個 IDL 到某種語言的編譯器。它們大多針對 C++ 或 Java 程式語言,當然也有其它的。新增加的還有針對 Python 和 Delphi 的。本欄我們要使用 Object Oriented Concepts, Inc. 的 Orbacus ORB 所帶的 JIDL。(見 參考資料) 當然你也可以使用任何 IDL 到 Java 的編譯器,但是要確定它相容 CORBA 2.3,因為如果編譯器的版本較早的話你的結果可能有本質的區別。

現在首先要做的就是執行 IDL-to-Java 的編譯器來編譯 motheridl.idl.

jidl --output-dir . . . . . . MotherIDL.idl

這一步很奇妙,它在提供支援和通用 CORBA 通道的同時給出了一大堆 IDL 檔案所對映的 Java 檔案。

IDL-to-Java 的庫結構

我們要學習的第一個對映是 IDL 關鍵詞 module 到 Java 的關鍵詞 package 的對映。這是一個簡單的完全對映。如果在 IDL 檔案中有關鍵詞 module ,你的 IDL 到 Java 編譯器將會用關鍵詞 package 生成一個 Java 類的目錄結構和庫結構。(如果你對於 Java 程式中如何使用關鍵詞 package 還有什麼困惑的話,那你現在應該去複習一下了。)這一對映規定了從 IDL 生成的大部分結構,對 IDL 到 Java 的對映有著重要影響。

以 motheridl.idl 為例,你將在 IDL 檔案中看到如下結構:

module corbasem { module gen { module motheridl { module holderexample { ... }; module conflicts { ... }; module basictypes { ... }; module constructedtypes { ... }; module holderexample2 { ... }; module MI { ... }; module MI2 { ... }; }; };};

這轉換為以下的目錄結構:

E:\_workTICORBAProjectscorbasemgenmotheridl>dir /AD /S Volume in drive E has no label. Volume Serial Number is B415-7161Directory of E:\_workTICORBAProjectscorbasem7/15/2000 01:41p .07/15/2000 01:41p .. 0 File(s) 0 bytesDirectory of E:\_workTICORBAProjectscorbasemgen07/15/2000 01:41p .07/15/2000 01:41p .. 0 File(s) 0 bytesDirectory of E:\_workTICORBAProjectscorbasemgenmotheridl07/15/2000 01:41p .07/15/2000 01:41p ..07/15/2000 01:41p basictypes07/15/2000 01:41p conflicts07/15/2000 01:41p constructedtypes07/15/2000 01:41p holderexample07/15/2000 01:41p holderexample207/15/2000 01:41p MI07/15/2000 01:41p MI2 0 File(s) 0 bytes

將 IDL 對映為 Java 元素的一個基本思想是一致性。如同其它任何類庫一樣,它們必須存在穩定性,也就是說在修改庫中的類時不必刪除現有的方法;不改變介面。CORBA 在這方面應該做的更好,因為多個 ORB 提供商將要使用這一對映來生成類庫。我們希望在不同 ORB 實現之間有著一致性;這意味著可移植性。如果 ORB 提供商A的 IDL 到 Java 對映在 org.VendA.Excep 的 package 中提供了 UserException ,而提供商B在 org.VendB.UtilTypes 的 package中也提供了相同的 UserException ,Client 或 Server 的程式碼將不能夠移植。Client 或 Server 移動到另一個 ORB 時需要改變程式碼並重新編譯。這可不是我們選擇 CORBA 的原因!我們希望並要求可移植性;因此 OMG 規定了庫結構。

在 Java 程式語言中,關鍵詞 package 將 Java 類組成類庫,並控制對類庫中的構件的訪問。我們的 Java 類庫中將包含 Java 程式語言中需要編譯的所有素材,這些我們已經在 IDL 中描述過了。但是為了不同提供商的類庫之間的可移植性,必須定義類庫結構或者類庫包,並且嚴格遵守這些定義。只有這樣 Client 才能依賴於程式碼並且保證不用在不同提供商的ORB之間移植時重寫程式碼。

在 IDL 到 Java 對映的可移植性部分中規定了 API,它提供了庫結構和最小功能集,使 Java ORB中可以使用可移植的存根和骨架。因為 Java 類經常被下載,它們往往來自獨立於ORB提供商的程式碼,因此對於 Java 程式語言的互操作性需求就超過了其它語言。出於這些原因,定義存根和骨架使用的介面是最基本的要求。如果這些結構不加以定義的話,存根(或骨架)的使用將需要一個或兩個方案。一個要求由 IDL 到 Java 編譯器或ORB提供商提供的類似工具(或者與ORB所使用的相容)生成存根(或骨架),以使生成的存根能夠適合ORB提供商的類庫結構,另一個方案要求下載存根或骨架時同時下載整個ORB執行時環境。我們不希望採用這兩種方案中的任何一個。理想的情況是將 IDL 傳送到 Client 端或者由 Client 下載,利用 Client 端選擇的工具生成存根,並從它們的環境連線到我們的 Server。

因此,Java 語言對映高度依賴於標準的結構,它在一套標準的 Java 包中實現 -- org.omg.*。IDL 到 Java 對映中重要的一項就是包含 PIDL,本地型別和ORB可移植介面的壓縮檔案。它給出了包中確切內容的定義性宣告。當然,如同這一行中的其它任何事一樣,在不遠的將來 IDL 到 Java 對映的版本也會發生改變。但是以你對目前的對映的理解,你一定會注意到將來的版本中任何可能的二進位制不相容性

yuxq 回覆於:2003-09-17 18:50:38

基本資料型別

基本資料型別的對映是很直接的。 下表會讓你瞭解到對映是多麼簡潔:

IDL 型別 Java 型別 異常

boolean Boolean

char Char CORBA:ATA_CONVERSION

wchar Char CORBA:ATA_CONVERSION

octet Byte

string java.lang.string CORBA::MARSHAL, CORBA:ATA_CONVERSION

wstring java.lang.string CORBA::MARSHAL, CORBA:ATA_CONVERSION

short Short

unsigned short Short large number mismatch ?test

long Int

unsigned long Int large number mismatch ?test

long long Long

unsigned long long Long large number mismatch ?test

float Float

double Double

long double **unmapped 現在還不清楚是否會增加這一型別作為新的基本型別或者是類庫的補充,如java.math.BigFloat

要瀏覽練習所有這些基本型別的 module,請訪問 motheridl.idl 的例子.

整型(Integer)

IDL 符號整型(signed integer)到 Java 型別的對映不存在任何問題。IDL 的 short 型別對映到 Java 的 short,IDL 的 long 對映到 Java 的 int,IDL 的 long long 對映為 Java 的 long。這些都是直接對映,不會給你帶來什麼麻煩的。

問題在於 IDL 的無符號整型(unsigned)。Java 程式語言沒有 unsigned 型別,並且它所有的整數型別都是有符號的。在多數情況下這不會發生問題,但是當一個 IDL 無符號整數取值正好落在最高位所限制的取值範圍中時,型別轉換就會發生不匹配的錯誤。如果不檢查並改正這種錯誤,轉換為 Java 後的結果就會是一個負數,而不是一個接近無符號整數型別取值上限的數值。

例如,假設有一個從 IDL 介面返回的 unsigned short 型別值,這一型別的取值範圍是0到65535。 Java 的有符號 short 型別能夠接收的取值範圍是-32768到32767。那麼你可以看到,對於任何在32767到65535之間的值對映為 Java 的 short 以後將成為負數。這就造成了不匹配的障礙,必須進行測試。對於 unsigned short, unsigned long, 以及 unsigned long long 來說也是這樣。

這意味著什麼呢?首先,我建議以後寫 IDL 定義時不要再使用無符號整型。這會使事情簡單的多。其次,如果你在使用或者支援現有的 IDL 介面,那你必須測試 輸入的無符號整數,並確保它在 Java 程式中被作為負數正確的處理,或者被複製到取值範圍較大的變數型別中。

布林型(Boolean)和8位位元組型(octet)

這兩種 IDL 型別到 Java 型別的對映也是直接對映。IDL 的布林常量 TRUE 和 FALSE 對映到相應的布林量 true 和 false。

IDL 的位元組型 octet 長度為8位,它對映為 Java 的 byte 型別。

字元型(Character)和字串型別(string)

字元型別的對映有一些困難。首先是所使用的字符集,其次是表示整個字符集所需要的編碼位數。不同的語言有不同的字元,它們分別被國際標準化組織對映為不同的字符集。這些字符集代表了某種語言的字母或符號到數字的對映。一種語言中符號的數量決定了這種語言所需要的位寬。現在有8位和16位兩種字符集。

IDL 的字元型資料用8位來表示字符集中的一個元素,而 Java 的字元型資料用16位無符號整數來表示 Unicode 字元。要正確的進行型別轉換,Java CORBA 執行時環境驗證了所有由 IDL 的 char 型對映來的 Java char 型的有效性範圍。這一方向的對映沒有什麼困難,因為我們是把8位的數值對映為16位的數值,Java 程式碰到的任何問題都很容易處理,因為空間是足夠的。然而,要把 Java 的 char 型對映為 IDL 的 char 型,Java 的 char 型就有可能會超出 IDL 使用的字符集所定義的範圍。這種情況下就會產生 CORBA:ATA_CONVERSION 的異常。 IDL 的 wchar 僅僅是對映為16位字符集的 IDL 型別,它對映為 Java 的基本型別 char。如果 wchar 超出了字符集所定義的範圍,將會產生 CORBA:ATA_CONVERSION 的異常。

IDL 的 string 型別對映為 java.lang.String。別忘了 IDL 的 string 是一個 char 的序列。這意味著 IDL 的 string 必須滿足 IDL char 和 IDL sequence 的要求。因此,在編譯過程中要進行字串中的字元範圍檢查和字元序列的越界檢查。字元範圍非法會引起 CORBA:ATA_CONVERSION 的異常。越界會引起 CORBA::BAD_PARAM 的異常。對於 IDL 的 wstring 型別來說其注意事項和使用規則也是一樣的。

浮點型(Floating-point)

因為OMG IDL 和 Java 的浮點型資料都遵從 IEEE 754- 1985 Standard for Binary Floating Point Arithmetic,所以浮點型資料的轉換沒有問題。然而,目前 Java 程式語言中還沒有對 IDL 的 long double 型別的支援。現在還不清楚 java.math.* 是否會增加這一型別作為基本資料型別或新的包,或者說什麼時候會增加,也許會作為 java.math.BigFloat 吧。這一問題就留待以後修訂了。

對映的合法性檢查

我們可以用 Orbacus ORB 帶有的 IDL 到 Java 編譯器來執行我們的 motheridl.idl 檔案:

jidl --output-dir . . . . . . MotherIDL.idl

執行結果所產生的 Java 介面定義在 UseAllTypesOperations.java 檔案中給出。

這一生成的檔案檢查對映的合法性。所有的 Java 型別都像我們所預期的那樣。唯一的訣竅大概就在於 inout 和 out 引數位置上的資料型別--它們都是 holder。

holder 類

在任何語言中,引數傳遞都是一個有趣的話題,當要把OMG IDL 這樣獨立於語言的體系結構進行語言對映時,它又是一個傷腦筋的問題。 Java 程式總是採用傳值的方式。這意味著要把原語傳遞到方法中時,會得到一個原語的本地複製。然而,如果方法的引數是 Java 物件的話,則不會傳遞物件本身而是物件的引用。因此,被傳遞的是引用的複製,但是這個引用透過值來傳遞。

CORBA 規定了 in 引數和返回型別採用"值呼叫"(call-by-value)的方式,而 CORBA 的 out 則是"結果呼叫 "(call-by-result)。inout 的引數型別在輸入伺服器時透過"值呼叫"的方式來傳遞,而在輸出時則採用"結果呼叫"的方式。 out 和 inout 的引數傳遞模式不能被直接對映到 Java 的引數傳遞機制。要支援 out 和 inout 的引數傳遞模式需要另外使用 holder 類。

IDL 到 Java 的對映為所有的 IDL 基本型別定義了 holder 類,它同時也作為使用者定義型別的標準格式。IDL 到 Java 編譯器可以為使用者定義的型別生成 holder 類,以便以後在 Java 程式中實現這些引數模式時使用。 Client 生成並傳遞一個適當的holder Java 類例項,這個例項的值在 Java 程式中被傳遞給每一個 IDL out 或者 inout 引數。Holder 例項的內容(而不是例項本身)被呼叫它的程式所修改,Client 使用的是呼叫返回後(有可能)改變了的內容。

CORBA-Java 類庫中提供了 IntHolder 的例子。要注意 Java 中 public int 的值,以及 _type() 方法的返回值--它的型別是 long。記住這點是因為 Java 的 int 對映為 IDL 的 long。

記住org.omg.CORBA 包中提供了所有基本 IDL 型別的 holder 類,併為所有已命名的使用者定義 IDL 型別生成 holder 類,那些用 typedef 定義的除外。

對於使用者定義的 IDL 型別來說,holder 類根據對映的(Java)型別名再附加一個 Holder 來命名。對於 IDL 基本資料型別來說,holder 類的名字就是資料型別對映的 Java 型別名,開頭字母大寫,並附加一個 Holder(例如,IntHolder)。

每個 holder 類都有一個來自例項的建構函式,一個預設的建構函式,以及一個公有的例項成員(value)),它是一個有型別的值。預設建構函式將值域設定為 Java 語言為不同型別所定義的預設值:boolean 為 false,numeric 和 char 型別為 0, string 為 null,物件引用也是 null。為了支援可移植的存根和骨架,holder 類也實現 org.omg.CORBA.portable.Streamable 介面。

 

結論

這裡只是 IDL 到 Java 對映的第一部分。你應該認識到,用 Java 程式語言編寫基於 CORBA 的應用程式和構件要求理解 IDL 到 Java 語言對映。CORBA 規範包括很多語言對映。它們在你工作的各方面中都會有所體現。你的程式碼的可移植性不僅取決於OMG的庫結構,而且也取決於你自己所生成的庫結構。對映的目的是將介面定義轉化為某種特定語言的實現,這種轉化可能會以犧牲定義的完美性來換取實際的可行性。正如我們在無符號整型的例子中所看到的,你必須保持一定的警惕性以保證你的應用程式能夠正常工作。

語言對映是一種翻譯,因為你在使用一種語言,而要把它轉換為另一種同樣可以工作並且可以理解為一種實現的語言。正如一些短語和結構沒法在兩種自然語言之間很好的翻譯一樣,有些結構也不太容易對映。我們必須找到解決的方案,雖然它們可能使對映變得更復雜,但是在實現時用起來更容易。holder 類就是這樣;開始理解它可能要花些功夫,但是長遠來看,它提供了一種通用的、一致的解決方案。

IDL-to-Java對映(2):

使用 IDL 對映建立元件介面

(本文摘自IBM developerWorks)

Dave Bartlett

顧問、作家兼講師

2000 年 11 月

內容:

結構

列舉

聯合

序列和陣列

陣列

序列

異常

Any

輔助

結束語

 

我們就本月的 CORBA 連線中更復雜的型別和輔助類的問題,來繼續研究 IDL-to-Java 對映。

上個月,在 IDL-to-Java 對映的第一部分中,我們研究了基本資料型別、結構和資料傳送。本月,我們將集中精力研究對映常數和結構,討論某些更復雜的型別,例如,序列、陣列、異常和 Any 型別。最後,將研究輔助類和它們的功能。

首先,應該提醒您我們正在使用介面定義語言,任何 IDL 的目的就是建立某些元件或伺服器的介面。這意味著我們正在建立新的型別。因此,讓我們從 interface 關鍵字的對映和使用 OMG IDL 建立新型別的機制開始討論。

介面

我們將回到所有 IDL 檔案的母板 -- MotherIDL.idl。我使用這個檔案來研究 IDL-to-Java 對映各個方面。在 MotherIDL 中,有一個名為 FindPerson 的介面。顯示如下:

清單 1. FindPerson 介面

interface FindPerson { Person GetByName(in string sName); Person GetBySSN(in string sSSN); };

我們現在只集中討論介面和兩個方法 GetByName() 和 GetBySSN()。關鍵字 interface 的確切含義是什麼?仔細研究 OMG CORBA 規範,就會發現 interface 關鍵字後帶有標識(本例中是 FindPerson)。FindPerson 是介面名稱,並且它定義了合法的型別名稱。只要識別符號合 IDL 的語法,就可以使用這種型別的標識。將 FindPerson 作為方法引數或結構成員在 IDL 中

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/8225414/viewspace-944564/,如需轉載,請註明出處,否則將追究法律責任。

相關文章