VisiBroker的CORBA NameService使用方法

品雪 1999.11.1
pinxue@hotmail.com http://pinxue.yeah.net

感性认识

NameService的原理就不多说了,先看做法:

一、Bind Name—为对象绑定名字

1、初始化CORBA:
CORBA::ORB_var orb = CORBA::ORB_init(argc, argv);
CORBA::BOA_var boa = orb->BOA_init(argc, argv);

2、指定要绑定名字的对象ID,及要绑定的名字
const char* id = argv[1];
const char* kind = argv[2];

3、将对象实例登记到BOA中。
MyImpl myObject("My Object");
boa->obj_is_ready(&myObject);

4、定义一个NamingContext:
CosNaming::NamingContext_var context = CosNaming::NamingContext::_bind();

5、定义一个Name对象,并把其id及kind设为想要绑定的名字参数
CosNaming::Name name;
name.length(1);
name[0].id = id;
name[0].kind = kind;

6、绑定名字
context->bind(name, &myObject);

7、等待客户请求
boa->impl_is_ready();


二、Solve Name—以名字查找取得对象

1、初始ORB: CORBA::ORB_var orb = CORBA::ORB_init(argc, argv);

2、建立NamingContext和Name对象:
CosNaming::NamingContext_var context = CosNaming::NamingContext::_bind();
CosNaming::Name name;

3、指定要查找的对象的名字参数:
const char* id = argv[1];
const char* kind = argv[2];
name.length(1);
name[0].id = id;
name[0].kind = kind;

4、使用Name获取对对象的引用:
CORBA::Object_var object = context->resolve(name);

5、使用获得的对象:
This::Is_var test = This::Is::_narrow(object);
cout << "Testing: " << test << endl;
if(!CORBA::is_nil(test)) { test->aTest(); }


三、测试运行

1、启动NameFactory,设定root NameContext为NorthAmerica,Log文件为na_log:
Solaris prompt> CosNamingExtFactory NorthAmerica na_log
Windows prompt> nameextf NorthAmerica na_log

2、运行bind程序,为程序中实现的My Object在NameContext中绑定一个名字(由指定ID和Type组成)
prompt> bind SanFrancisco City

3、运行resolve程序,尝试以Name{ID、Type}获得对象
prompt> resolve SanFrancisco City

4、在resolve程序中会使用获得的This::Is("My Object")型的对象引用aTest()方法。



原 理
一、背景
  1. 有一大公司,在Asia、Europe、NorthAmerica有分部。
  2. 以北美为例,NorthAmerica有Shipping Department和Sales Department
  3. 在北美的Shipping Department要管理Inventory、Orders资料
  4. 在北美的Sales Department要处管理Cutsomer、Billing资料

现在在要使用CORBA来建立其信息系统。为此,我们为Invetory、Orders等建立了对象在各地的相应系统进行数据处理。为简单化全球系统的互相访问,就需要使用Name Service来解决。

二、解决之道

利用Name Service我们可以一个Name Space,内容为分部名字;再建立每个分部的部门名Name Service;最后为每个部门建立业务名Name Space。每项业务都会有自己的对象,我们可以为这些对象取一些有意义的名字并登记到相应的名字空间里。于是我们得到了一个树形结构,由根到叶的路径时由有意义的名字组成的(如 [{北美},{销售部},{客户}])。

这样,我们就可以用一串有意义的名字形成一条路径来访问所需的对象,比起使用抽象的对象ID要容易些,另外处理同一业务的对象可以取相同的名字,由于名字空间不同不会发生冲突。

在VisiBroker里是使用NamingContext对象来实现上边所述的Name Space的。该对象包含一个Name structure的清单,名字清单中的每个Name已经被绑定给某个CORBA对象或其它的NamingContext对象(如果是NamingContext则代表下一级名字空间);NamingContext对象还提供对空间内名字的管理功能,如服务器对象使用NamingContext给自己绑定名字(bind),客户端以逻辑名字调用NamingContext的resolve方法来取得所需要的对象等。(NamingContext的方法成员用法略,需要时请查联机文档)

IDL语法的Name Context形式化描述:
module CosNaming {
 interface NamingContext {
  void bind(in Name n, in Object obj) raises(NotFound, CannotProceed, InvalidName, AlreadyBound);
  void rebind(in Name n, in Object obj) raises(NotFound, CannotProceed, InvalidName);
  void bind_context(in Name n, in NamingContext nc) raises(NotFound, CannotProceed, InvalidName, AlreadyBound);
  void rebind_context(in Name n, in NamingContext nc) raises(NotFound, CannotProceed, InvalidName);
  Object resolve(in Name n) raises(NotFound, CannotProceed, InvalidName);
  void unbind(in Name n) raises(NotFound, CannotProceed, InvalidName);
  NamingContext new_context();
  NamingContext bind_new_context(in Name n) raises(NotFound, CannotProceed, InvalidName, AlreadyBound);
  void destroy() raises(NotEmpty);
  void list(in unsigned long how_many, out BindingList bl, out BindingIterator bi);
 };
};

那么Name Space将保存在什么地方呢?Visibroker提供了两个程序(namefact,nameextf)来提供名字空间服务。这两个程序实质上是用来创建NamingContext对象的,所以我们称它们为NamingContext Factory。两个factory的区别在于ext版的在建立NamingContext的同时会建立一个根名字空间(root name)。如果想使用名字空间服务先运行namefact FactName logfilename,这样就会建立起指定名字的名字工厂并记录在log中,下次再启动时服务程序会自动根据log重建名字空间。

说了半天的名字,Visibroker里的名字是什么呢?它是一个CosNaming::Name对象,它表示的是可以可以绑定给一个对象实例或NamingContext的标识符。一个Name可不只是一串字符,它是一个或多个NameComponent结构的序列。每个NameComponent包含两个字符串:id和kind。Naming Service并不对这些字符串加以解释或管理(除了检查同一NamingContext里字串是否唯一)。id代表名字将要绑定给的对象。kind成员则给名字增加了一个性质描述,如Inventory的kind可设为RDBMS。

用IDL语法对名字做一个形式化的描述:
module CosNaming
  typedef string Istring;
  struct NameComponent {
    Istring id;
    Istring kind;
  };
  typedef sequence<NameComponent> Name;
};

注:LName面提供了另外一种为CORBA对象创建名字的方法,略。

给对象都起好有意义的名字之后,客户程序就可以据此访问对应的对象了。这要使用名字求解服务,NamingContext提供了resolve方法来完成逻辑名到对象引用的变换。一个Name由一个或多个NameComponent组成,所以求解过程需要组成Name路径的所有NameComponet。

举几个实际Name的例子,其中用{}表示NameComponent,[]表示一个名字:

简单的名字[{Billing}],可以绑定给对象实例或NameContext。

复杂的名字[{North American},{ShippingDepartment},{Inventory}],由三个成员序列组成。

1、 象这样由N个NamingComponent组成的复杂名字,是绑定给对象实例的,那么其中的前N-1个必须解得NamingContext,最后一个必须解得一个对象实例。
2、显然,绑定给NamingContext的名字的所有成员都必须解得对NamingContext对象的引用。

一个绑定给ORB对象的复杂名字:Name[{id=NorthAmerica,kind=NULL},{id=SalesDapartment,kind=NULL},{id=Customer,kind=NULL},{id=InternationalSupplies,kind=COM}]

一个绑定给NamingContext对象的复杂名字:
Name[{id=NorthAmerica,kind=NULL},{id=SalesDepartment,kind=NULL}]

三、小结一下:

1、NameFact.EXE--->FactLogFile---->[NamingContext]-->[{NamingContext}{Name-->NameComponent}]

  名字服务程序  静态的名字空间 名字空间     下级名字空间 或者 ORB对象

2、默认Context:对于一个客户程序来说,需要设定一个NamingContext做为自己的根Context,这就是它的Default Context。通过从命令行传递
-SVCnameroot :<name 1&rt;.<kind 1>;/.../<name n>.<kind n>;
参数给客户程序即可完成此项设定工作。该参数将传ORB_init(argc,argv),由该方法真正完成设定工作。

所以,建立名字空间树及在客户端正确访问的命令如下:
A prompt1>NameExtF ShipDep ship.log
B 关闭NameExtf.exe(ship)
C prompt2>NameExtF NorthAm nod.log
D prompt1>NameExtF -SVCnameroot NorthAm ShipDep ship.log
//显然这些工作放到程序里会更好控制些。
prompt> MyClient -SVCnameroot NorthAm:ShipDep/Inventory

 

四、程序实现:(C++)

述于专章