解決了所有問題后,您應該知道 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 = '/0'; 可以用十進制、十六進制或八進制記數法定義整數常數: 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 = '/t';const char NEWLINE = '/n'; 只要沒有混合的類型表達式,就可以在常數說明中使用算術運算符。 用戶異常 IDL 答應創建異常來指出錯誤條件。IDL 用戶異常類似于一個結構,在這個結構中,異??梢园x類型的任意多錯誤信息。最終是從方法中使用異常。這里有一個例子: 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<long> Unbounded;typedef sequence<long, 31> 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<string> 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月 內容:
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)