OMG IDL接口定义语言.docx
《OMG IDL接口定义语言.docx》由会员分享,可在线阅读,更多相关《OMG IDL接口定义语言.docx(13页珍藏版)》请在冰豆网上搜索。
OMGIDL接口定义语言
∙developerWorks中国
∙Javatechnology
∙文档库
OMG接口定义语言
定义分布式服务的能力
DaveBartlett (dbartlett@),顾问、作家和讲师
简介:
一切都要从接口定义语言(IDL)开始。
当我们采用RPC或COM技术以及CORBA技术来编写分布式系统时都需要它。
在各种情况下,接口定义语言提供了将对象的接口与其实现分离的能力。
IDL提供了抽象,它提供了将事务与其具体实现分离的概念。
它还为我们提供了一套通用的数据类型使得我们可以使用它们来定义更为复杂的类型。
我们将采用所有这些数据类型来定义分布式服务的功能。
IDL的另一个好处是它剥离了编程语言和硬件的依赖性。
本文探讨了OMGIDL的内置类型和关键字。
发布日期:
2000年9月01日
级别:
初级
访问情况:
1696次浏览
评论:
0 (查看 | 添加评论 -登录)
平均分(4个评分)
为本文评分
IDL是一种规范语言。
它允许我们从实现中剥离对象的规范(如何与它交互)。
这是一个约定:
“客户机女士,如果您要调用这个方法,请传送这些参数,然后我,服务器先生,将把这个字符串数组返回给您。
”使用这个接口的客户机程序员不知道接口背后的实现细节。
OMGIDL看上去很像C语言。
这就很容易将这两种语言以及它们的关键字做比较。
但是,这种相似性只流于表面。
每种语言的目的是完全不同的。
我们在讨论这种语言时,您已经记住OMGIDL的目的是定义接口和精简分布对象的过程。
IDL基本类型
OMG接口定义语言有一些看上去应该很熟悉的基本类型。
以下就是这些内置类型的表:
表1.IDL基本类型
类型
范围
最小大小(以位为单位)
short
-2 15到2 15-1
16
unsignedshort
0到2 16-1
16
long
-2 31到2 31-1
32
unsignedlong
0到2 32-1
32
longlong
-2 63到2 63-1
64
unsignedlonglong
0到2 64-1
64
float
IEEE单精度
32
double
IEEE双精度
64
longdouble
IEEE双字节扩展浮点数
15位指数,64位带符号小数
char
ISOLatin-1
8
wchar
从任何宽字符集编码宽字符,如Unicode
依赖于实现
string
ISOLatin-1,除了ASCIINUL以外
可变化
Boolean
TRUE或FALSE
未指定
octet
0到255
8
any
自己描述的数据类型,可表示任何IDL类型
可变化
整数类型
OMGIDL的整数类型非常简单。
虽然它没有提供 int 类型,但它不会受到 int 在不同平台上的取值范围不同所带来的多义性的困扰。
然而,IDL确实提供几种整数类型,2字节( short )、4字节( long )和8字节( longlong )的整数类型。
所有这些整数类型都有相应的无符号数类型。
这对于Java程序又产生了问题,因为Java编程语言不支持无符号数类型。
尽管这不是OMGIDL的特性,它还是在Java-to-IDL的映射中创建了一种独有的局面,我们将在下个月的专栏文章中讨论Java-to-IDL的映射。
但在此之前,您已经考虑如何将IDL中的 unsignedshort 映射成一种Java类型。
使用Java short 还是Java int ?
它们各自的利弊是什么?
这些是语言映射的作者必须努力解决的问题,并且这是一个很好的练习,可以帮助您为阅读下一篇专栏文章做好准备。
浮点类型
OMGIDL浮点数类型 float 、 double 和 longdouble 遵循IEEE754-1985二进制浮点数算术的标准。
目前, longdouble 用于巨大数字,您也许会发现您的特殊语言映射还不支持这种类型。
char和wchar
我们都使用相同的术语,字符集就是字母或其它构成单词的字符以及其它本机语言或计算机语言的基本单元的集合。
编码字符集(或代码集)是一组明确的规则,它建立了字符集和集合的每个字符与其位表示法之间的一一对应关系。
处理 char 时,必须记住OMGIDL必须分两个层次处理字符集。
首先必须明确规定从哪个字符集生成IDL定义。
词法约定(表示IDL文件的关键字、注释和文字的字符记号)规定ISO8859.1字符集表示IDL文件中的字符。
是的,连IDL都必须有一个标准字符集,它将构建在这个字符集上。
ISO464定义了空字符(null)和其它图形字符。
接着,OMG必须处理从一个计算机系统到另一个计算机系统之间的字符传输。
这意味着可能涉及到从一个字符代码集到另一个字符代码集的转换,这取决于语言绑定。
在 上个月的专栏文章中,我们对OrbacusObjectReference执行了IORDump操作,并且发现了以下信息:
Nativecharcodeset:
"ISO8859-1:
1987;LatinAlphabetNo.1"
Charconversioncodesets:
"X/OpenUTF-8;UCSTransformationFormat8(UTF-8)"
"ISO646:
1991IRV(InternationalReferenceVersion)"
Nativewcharcodeset:
"ISO/IEC10646-1:
1993;UTF-16,
UCSTransformationFormat16-bitform"
Wcharconversioncodesets:
"ISO/IEC10646-1:
1993;UCS-2,Level1"
"ISO8859-1:
1987;LatinAlphabetNo.1"
"X/OpenUTF-8;UCSTransformationFormat8(UTF-8)"
"ISO646:
1991IRV(InternationalReferenceVersion)"
可以看到,IOR可以包含代码集信息,以在转换时协调首选代码集和可用代码集。
解决了所有问题后,您应该知道OMGIDL char 是一个8位变量,可以用两种方法表示一个字符。
首先,它可以从面向字节的代码集编码单字节字符,其次,当在数组中使用时,它可以从多字节字符集(如Unicode),编码任何多字节字符。
Wchar 只允许大于8个字节的代码集。
规范不支持特殊的代码集。
它允许每个客户机和服务器使用本机的代码集,然后指定如何转换字符和字符串,以便在使用不同代码集的环境之间进行传输。
Boolean
这里没有什么可以多说的--Boolean值只能是TRUE或FALSE。
Octet
octet 是8位类型。
因为保证了 octet 在地址空间之间传送时不会有任何表示更改,因此这就使它变成了一种非常重要的类型。
这就表示您可以发送二进制数据,并且知道当将它打包时,它的形式仍然相同。
其它每种IDL类型在传输时都有表示变化。
例如,根据IOR代码集信息的指示, char 数组会经历代码集转换。
而 octet 数组却不会。
any类型
IDL any 是一种包含任何数据类型的结构。
该类型可以是 char 或 longlong 或 string 或另一种 any ,或者是已经创建的一种类型,如 Address 。
any 容器由类型码和值组成。
类型码描述 any 的值部分中的内容是什么。
如果您拥有C++经验,则可以将 any 看作是自我描述的数据类型,它类似于 void* ,但更安全。
如果有VisualBasic经验,可以将any 看作类似于 variant 。
当我们讨论IDL-to-Java映射时, any 类型的结构和它如何对用户定义的类型产生作用将变得一目了然。
回页首
用户定义的类型
基本类型是必不可少的;它们为接口定义提供了构件块。
OMGIDL为您提供了定义您自己的类型的能力,这可以帮助减少复杂程度并且让您可以根据基本类型组成更精巧的数据类型。
这些复杂的类型可以是枚举、结构和联合,或者您可以使用 typedef 来创建类型的新名称。
命名的类型
应该使用 typedef 创建新的类型名称,这将帮助解释接口或保存输入。
例如,您也许想在方法 PresentWeather(...,infloatPressure,...) 中传送气压值。
如果在该方法中使用 typedef float 语句,这将使该方法更具可读性。
typedeffloatAtmosPressure;
在C++中, typedef 关键字表示 类型定义,实际上 别名也许是更为精确的术语。
对于OMGIDL,也许是这样,也许不是,这取决于其所映射到的实现语言。
CORBA规范不保证 short 的两种 typedef 是兼容的和可互换的。
在文体上,应注意不要为现有类型创建别名。
您应该尝试创建不同概念的类型,它将为您的IDL添加可读性和可扩展性。
最好是明确定义一次逻辑类型,然后在整个接口中不断使用该定义。
枚举
OMGIDL枚举是将名称附加到数字的一种方法,从而读取代码的人就可以了解到更多的含义。
OMGIDL版的枚举看上去象C++版本的枚举。
enumCloudCover{cloudy,sunny};
CloudCover 现在就成为可以在IDL中使用的一种新类型。
由于在一个枚举中可以有最多2 32个标识,OMGIDL保证枚举被映射到至少32位的类型。
规范中没有规定标识的有序数值,但它规定了将保持顺序。
因此,不能假设 cloudy 永远拥有序数值0--某些语言映射可能将1赋值给它。
但可以确保 cloudy 小于 sunny 。
如果认为IDL的目的是定义跨各种系统的接口,那么不指定序数值是明智的。
您只将值发送到服务器。
即,"cloudy"。
在服务器空间中, cloudy 可以由0、1或如何实现语言规定的值表示。
某些实现语言不允许您控制序数值,而C++允许。
OMGIDL不允许空的枚举。
结构
struct 关键字提供了将一组变量集中到一个结构的方法。
一旦创建了, struct 表示可以在整个接口定义中被使用的 新类型。
structDate{
shortmonth;
shortday;
longyear;
};
定义 struct 时,要确保所创建的类型是可读的。
不要在不同的名称空间中创建几个不同的同名结构,这只会使IDL的用户搞糊涂。
识别联合
OMGCORBA规范将IDL联合描述成C联合类型和switch语句的混合物。
IDL识别联合必须有一个类型标记字段用于确定在当前实例中使用哪个联合成员。
像C++一样,一次只能有一个联合成员是活动的,并且可以从其识别名称来确定该成员。
enumPressureScale{customary,metric};
unionBarometricPressureswitch(PressureScale){
casecustomary:
floatInches;
casemetric:
default:
shortCCs;
};
在以上示例中,如果识别名称是metric,或者使用了不能识别的识别名称值,那么 shortCCs 就是活动的。
如果识别名称是customary,那么 float 成员Inches是活动的。
联合成员可以是任何类型,包括用户定义的复杂类型。
识别名称类型必须是整数类型( short 、 long 、 longlong 等,以及 char 、 boolean 或 enumeraton )。
回页首
常数定义
在IDL中定义常数的语法和语意与C++一样。
常数可以是整数、字符、浮点数、字符串、Boolean、octet或枚举型,但不能是 any 类型或用户定义的类型。
这里有一些例子:
constfloatMeanDensityEarth=5.522;//g/cm^3
constfloatknot=1.1508;//milesperhour
constcharNUL='\0';
可以用十进制、十六进制或八进制记数法定义整数常数:
constlongARRAY_MAX_SIZE=10000;
constlongHEX_NUM=0xff;
对于指数和小数,浮点字符使用常用的C++约定:
constdoubleSPEED_OF_LIGHT=2.997925E8;
constdoubleAVOGADRO=6.0222E26;
字符和字符串常数支持标准换码序列:
constcharTAB='\t';
constcharNEWLINE='\n';
只要没有混合的类型表达式,就可以在常数说明中使用算术运算符。
回页首
用户异常
IDL允许创建异常来指出错误条件。
IDL用户异常类似于一个结构,在这个结构中,异常可以包含所选类型的任意多错误信息。
最终是从方法中使用异常。
这里有一个例子:
exceptionDIVIDE_BY_ZERO{
stringerr;
};
interfacesomeIface{
longdiv(inlongx,inlongy)raises(DIVIDE_BY_ZERO);
};
异常将创建名称空间--因此,异常中的成员名必须是唯一的。
异常不能当作用户定义类型的数据成员使用。
OMGIDL中没有异常继承。
回页首
数组、序列和字符串
每次只传送一个元素是可以的,但我们通常有一个列表或向量或矩阵的信息要在客户机和服务器之间来回传送。
数组几乎是所有编程语言所共有的类型,但一种语言的数组与另一种语言的数组实现通常是不同的。
OMGIDL开发者面临的挑战是创建一组数组类型,它可以轻易地被映射到实现语言中。
这种需求产生了IDL array 和 sequence 。
string 类型是一种特殊的序列,它允许语言使用它们的字符串库和优化。
数组
OMGIDL有任意元素类型的多维固定大小的数组。
所有数组都必须是有界的。
数组非常适合于与拥有固定数量元素的列表一起使用,而这些元素通常都是存在的。
例如:
//boundedandunboundedarrayexamples
typedeflongshares[1000];
typedefstringspreadsheet[100][100];
structofArrays{
longanArray[1000];};
//unboundedarraysNOTALLOWED
//typedeflongorders[];
必须指定数组维数,并且它们必须为正的整型常量来表示。
IDL不支持在C和C++中的开放数组,这是因为没有指针支持。
必须出现typedef 关键字,除非指定的数组是结构的一部分。
在许多实例中,CORBA规范所没有提及的内容与它提及的内容是一样重要的。
规范 不以任何方式、形态或形式指定数组下标编排方法。
这表示从一种实现语言到另一种实现语言的数组下标可以是不同的,这样您不能假定将数组下标从客户机发送到服务器时,服务器会调整并指向正确的数组元素。
某些语言的数组下标从0开始,而其它的则是从1开始。
序列
在开发接口定义时,会大量使用序列。
如果正在处理数据数组,其中许多值相同,那么序列就可以提供灵活性。
序列是变长向量,它有两个特征:
元素的最大大小,在编译时确定,可以是无限的;长度,在运行时确定。
序列可以包含所有类型的元素,不管是基本类型还是用户定义的类型。
序列可以是有界的,也可以是无界的。
例如:
//boundedandunboundedsequenceexamples
typedefsequenceUnbounded;
typedefsequenceBounded;
一个无限序列可以拥有任意多个元素,只会受到平台内存大小的限制。
有限序列则有边界限制。
这两种序列都可以不包含元素、用户定义的类型,但可以包含其它序列。
string和wstring
string 等价于 char 的序列,而 wstring 表示 wchar 的序列。
作为C和C++的折衷,OMGIDL string 和 wstring 可以包含任何字符,除空字符以外。
char 或 wchar 约定确定了类型为 string 的元素大小由8个字节表示, wstring 类型的元素大小是16个字节或更多。
回页首
名称和作用域
IDL中的字符串很特殊,然而在大多数语言中字符串都很特殊。
许多语言都用库和特殊优化来处理字符串处理。
通过将字符串归到它自己的类型,OMG允许语言映射使用特殊优化,这些优化不会与通用序列一起处理。
所有OMGIDL标识都是区分大小写的。
这意味着将把两个只有字符大小写不同的标识看作是彼此的重新定义。
应该注意根据区分大小写的语言,所有的定义引用必须与定义的大小写相同。
IDL作用域规则非常易于掌握。
整个OMGIDL内容和通过预处理器伪指令传入的所有文件共同组成了命名作用域。
任何未出现在某个作用域中的定义都是全局作用域的一部分--只有一个全局作用域。
在全局作用域中,以下定义组成了作用域:
module 、 interface 、struct 、 union 、 operation 和 exception 。
module 关键字用于创建名称空间;这是其唯一目的。
您定义的模块将创建一个逻辑组,模块的自由使用防止了全局名称空间的污染。
根或全局空间被认为是空的,文件扫描中每次遇到模块关键字时,字符串" :
:
"和其标识都会附加到当前根的名称后面。
这就可以通过包括其它名称作用域来引用其它模块中的类型,如以下示例中的 Pennsylvania:
:
river 。
一个标识可以在一个作用域中定义一次,但可以在嵌套作用域中重新定义。
下例将解释这些要点:
moduleStates{
//error:
redefinition
//typedefsequencestates;
modulePennsylvania{
typedefstringriver;
interfaceCapital{
voidvisitGovernor();
};
};
moduleNewYork{
interfaceCapital{
voidvisitGovernor();
};
interfacePennsylvania{
voidvisit();
};
};
moduleNewJersey{
typedefPennsylvania:
:
riverNJRiver;
//Error
//typedefstringPennsylvania;
interfaceCapital{
voidvisitGovernor();
};
};
};
每个内部模块( Pennsylvania 、 NewYork 和 NewJersey )都有一个接口 Capital 和一个操作 visitGovernor() 。
但它们并不相互牵连,因为它们在各自的模块中。
当我们尝试在模块 States 中创建一个同名序列时,遇到了一个重新定义'State'的问题。
重新定义Pennsylvania 发生在已经将它介绍为 NewJersey 中'NJRiver'的作用域解析标识之后。
请注意,我们在带有接口 Pennsylvania 的 NewYork 模块中没有发生错误,因为通过某些作用域解析标识介绍外部 Pennsylvania 模块。
回页首
接口
现在该定义接口了,它是我们学习OMG接口定义语言的首要原因。
有一个好方法来理解IDL接口:
它指定了服务实现和使用它的客户机之间的软件约定。
让我们开始定义接口吧,这将运用我们所学到的IDL知识。
由于这一切都与通信有关,就让我们看一些定义Listener 和 Speaker 的IDL。
Listener 必须连接到 Speaker ,然后 Speaker 将消息传送给 Listener 。
这是一个回调的例子。
//Thrownbyserverwhentheclientpasses
//aninvalidconnectionidtotheserver
exceptionInvalidConnectionIdException
{
longinvalidId;
};
//Thisisthecallbackinterfacethat
//theclienthastoimplementinorder
//tolistentoatalker.
interfaceListener
{
//Calledbytheservertodispatchmessagesontheclient
voidlisten(instringmessage);
//Calledbytheserverwhentheconnection
//withtheclientissuccessfullyopened
voidengage(instringperson);
//Calledbytheserverwhentheconnectionwiththeclientisclosed
voiddisengage(instringperson);
};
//interfaceontheserverside
interfaceSpeaker
{
//Calledbytheclienttoopenanewconnection
//ReturnedlongistheconnectionID
longregister(inListenerclient,instringlistenerName);
//Makestheserverbroadcastthemessagetoallclients
voidspeak(inlongconnectionId,instringmessage)
raises(InvalidConnectionIdException);
//Calledbytheclienttoseverthecommunication
voidunregister(inlo