4.1 详解CORBA事件服务实现
CORBA事件服务通过对事件(由对象产生并且传送给其他对象)封装而提供了基本的消息传递功能,在事件被产生之后,CORBA事件服务是将事件从事件提供者对象传送给事件消费者对象这样一种机制。而且事件服务允许对象动态地注册或注销他们感兴趣的特定事件,事件服务在相互不很了解的对象之间建立起一条宽松耦合的通信信道。事件耦合程度比远程过程调用要松,但比面向消息的中间件(MOM)要紧。
4.1.1两种事件数据传送模型:
•推push模型:
在推模型中,事件的提供者起带头作用,发起事件的传送;
•拉pull模型:
在拉模型中,事件的消费者起带头作用,向提供者请求事件数据。
事件信道(event channel)是一个既是事件提供者又是事件消费者的插入对象,它允许多个事件提供者和多个事件消费者异步地通信而不需要相互了解。事件信道又是一个标准的CORBA对象,驻留在对象请求中介上,断开提供者和消费者的通信。
事件信道利用代理(proxy)对象撤消时间的提供者和消费者。提供者和消费者不是直接交互作用,而是从事件信道那里获得代理对象,让代理对象在将来的事件交换中代表自己。提供者获得一个消费者代理,而消费者获得一个提供者代理。事件信道通过这些代理对象代理事件的交换。
4.1.2事件信道
•对于推模型:
事件提供者发出一个调用,调用事件信道对象上的push方法,事件信道接着把数据推给消费者对象。消费者可以通过调用事件信道上的方法disconnect_push_consumer来停止接受事件,也可以调用事件信道上的connect_push_consumer方法来注册感兴趣的事件类型。
•对于拉模型:
事件消费者发出一个调用,调用事件信道对象上的pull方法,事件信道接着把数据从提供者那里拉回来。利用try_pull方法,消费者可以周期性地轮询事件。通过调用事件信道上的disconnect_pull_ supplier方法,提供者可以停止接受要求提供事件的请求,提供者也可以调用事件信道上的add_pull_supplier方法,注册其对象标记,提供其服务。
我们可以通过理解CORBA事件序列的上下文来理解CORBA事件服务体系结构。
4.1.3推模型
如图所示的Push事件脚本显示了一个推提供者通过事件信道向一个推消费者发送事件的简要过程。
1. 对于一个推模型的推提供者来讲,基本的事件序列如下:
(1)绑定到ORB和事件信道上:
org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init(agrs,null);
EventChannel eventChannel = EventChannelHelper.bin(orb);
(2) 从事件信道中获取一个推消费者代理:
SupplierAdmin admin = eventChannel.for_suppliers(); // 对应Push事件脚本的第一步
ProxyPushConsumer pushConsumer = admin .obtain_push_consumer(); // 对应图中Push事件脚本的第二步
(3) 创建一个推提供者:
MySupplier pushSupplier = new MySupplier();
(4)将提供者连接到事件信道:
pushConsumer.connect_push_supplier(pushSupplier);//对应图中Push事件脚本的第三步
(5) 创建一个CORBA消息:
HelloImplementation msg=new HelloImplementation()
(6)利用CORBA消息创建一个Any事件对象:
Org.omg.CORBA.Any pushMessage=orb.create_any();
PushMessage.insert_Object(msg);
(7) 将消息推给消费者:
pushConsumer.push(pushMessage);
// 对应图中Push事件脚本的第七步
2. 对于一个推模型的推消费者来讲,基本的事件序列如下:
(1)绑定到ORB和事件信道上:
org.omg.CORBA.ORB orb= org.omg.CORBA.ORB.init(agrs, null);
EventChannel eventChannel= EventChannelHelper.bin(orb);
(2)从事件信道中获取一个推提供者代理:
ConsumerAdmin admin= eventChannel.for_consumers();// 对应图中Push事件脚本的第四步
ProxyPushSupplier pushSupplier = admin .obtain_push_supplier();
// 对应图中Push事件脚本的第五步
(3) 创建一个推消费者:
MyConsumer pushConsumer=new MyConsumer ();
(4) 将消费者连接到事件信道:
pushSupplier.connect_push_consumer(pushConsumer); // 对应图中Push事件脚本的第六步
(5) 在一个 push()实现中被接收:
public void push(Any pushMsg)
{
// 对应图中Push事件脚本的第七步
org.omg.CORBA.Object object=pushMsg.extract_Object();
Hello msg=HelloHeper.narrow(object);
}
4.1.4拉模型
1. 对于一个拉模型的拉提供者来讲,基本的事件序列如下:
(1)绑定到ORB和事件信道上:
org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init(agrs, null);
EventChannel eventChannel = EventChannelHelper.bin(orb);
(2) 事件信道中获取一个拉消费者代理:
SupplierAdmin admin = eventChannel.for_suppliers();
ProxyPullConsumer pullConsumer = admin .obtain_pull_consumer();
(3) 创建一个拉提供者:
MySupplier pullSupplier = new MySupplier();
(4) 将提供者连接到事件信道:
pullConsumer.connect_pull_supplier(pullSupplier);
(5) 为消费者提供一个pull()接口用于拉消息:
public org.omg.CORBA.Any pull()
{
org.omg.OCRBA.Any pullMsg = org.create_any();
HelloImplementation msg = new HelloImplementation();
pullMsg.insert_Object(msg);
ruturn pullMsg;
}
(6) 为消费者设计一个try_pull()接口,实现只有当一个消息可用时它才会拉消息的功能:
public Org.omg.CORBA.Any try_pull(org.omg.CORBA.BooleanHolder isAvail)
{ }
2.对于一个拉模型的拉消费者来讲,基本的事件序列如下:
(1) 绑定到ORB和事件信道上:
org.omg.CORBA.ORB orb= org.omg.CORBA.ORB.init(agrs, null);
EventChannel eventChannel= EventChannelHelper.bin(orb);
(2) 从事件信道中获取一个拉提供者代理:
ConsumerAdmin admin= eventChannel.for_consumers();
ProxyPullSupplier pullSupplier = admin .obtain_pull_supplier();
(3) 创建一个拉消费者:
MyConsumer pullConsumer = new MyConsumer ();
(4) 将消费者连接到事件信道:
pullSupplier.connect_pull_consumer(pullConsumer);
(5) 对拉提供者代理调用try_pull()接口或者pull()接口并且将它转换为消息类型:
org.omg.CORBA.BooleanHolder hoder = new org.omg.CORBA.BooleanHolder();
org.omg.CORBA.Any pullMsg = pullSupplier.tyr_pull(holer);
org.omg.CORBA.Object obj = pullMsg.extract_Object();
Hello hello = HelloHelper.narrow(obj);
//转换为消息类型
图4-1 Push事件脚本
总的来说,CORBA事件服务只是在CORBA中引入了一个最低限度的MOM通信,它之所以是最低的,是因为它不支持像MOM那样的消息优先级、过滤器、交易保护和接受确认等管理机制。尽管如此,CORBA事件服务为对象动态地注册或注销它们感兴趣的特定事件提供了一个框架,利用这个框架,提供者可以把事件推给(push)消费者,消费者可以从提供者那里拉(pull)事件数据,而且多个提供者和消费者可以在一个事件信道上异步通信。件数据,而且多个提供者和消费者可以在一个事件信道上异步通信。
4.2 Corba互操作的命名服务
Corba的对象命名服务就是给对象实例提供一个名称,以便用户通过这些名称来获取对象的实例。对象命名服务是ORB上的对象找到其它对象的基本机制。名字是用来识别一个对象的可人工辨认的值,命名服务将这些名字映射到对象标记,名字-对象关联叫做名字联编。命名语言环境是一个名字空间,对象名字在这里是独一无二的。每个对象都有一个独一无二的参考标识符。可以有选择地将一个或多个名字与一个对象标记关联起来。相对于其命名语言环境始终定义一个名字。利用命名服务可以创建命名分层结构,客户可以搜寻不同的命名语言环境树,查找所要的对象。来自不同域的名字语言环境可以一起使用,为对象创建联合命名服务。CORBA命名分层结构不需要一个“统一”的根目录。一般情况下,用户可以规定对象的命名原则,表示对象所在的主机,功能等一系列的信息,这些信息主要包括如下三个方面的内容。
(1) Corba对象的句柄定义成如URL(统一资源定位)的形式,从而允许ORB(Object Request Broker)来调用基于Corba的服务或者远程ORB上的对象实例
(2) 任何一个厂商的ORB都可以通过配置客户端的ORB来初始化根命名服务的上下文对象(NamingContext)。
(3) 对于Corba对象的复合命名。定义一个标准的语法规则。这样服务器端和客户端就可以通过相同的格式来进行读写消息。
下面将分别讨论Corba命名服务的一些特点。
一、Corba对象的统一资源定位(URL):Corbaloc
在Internet上,你可以在浏览器中直接输入地址,即Url,就可以到你指定的网站区,这项技术在Corba中也得到了运用。
通常的做法是把一个Corba的服务器放在一台有指定域名地址和端口的机器上。Corba的服务器要为许多的Corba对象服务。一般我们需要在对象实例的URL地址后加上特定的对象健值(Object Key ID)或对象名字,这些对象的名字或健值就指明了我们所需要的特定的服务。如下所示:
Corbaloc:yourdomain.com/NameService
其中Corbaloc是Corba URL的关键字,用于对象实例和对象句柄的转换yourdomain.com是所在机器的域名地址或IP地址,/后面的NameService是对象健值.
1.对象的健值
对象的健值是接口对象仓库的一部分,主要用于表示客户端调用的特定对象实例。对象健值由ORB在生成对象句柄的过程中生成,并由特定的生成该对象健值的ORB来使用,因此Corba对于它的形式和内容没有做任何的标准化工作。
对象健值也不一定是一个单词,它也可以是一个字符串序列。在主域名或IP地址后面,紧跟/的都是对象健值。如:
Corbaloc:yourdomain.com/dev/sand/box/corba/nameservice
其对象健值为dev/sand/box/corba/nameservice
2.Corbaloc的完整格式和IIOP(Internet Inter-ORB protocal)
(1) Corbaloc URL的完整格式
Corbaloc URL的完整格式如下:
Corbaloc:IIOP:1.2@yourdomain.com:2809/pub/nameservice
即Corbaloc后面的是协议的类型(IIOP是默认的协议类型,可以省略),另一种协议是RIR(Resolove Initial References).1.2是该协议的版本号。由于每一个协议都定义了特定的消息格式,从而来查询目标对象,因此具体的地址信息包括了特定的协议类型,该协议的版本号,域名地址和端口号。IONA(Internet Association Naming Authority)注册的默认端口号是2809,在上例中的地址为:
IIOP:1.2@yourdomain.com:2809,再后面的是对象健值。
(2)Cobarloc和RIR协议
除了IIOP协议,还有一个RIR协议,通过RIR,可以用URL来访问ORB的服务把字符串Corbaloc:rir@yourdomain.org/nameservice传给string_to_object后,返回与之相对应的对象句柄,在Corbaloc:rir中调用的对象健值,可以是任何一个在resolve_initial_references中定义的健值。
3.编码以及Corbaloc的使用
每一个ORB都有一个标准的接口,用来把类似URL的字符串,通过string_to_object转化为对象句柄。同时返回给一个session的句柄给客户端,这个session的句柄和你所需要的NameService,TradeService或任何对象健值实现一一的映射。
再服务器端,可以使用两种方法实现对客户端的响应。
(1) 通常一个Corba命名或事务的对象实例会接受客户端的请求,然后把处理的结果返回给客户,服务器端的程序只要运行在特定端口的网关机器上,接受用户的请求即可。
(2) 或者为了减轻网关的负担,可以在你的网关上安装一个小的代理软件,不所有来自客户端的请求通过Locate_forward来重定向到一个比较稳定的服务器上来处理,在把处理好的结果返回给客户,网关起到了一个Proxy的作用。
二、对象URL的命名(CorbaName)
CorbaName运行在Corbaloc之上,用来解析远程命名服务。如下所示:
CorbaName::yourdomain.org/pub/catalog#year2000/Menswear/outdoors.obj
在#之前,除了CorbaName这个表识符,其它的就是Corbaloc的URL,#之后的就是对象命名的字符串。
把URL的字符串传给string_to_object函数,ORB把Corbaloc部分解析为主机命名服务的命名上下文(NamingContext)的一个实例。例如,客户端的ORB来解析名字上下文pub/catalog实例上的Menswear/outdoors.obj字符串,这些名字实例驻留在域名为yourdomain.org的Corba服务器上。
三、配置初始的服务和对象的句柄
在客户端的程序启动时要对根命名的上下文做一些配置。例如,把所有用户的ORB指向同一个根;组织和分配服务器上所有的名字空间,是所有的用户都可以相互交换对象的信息,而不同的用户也可以组织和分配他们自己的根名字空间和名字空间。客户端的程序可以通过list_initial_services来查询已经初始化好的服务。INS(Interoperable Name Service)对也命名服务器中的初始化对象句柄的设置提供了如下的三种方式。
1. 管理设置
把一个在该ORB上的服务,配置成为一个返回远程对象的句柄
2. ORBInitRef
启动ORB时,传递给系统如下的参数,来设置服务的对象句柄,如下所示:
-ORBInitRef <object_ID>=<object URL>
其中Object Idk可以是一个已经初始化好的服务,也可以是一个Object ID,即在ORB还没有写进去之前来初始化一个新的服务号。
Object URL可以是任何的Corba::ORB::string_to_object所支持的URL,如
-ORBInitRef NameService=IOR::0023021ABCS1
也可以用字符形式的Corba IOR来配置命名服务,如
-ORBInitRef NotificationService=Corbaloc::Tele/NotificationService
3. ORBDefaultInitRef
用ORBDefaultInitRef可以定义默认的URL形式的对象句柄的位置。如下所示:
-ORBDefaultInitRef corbaloc::yourdomain.com
ORG启动时会调用resolve_initial_references("NotificationService"),然后生成如下的完整的URL,如下所示:
Corbaloc::yourdomain.com/NotificationService
然后把这个完整的URL传给string_to_object,获取服务的session句柄,这样就可以和服务器端进行通信了。
四、总结
通过对象命名服务,可以简化ORB客户端和服务器端的通信,提高通信的质量和效率。对提高Corba在Internet在应用起了很大的作用。