CORBA 程序中,获取 CORBA 对象有通过命名服务和可操作对象引用 (Interoperable Object Reference,IOR) 两种方式。
IOR 存储几乎所有 ORB(Object Request Broker, 对象请求代理 ) 间协议信息,用于建立客户机和目标对象之间的通信,为 ORB 的互操作提供标准化的对象引用格式。每个 IOR 指定一个或多个所支持的协议,对于每个协议, IOR 包括那个协议所专有的信息。对于 IIOP ,每个 IOR 包括一个主机名, TCP/IP 端口号和一个对象密钥,密钥根据所给出的主机名和端口组合来识别目标对象。一个 IOR 主要有三个部分组成:仓库 ID ,终点信息和对象密钥。
IOR 将所有的 ORB 信息编码在一个字符串中,应用程序通过这个 IOR 字符串就可以获得所要操作的 CORBA 对象,一个 IOR 的例子如下:
IOR:000000000000001749444C3A48656C6C6F4170702F48656C6C6F3A312E30000000000001000000000000005C0
00102000000000C31302E3134302E312E393700290500000000002A5374616E64617264496D706C4E616D652F5065
7273697374656E74504F412F4D7948656C6C6F496D706C0000000000010000000000000008000000004A414300
使用 Jacorb 的 dior 命令可以解析 IOR 字符串的内容,上面的 IOR 解析后的内容为:
TypeId : IDL:HelloApp/Hello:1.0
TAG_INTERNET_IOP Profiles:
Profile Id: 0
IIOP Version: 1.2
Host: 10.140.1.97
Port: 10501
Object key (URL): StandardImplName/PersistentPOA/MyHelloImpl
Object key (hex): 0x53 74 61 6E 64 61 72 64 49 6D 70 6C 4E 61 6D 6
5 2F 50 65 72 73 69 73 74 65 6E 74 50 4F 41 2F 4D 79 48 65 6C 6C 6F 49 6D 70 6C
-- Found 1 Tagged Components--
#0: TAG_ORB_TYPE
Type: 1245790976 (JacORB)
要想创建持久化的IOR,则必须让IOR中的Host,Port和Object key固定不变,其中Object key组成:ImplName/POAName/ObjectId。
命名服务方式在上篇博客《 java 构建简单的 CORBA 应用 》中已经简单介绍过,本文主要介绍 IOR 方式, IOR 结构为支持两种方式的 IOR :每次都变化的 IOR ;固定不变的 IOR 。 CORBA 默认使用每次都变化的 IOR ,即每次启动服务端 CORBA 程序后,因为进程所使用的端口号不固定,因此 IOR 内容是每次都会随着端口号变化而变化的,相对比较简单。与每次都变化的 IOR 不同的是,很多时候应用场景要求 IOR 保持固定不变,即 CORBA 服务端应用程序进程号是固定不变的,这样就必须使用持久化的 POA 生成策略。
非常感谢 http://blog.csdn.net/njchenyi/archive/2008/10/16/3086559.aspx 这篇文章给出的小例子,但是由于例子说的不是很清楚,另外,源码不全,因此在实际工作中困难重重,下面我把我自己做的一个实验程序作为例子,讲解固定不变 IOR 的实现。
1. 写一个最简单的 IDL 文件,文件名称是 hello.idl 。代码如下:
module HelloApp{ interface Hello{ string sayHello(); oneway void shutdown(); }; };
2. 就是把这个 idl 文件编译成对应的 java 文件,这是通过 JDK 自带的 idlj 工具完成的,这个工具和 javac 在一个目录下。它的命令格式如下:
idlj hello.idl
我们会发现新生成了一个目录 HelloApp ,下面包含了 6 个 java 源文件,分述如下:
HelloPOA POA 指的是 Portable Object Adapter (轻便对象适配器)。这个抽象类是一个基于流的服务器端骨架,提供了服务器端基本的 CORBA 功能。
_HelloSutb 客户端的存根类,为客户端提供了 CORBA 功能。
Hello 这是 java 版的 Hello 接口,它提供了标准的 CORBA 对象功能。
HelloHelper 这是一个辅助类,负责向 CORBA 流中写入或读取对象。
HelloHolder 这是一个 final 类,它持有一个 public 的 Hello 实例变量。它用来操作 CORBA 输入输出流的参数。
HelloOperations 这个类才是我们所预想的那个接口,只包含我们定义的那个方法,不包含 CORBA 的任何东西。
3. 提供一个服务器端的对象,注意这个实现类继承的是 HelloPOA :
package com.corba; import org.omg.CORBA.ORB; import HelloApp.HelloPOA; public class HelloImpl extends HelloPOA{ private ORB orb; public void setOrb(ORB orb) { this.orb = orb; } public String sayHello() { return "/n Hello World!/n"; } public void shutdown() { orb.shutdown(false); } }
4. 服务器端程序:
由于使用 jacorb 作为 CORBA 的实现方案,因此需要下载 JacORB2.3.zip 文件,解压后将其 lib 目录的 slf4j-api-1.5.6.jar 、 slf4j-jdk14-1.5.6.jar 和 jacorb.jar 添加到程序的 classpath 中,服务器端程序代码如下:
package com.corba; import java.util.Properties; import org.omg.CORBA.ORB; import org.omg.PortableServer.IdAssignmentPolicyValue; import org.omg.PortableServer.LifespanPolicyValue; import org.omg.PortableServer.POA; import org.omg.PortableServer.POAHelper; import org.omg.PortableServer.ServantRetentionPolicyValue; public class HelloServer { //持久化的POA private static POA persistentPOA = null; public static void main(String[] args) { //生成一个对象请求代理(ORB),并初始化 Properties props = new Properties(); //使用jacorb的CORBA实现方案 props.put("org.omg.CORBA.ORBClass", "org.jacorb.orb.ORB"); props.put("org.omg.CORBA.ORBSingletonClass", "org.jacorb.orb.ORBSingleton"); //使用持久化IOR,必须指定持久化POA的实现名称,默认是"StandardImplName", //可以随便指定 props.put("jacorb.implname", "StandardImplName"); //这里是指定CORBA服务器端端口为固定端口,是CORBA的IOR固定不变的关键 props.put("OAPort", "12500"); //如果需要指定服务器端的ip地址,则需要使用下面这种方式,默认使用上面的方式//只指定端口即可,ip地址是服务器端程序所在机器的ip,注意这两种只能二选其一 //props.put("OAAddress", "iiop://10.140.1.97:10501"); try{ //创建ORB实例 ORB orb = ORB.init(args, props); //得到一个 RootPOA引用 POA rootPoa = POAHelper.narrow(orb.resolve_initial_references("RootPOA")); //指定创建持久化POA的策略,使用持久化POA必须指定以下三种策略 org.omg.CORBA.Policy[] policies = new org.omg.CORBA.Policy[3]; //POA生命周期是持久化 policies[0] = rootPoa.create_lifespan_policy(LifespanPolicyValue.PERSISTENT); //CORBA对象的标识符是用户指定的 policies[1] = rootPoa.create_id_assignment_policy(IdAssignmentPolicyValue.USER_ID); //每次接到一个请求时,POA期望应用程序提供目标对象标识符作为 //查找伺服程序的索引 policies[2] = rootPoa.create_servant_retention_policy(ServantRetentionPolicyValue.RETAIN); //创建持久化的POA persistentPOA = rootPoa.create_POA("PersistentPOA", rootPoa.the_POAManager(), policies); //清除策略 policies[0].destroy(); policies[1].destroy(); policies[2].destroy(); policies = null; //创建伺服程序并注册到ORB上 HelloImpl helloImpl = new HelloImpl(); helloImpl.setOrb(orb); //创建伺服程序标识符,因为使用IdAssignmentPolicyValue.USER_ID //策略,所有必须要指定伺服程序id byte[] servantId = "MyHelloImpl".getBytes(); //将伺服程序标识符和服务器端CORBA对象关联起来并激活 persistentPOA.activate_object_with_id(servantId, helloImpl); //激活POAManager rootPoa.the_POAManager().activate(); //通过持久化POA获取CORBA对象 org.omg.CORBA.Object ref = persistentPOA.servant_to_reference(helloImpl); //打印CORBA对象的IOR System.out.println("CORBA IOR is:" + orb.object_to_string(ref)); System.out.println("HelloServer ready and waiting..."); //启动线程服务,等待调用 orb.run(); }catch(Exception e){ System.out.println("HelloServer occur error:" + e); e.printStackTrace(System.out); } System.out.println("HelloServer exiting ..."); } }
该小应用其实可以不用要客户端程序,直接运行服务器端程序就可以,运行起来之后记录其输出的 IOR 字符串,然后结束服务端程序,多运行几次,比较生成的 IOR 字符串,你就会发现 IOR 每次生成都是一样的,如果不指定端口和策略,每次生成的 IOR 都是不一样的,因为每次 CORBA 都会使用不同的端口。
5. 客户端程序:
为了使应用看起来更完整,同时为了演示 CORBA 客户端调用服务器端的简单过程,下面是一个简单的客户端程序:
package com.corba; import org.omg.CORBA.ORB; import HelloApp.Hello; import HelloApp.HelloHelper; public class HelloClient { static Hello hello; public static void main(String[] args) { try { // 创建一个ORB实例 ORB orb = ORB.init(args, null); // 直接通过IOR向CORBA获取目标对象,IOR是服务器端生成的(自己实现时,第一次需要//拷贝服务器端生成的IOR),因为是固定不变的IOR,因为这里可以直接硬编码写死 hello = HelloHelper.narrow(orb.string_to_object("IOR:000000000000001749444C3A48656C6C6F4170702F48656C6C6F3A312E30000000000001000000000000005C000102000000000E3139322E3136382E312E3130300030D40000002A5374616E64617264496D706C4E616D652F50657273697374656E74504F412F4D7948656C6C6F496D706C0000000000010000000000000008000000004A414300")); // 调用接口对象的方法 System.out.println("Get hello object from corba server:" + hello); System.out.println(hello.sayHello()); //关闭CORBA服务 hello.shutdown(); } catch (Exception e) { System.out.println("HelloClient occur error:" + e); e.printStackTrace(System.out); } } }
首先启动服务端程序,然后启动客户端程序,客户端程序打印出“ Hello World! ”之后,就会关闭 CORBA 服务,服务端程序随之运行结束,由于实现了固定不变的 IOR ,因此服务器端程序和客户端程序可以不用做任何更改反复正常运行。
注意:在测试持久化的IOR时,不能简单的比较每次生成的IOR字符串是否相同,只要IOR中的Host,Port和Object key相同即可,另外由于IOR除了上述内容外,还会有一些填充字段,所以有可能持久化的IOR字符串每次也不相同,最好的测试方法是不论重启多少次服务,使用同一个IOR能成功调用服务端的伺服程序。