Download presentation
Presentation is loading. Please wait.
1
第三章 简单Corba程序设计
2
1 CORBA应用开发过程 CORBA规范并没有限制ORB的具体实现方法,所以不同厂商对ORB的具体实现方法可能差别很大,这就导致不同厂商提供的ORB上操作可能有很大的差异。但基本过程都是类似的。
3
1.1 开发环境 Inprise VisiBroker 4.5 + JDK 1.3 + UltraEdit
Inprise Visibroker 5 + JDK 1.4 ( + Jbuilder / SunOne Studio EE)
4
1.2 静态工作方式 客户方 对象实现方 IDL构架(服务方代理) IDL桩 (客户方代理) ORB内核
5
设计一个静态方式的程序 IDL文件 客户方调用 对象实现 IDL编译器 Java C++ … IDL桩 Java C++ … IDL构架
服务方主程序
6
1.4典型的CORBA应用实现过程 一个典型CORBA应用的实现过程 用IDL编写对象规格说明 编译IDL生成桩和框架 编写客户程序代码
编写对象实现和服务程序代码 编译客户程序 编译服务程序 运行客户程序 运行服务程序 启动对象请求代理(ORB)内核 一个典型CORBA应用的实现过程
7
对象接口 对象接口实际上是分布式对象向外提供服务的规格说明
是客户程序与对象实现之间的一种合约,双方必须严格遵守对象接口定义中的约定,包括操作名字,参数表,返回表,异常表,上下文等 对象接口定义存放在一个或多个IDL文本文件中,指明每一对象对外提供的服务,以及客户程序如何使用这些服务或处理服务的返回结果
8
1.3 IDL语言 说明性语言,定义组件接口,不定义实现。
语法上可以看成C++的一个子集,规定组件的属性、所继承的父类、产生的异常、事件和各类数据类型。 编译器作用:将IDL映射到具体程序设计语言,产生桩代码和框架代码 调用请求经客户端桩传递给ORB,然后转发到服务端框架,最后到达真正要执行请求的对象实现实例
9
编写对象实现和服务程序 IDL文件只定义了对象的语法规格说明,必须编写这些对象的具体实现代码
对象实现可用各种语言实现,且与客户程序的语言无关 IDL到编程语言的映射规则 生成IDL框架代码和各种辅助性的java接口或类 编写对象实现代码时必须继承或使用其中的某些接口或类 服务程序 利用POA激活伺服对象供客户对象使用 通常是一个循环执行的进程,不断监听客户程序请求并为之服务
10
编写客户程序 初始化ORB 获取分布式对象引用,利用其调用对象实现提供的服务 是应用程序进入CORBA的起点 作用
获取ORB伪对象的引用,以备调用ORB内核提供的操作时使用 伪对象(pseudo object):在CORBA基础设施中的一个对象 获取分布式对象引用,利用其调用对象实现提供的服务
11
创建并部署应用程序 客户端:客户程序代码与IDL编译器自动生成的IDL桩代码一起编译
12
1.5 例子背景 银行账户管理 服务端管理大量银行顾客的账户,提供基本的开户、存款、取款、查询余额的功能。
13
1.5.1 对象认定 manage 银行中的储蓄员的实体模型。 accountList :记录当前已开设的所有帐户。
一个银行帐户的实体模型。 balance:表示当前的余额。 deposit:存款 withdraw:取款 getBalance:查询余额 manage 银行中的储蓄员的实体模型。 accountList :记录当前已开设的所有帐户。 open:根据帐户标识查找某一帐户,如果该标识的帐户不存在则创建一个新帐户。
14
1.5.2 定义对象接口 Bank.idl // 银行帐户管理系统的对象接口定义 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
15
1.5.3 生成Stub与Skeleton IDL编译器作用是将IDL映射到具体程序设计语言,产生桩代码和框架代码
Visibroker for java提供的编译器idl2java将IDL映射到java语言,生成java语言的桩和框架语言 每个对象实例都有一个用于唯一标识自身的对象引用。客户程序利用对象引用指明调用的方向 表面上看,客户程序调用的是远程对象实现上的操作,实际被调用的代码是作为其代理的IDL桩
16
生成Stub与Skeleton prompt> idl2java Bank.idl Stub Bank.idl 输入 Skeleton
输出 其它辅助 文件
17
1.5.4 生成7个文件 VisiBroker for Java的IDL编译器idl2java为每个接口自动生成7个文件:
AccountOperations.java Account.java _AccountStub.java AccountPOA.java AccountPOATie.java AccountHelper.java AccountHolder.java
18
生成的接口定义 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(); }
19
生成的接口定义 客户程序代码中,程序员通常使用的是操作接口的派生接口Account(位于Account.java)
package Bank; public interface Account extends com.inprise.vbroker.CORBA.Object, Bank.AccountOperations, org.omg.CORBA.portable.IDLEntity {}
20
1.5.4.2 生成的Stub _AccountStub.java是Account对象在客户端的桩代码,它实现了Account接口。
程序员编写的客户程序代码通常不直接调用这个类中的方法。 VisiBroker for Java生成了另外的辅助类AccountHelper。
21
生成的Stub _AccountStub.java package Bank; public class _AccountStub
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
22
1.5.4.3 生成的Skeleton AccountPOA.java是Account对象的服务端框架代码,该类的功能:
解包in类型的参数并将参数传递给对象实现。 打包返回值与所有out类型的参数。 打包(marshal):指将特定程序设计语言描述的数据类型转换为CORBA的IIOP流格式。 解包(unmarshal):从IIOP流格式转换为依赖于具体程序设计语言的数据结构。 编写对象实现的最简单途径是继承这些POA类,即把它们作为对象实现的基类。
23
生成的Skeleton AccountPOA.java 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
24
生成的辅助工具类 IDL编译器为每一个用户自定义类型还生成一个辅助工具类。AccountHelper.java声明了AccountHelper类,该类为Account接口定义了许多实用功能和支持功能的静态方法(又称类方法)。 从Any对象提取或向Any对象插入对象(extract和insert方法); 从输入/输出流读写对象(read和write方法); 获取对象的库标识和类型码(id和type方法); 绑定对象与类型转换操作(bind和narrow方法)等等。 编程时会用到该类中提供的方法。
25
生成的辅助工具类 AccountHelper.java 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
26
1.5.4.5 生成的对象传递支撑类 AccountHolder.java声明的AccountHolder类为传递对象提供支持。
IDL有三种参数传递方式:in、out和inout。 in类型的参数以及返回结果与Java的参数传递方式与结果返回方式完全相同。 out和inout两种类型的参数允许参数具有返回结果的能力,无法直接映射到Java语言的参数传递机制,这时AccountHolder类为传递out和inout参数提供了一个托架(holder)。
27
In表明实际参数从客户程序传向对象实现 Out表明数据从实现对象传递给客户程序,并且对象实现无需从客户程序获取参数的初始值 Inout表明数据从客户程序传给对象实现,然后经对象实现加工后再返回给客户程序
28
生成的对象传递支撑类 AccountHolder.java 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
29
1.5.5 编写对象实现 对象实现代码所在的类名字可由程序员自由掌握,只要不与IDL编译器自动产生的Java类产生名字冲突即可。客户程序也无须了解对象实现是由哪一个Java类完成的。 CORBA应用程序的对象实现最常用、最简单的实现方式是使用继承,即直接继承由IDL编译器生成的xxxPOA类。 当对象实现需要利用继承机制达到其他目的时,就必须改用CORBA对象实现的另一种实现方式 ── 纽带机制(tie mechanism)。 我们的例子程序采用简单的继承方式编写对象实现。
30
账户的对象实现 AccountImpl.java 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
31
账户管理员的对象实现 AccountManagerImpl.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
32
1.5.6 编写服务程序 通常程序员都会编写一个名为Server.java的服务程序,服务程序创建伺服对象供客户端使用。
33
编写服务程序 初始化ORB 创建一个POA 创建提供服务的伺服对象 激活伺服对象 激活POA管理器 等待客户程序发来请求 服务程序的处理流程
34
编写服务程序 服务程序Server.java 初始化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(); } 初始化ORB 创建一个POA 创建提供服务的伺服对象 激活伺服对象 激活POA管理器 等待客户程序发来请求 服务程序Server.java
35
1.5.7 编写客户程序 初始化ORB 绑定到服务对象 调用服务对象提供的服务 客户程序操作流程
36
编写客户程序 客户程序Client.java 初始化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元后,余额为” + } else { System.out.println("余额不足600元,取款失败,余额保持不变"); } 初始化ORB 绑定到服务对象 调用服务对象提供的服务 客户程序Client.java
37
1.5.8 编译应用程序 利用VisiBroker for Java提供的编译器vbjc完成这一工作:
prompt> vbjc Server.java prompt> vbjc Client.java vbjc实际上封装了JDK提供的Java编译器。 Holder类和POATie类需要指定额外的参数才会生成。
38
1.5.9 运行应用程序 按一定的顺序启动应用程序 1. 启动智能代理 2.启动服务程序 3.启动客户程序
运行CORBA应用程序之前,网络中必须至少有一台主机上启动了智能代理osagent。这是VisiBroker特有的分布式位置服务(location service)守护进程,网络中多个智能代理可协作以查找合适的对象实现。 prompt> osagent 2.启动服务程序 prompt> start vbj Server 3.启动客户程序 prompt> vbj Client
Similar presentations