380 likes | 581 Views
第三章 简单 Corba 程序设计. 1 CORBA 应用开发过程. CORBA 规范并没有限制 ORB 的具体实现方法,所以不同厂商对 ORB 的具体实现方法可能差别很大,这就导致不同厂商提供的 ORB 上操作可能有很大的差异。但基本过程都是类似的。. 1.1 开发环境. Inprise VisiBroker 4.5 + JDK 1.3 + UltraEdit Inprise Visibroker 5 + JDK 1.4 ( + Jbuilder / SunOne Studio EE). 1.2 静态工作方式. 客户方. 对象实现方. IDL 构架(服务方代理).
E N D
1 CORBA应用开发过程 • CORBA规范并没有限制ORB的具体实现方法,所以不同厂商对ORB的具体实现方法可能差别很大,这就导致不同厂商提供的ORB上操作可能有很大的差异。但基本过程都是类似的。
1.1 开发环境 • Inprise VisiBroker 4.5 + JDK 1.3 + UltraEdit • Inprise Visibroker 5 + JDK 1.4 ( + Jbuilder / SunOne Studio EE)
1.2 静态工作方式 客户方 对象实现方 IDL构架(服务方代理) IDL桩 (客户方代理) ORB内核
对象实现 IDL编译器 Java C++ … IDL桩 Java C++ … IDL构架 Java C++ … 设计一个静态方式的程序 IDL文件 客户方调用 服务方主程序
用IDL编写对象规格说明 编译IDL生成桩和框架 编写客户程序代码 编写对象实现和服务程序代码 编译客户程序 编译服务程序 运行客户程序 运行服务程序 启动对象请求代理(ORB)内核 1.4典型的CORBA应用实现过程 一个典型CORBA应用的实现过程
对象接口 • 对象接口实际上是分布式对象向外提供服务的规格说明 • 是客户程序与对象实现之间的一种合约,双方必须严格遵守对象接口定义中的约定,包括操作名字,参数表,返回表,异常表,上下文等 • 对象接口定义存放在一个或多个IDL文本文件中,指明每一对象对外提供的服务,以及客户程序如何使用这些服务或处理服务的返回结果
1.3 IDL语言 • 说明性语言,定义组件接口,不定义实现。 • 语法上可以看成C++的一个子集,规定组件的属性、所继承的父类、产生的异常、事件和各类数据类型。 • 编译器作用:将IDL映射到具体程序设计语言,产生桩代码和框架代码 • 调用请求经客户端桩传递给ORB,然后转发到服务端框架,最后到达真正要执行请求的对象实现实例
编写对象实现和服务程序 • IDL文件只定义了对象的语法规格说明,必须编写这些对象的具体实现代码 • 对象实现可用各种语言实现,且与客户程序的语言无关 • IDL到编程语言的映射规则 • 生成IDL框架代码和各种辅助性的java接口或类 • 编写对象实现代码时必须继承或使用其中的某些接口或类 • 服务程序 • 利用POA激活伺服对象供客户对象使用 • 通常是一个循环执行的进程,不断监听客户程序请求并为之服务
编写客户程序 • 初始化ORB • 是应用程序进入CORBA的起点 • 作用 • 让ORB了解有新的成员加入 • 获取ORB伪对象的引用,以备调用ORB内核提供的操作时使用 • 伪对象(pseudo object):在CORBA基础设施中的一个对象 • 获取分布式对象引用,利用其调用对象实现提供的服务
创建并部署应用程序 • 客户端:客户程序代码与IDL编译器自动生成的IDL桩代码一起编译 • 服务端:对象实现代码与服务程序代码与IDL框架代码一起编译
1.5 例子背景 • 银行账户管理 • 服务端管理大量银行顾客的账户,提供基本的开户、存款、取款、查询余额的功能。
manage 1.5.1 对象认定 • 一个银行帐户的实体模型。 • balance:表示当前的余额。 • deposit:存款 • withdraw:取款 • getBalance:查询余额 • 银行中的储蓄员的实体模型。 • accountList :记录当前已开设的所有帐户。 • open:根据帐户标识查找某一帐户,如果该标识的帐户不存在则创建一个新帐户。
1.5.2 定义对象接口 // 银行帐户管理系统的对象接口定义 module Bank { // 帐户 interface Account { // 存款 void deposit(in float amount); // 取款 boolean withdraw(in float amount); // 查询余额 float getBalance(); }; // 帐户管理员 interface AccountManager { // 查询指定名字的帐户,查无则新开帐户 Account open(in string name); }; }; Bank.idl
1.5.3 生成Stub与Skeleton • IDL编译器作用是将IDL映射到具体程序设计语言,产生桩代码和框架代码 • Visibroker for java提供的编译器idl2java将IDL映射到java语言,生成java语言的桩和框架语言 • 每个对象实例都有一个用于唯一标识自身的对象引用。客户程序利用对象引用指明调用的方向 • 表面上看,客户程序调用的是远程对象实现上的操作,实际被调用的代码是作为其代理的IDL桩
生成Stub与Skeleton • prompt> idl2java Bank.idl Stub Bank.idl Skeleton 输入 idl2java 输出 其它辅助 文件
1.5.4 生成7个文件 • VisiBroker for Java的IDL编译器idl2java为每个接口自动生成7个文件: • AccountOperations.java • Account.java • _AccountStub.java • AccountPOA.java • AccountPOATie.java • AccountHelper.java • AccountHolder.java
1.5.4.1 生成的接口定义 • Account.java和AccountOperations.java定义了IDL接口Account的完整基调。 • AccountOperations.java(操作基调)定义了Account接口中定义的所有常量和方法。 package Bank; public interface AccountOperations//操作接口 { public void deposit(float amount); public boolean withdraw(float amount); public float getBalance(); }
生成的接口定义 • 客户程序代码中,程序员通常使用的是操作接口的派生接口Account(位于Account.java) package Bank; public interface Account extends com.inprise.vbroker.CORBA.Object, Bank.AccountOperations, org.omg.CORBA.portable.IDLEntity {}
1.5.4.2 生成的Stub • _AccountStub.java是Account对象在客户端的桩代码,它实现了Account接口。 • 程序员编写的客户程序代码通常不直接调用这个类中的方法。 • VisiBroker for Java生成了另外的辅助类AccountHelper。
生成的Stub package Bank; public class _AccountStub extends com.inprise.vbroker.CORBA.portable.ObjectImpl implements Account { final public static java.lang.Class _opsClass = Bank.AccountOperations.class; private static java.lang.String[] __ids = {"IDL:Bank/Account:1.0"}; public java.lang.String[] _ids(){ return __ids; } public void deposit(float amount){ //与ORB交互,完成真正的deposit方法调用 } public boolean withdraw(float amount){ //与ORB交互,完成真正的withdraw方法调用 } public float getBalance(){ //与ORB交互,完成真正的getBalance方法调用 } } _AccountStub.java
1.5.4.3 生成的Skeleton • AccountPOA.java是Account对象的服务端框架代码,该类的功能: • 解包in类型的参数并将参数传递给对象实现。 • 打包返回值与所有out类型的参数。 • 打包(marshal):指将特定程序设计语言描述的数据类型转换为CORBA的IIOP流格式。 • 解包(unmarshal):从IIOP流格式转换为依赖于具体程序设计语言的数据结构。 • 编写对象实现的最简单途径是继承这些POA类,即把它们作为对象实现的基类。
生成的Skeleton package Bank; public abstract class AccountPOA extends org.omg.PortableServer.Servant implements org.omg.CORBA.portable.InvokeHandler, Bank.AccountOperations { public static org.omg.CORBA.portable.OutputStream _invoke( ...) { org.omg.CORBA.portable.OutputStream _output = null; { switch (_method_id) { case 0: { float amount; amount = _input.read_float(); _self.deposit(amount); _output = _handler.createReply(); return _output; } case 1: {//... } case 2: {//... } }}}} AccountPOA.java
1.5.4.4 生成的辅助工具类 • IDL编译器为每一个用户自定义类型还生成一个辅助工具类。AccountHelper.java声明了AccountHelper类,该类为Account接口定义了许多实用功能和支持功能的静态方法(又称类方法)。 • 从Any对象提取或向Any对象插入对象(extract和insert方法); • 从输入/输出流读写对象(read和write方法); • 获取对象的库标识和类型码(id和type方法); • 绑定对象与类型转换操作(bind和narrow方法)等等。 • 编程时会用到该类中提供的方法。
生成的辅助工具类 package Bank; public final class AccountHelper { public static Bank.Account narrow (final org.omg.CORBA.Object obj) { //... } public static Bank.Account bind(org.omg.CORBA.ORB orb, java.lang.String name) { //... } //... } AccountHelper.java
1.5.4.5 生成的对象传递支撑类 • AccountHolder.java声明的AccountHolder类为传递对象提供支持。 • IDL有三种参数传递方式:in、out和inout。 • in类型的参数以及返回结果与Java的参数传递方式与结果返回方式完全相同。 • out和inout两种类型的参数允许参数具有返回结果的能力,无法直接映射到Java语言的参数传递机制,这时AccountHolder类为传递out和inout参数提供了一个托架(holder)。
In表明实际参数从客户程序传向对象实现 • Out表明数据从实现对象传递给客户程序,并且对象实现无需从客户程序获取参数的初始值 • Inout表明数据从客户程序传给对象实现,然后经对象实现加工后再返回给客户程序
生成的对象传递支撑类 package Bank; public final class AccountHolder implements org.omg.CORBA.portable.Streamable { public Bank.Account value; public AccountHolder() {} public AccountHolder(final Bank.Account _vis_value){ this.value = _vis_value; } public void _read( final org.omg.CORBA.portable.InputStream input){ value = Bank.AccountHelper.read(input); } public void _write(final org.omg.CORBA.portable.OutputStream output){ Bank.AccountHelper.write(output, value); } public org.omg.CORBA.TypeCode _type() { return Bank.AccountHelper.type(); } } AccountHolder.java
1.5.5 编写对象实现 • 对象实现代码所在的类名字可由程序员自由掌握,只要不与IDL编译器自动产生的Java类产生名字冲突即可。客户程序也无须了解对象实现是由哪一个Java类完成的。 • CORBA应用程序的对象实现最常用、最简单的实现方式是使用继承,即直接继承由IDL编译器生成的xxxPOA类。 • 当对象实现需要利用继承机制达到其他目的时,就必须改用CORBA对象实现的另一种实现方式 ── 纽带机制(tie mechanism)。 • 我们的例子程序采用简单的继承方式编写对象实现。
账户的对象实现 • public class AccountImpl • extends Bank.AccountPOA • { • // 属性定义 • protected float balance; • // 构造方法,按指定余额创建新的帐户 • public AccountImpl(float bal){ • balance = bal; • } • // 往帐户中存款 • public void deposit(float amount){ • balance += amount; • } • // 从帐户中取款,不足余额则返回false • public boolean withdraw(float amount){ • if (balance < amount) return false; • else { • balance -= amount; • return true; • } • } • // 查询帐户余额 • public float getBalance(){ • return balance • } • } AccountImpl.java
账户管理员的对象实现 public class AccountManagerImpl extends Bank.AccountManagerPOA { protected Hashtable accountList; // 该帐户管理员所负责的帐户清单 public AccountManagerImpl(){ accountList = new Hashtable(); } public synchronized Bank.Account open(String name){ Bank.Account account=(Bank.Account)accountList.get(name); if (account == null) { Random random = new Random(); float balance = Math.abs(random.nextInt())%100000/100f; AccountImpl accountServant = new AccountImpl(balance); try { org.omg.CORBA.Object obj = _default_POA().servant_to_reference(accountServant); account = Bank.AccountHelper.narrow(obj); } catch(Exception exc) { exc.printStackTrace(); } accountList.put(name, account); System.out.println("新开帐户:" + name); } return account; } } AccountManagerImpl.java
1.5.6 编写服务程序 • 通常程序员都会编写一个名为Server.java的服务程序,服务程序创建伺服对象供客户端使用。
编写服务程序 初始化ORB 创建一个POA 创建提供服务的伺服对象 激活伺服对象 激活POA管理器 等待客户程序发来请求 服务程序的处理流程
初始化ORB 创建一个POA 创建提供服务的伺服对象 激活伺服对象 激活POA管理器 等待客户程序发来请求 编写服务程序 public class Server { public static void main(String[] args) { try { org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init(args, null); POA rootPOA = POAHelper.narrow( orb.resolve_initial_references("RootPOA")); org.omg.CORBA.Policy[] policies = { rootPOA.create_lifespan_policy( LifespanPolicyValue.PERSISTENT) }; POA myPOA = rootPOA.create_POA("BankPOA", rootPOA.the_POAManager(), policies); AccountManagerImpl managerServant = new AccountManagerImpl(); myPOA.activate_object_with_id( "BankManager".getBytes(), managerServant); rootPOA.the_POAManager().activate(); System.out.println("帐户管理员BankManager已就绪 ...\n"); orb.run(); } catch(Exception exc) { exc.printStackTrace(); } } } 服务程序Server.java
初始化ORB 绑定到服务对象 调用服务对象提供的服务 1.5.7 编写客户程序 客户程序操作流程
初始化ORB 绑定到服务对象 调用服务对象提供的服务 编写客户程序 public class Client { public static void main(String[] args) { org.omg.CORBA.ORB orb=org.omg.CORBA.ORB.init(args, null); // 利用POA全称与对象标识"BankManager"查找帐户管理员 Bank.AccountManager manager = Bank.AccountManagerHelper.bind( orb, "/BankPOA", "BankManager".getBytes()); String name = args.length > 0 ? args[0] : "David Zeng"; // 请求帐户管理员找出一个指定名字的帐户,无此帐户则新开一个 Bank.Account account = manager.open(name); System.out.println(name + “的帐户余额为”+ account.getBalance() + "元"); account.deposit(200); System.out.println(“存款200元后,余额为”+ account.getBalance() + “元”); if (account.withdraw(600)) { System.out.println(“取款600元后,余额为”+ account.getBalance() + "元"); } else { System.out.println("余额不足600元,取款失败,余额保持不变"); } } } 客户程序Client.java
1.5.8 编译应用程序 • 利用VisiBroker for Java提供的编译器vbjc完成这一工作: • prompt> vbjc Server.java • prompt> vbjc Client.java • vbjc实际上封装了JDK提供的Java编译器。 • Holder类和POATie类需要指定额外的参数才会生成。
1.5.9 运行应用程序 • 按一定的顺序启动应用程序 • 1. 启动智能代理 • 运行CORBA应用程序之前,网络中必须至少有一台主机上启动了智能代理osagent。这是VisiBroker特有的分布式位置服务(location service)守护进程,网络中多个智能代理可协作以查找合适的对象实现。 • prompt> osagent • 2.启动服务程序 • prompt> start vbj Server • 3.启动客户程序 • prompt> vbj Client