新竹论坛  新竹视聊  实用网址大全    
网站首页 新竹主站 我的文章大学恋情校园音乐青春岁月学海泛舟男生女生可爱女孩为爱执着
诗坛初蕾青春讨论编程世界小说世界快乐英语天南地北往事歌谣心情日记网络世界 留 言 板
从此开始了北漂,在这个城市里,我就不相信没有我的容身之地,倘大一个城市没有属于我的小屋,五年时间见证今日的誓言,于北京朝阳区!北京,狼来拉!!!!
  当前位置:网站首页 >> 往事歌谣  >> delphi  >> 第二十章 使用DelphiCORBA开发  双击自动滚屏  
第二十章 使用DelphiCORBA开发

发表日期:2007年2月13日        已经有132位读者读过此文

本章内容:
. ORB
. 接口
. Stub和S k e l e t o n
. Vi s i B r o k e r的O R B
. Delphi中的C O R B A支持
. 在Delphi 5中创建C O R B A解决方案
. 使用Vi s i B r o k e r的O R B
C O R B A是Common Object Request Broker Architecture的缩写。C O R B A是一种由O M G ( O b j e c t
Management Group)定义的标准,其中定义了不同语言和不同平台实现对象的标准结构。O M G是一个
致力于开发标准的、开放的、多种平台适用的分布式对象的独立组织。与一些同类的标准不同(比如,
M i c r o s o f t的C O M / D C O M ),O M G并不提供对标准的具体实现。
27.1 ORB
ORB(Object Request Broker)提供了C O R B A的技术实现,并把整个解决方案结合在一起。如果你
非常熟悉M i c r o s o f t的C O M / D C O M技术,就会注意到O R B提供了类似于C O M / D C O M库的运行期、安全
和传输层。所有客户端与服务器端的通信都通过O R B,这样可以使方法的调用和参数能在调用者和被
调用者的地址空间上完成。类似于在C O M / D C O M中提供的o l e a u t 3 2 . d l l的功能, O R B也提供了许多直
接从客户端或服务器端被调用的辅助程序。正如前面提到的, C O R B A标准没有对如何实现O R B提供
具体的方法。因为建立一个O R B不是一件简单事,所以C O R B A的开发者要依靠第三方支持遵循
C O R B A标准来实现O R B。关于O R B有一个好消息:有许多的厂商、所有主要的操作平台(诸如
Wi n d o w s、U N I X )及一些其他的操作系统都支持它。当前,两个受到最广泛支持的C O R B A实现是
Inprise VisiBroker ORB 和IONA Orbix ORB。
27.2 接口
一个简单的C O R B A解决方案涉及多种对象、在不同开发语言的环境中进行开发并运行于不同的
平台。所以,某个对象要向另一些对象、客户端和O R B说明自己,这应采用一些标准的方式。这是利
用接口实现的。一个接口定义了一个列表,在该列表中有该接口的方法和参数,但是它不实现程序中
的任何功能。当一个C O R B A对象实现一个接口时,必须保证实现接口定义的所有方法。从低层看,一
个接口仅仅是一个函数表或指定方法入口点的列表。因为这种结构可以表达在任何的硬件平台及任何
严格的开发工具上,所以,接口成为了C O R B A世界的统一语言。由于开发语言语法普遍都不一样,所
以O M G定义了一种接口定义语言I D L,它用来定义C O R B A接口。I D L是一种标准的C O R B A接口语言,
为了使开发者很容易地构造C O R B A可编译接口, I D L能被许多开发工具翻译为可识别语法。使用
D e l p h i,我们不用手工编写I D L,可以利用类型库编辑器来可视化地定义我们的接口,并且有选择地导
出对应的I D L代码。
第2 7章使用D e l p h i开发CORBA 9 3 3
服务器
对象实现
接口
接口
客户
图27-1 一个简单的CORBA结构
下载
27.3 Stub和Skeleton
C O R B A机制是使用代理来工作的。使用代理目前已成为解决复杂问题的主流设计模式,这些复
杂问题一般都涉及到在分布式对象间传递数据。一个代理驻留在服务器和客户机,当它通过一个本地
进程进行通信时,就能在客户机或服务器上被激活。然后, O R B处理发生在代理间的细节(例如,网络
通信)。这种结构如图2 7 - 1所示,它显示了一个C O R B A客户端或服务器端较底层的传输细节以及使它
们集中完成特定的业务解决方案。按照C O R B A的观点,在一个客户端代表服务器端的代理被称为S t u b,
在服务器端表示一个客户端的代理称为S k e l e t o n。当你使用D e l p h i向导创建一个C O R B A服务对象时,
一个包括S t u b和S l e l e t o n的接口定义的单元将被自动生成。
27.4 VisiBroker的ORB
正如前面提到的, C O R B A是一个要求第三方实现O R B功能的标准。在Delphi 4 和Delphi 5中,
C O R B A使用I n p r i s e公司的VisiBroker ORB来实现它的规范。Vi s i B r o k e r产品提供了对C O R B A规范的全
面支持,以及许多Vi s i B r o k e r的扩展(诸如,命名和事件服务)。由于详细讨论Vi s i B r o k e r产品超出了本
章内容,所以我们将研究与D e l p h i的C O R B A实现有关的部分。更多关于Vi s i B r o k e r的信息(包括产品文
档)都可以在w w w. b o r l a n d . c o m / v i s i b r o k e r找到。
27.4.1 VisiBroker的运行时支持服务
在VisiBroker ORB库中包含许多运行时支持服务的函数,它们使整个CORBA/ Vi s i B r o k e r分布式结
构成为一体。我们将分别讨论它们。
1. Smart Agent(osagent)
VisiBroker Smart Agent提供了C O R B A程序中的对象定位(Object location)服务。Smart Agent给
C O R B A环境提供了透明定位。简单地讲,客户端不关心如何定位服务器的位置,客户端只需要能定位
Smart Agent,由Smart Agent来处理如何查询一个相对应的服务器。一个Smart Agent必须能在局域网
中运行。若在一个简单网络中有多个Smart Agent能被配置在不同端口进行侦听,事实上就是分成多个
O R B域。这对于提供一个O R B环境和一个开发O R B的环境是非常重要的。Smart Agent也能够被配置成
与其他网络的Smart Agent的通信,这样可以扩展你的C O R B A基础结构的范围。
9 3 4 第三部分基于组件的开发
下载
2. OAD(Object Activation Daemon)
当需要服务时,O A D提供了一种动态的方式来启动服务。Smart Agent仅能把客户捆绑到已经运行
起来的对象上。然而,对于一个使用O A D注册的C O R B A对象,如果没有一个有效的服务进程, S m a r t
A g e n t和O A D将协作启动一个有效的服务进程。
3. 接口库(Interface Repository,I R E P )
接口库是一个在线的对象类型信息数据库。这个库对于想动态绑定C O R B A接口的客户是非常必
要的。O R B能够使用“静态绑定”的方式访问服务器的接口的方法。为了动态绑定可以使用,接口库
必须运行在客户可以访问的网络中,并且接口必须在接口库中注册。
27.4.2 VisiBroker管理工具
为了配制和管理上述运行时支持工具, Delphi Vi s i B r o k e r包附带一个G U I和命令行管理工具集。我
们在表2 7 - 1中列出了它们,但是,要等到本章后面需要的地方才会对它们进行讲解。
具工
o s a g e n t
o s f i n d
o a d
o a d u t i l
i r e p
i d l 2 i r
v r e g e d i t
v b v e r
表27-1 V i s i B r o k e r管理工具
途用
用于管理Smart Agent
枚举网络中有效的对象实现
用于管理O A D
用于O A D的注册、注销和侦听接口
管理接口库
对于使用接口库注册I D L有用
允许简单注册对Smart Agent的默认值的改变
报告Vi s i B r o k e r服务的版本号
27.5 Delphi的CORBA支持
C O R B A在D e l p h i中(开始于版本4 )经常被批评。虽然有些局限性,但其中有些传闻是夸大或是错误
的。首先, D e l p h i确实支持一个真的C O R B A实现。C + +的VisiBroker ORB(orb_br. d l l )在底层使用,它
被包装在动态链接库o r b p a s 5 0 . d l l中这是为了允许P a s c a l和D e l p h i的接口定义及数据类型在Vi s i B r o k e r
O R B使用。
当C O R B A忠实的支持者看到D e l p h i产生的S t u b和S k e l e t o n代码,并且明白其中涉及到G U I D、
I U n k n o w m和I D i a p a t c h接口,他们会因此沮丧。这些结构都散发着C O M / D C O M的味道,而大多数的
C O R B A支持者希望他们心爱的C O R B A是大大区别于这些结构的。围绕着这些C O M成分,有许多奇怪
的事,包括:C O R B A通过C O M调用;参数被调度两次(一次通过C O M,一次通过C O R B A )。在追究各
种疯狂的设想前,我们先看一下为什么这些C O M定义存在于D e l p h i产生的C O R B A服务器:
. 首先,当接口的概念被加入D e l p h i中时,是基于C O M基础的。所有的D e l p h i接口继承于基础的
C O M接口( I U n k n o w n )。这意味着,当在D e l p h i中定义一种被用于C O R B A的接口时,三种附加的
I U n k n o w n方法( Q u e r y I n t e r f a c e、A d d R e f和R e l e a s e )必须被实现。这对于一个C O R B A接口是确实
必要的;T C o r b a I m p l e m e n t a t i o n类的基础实现为D e l p h i开发者实现了这些方法。
. 其次,当使用D e l p h i向导创建一个C O R B A对象时,你会注意到一个C O M“双重”接口被缺省地
创建。通过检查生成的Stub 和S k e l e t o n代码,会看到C O R B A接口继承于I D i s p a t c h,并且定义了
一个调度接口。虽然,这对于C O R B A来说并不是很必要的(你可以使它改为派生于I U n k n o w n ),
但对象实现必须定义I D i s p a t c h的附加方法,以使这些对象被正确地编译。T C o r b a D i s p a t c h S t u b和
T C o r b a I m p l e m e n t a t i o n的类实现声明了I D i s p a t c h的四种附加的方法。仔细地查看代码,会发现这
第2 7章使用D e l p h i开发CORBA 9 3 5
图27-2 VCL的CORBA支持层次
下载
些实现中并没有真正地做什么。这是为了类型库编辑器能被C O R B A对象使用。
. 最后,接口被包括G U I D (或I I D )的向导产生。这些是C O M用来唯一标识接口的标识符。虽然,
C O R B A本身并不使用G U I D标识对象或接口,但是一些V C L的内部程序要使用G U I D来唯一标识
C O R B A的接口。由于这个原因,在由C O R B A对象生成的接口中,G U I D不能被去掉。
从上面讨论中可以看出,在由C O R B A向导产生的内容中C O M所占的成分要比一些开发人员想像
的少许多。另外, D e l p h i的独特特征是,它有一个好处:它能轻易地编译出能同时被C O M / D C O M和
C O R B A使用的类。
在编写程序时, D e l p h i的C O R B A实现的一个显著弱点是没有由I D L向P a s c a l转换的工具,目前有
一个用于由I D L向J a v a和C + +转换的工具。D e l p h i不能静态绑定用不同语言编写的C O R B A服务器,这
是一个普遍的误解。对于使用D e l p h i或任意其他语言编写的C O R B A服务器,D e l p h i的客户端可以执行
静态或动态的绑定。然而, D e l p h i因为具有引入I D L文件和编译器可以理解的P a s c a l代码的能力,却对
它静态绑定用不同语言编写的C O R B A服务器增加了许多的困难。因为这个原因,当开发人员想要在客
户端绑定一个用C + +或J a v a编写的C O R B A对象实现时,必须手工编写C O R B A的S t u b类代码。I n p r i s e已
经开发了一个I d l 2 p a s转换器可以简化D e l p h i / C O R B A的开发,这已被加入Delphi 5当中。本章后面将会
介绍这一新技术。
27.5.1 CORBA的类支持
为了使开发人员能创建C O R B A的客户端和服务器端,D e l p h i框架使用了一种由接口和实现继承相
结合的结构。C O R B A的工作是由实现对象接口、S t u b和S k e l e t i o n来完成的。因为接口不支持继承实现
代码的概念,所以所有的接口都需要调用C O R B A的O R B来实现这一步,而这项工作是非常乏味的。
为此,D e l p h i提供了一组V C L基础类来实现主要的C O R B A接口(例如,I C o r b a O b j e c t、I S k e l e t o n O b j e c t
和I S t u b O b j e c t )。主要的基础类被列于图2 7 - 2中,并且在下面的列表中有说明。
. T C o r b a I m p l e m e n t a t i o n。这个类支持I U n k n o w n,并且提供了接口查询和对象计数的能力。I D i s p a t c h
的方法也在这个类中得到了体现,这样就能支持由类型库编辑器增加的双重接口。D e l p h i的
C O R B A对象将从这个类中派生。
. T C o r b a S t u b。这个类实现了I C o r b a O b j e c t和I S t u b O b j e c t接口。T C o r b a S t u b是由D e l p h i的类型库编
辑器产生的S t u b的基类。S t u b被用于配置一个C O R B A客户端的调用。希望开发人员能编写代码
9 3 6 第三部分基于组件的开发
下载
来创建T C o r b a S t u b的派生类。
. T C o r b a D i s p a t c h S t u b。这个类继承自T C o r b a S t u b并实现(体现出) I D i s p a t c h接口的方法。这样,由
D e l p h i类型库编辑器产生并继承于I D i s p a t c h的接口可以用于C O R B A。
. T C o r b a S k e l e t i o n。这个类实现了I S k e l e t o n O b j e c t的接口,并且负责与O R B通信和给服务器对象传
递调用。不像S t u b,这个s k e l e t o n类不能真正实现服务器的接口。取而代之的是, s k e l e t o n拥有一
个服务的引用,并用这个引用调用对应的方法。
. T C o r b a F a c t o r y和T C o r b a O b j e c t F a c t o r y。T C o r b a F a c t o r y是能创建C O R B A对象实例的对象的的基类。
T C o r b a O b j e c t F a c t o r y能够实例化任何T C o r b a I m p l e m e n t a t i o n派生类。
. T C o r b a L i s t M a n g e r (和子类)。D e l p h i的O C R B A框架在运行期间必须跟踪多项内容,诸如s k e l e t o n、
s t u b、类工厂和接口I D。T C o r b a L i s t M a n g e r是一个提供线程同步支持的基础类。这就允许V C L提
供一种内部自主的线程安全方式。一个开发者除了偶而注册一个自定义的s t u b对象外,一般不需
要用此列表管理器来管理类。
. T B O A。这是代表基础对象适配器( B O A )的D e l p h i类,一个用于O R B与s k e l e t o n之间的通信
C O R B A机制。T B O A类是一个单独的对象,并且从不需要直接实例化。
. TO R B。这是使D e l p h i的V C L与VisiBroker ORB通信的类。如同T B O A类,TO R B类是单独的,并
且从不需要直接实例化。TO R B的许多方法实现是调用o r b p a s 5 0 . d l l中的函数,o r b p a s 5 0 . d l l再调用
VisiBroker C++ ORB(orb_br. d l l )中的例程。
图27-3 Dephi的对象库/CORBA向导
图27-4 CORBA对象向导
27.5.2 CORBA对象向导
这个类列表列出了D e l p h i开发人员需要直接处理的几乎所有VCL CORBA类。然而,你可能很高
兴知道有一个D e l p h i向导可以帮助你正确地实现C O R B A对象。选择系统菜单中的F i l e | N e w菜单项就激
活了D e l p h i的对象库(Object Repository),如图2 7 - 3所示,并选择M u l t i t i e r标签。
现在双击CORBA Object,将看到C O R B A对象向导,如图
2 7 - 4所示。
填入C O R B A对象和接口的名字。注意,不必使用标准约定
在D e l p h i的类名前加上字母T,因为它会被自动添加。例如,如
果填入M y O b j e c t,一个D e l p h i的类名T M y O b j e c t将被产生,并生
成接口I M y O b j e c t。
实例化选项(Instancing option)将决定产生怎样的对象实例。
下面两个选项中的一个可能被选中:
第2 7章使用D e l p h i开发CORBA 9 3 7
清单27-1 一个D e l p h i产生s t u b和s k e l e t o n单元
下载
. Shared Instance。这种模式一般用于C O R B A开发。所有客户使用一个共享实例的对象实现。使
用这种模式的服务器被作为一种无状态服务器被建立。因为许多客户共享一个对象实例,任何
一个特定的客户都不能保证服务器处于它上一次调用后的状态。
. I n s t a n c e - p e r- c l i e n t。这种模式下,每当一个客户试图连接时, C O R B A对象就生成一个服务实例。
这种模式允许在客户调用之间维持对象状态一致。然而,由于它要求服务器跟踪连接用户的状
态,以便在用户不使用对象时释放它,所以这种模式占用的资源更多。
线程模式(Threaad Model option)指出了如何选择C O R B A对象被调用的线程模式。以下是两种有效
选项:
. s i n g l e - t h r e a d e d。每个对象实例只能被一个线程调用;因此,对象本身不需要是线程安全的。注
意C O R B A服务器程序可能包含多个对象或实例;因此,全局或共享数据必须是线程安全的。
性。
. M u l t i t h r e a d e d。在同一时刻,每个C O R B A对象的实例可以接受多个客户的请求,每一个请求均
在一个专门的线程中进行。在这种情况下,全局以及对象数据必须是线程安全的。在此模式下,
使用共享对象实例是最困难的情况。而s i n g l e - t h r e a d e d模式加i n s t a n c e - p e r- c l i e n t模式是最简单的。
记住,仅仅选择一个线程选项并不能保证以线程安全的方式来实现服务器或对象。这些线程选项
纯粹是指定对象支持的线程模式。基于线程模式实现C O R B A服务器可以保持线程安全方式下的可靠
当成功地完成了C O R B A向导时,两个P a s c a l单元代码将被产生。一个是s t u b / s k e l e t o n单元:将以
Yo u r P r o j e c t _ T L B . p a s命名格式产生。Yo u r P r o j e c t _ T L B . p a s包含了所产生的对象的主要接口定义、一个
s t u b和s k e l e t o n类、一个C O R B A类工厂、注册s t u b和s k e l e t o n的代码以及相应的D e l p h i机制的接口。清单
2 7 - 1列出了为一个以M y F i r s t C O R B A S e v e r命名的类产生的代码。
9 3 8 第三部分基于组件的开发
下载
第2 7章使用D e l p h i开发CORBA 9 3 9
下载
9 4 0 第三部分基于组件的开发
下载
查看上面的s t u b和s k e l e t o n单元,有趣的是, s k e l e t o n类并没有真正实现I M y F i r s t C o r b a S e r v e r接口,
但s k e l e t o n将会有与被支持的接口一样的方法,不过参数是不同的。s k e l e t o n的方法收到未处理的调度
信息,然后把它们传递给相应接口。由于这个原因, s k e l e t o n并不真正直接实现接口。取而代之的是,
它拥有一个被支持的接口的内部引用,并把它的调用转给这个引用。
第二个单元包含一个实现对象的框架。一个从T C o r b a I m p l e m e n t a t i o n派生并实现主要接口的D e l p h i
类将被产生。这个单元还会创建一个类工厂的实例来创建C O R B A对象。清单2 7 - 2列出了一个典型的
C O R B A对象实现单元。
清单27-2 一个D e l p h i产生的C O R B A对象实现单元
第2 7章使用D e l p h i开发CORBA 9 4 1
下载
这个单元最终将包含所有的I M y F i r s t C O R B A S e r v e r接口方法,以及每个T M y F i r s t C O R B A S e r v e r类
的内部功能。通过继承实现T M y F i r s t C O R B A S e r v e r类将自动产生一个C O R B A对象。通过支持
I M y F i r s t C O R B A S e r v e r接口,对象将满足这个接口的要求。在手工声明对象的接口及实现的地方,现
在利用可视的类型库编辑器来完成。
27.5.3 Delphi的类型库编辑器
为了完全地实现这个自定义的C O R B A对象,代码必须被添加到s t u b和s k e l e t o n单元和前面列出的
对象实现部分。虽然,这是一个让人感到困难的任务,但D e l p h i的类型库编辑器会有效地帮助你完成
它。选择系统菜单上的Vi e w项,再选择Type Library。会看到在图2 7 - 5中可视地描述了接口和其他在
s t u b和s k e l e t o n单元中定义的项。
图27-5 Delphi的类型库编辑器
9 4 2 第三部分基于组件的开发
下载
在类型库编辑器中选择I M y F i r s t C o r b a S e r v e r接口,并单击按钮来增加一个新的方法。一旦新方法被
增加,你就可以利用编辑器可视地定义参数、返回类型等。注意,并不是编辑器中所列的所有类型都
对C O R B A对象有效。因为类型编辑器现在是一个可用于C O M和C O R B A的双重工具,所以许多的数据
类型只对C O M /自动化对象有效。D e l p h i的帮助文件详细列出了有效的C O R B A ( I D L )数据类型。一旦使
用类型编辑器增加了接口的方法,当单击刷新按钮时将会在项目中自动产生新的代码。s t u b和s k e l e t o n
单元将被刷新,空的新方法将被增加到实现单元,留给你的工作只是向类型编辑器生成的空方法填入
代码。
注意Delphi 5包含了一个新特色。它将产生包含于类型库中的组件类的组件外套。不幸的是,
无论是引入一个已存在的类型库或是创建一个自己的类型库,外套都会产生。而这些外套并不
适用于C O R B A对象,因此需要按以下步骤执行来防止产生这些多余的代码。在D e l p h i的菜单
在下面的例子中,为了验证服务器是否在运行,我们保
中选择P r o j e c t,选择Import Type Library。当对话框出现时,使左下角的Generate Component
Wr a p p e r复选框不被选中。最后,选择类型库编辑器中的刷新按钮,这样多余的代码就不会出
现在程序当中了。
图27-6 CORBA服务器的主窗体
27.6 在Delphi 5中创建CORBA解决方案
现在我们来讨论基础的C O R B A框架和D e l p h i中的I D E工具,我们将应用已有的知识创建一个
C O R B A服务器。而后,再建立一个使用我们自定义的C O R B A服务的客户。
27.6.1 建立一个CORBA服务器
在了解了创建C O R B A服务器的基础知识后,现在,我们进入从头到尾创建一个C O R B A服务器的
过程。我们的目的是创建一个间层C O R B A对象,它可以接受一个客户的S Q L请示、查询数据库并且能
向调用服务的客户返回结果。为了很容易地从一个数据库服务器找到数据,我们使用B D E来实现它。
需要注意这种从属关系是从服务器的角度出发的。客户端程序并不需要B D E的知识,使用Delphi 5新
的A D O数据集或一个自定义的T D a t a s e t,服务器就能轻易地找到数据。
1. 调用C O R B A对象向导
创建一个新D e l p h i程序,然后使用前面讲到的C O R B A对象向导。我们的对象将以Q u e r y S e r v e r命名,
这将产生一个以I Q u e r y S e r v e r命名的接口和一个名字为T Q u e r y S e r v e r的实现类。选择I n s t a n c e - P e r- C l i e n t
实例化选项,因为我们要求对象支持数据浏览(第一项、下一项等等),因此不能是一个无状态的对象。
为了避免写线程安全的代码的复杂性,可以选择S i n g l e - T h r e a d e d的线程模式选项。当选择O K后,s t u b
和s k e l e t o n单元以及对象实现单元将会被增加到项目中去。
你可能已经注意到缺省的D e l p h i程序有一个缺省的窗体。为了拥有Wi n d o w s的消息循环,一个
Delphi GUI程序必须有一个窗体。许多的C O R B A服务程序并不需要可视的窗体;因此,我们可以在程
序的代码中加入一行代码:
持一个可视的窗体,并且提供了一个T L a b e l控件来通知我们
C O R B A服务是激活的。这个窗体如图2 7 - 6所示。
要知道这个窗体是全局数据,即使我们以s i n g l e - t h r e a d e d
模式创建了C O R B A对象,C O R B A服务器程序也可以包含在
其他线程中为调用服务的对象。因此,从对象代码来访问此窗体不能被认为是线程安全的。
2. 使用类型库编辑器
在生成了实现C O R B A对象的代码后,我们使用类型库编辑器为接口增加支持方法。我们将为接
第2 7章使用D e l p h i开发CORBA 9 4 3
图27-7 在类型库编辑器中的IQueryServer的方法
下载
口I Q u e r y S e r v e r增加以下功能:允许客户登录数据库、发送S Q L语句、浏览数据以及从结果集中检索一
行。这些工作都是通过选中I Q u e r y S e r v e r接口并点击New Method按钮来完成的。当每一种新的方法被
增加时,我们可以通过A t t r i b u t e s页中的N a m e编辑框来对其进行命名。对于每一种新的方法,还需要
使用P a r a m e t e r s页来提供参数的类型和返回值。在增加了几个提供一定功能的方法后,类型库编辑器
如图2 7 - 7所示。

27.6.2 实现IQueryServer的方法
现在我们已经定义了C O R B A对象的接口,应该为这些接口增加代码来完成其方法的功能。为了
访问B D E和服务器数据,在实现类中封装了T D a t a b a s e和T Q u e r y。这样,剩下的工作就很轻松了,接
口方法只需要调用T D a t a b a s e和T Q u e r y提供的功能。
在实现过程中,唯一困难的方法是D a t a方法(函数)。这个方法将检索查询结果中的当前行。因为
我们正在返回多个值,所以需要返回一些类型的结构来说明对应值。在I D L中,这通常导致使用一个
s e q u e n c e,这是一个多种数据类型的Va r i a n t数组。类型库编辑器并不允许我们定义一个IDL sequence,
因此我们使D a t a方法的返回类型为O L E Va r i a n t。这个O L E Va r i a n t事实上是一个数组,它的每一个元素
中包含行中各个列的值。因为I D L有一个被称为A n y的类似结构,它能包含任何I D L类型,所以我们能
使用一个O L E Va r i a n t来完成此项任务。D e l p h i产生的I D L会把O L E Va r i a n t作为I D L的A n y,因为D e l p h i的
C O R B A框架允许把这个值转换为A n y,并由O R B来正确调度。事实上,有一种在Delphi VCL中声明的
类型被称为TA n y,它被直接地映射成Va r i a n t。在创建一个Va r i a n t数组时,我们需要做的是把它作为
D a t a函数的返回值来传递。如下所示:
// 包装和发送数据
一旦我们实现了其他的方法,我们会得到一个s t u b和s k e l e t o n单元,如清单2 7 - 3所示。
9 4 4 第三部分基于组件的开发
下载
清单27-3 IQueryServer 的s t u b和s k e l e t o n单元
第2 7章使用D e l p h i开发CORBA 9 4 5
下载
9 4 6 第三部分基于组件的开发
下载
第2 7章使用D e l p h i开发CORBA 9 4 7
下载
9 4 8 第三部分基于组件的开发
下载
第2 7章使用D e l p h i开发CORBA 9 4 9
下载
9 5 0 第三部分基于组件的开发
下载
第2 7章使用D e l p h i开发CORBA 9 5 1
下载
9 5 2 第三部分基于组件的开发
求从s t u b调度到O R B,而从s k e l e t o n到实际的对象实现并不需要调度参数。
下载
要注意为了正确地调度参数,类型库编辑器与D e l p h i的向导联合生成了所有必要的代码。参数要
清单2 7 - 4列出了我们必须增加的代码。你会看到只需要正确地处理对象行为的实现,而不必处理
杂乱的C O R B A细节和调度参数。
清单27-4 TQueryServer的实现单元
第2 7章使用D e l p h i开发CORBA 9 5 3
下载
9 5 4 第三部分基于组件的开发
下载
清单2 7 - 4列出了操作T D a t a b a s e对象的代码。B D E命名空间仅仅允许在同一个会话中有一个唯一命
名的数据库。因为在这个共享单一T S e s s i o n对象的C O R B A服务中,我们能有多个T Q u e r y S e r v e r对象,
所以必须设置T D a t a b a s e的H a n d l e S h a r e d属性为真。如果我们不这样做,下一个创建T Q u e r y S e r v e r的客
户将不能连接服务器。
从类型库编辑器中可以看到代表接口的I D L。点击类型库编辑器中Export to IDL按钮右边的下拉箭
头,选中Export to CORBA IDL(注意它与Microsoft IDL或M I D L相似,但是不同)。在清单2 7 - 5中,可
以看到I D L代码。
清单27-5 IQueryServer的CORBA IDL
第2 7章使用D e l p h i开发CORBA 9 5 5
下载
请注意在类型库编辑器中我们选择的C O M数据类型被正确地转换为I D L。这个I D L能被导入到其
他任何支持C O R B A的工具。像CBuilder 和J B u i l d e r这些工具将产生外套类,以便使用这些语言编写的
客户,可以很容易地使用D e l p h i的C O R B A对象。
注意事实上,在清单27-5中的代码稍有些错误。函数Set_SQL不应该返回一个值。虽然Delphi
应该正确地处理它,但问题在于我们在类型库编辑器中增加了一个属性( S Q L )。这个属性可以
被C O M识别,但是在C O R B A中不能被正常识别。D e l p h i为此属性创建了读和写的方法,但是
不能正确地把写方法导出为I D L。为解决这个问题,可以在C O R B A接口中声明方法,或手工
地编辑产生的IDL,使声明如下:
运行C O R B A服务器
创建查询服务器的工作已经完成。现在应该运行C O R B A服务器程序,以使VisiBroker ORB知道对
象对于客户端是有效的。为使客户能使用VisiBroker ORB去定位和连接O C R B A对象的实现,在本地网
络上必须运行着VisiBroker Smart Agent。这个代理不需要作为客户或服务器运行在同一台机器上。
Smart Agent可以从命令行启动(在Windows NT上Smart Agent作为服务运行),命令如下:
下面是命令的选项:
. -p设置代理要监听的端口号。
. -v记录有关调试信息到一个名为o s a g e n t . l o g的文件。
. -?记录使用信息到文件o s a g e n t . l o g。
. -c如果Smart Agent在N T上运行(默认为9 5 / 9 8 ),使其为控制台方式。
如果是在Windows NT中人工启动Smart Agent,一定要使用参数- C启动o s a g e n t。这样才允许
o s a g e n t以控制台方式作为N T服务运行。下面的命令在Windows NT上作为控制台程序启动Smart Agent,
它用于监听端口1 4 0 0 5:
这样它就对客户连接可用了。注意此时你必须运行这个服务器程序。除非使用O A D,没有内置工具来
启动一个服务(作为D C O M )。
一旦Smart Agent在网络上运行,就可以运行刚才编译的项目,然后它将使用Smart Agent来注册,
9 5 6 第三部分基于组件的开发
下载
图27-8 CORBA客户GUI
27.6.3 编译一个静态绑定的CORBA客户
现在,我们已经有一个C O R B A服务器对象了,我们可以使用D e l p h i创建一个C O R B A客户。我们
将编译一个简单的客户,这个客户使用I Q u e r y S e r v e r接口以从服务器读取数据,然后再用获得的数据
填充一个字符串网格。认识到我们正从这种结构中获得益处是很重要的。我们的客户只需要访问
VisiBroker ORB,而不需要任何D e l p h i数据集或B D E的知识。
一个C O R B A客户可以以两种方式与C O R B A对象通信:静态绑定和动态绑定。静态绑定意味着,
编译器可以直接调用s t u b的v t a b l e编译。这种方式不仅运行速度快,而且能够在编译期对传送的参数进
行类型检查。在动态绑定的情况下,所有的远端调用都利用A n y类型。因为参数的信息必须从
VisiBroker Interface Repository获得,并且在运行前错误的参数类型不会被发现,所以运行的速度会慢
些。为了使D e l p h i静态绑定一个s t u b,编译器必须在一个s t u b接口提供一些P a s c a l说明。对于一个用其
他语言建立的对象,这样做会比较困难,因为Delphi 5不能提供由I D L向P a s c a l的有效转换。在本例中,
我们在D e l p h i中建立了服务器并且向导产生了一个P a s c a l版本的s t u b接口。因此,我们可以仅仅在前面
的例子的u s e s子句中包含s t u b和s k e l e t o n单元,就可以实现静态绑定。
1. 创建C O R B A客户
我们首先创建一个简单的Delphi GUI程序,通过它可以看到从I Q u e r y S e r v e r接口获得的数据,如图
2 7 - 8所示。
完成后,我们将在窗体单元( S i m p l e C o r b a S e r v e r _ T L B . p a s )的u s e s子句中增加stub 和s k e l e t o n单元。
2. 连接C O R B A服务器
现在要做的是连接服务器,并且开始创建调用远程接口的方法。使用stub 和s k e l e t o n单元定义一个
I Q u e r y S e r v e r的类工厂(命名为T Q u e r y S e r v e r C o r b a F a c t o r y )。这个类提供了一个被命名为C r e a t e I n s t a n c e
的类函数(以便我们不用创建一个T Q u e r y S e r v e r C o r b a F a c t o r y的实例),它将创建相应的s t u b对象,并且
给我们返回I Q u e r y S e r v e r接口。然后,利用静态绑定来调用远程I Q u e r y S e r v e接口。在客户端的工作是
调用I Q u e r y S e r v e r的D a t a方法,并且把O L E Va r i a n t数组“解开”以填充字符串网格。这项工作由客户端
的E x e c u t e C l i c k事件完成。C O R B A客户的实现列于清单2 7 - 6。
清单27-6 SimpleCorbaClient的实现
第2 7章使用D e l p h i开发CORBA 9 5 7
下载
9 5 8 第三部分基于组件的开发
下载
如果已经启动了Smart Agent并且服务器在它可以看到的地方运行着,我们现在就运行这个程序,
并且从C O R B A服务器接受数据。
27.6.4 编译一个动态绑定的CORBA客户
我们现在修改C O R B A客户,以便它使用动态绑定来与远程接口通信。在C O R B A中我们使用了
DII(Dynamic Invocation Interface)。动态绑定在这里是没有必要的,因为客户和服务器都用D e l p h i开发
的。然而,如果想很容易地使用用在其他语言开发的C O R B A服务器,这项技术会很有用的。
首先,在窗体单元的u s e s子句中删除s t u b和s k e l e t o n单元。记住,如果服务器是用J a v a语言写的,
那么对你来说使用什么都是无效的。
其次,我们的客户现在没有I Q u e r y S e r v e r接口的知识。因此,我们需要把封装的F Q u e r y S e r v e r字段
的数据类型由I Q u e r y S e r v e r转换为TA n y。
第三,我们需要以一种不同于以往的方式获得一个普通的CORBA stub。可以调用全局的P a s c a l方
法C o r b a B i n d (来自C o r b a O b j单元),并且传递我们所需要的类工厂的库I D。当我们获得了类工厂后,就
能利用类工厂的C r e a t e I n s t a n c e方法返回一个普通的接口。我们能保持这种A n y接口并且调用动态绑定。
清单2 7 - 7列出了动态绑定客户的完整源代码。
清单27-7 动态绑定客户
第2 7章使用D e l p h i开发CORBA 9 5 9
下载
你将会注意到在动态绑定客户代码中有一些变化。
在C O M中I D L不支持属性的概念。当我们使用静态绑定时,因为编译器解析读/写方法的地址,所
9 6 0 第三部分基于组件的开发
方法。例如,我们可以调用G e t _ F i e l d C o u n t,而不是读F i e l d C o u n t。
下载
以我们可以避开它。当我们使用动态绑定时,由于D I I并不认识属性,所以我们必须明确地调用读/写
所有的D I I参数都是作为A n y类型来传递和存储的。为了正确设置A n y类型的数据,一些值需要被
明确地进行类型转换。例如,给L o g i n方法发送一个字符串值的D b参数将使A n y类型被设置为Va r S t r i n g。
如果这个字符串不被转换为Wi d e S t r i n g类型以使A n y类型被设置为v a r O l e S t r (一个Wi d e S t r i n g ),将会导
致一个参数错误。
最后,除Smart Agent 外,在网络上必须运行VisiBroker Interface Repository ,并且一定要用
唯一需要讨论的是I R n a m e。因为可能有多个Interface Repository实例在运行,这就需要以某种方
Interface Repository注册I Q u e r y S e r v e r接口。Interface Repository如同一个在线数据库,它允许O R B使用
D I I来检查接口信息。VisiBroker Interface Repository能以下面命令被启动。
式标识其中一个。- c o n s o l e参数指定是否让I R E P程序以控制台方式运行(默认是G U I模式)。
f i l e . i d l用于在启动这个程序时指定一个要加载的初始化I D L文件(扩展名为. i d l )。使用菜单选项或运
行i d l 2 i r能使附加的I D L文件被加载。
27.6.5 跨语言的CORBA
当我们正在编写本书时,在D e l p h i中仍然没有I d l 2 P a s编译器。然而,已经有一个预发行版的这类
工具。在本节中,我们将讨论手工静态绑定一个使用其他语言编写的C O R B A服务器,并介绍I d l 2 P a s
编译器。
1. 手工调度一个J a v a服务器
下面的例子中,使用了一个简单的在J a v a中构造的C O R B A服务器,它被一个D e l p h i程序调用。这
个C O R B A服务器的I D L列于清单2 7 - 8中。
清单27-8 一个J a v a服务器的I D L
如果用Interface Repository注册了这个C O R B A服务器,D e l p h i就可以很容易地使用D I I访问它(对应
代码在清单27-9 btnDelphiTe x t E a r l y方法中)。
为了不使用I d l 2 P a s编译器实现静态绑定,我们必须手工编辑自己的s t u b类来执行调度代码。这项
工作是很乏味的,而且对于大量的方法很容易出错。还必须使用适当的D e l p h i机制来注册s t u b类和它的
接口。清单2 7 - 9包含了全部代码。
清单27-9 从D e l p h i客户访问J a v a服务(静态和动态绑定)
第2 7章使用D e l p h i开发CORBA 9 6 1
下载
9 6 2 第三部分基于组件的开发
下载
你会注意到上面的代码与我们在D e l p h i中利用类型库编辑器创建C O R B A对象时产生的代码很相
似。我们已经增加了自己的T C o r b a S t u b派生类,这个派生类将提供服务器端调度。因为类型库编辑器
并没有涉及到这里,所以并没有必要派生T C o r b a D i s p a t c h S t u b。接下来,实现自定义的s t u b以从/向调
度缓冲区接口I M a s h a l l I n B u ff u e r和I M a s h a l l O u t B u ff e r调度参数。这些接口包含了一些方法,利用这些方
法可以方便地把变体类型数据读出或写入缓冲区。在Delphi 5的在线帮助中有更多的使用这些方法的
信息。最后,我们需要利用D e l p h i的C O R B A框架来注册我们自定义的s t u b和接口。其代码包含在单元
的i n i t i a l i z a t i o n部分。
2. Inprise的I d l 2 P a s编译器
查看清单2 7 - 9,很显然手工调度一个大的C O R B A对象需做大量的工作。使用I d l 2 P a s编译器可以有
效地解决这个问题, I d l 2 P a s编译器能自动产生相应于s t u b的调度代码。当你读本章时,应该已经有这
样的工具了。
I n p r i s e的I d l 2 P a s编译器在J a v a中实现,因此,在你的开发机器上要安装一个J a v a虚拟机。当你安
装Delphi 5时,就提供了一个合适的J a v a运行环境。当前预发行版的I d l 2 P a s编译器并没有完全进入
D e l p h i的集成环境,所以我们必须使用批处理文件I d l 2 P a s . b a t以命令行方式来调用I d l 2 P a s编译器。要在
S i m p l e Te x t . i d l上调用I d l 2 P a s并且在c : \ i d l中存储产生的文件,命令格式如下:
I d l 2 P a s将在指定目录产生两个文件,它们根据i d l文件包含的模块名命名。在这个例子中, C o r b a -
S e r v e r _ i . p a s包含了i d l接口的p a s c a l声明。如清单2 7 - 1 0所示。
清单27-10 Idl2Pas产生的接口定义
下载
产生的第二个文件是C o r b a S e r v e r _ c . p a s,其中包括了s t u b类的实现代码以及一个辅助对象( T S i m p l e
Te x t H e l p e r ),这个对象使结构、联合和用户定义数据类型传递起来更简单。产生的实现代码如清单2 7 - 11
所示。
第2 7章使用D e l p h i开发CORBA 9 6 3
清单2 7 - 11 Id2Pas产生的S t u b和H e l p e r类
9 6 4 第三部分基于组件的开发
下载
第2 7章使用D e l p h i开发CORBA 9 6 5
下载
9 6 6 第三部分基于组件的开发
下载
第2 7章使用D e l p h i开发CORBA 9 6 7
下载
在S e t Te x t方法中产生的调度代码与手工编写的稍微有些不同。这是因为I d l 2 P a s使用了另一个D L L
提供O R B / p a s c a l访问( O r b P a s 3 3 . d l l ),并且提供了两个新的支持Delphi CORBA框架的单元( C o r b a . p a s和
O r b P a s 3 0 . p a s )。这些新增加的部分将与Delphi 5中原有的库和单元共存,而不是完全替代。
I d l 2 P a s编译器将会帮助你简化一些复杂的O C R B A任务,诸如调用用其他语言编写的服务器、调
度复杂数据类型和处理自定义的用户异常。
27.7 使用VisiBroker ORB
VisiBroker ORB需要一个运行许可证。虽然, Delphi 5的开发环境中包含了Vi s i B r o k e r服务,在实
际使用解决方案前,还是应该检查一下。
O R B服务被使用于服务器端以及客户机端的机器上。许多其他的Vi s i B r o k e r服务(如o s a g e n t、i r e p
和o a d )可以在本地网络的任何地方执行。因此,在正在使用O R B软件的所有机器上启动这些服务是没
有必要的。用于D e l p h i的C++ ORB是动态链接库o r b _ b r. d l l。Windows Vi s i B r o k e r的常见问题是D O S路
径定义不正确。为了让系统定位O R B的D L L,这一步必须做。记住,为了把I D L接口映射到D e l p h i的
接口,D e l p h i使用了一个特殊的“ t h u n k i n g”层( o r b p a s 5 0 . d l l ),D e l p h i还提供对C++ ORB的其他访问。
对于所有Delphi 5 的C O R B A,O r b p a s 5 0 . d l l必须被使用。
27.8 总结
在这一章,我们了解了Delphi 5的C O R B A开发基础。我们创建了C O R B A的客户和服务器,并实现了
静态绑定和动态绑定。我们也清楚了静态绑定一个用其他语言编写的C O R B A服务器的要求。最后,我们
还接触到了I n p r i s e的I d l 2 P a s编译器,并且演示了如何利用这个工具使D e l p h i的C O R B A开发变得简单。



  打印本页

碧海晴天设为首页加入收藏联系我们

联系地址:美国拉斯维加斯   联系电话:010--1234567890   联系人:cocoa