- 写在前面的话
- 引言
- 第 1 章 对象入门
- 第 2 章 一切都是对象
- 第 3 章 控制程序流程
- 第 4 章 初始化和清除
- 第 5 章 隐藏实施过程
- 第 6 章 类再生
- 第 7 章 多形性
- 第 8 章 对象的容纳
- 第 9 章 违例差错控制
- 第 10 章 Java IO 系统
- 第 11 章 运行期类型鉴定
- 第 12 章 传递和返回对象
- 第 十三 章 创建窗口和程序片
- 第 14 章 多线程
- 第 15 章 网络编程
- 第 16 章 设计范式
- 第 17 章 项目
- 附录 A 使用非 JAVA 代码
- 附录 B 对比 C++和 Java
- 附录 C Java 编程规则
- 附录 D 性能
- 附录 E 关于垃圾收集的一些话
- 附录 F 推荐读物
A.6.2 一个例子
这儿显示的代码可能并不详尽,因为不同的 ORB 有不同的方法来访问 CORBA 服务,所以无论什么例子都要取决于具体的厂商(下例使用了 JavaIDL,这是 Sun 公司的一个免费产品。它配套提供了一个简化版本的 ORB、一个命名服务以及一个“IDL→Java”编译器)。除此之外,由于 Java 仍处在发展初期,所以在不同的 Java/CORBA 产品里并不是包含了所有 CORBA 特性。
我们希望实现一个服务器,令其在一些机器上运行,其他机器能向它查询正确的时间。我们也希望实现一个客户,令其请求正确的时间。在这种情况下,我们让两个程序都用 Java 实现。但在实际应用中,往往分别采用不同的语言。
1. 编写 IDL 源码
第一步是为提供的服务编写一个 IDL 描述。这通常是由服务器程序员完成的。随后,程序员就可用任何语言实现服务器,只需那种语言里存在着一个 CORBA IDL 编译器。
IDL 文件已分发给客户端的程序员,并成为两种语言间的桥梁。
下面这个例子展示了时间服务器的 IDL 描述情况:
module RemoteTime { interface ExactTime { string getTime(); }; };
这是对 RemoteTime 命名空间内的 ExactTime 接口的一个声明。该接口由单独一个方法构成,它以字串格式返回当前时间。
2. 创建根干
第二步是编译 IDL,创建 Java 根干代码。我们将利用这些代码实现客户和服务器。与 JavaIDL 产品配套提供的工具是 idltojava:
idltojava -fserver -fclient RemoteTime.idl
其中两个标记告诉 idltojava 同时为根和干生成代码。idltojava 会生成一个 Java 包,它在 IDL 模块、RemoteTime 以及生成的 Java 文件置入 RemoteTime 子目录后命名。_ExactTimeImplBase.java 代表我们用于实现服务器对象的“干”;而_ExactTimeStub.java 将用于客户。在 ExactTime.java 中,用 Java 方式表示了 IDL 接口。此外还包含了用到的其他支持文件,例如用于简化访问命名服务的文件。
3. 实现服务器和客户
大家在下面看到的是服务器端使用的代码。服务器对象是在 ExactTimeServer 类里实现的。RemoteTimeServer 这个应用的作用是:创建一个服务器对象,通过 ORB 为其注册,指定对象引用时采用的名称,然后“安静”地等候客户发出请求。
import RemoteTime.*; import org.omg.CosNaming.*; import org.omg.CosNaming.NamingContextPackage.*; import org.omg.CORBA.*; import java.util.*; import java.text.*; // Server object implementation class ExactTimeServer extends _ExactTimeImplBase{ public String getTime(){ return DateFormat. getTimeInstance(DateFormat.FULL). format(new Date( System.currentTimeMillis())); } } // Remote application implementation public class RemoteTimeServer { public static void main(String args[]) { try { // ORB creation and initialization: ORB orb = ORB.init(args, null); // Create the server object and register it: ExactTimeServer timeServerObjRef = new ExactTimeServer(); orb.connect(timeServerObjRef); // Get the root naming context: org.omg.CORBA.Object objRef = orb.resolve_initial_references( "NameService"); NamingContext ncRef = NamingContextHelper.narrow(objRef); // Assign a string name to the // object reference (binding): NameComponent nc = new NameComponent("ExactTime", ""); NameComponent path[] = {nc}; ncRef.rebind(path, timeServerObjRef); // Wait for client requests: java.lang.Object sync = new java.lang.Object(); synchronized(sync){ sync.wait(); } } catch (Exception e) { System.out.println( "Remote Time server error: " + e); e.printStackTrace(System.out); } } }
正如大家看到的那样,服务器对象的实现是非常简单的;它是一个普通的 Java 类,从 IDL 编译器生成的“干”代码中继承而来。但在与 ORB 以及其他 CORBA 服务进行联系的时候,情况却变得稍微有些复杂。
4. 一些 CORBA 服务
这里要简单介绍一下 JavaIDL 相关代码所做的工作(注意暂时忽略了 CORBA 代码与不同厂商有关这一事实)。main() 的第一行代码用于启动 ORB。而且理所当然,这正是服务器对象需要同它进行沟通的原因。就在 ORB 初始化以后,紧接着就创建了一个服务器对象。实际上,它正式名称应该是“短期服务对象”:从客户那里接收请求,“生存时间”与创建它的进程是相同的。创建好短期服务对象后,就会通过 ORB 对其进行注册。这意味着 ORB 已知道它的存在,可将请求转发给它。
到目前为止,我们拥有的全部东西就是一个 timeServerObjRef——只有在当前服务器进程里才有效的一个对象引用。下一步是为这个服务对象分配一个字串形式的名字。客户会根据那个名字寻找服务对象。我们通过命名服务(Naming Service)完成这一操作。首先,我们需要对命名服务的一个对象引用。通过调用 resolve_initial_references(),可获得对命名服务的字串式对象引用(在 JavaIDL 中是“NameService”),并将这个引用返回。这是对采用 narrow() 方法的一个特定 NamingContext 引用的模型。我们现在可开始使用命名服务了。
为了将服务对象同一个字串形式的对象引用绑定在一起,我们首先创建一个 NameComponent 对象,用“ExactTime”进行初始化。“ExactTime”是我们想用于绑定服务对象的名称字串。随后使用 rebind() 方法,这是受限于对象引用的字串化引用。我们用 rebind() 分配一个引用——即使它已经存在。而假若引用已经存在,那么 bind() 会造成一个异常。在 CORBA 中,名称由一系列 NameContext 构成——这便是我们为什么要用一个数组将名称与对象引用绑定起来的原因。
服务对象最好准备好由客户使用。此时,服务器进程会进入一种等候状态。同样地,由于它是一种“短期服务”,所以生存时间要受服务器进程的限制。JavaIDL 目前尚未提供对“持久对象”(只要创建它们的进程保持运行状态,对象就会一直存在下去)的支持。
现在,我们已对服务器代码的工作有了一定的认识。接下来看看客户代码:
import RemoteTime.*; import org.omg.CosNaming.*; import org.omg.CORBA.*; public class RemoteTimeClient { public static void main(String args[]) { try { // ORB creation and initialization: ORB orb = ORB.init(args, null); // Get the root naming context: org.omg.CORBA.Object objRef = orb.resolve_initial_references( "NameService"); NamingContext ncRef = NamingContextHelper.narrow(objRef); // Get (resolve) the stringified object // reference for the time server: NameComponent nc = new NameComponent("ExactTime", ""); NameComponent path[] = {nc}; ExactTime timeObjRef = ExactTimeHelper.narrow( ncRef.resolve(path)); // Make requests to the server object: String exactTime = timeObjRef.getTime(); System.out.println(exactTime); } catch (Exception e) { System.out.println( "Remote Time server error: " + e); e.printStackTrace(System.out); } } }
前几行所做的工作与它们在服务器进程里是一样的:ORB 获得初始化,并解析出对命名服务的一个引用。
接下来,我们需要用到服务对象的一个对象引用,所以将字串形式的对象引用直接传递给 resolve() 方法,并用 narrow() 方法将结果造型到 ExactTime 接口引用里。最后调用 getTime()。
5. 激活名称服务进程
现在,我们已分别获得了一个服务器和一个客户应用,它们已作好相互间进行沟通的准备。大家知道两者都需要利用命名服务绑定和解析字串形式的对象引用。在运行服务或者客户之前,我们必须启动命名服务进程。在 JavaIDL 中,命名服务属于一个 Java 应用,是随产品配套提供的。但它可能与其他产品有所不同。JavaIDL 命名服务在 JVM 的一个实例里运行,并(默认)监视网络端口 900。
6. 激活服务器与客户
现在,我们已准备好启动服务器和客户应用(之所以按这一顺序,是由于服务器的存在是“短期”的)。若各个方面都设置无误,那么获得的就是在客户控制台窗口内的一行输出文字,提醒我们当前的时间是多少。当然,这一结果本身并没有什么令人兴奋的。但应注意一个问题:即使都处在同一台机器上,客户和服务器应用仍然运行于不同的虚拟机内。它们之间的通信是通过一个基本的集成层进行的——即 ORB 与命名服务的集成。
这只是一个简单的例子,面向非网络环境设计。但通常将 ORB 配置成“与位置无关”。若服务器与客户分别位于不同的机器上,那么 ORB 可用一个名为“安装库”(Implementation Repository)的组件解析出远程字串式引用。尽管“安装库”属于 CORBA 的一部分,但它几乎没有具体的规格,所以各厂商的实现方式是不尽相同的。
正如大家看到的那样,CORBA 还有许多方面的问题未在这儿进行详细讲述。但通过以上的介绍,应已对其有一个基本的认识。若想获得 CORBA 更详细的资料,最传真的起点莫过于 OMB Web 站点,地址是 http://www.omg.org。这个地方提供了丰富的文档资料、白页、程序以及对其他 CORBA 资源和产品的链接。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论