返回介绍

A.6.2 一个例子

发布于 2024-10-15 23:56:38 字数 6085 浏览 0 评论 0 收藏 0

这儿显示的代码可能并不详尽,因为不同的 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文