第五章 编写服务端程序
Agenda 可移植对象适配器 设计POA策略 使用POA 伺服对象管理器 适配器激活器 纽带机制 POA与BOA
5.1 可移植对象适配器 CORBA对象与伺服对象 对象适配器 可移植对象适配器 POA及其组件的IDL定义
5.1.1 CORBA对象与伺服对象 CORBA对象与具体的伺服对象是两个不同抽象层次的概念: 它们之间的彻底分离使得CORBA独立于任何特定程序设计语言,并为服务端程序的可移植性打下基础。对象适配器(object adapter)是一个重要的ORB组件,它负责将抽象的CORBA对象映射到具体的伺服对象。 CORBA对象可看作是一个具有对象标识、对象接口及对象实现的抽象实体。 抽象:没有硬性规定CORBA对象的实现机制,独立于程序设计语言和特定ORB产品 可互操作的对象引用(Interoperable Object Reference) :一个CORBA对象的引用。从客户程序的角度看,IOR中包含了对象的标识、接口类型及其他信息以查找对象实现。
CORBA对象与伺服对象 伺服对象(servant)是指具体程序设计语言的对象或实体,通常存在于一个服务程序进程之中。 客户程序通过对象引用发出的请求经过ORB担当中介角色,转换为对特定的伺服对象的调用。在一个CORBA对象的生命期中,它可能与多个伺服对象相关联,因而对该对象的请求可能被发送到不同的伺服对象。 对象标识(Object ID)是一个用于在POA中标识一个CORBA对象的字符串。 它既可由程序员指派,也可由对象适配器自动分配,这两种方式都要求对象标识在创建它的对象适配器中必须具有唯一性。
CORBA对象与伺服对象 伺服对象通过对象标识关联到CORBA对象。 建立一个伺服对象与一个CORBA对象之间关联的过程称为“激活”(activate)或“体现”(incarnate),反之,撤销这种关联的过程称为“冻结”(deactivate)或“净化”(etherealize)。 经过激活或体现后,CORBA对象、伺服对象以及对象标识均可称为活动的(active),否则称它们为非活动的(inactive)。 持久对象(persistent object)可在创建它的服务程序进程之外存在,瞬时对象(transient object)只能在创建它的服务程序进程中存在。它们都是指一个CORBA对象。
Corba对象 伺服对象 ID
5.1.3 对象适配器 服务程序: 利用对象实现创建伺服对象实例, 将服务端本地的对象实例转换为可供远程调用的CORBA对象
对象适配器 作用:管理服务器端伺服对象,对象标识,CORBA对象以及它们之间关联的主要工具 决定在收到一个客户请求时应调用哪一个伺服对象,然后调用该伺服对象上的合适操作 创建CORBA对象引用,将其与伺服对象关联 POA的可移植性指建立在POA基础上的服务端程序不依赖于特定的ORB产品,从而在不同ORB产品之间是可移植的
可移植对象适配器 POA是对象实现与ORB其他组件之间的中介,它将客户请求传送到伺服对象,按需创建子POA,提供管理伺服对象的策略。 对CORBA对象发出的所有调用请求都必须经过POA,即使目标对象是本地的(即伺服对象与客户程序处于同一地址空间),这样POA能够统一地应用POA策略 ORB内核 对象适配器 对象实现
POA 体系结构 客户请求处理过程 层次 管理器 活动对象映射表 伺服对象管理器
1 POA体系结构 POA体系结构 服务程序 伺服对象管理器 客户请求 伺服对象1 活动对象映射表 伺服对象2 对象标识1 对象标识2 伺服对象3 POA 根POA 注册的伺服对象管理器 活动对象映射表 对象标识1 对象标识2 对象标识3 管 理 器 POA体系结构
2客户请求的传递过程 客户程序发出的请求中包含:创建对象引用的POA名字、对象标识及目标机器与端口等信息。 如果目标POA不存在,ORB还允许调用适配器激活器创建所需的POA。 服务程序 伺服对象管理器 伺服对象1 客户请求 伺服对象2 伺服对象3 POA 根POA 注册的伺服对象管理器 活动对象映射表 对象标识1 对象标识2 对象标识3 管 理 器
POA管理器利用对象关键码将请求传送给正确的POA 一旦请求被ORB传送到正确的机器与端口,监听该端口的POA管理器负责检查对象关键码(object key),对象关键码中含有POA名字与对象标识; POA管理器利用对象关键码将请求传送给正确的POA 服务程序 伺服对象管理器 伺服对象1 客户请求 伺服对象2 伺服对象3 POA 根POA 注册的伺服对象管理器 活动对象映射表 对象标识1 对象标识2 对象标识3 管 理 器
根据POA的策略集直接或间接地利用对象标识将请求传送到正确的伺服对象。 服务程序 伺服对象管理器 伺服对象1 客户请求 伺服对象2 伺服对象3 POA 根POA 注册的伺服对象管理器 活动对象映射表 对象标识1 对象标识2 对象标识3 管 理 器
2. ORB根据其中的目标机器和端口信息将请求发送到指定端口 客户请求的传递 对象定位信息 请求内容 客户程序 ORB 1. 客户程序向ORB发出请求 目标机器、端口 对象定位信息 目标机器、端口 对象关键码 请求内容 ORB POA管理器 POA管理器正在 监听的端口号 2. ORB根据其中的目标机器和端口信息将请求发送到指定端口
3. POA管理器根据请求中的POA名字将请求发送到特定的POA 4. POA根据对象标识将请求传到正确的伺服对象 客户请求的传递 name1 POA ... name2 POA 对象关键码 POA名字 POA名字 对象标识 请求内容 POA管理器 3. POA管理器根据请求中的POA名字将请求发送到特定的POA POA管理器管理 多个POA 伺服对象1 name2 POA 活动对象映射表 对象标识1 对象标识2 对象标识3 对象标识 请求内容 伺服对象2 伺服对象3 4. POA根据对象标识将请求传到正确的伺服对象
3 POA层次 一个服务程序进程中可使用多个POA,不同POA以名字区分。这些POA的集合呈现一种层次结构,即每个POA都有一个父POA,所有POA都是根POA的后代。每个ORB在创建时都自动带有一个根POA,可根据需要从根POA创建其他子POA。 POA层次为服务程序中的对象标识提供了一个层次化的名字空间。通常每个伺服对象最多仅与一个POA相关联,POA“拥有”这些对象并负责删除这些对象,当POA被删除时其中的所有对象以及子POA也将被删除。 服务程序 伺服对象管理器 伺服对象1 客户请求 伺服对象2 伺服对象3 POA 根POA 注册的伺服对象管理器 活动对象映射表 对象标识1 对象标识2 对象标识3 管 理 器
4 POA管理器 POA管理器(POA Manager)是一个对象,它将一个或多个POA组织在一起,为其中的POA提供共同的操作,POA管理器的状态代表了它所管理的所有POA的状态。 例如开发人员可通过POA管理器提供的操作决定是否接收或丢弃POA的请求,也可利用POA管理器终止POA。 服务程序 伺服对象管理器 伺服对象1 客户请求 伺服对象2 伺服对象3 POA 根POA 注册的伺服对象管理器 活动对象映射表 对象标识1 对象标识2 对象标识3 管 理 器
5 对象映射表 每一个POA中都有一个活动对象映射表(Active Object Map),表中保存了活动对象的对象标识及与之关联的伺服对象,其作用是将活动对象通过对象标识映射到伺服对象。在一个特定的POA中,对象标识唯一地标识了一个CORBA对象。 为将伺服对象转换为一个可供远程调用的CORBA对象,必须建立CORBA对象与伺服对象之间的关联。此外,POA还允许单个伺服对象(即缺省伺服对象)同时与多个CORBA对象相关联,这种特性对开发大规模应用意义重大。 服务程序 伺服对象管理器 伺服对象1 客户请求 伺服对象2 伺服对象3 POA 根POA 注册的伺服对象管理器 活动对象映射表 对象标识1 对象标识2 对象标识3 管 理 器
6 伺服对象管理器 伺服对象管理器(servant manager)是程序员自己提供的代码,用于取代POA活动对象映射表的功能。如果应用程序需要以一种更复杂的方案将对象标识映射到伺服对象,这时开发人员可设计专用的伺服对象管理器。伺服对象管理器负责决定一个CORBA对象是否存在,然后查找伺服对象并将伺服对象指派给CORBA对象。 为满足不同的应用需要,开发人员可设计多个伺服对象管理器。有两类伺服对象管理器可供选择:伺服对象激活器和伺服对象定位器,开发人员可利用POA策略决定选用哪一种类型。 服务程序 伺服对象管理器 伺服对象1 客户请求 伺服对象2 伺服对象3 POA 根POA 注册的伺服对象管理器 活动对象映射表 对象标识1 对象标识2 对象标识3 管 理 器
2.1.5 POA接口 POA接口 // POA接口 interface POA { // POA属性 readonly attribute string the_name; readonly attribute POA the_parent; readonly attribute POAList the_children; readonly attribute POAManager the_POAManager; attribute AdapterActivator the_activator; // 异常定义 exception AdapterAlreadyExists {}; exception AdapterNonExistent {}; exception InvalidPolicy { unsigned short index; }; exception NoServant {}; exception ObjectAlreadyActive {}; exception ObjectNotActive {}; exception ServantAlreadyActive {}; exception ServantNotActive {}; exception WrongAdapter {}; exception WrongPolicy {}; POA接口
POA接口 POA接口 // 创建与撤销POA POA create_POA(in string adapter_name, in POAManager a_POAManager, in CORBA::PolicyList policies) raises(AdapterAlreadyExists, InvalidPolicy); POA find_POA(in string adapter_name, in boolean activate_it) raises(AdapterNonExistent); void destroy(in boolean etherealize_objects, in boolean wait_for_completion); // 用于创建策略对象的factory操作 ThreadPolicy create_thread_policy(in ThreadPolicyValue value); LifespanPolicy create_lifespan_policy( in LifespanPolicyValue value); //... POA接口
POA接口 POA接口 // 伺服对象管理器的注册 ServantManager get_servant_manager() raises(WrongPolicy); void set_servant_manager(in ServantManager imgr) // 为USE_DEFAULT_SERVANT策略提供的操作 Servant get_servant() raises(NoServant, WrongPolicy); void set_servant(in Servant p_servant) // 对象激活与冻结 ObjectId activate_object(in Servant p_servant) raises(ServantAlreadyActive, WrongPolicy); void activate_object_with_id(in ObjectId id, in Servant p_servant) raises(ServantAlreadyActive, ObjectAlreadyActive, WrongPolicy); void deactivate_object(in ObjectId oid) raises(ObjectNotActive, WrongPolicy); POA接口
POA接口 POA接口 // 创建CORBA对象引用的操作 Object create_reference(in CORBA::RepositoryId intf) raises(WrongPolicy); Object create_reference_with_id(in ObjectId oid, in CORBA::RepositoryId intf) // 对象标识映射操作 ObjectId servant_to_id(in Servant p_servant) raises(ServantNotActive, WrongPolicy); Object servant_to_reference(in Servant p_servant) Servant reference_to_servant(in Object reference) raises(ObjectNotActive, WrongAdapter, WrongPolicy); ObjectId reference_to_id(in Object reference) raises(WrongAdapter, WrongPolicy); Servant id_to_servant(in ObjectId oid) raises(ObjectNotActive, WrongPolicy); Object id_to_reference(in ObjectId oid) }; POA接口
5.2 设计POA策略 定义 选择 组合 请求的处理过程
5.1.1 什么是POA策略? POA策略是一个对象,负责控制相关POA的行为并影响POA所管理的对象,使用POA前应仔细考虑应用程序所需的策略集。 POA策略用于定制POA的行为,可为不同的应用程序设计目标而配置不同的POA。 服务器管理对象的重要任务:根据需求设计合适的POA策略 目前CORBA规范定义了7种标准的POA策略,不同的ORB产品从可伸缩性或可靠性等因素考虑引入一些新的POA策略。
5.2.2 选用POA策略 选用POA策略时应注意某些策略值之间存在依赖关系(选用了一种,隐含的选用另一种)。 线程策略 ORB_CTRL_MODEL(缺省值):表示由ORB负责将对POA的请求指派到线程。在多线程环境中,并发请求可以用多线程传送。 SINGLE_THREAD_MODEL:这时只有一个线程,POA顺序地处理请求。
选用POA策略 生命期策略 该策略指定POA中对象实现的使用期限,它可有以下值: TRANSIENT(缺省值):由POA创建的对象引用是瞬时的,这些对象在创建它的POA之外不可存在。一旦POA被冻结为非活动状态,调用该POA创建的任何对象引用将引发OBJECT_NOT_EXIST异常。对话型对象通常设计为瞬时对象。 PERSISTENT:由POA创建的持久对象可在创建它的POA之外存在,因而使用这一策略通常还会同时采用USER_ID策略。对持久对象的请求可能导致隐式地激活一个进程、一个POA以及实现该对象的伺服对象,这意味着POA应注册伺服对象定位器或激活器。实体型对象通常设计为持久对象。
选用POA策略 对象标识唯一性策略 该策略允许多个抽象对象共享一个伺服对象,它可取下列值: UNIQUE_ID(缺省值):被激活的伺服对象仅支持一个对象标识,POA不允许一个伺服对象与多个CORBA对象相关联。 MULTIPLE_ID:被激活的伺服对象可以有一个或多个对象标识,在运行时刻调用伺服对象的操作时必须由操作内部决定对象标识。 应指出的是,对象标识在特定的POA中总是唯一的,对象标识唯一性策略指的是对象标识与伺服对象之间关联的唯一性或多重性。
选用POA策略 对象标识指派策略 该策略指定对象标识是由程序员编写的服务程序生成还是由POA自动生成,它可取以下值: USER_ID:由应用程序为POA的对象引用指定对象标识。 SYSTEM_ID(缺省值):由POA为它的对象引用分配对象标识。如果同时还采用了PERSISTENT策略,则在同一POA的所有实例中对象标识必须是唯一的。 典型情况将是USER_ID策略用于持久对象,将SYSTEM_ID策略用于瞬时对象。如果想将SYSTEM_ID策略用于持久对象,可从伺服对象或对象引用中提取对象标识。
选用POA策略 伺服对象保持策略 该策略指定POA是否将活动伺服对象保存在活动对象映射表中,它有两种取值: RETAIN(缺省值):POA利用活动对象映射表跟踪对象的激活情况,通常与伺服对象激活器或POA显式激活方式结合使用。 NON_RETAIN:POA不在活动对象映射表中保存活动的伺服对象,通常结合伺服对象定位器一起使用。 该策略决定POA是否利用活动对象映射表跟踪对象标识与伺服对象之间的关联。如果选择NON_RETAIN策略则意味着不使用活动对象映射表,因而使用该策略的应用程序必须提供一个伺服对象定位器类型的伺服对象管理器。
选用POA策略 请求处理策略 该策略指定POA如何处理请求,它有三种取值: USE_ACTIVE_OBJECT_MAP_ONLY(缺省值):POA仅依赖于活动对象映射表决定哪些对象标识可用及对象标识关联到哪些伺服对象。如果在活动对象映射表中找不到对象标识,则引发OBJECT_NOT_EXIST异常。该值必须结合RETAIN策略使用。 USE_DEFAULT_SERVANT:如果POA在活动对象映射表中找不到对象标识,或已设置NON_RETAIN策略,则将请求分派给一个缺省伺服对象。缺省伺服对象必须先注册,如果未注册则引发OBJ_ADAPTER异常。该值必须结合MULTIPLE_ID策略使用。 USE_SERVANT_MANAGER:如果POA在活动对象映射表中找不到对象标识,或已设置了NON_RETAIN策略,则POA使用一个伺服对象管理器激活或定位伺服对象。
选用POA策略 隐式激活策略 该策略指定POA是否支持伺服对象的隐式激活,它可取以下值: IMPLICIT_ACTIVATION:POA支持隐式激活,服务程序可调用servant_to_reference操作或servant_to_id操作将伺服对象添加到活动对象映射表并转换为对象引用,也可调用伺服对象的_this方法激活伺服对象。该值要求同时使用SYSTEM_ID和RETAIN策略。 NO_IMPLICIT_ACTIVATION(缺省值):POA不支持伺服对象的隐式激活,只有通过显式的调用才可将伺服对象与一个对象标识相关联。
5.2.3 组合使用POA策略 策略值之间存在依赖关系 不同请求处理策略与伺服对象保持策略组合,可定制不同的POA行为 见P117
5.2.4 请求的处理过程 POA接收请求后,对请求的进一步处理过程取决于POA所采用的策略以及被调用对象当前的激活状态 RETAIN NON_TETAIN或RETAIN但在活动对象映射表中找不到关联对象 详见P117
5.3 使用POA 调用ORB伪对象的resolve_initial_references()操作获取根POA的对象引用 利用根POA提供的操作定义应用程序所需的POA策略集 用自定义POA策略集在根POA下创建一个子POA甚至一个完整的POA层次 创建或激活对象引用 激活POA管理器,通常整个服务程序只需使用一个POA管理器
使用POA 服务程序Server.java 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的引用 调用ORB伪对象的resolve_initial_references 操作获取根POA的引用 调用根POA的操作 定义应用程序所需的POA策略 用自定义策略在根POA下创建一个子POA- myPOA, 甚至创建一个完整的POA层次; 创建并激活伺服对象 激活POA管理器,等待处理客户程序的请求 服务程序Server.java
5.3.0 初始化ORB 作用:获取ORB伪对象的引用,以备调用ORB内核提供的操作时使用
5.3.1 获取根POA的对象引用 所有CORBA服务程序必须获取根POA的对象引用 根POA即可直接管理对象,也可创建不同策略集的子POA //解析”RootPOA”为一个通用对象 Org.omg.CORBA.Object obj = orb.resolve_initial_references(“RootPOA”); //将通用对象类型窄化为POA类型 POA rootPOA = POAHelper.narrow(obj);
5.3.2 创建自定义策略的POA 创建一个新的子POA的主要目的是为了获取不同的POA行为,例如使用持久对象或使用伺服对象管理器等 注:POA层次结构并不意味着POA策略也具有相应的层次结构,子POA并不继承其父POA的任何策略 利用create_POA()方法可以创建一个新的POA作为该POA的子POA, 可以根据实际需要以这种方式创建多个子POA,从而形成一个POA层次 org.omg.CORBA.Policy[] policies = { rootPOA.create_lifespan_policy(LifesPERSISTENT)}; POA myPOA = rootPOA.create_POA(“ABC”,rootPOA.the_POAManager(),policies);
服务程序创建子POA只需提供子POA的名字,客户程序必须使用完整的POA名字指定一个子POA 一个完整的POA名字记录了该子POA名字在内的整个层次路径,层次之间用”/”分割,如“/A/B/C”,”/”表示根POA
5.3.3 使用POA管理器 创建一个新的POA时,必须为其指定一个POA管理器 控制新POA的状态
POA管理器的状态以及引起状态转换的操作如下面状态转换图所示。 持有状态 create_POA 非活动状态 丢弃状态 活动状态 activate hold_requests deactivate destroy discard_requests
使用POA管理器 持有状态 create_POA 非活动状态 丢弃状态 活动状态 activate hold_requests deactivate destroy discard_requests 持有状态 POA管理器被创建后即处于持有状态,在该状态下所有接入的请求被引导到一个队列中等候处理,POA并没有对请求作任何处理。 为分派这些请求,必须将POA管理器转换为活动状态,即利用POA管理器的activate操作激活该POA管理器。例如代码rootPOA.the_POAManager().activate(); 将根POA的POA管理器激活为活动状态。
使用POA管理器 持有状态 create_POA 非活动状态 丢弃状态 活动状态 activate hold_requests deactivate destroy discard_requests 活动状态 当POA管理器处于活动状态时,由它控制的所有POA将接收并开始处理请求。调用POA管理器的activate操作可将POA管理器从持有或丢弃状态改为活动状态。 void activate()raises(AdapterInactive);
使用POA管理器 持有状态 create_POA 非活动状态 丢弃状态 活动状态 activate hold_requests deactivate destroy discard_requests 丢弃状态 当POA管理器处于丢弃状态时,由它控制的所有POA丢弃任何未开始处理的请求,此外不会调用注册到这些POA的任何适配器激活器。 引入丢弃状态为服务程序提供了一种流量控制手段,例如为避免服务程序被突如其来的大量请求淹没,可利用该状态拒绝接入请求,这时ORB会返回TRANSIENT异常通知客户程序它们的请求已被丢弃,由客户程序决定是否重新发送请求。
使用POA管理器 非活动状态 当POA管理器处于此状态时,由它控制的所有POA拒绝接入请求。 持有状态 create_POA 非活动状态 丢弃状态 活动状态 activate hold_requests deactivate destroy discard_requests 非活动状态 当POA管理器处于此状态时,由它控制的所有POA拒绝接入请求。 与丢弃状态不同,仅当POA管理器要关闭时才使用该状态,因为处于该状态的POA管理器不能再转换到任何其他状态,否则会引发AdapterInactive异常。
5.3.4 激活与冻结对象 对象引用:是客户程序操纵CORBA对象的句柄,服务端程序必须向客户端程序输出对象引用才可为客户程序提供进一步的信息或服务 激活:对象引用通过对象标识与伺服对象建立关联 如果POA采用RETAIN策略,可有三种激活方式:显示激活,隐式激活,按需激活;若采用NON_RETAIN策略,对象只能按需激活
显式激活 调用POA的activate_object_with_id()或activate_obj()显式地建立伺服对象与一个对象标识的关联 myPOA.active_object_with_id(“BankManager”.getBytes(),managerServant) activate_obj():提供一个伺服对象,由系统自动指派一个对象标识,然后将两者关联登记在活动对象映射表中,最后返回系统分配的对象标识符
隐式激活 调用POA的servant_to_reference(), servant_to_id()操作或调用伺服对象的_this()操作隐式地激活对象 对象激活是上述操作的一个副操作,是“隐式”的 Servant_to_reference():将一个伺服对象转换为一个对象引用 同时采用的策略:IMPLICIT_ACTIVATION, SYSTEM_ID,RETAIN
按需激活对象 客户发送请求才激活对象引用(对象引用不依赖于任何伺服对象存在) Create_reference Create_reference_with_id 通过POA调用伺服对象管理器提供的方法激活一个对象 调用POA的set_servant_manager()设置伺服对象管理器 POA收到客户程序的调用请求且该对象引用不是活动的,则以对象标识为参数,调用已注册的伺服对象管理器的incarnate或preinvoke方法
冻结对象 从活动对象映射表中删除对象标识与伺服对象之间的关联 不意味着该对象被永久撤销,以后还可重新激活
为什么要有伺服对象管理器,直接通过活动对象映射表就可以了?
5.4 伺服对象管理器 是程序员自己编写的代码,主要作用是查找并返回一个伺服对象 并不是所有CORBA应用程序都需要使用伺服对象管理器 有两类伺服对象管理器:伺服对象激活器和伺服对象定位器。 要使用伺服对象管理器,必须为POA设置USE_SERVANT_MANAGER策略,并结合伺服对象保持策略决定使用哪一种类型的伺服对象管理器。 采用RETAIN表示使用伺服对象激活器,常用于激活持久对象;采用NON_RETAIN表示使用伺服对象定位器,常用于查找瞬时对象。
5.4.1 伺服对象激活器 由ServantActivator类型的伺服对象管理器激活的对象被记录在活动对象映射表中。
调用伺服对象激活器的incarnate操作 POA首先查找活动对象映射表 找到对象标识 N Y 以对象标识与POA作为参数 调用伺服对象激活器的incarnate操作 查找并返回一个合适的伺服对象 将该伺服对象登记 到活动对象映射表中 调用伺服对象的合适操作 并将结果返回给客户程序 实际应用需要 决定是将伺服对象继续保留在活动对象映射表中 还是冻结该伺服对象
伺服对象激活器 实现伺服对象激活器 活动对象映射表中找不到对象标识,调用incarnate,根据不同的对象标识创建不同类型的伺服对象 // 一个伺服对象激活器类型的伺服对象管理器 import org.omg.PortableServer.*; public class AccountManagerActivator extends ServantActivatorPOA { public Servant incarnate(byte[] oid, POA adapter) throws ForwardRequest { Servant servant; System.out.println("incarnate with ID="+new String(oid)); if ((new String(oid)).equalsIgnoreCase("Zhang3")) servant = (Servant) new AccountManagerImpl_1(); else servant = (Servant) new AccountManagerImpl_2(); new DeactivateThread(oid, adapter).start(); return servant; } public void etherealize(byte[] oid, POA adapter, Servant serv, boolean cleanup_in_progress, boolean remaining_activations){ System.out.println("etherealize with ID="+new String(oid)); System.gc(); 实现伺服对象激活器
伺服对象激活器 实现伺服对象激活器 class DeactivateThread extends Thread{ byte[] _oid; POA _adapter; public DeactivateThread(byte[] oid, POA adapter){ _oid = oid; _adapter = adapter; } public void run(){ try{ Thread.currentThread().sleep(15000); System.out.println("dactivate with ID="+new String(_oid)); _adapter.deactivate_object(_oid); }catch(Exception exc){ exc.printStackTrace();} } 实现伺服对象激活器
服务器使用伺服激活器 POA newPOA = rootPOA.create_POA("SAPOA",rootPOA.the_POAManager(),plicies); //创建一个伺服激活器并注册到POA ServantActivator sa = new AccountManagerActivator()._this(orb); newPOA.set_servant_manager(sa); //创建某对象标识的对象引用 newPOA.create_reference_with_id("Zhang3".getBytes(),"IDL:Bank/AccountManager:1.0"); //激活POA管理器等待接入请求 rootPOA.the_POAManager().activate(); Orb.run();
// 客户端的主程序 import Bank.*; public class Client { public static void main(String[] args) { try { // 初始化ORB org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init(args, null); // 查找对象标识为Zhang3的账户管理员 System.out.println("第1次绑定对象标识Zhang3"); AccountManager mngr1 = AccountManagerHelper.bind(orb, "/SAPOA", "Zhang3".getBytes()); // 再次以同一对象标识绑定(注意此时服务端不会调用incarnate方法) System.out.println("第2次绑定对象标识Zhang3"); AccountManager mngr2 = AccountManagerHelper.bind(orb, "/SAPOA", "Zhang3".getBytes()); // 以对象标识Li4绑定会导致创建另一类型的对象实例 System.out.println("绑定对象标识Li4"); AccountManager mngr3 = AccountManagerHelper.bind(orb, "/SAPOA", "Li4".getBytes()); // 请求账户管理员找出一个指定名字的账户并显示余额,无此账户则新开一个 System.out.println("David的余额:" + mngr1.open("David").getBalance()); System.out.println("Leeman的余额:" + mngr2.open("Leeman").getBalance()); System.out.println("Edward的余额:" + mngr3.open("Edward").getBalance()); } catch(Exception exc) { exc.printStackTrace(); }
结果 见P128页
5.4.2 伺服对象定位器 在许多应用场合,POA的活动对象映射表可能变得很大并占用大量内存,这时可考虑以USE_SERVANT_MANAGER结合NON_RETAIN策略创建POA,这意味着伺服对象与CORBA对象的关联不保存在活动对象映射表中。 由于没有保存任何关联,每一次请求都导致POA直接以对象标识、POA等参数调用已注册的伺服对象定位器的preinvoke操作。 伺服对象定位器负责查找合适的伺服对象返回给POA,由POA调用伺服对象的合适操作并将结果返回给客户程序后,再调用伺服对象定位器的postinvoke操作。
伺服对象定位器 实现伺服对象定位器 // 一个伺服对象定位器类型的伺服对象管理器 import org.omg.PortableServer.*; import org.omg.PortableServer.ServantLocatorPackage.CookieHolder; public class AccountManagerLocator extends ServantLocatorPOA { public Servant preinvoke(byte[] oid, POA adapter, java.lang.String operation, CookieHolder the_cookie) throws ForwardRequest System.out.println("preinvoke with ID = " + new String(oid)); if ((new String(oid)).equalsIgnoreCase("Zhang3")) return new AccountManagerImpl_1(); return new AccountManagerImpl_2(); } public void postinvoke(byte[] oid, POA adapter, java.lang.String operation, java.lang.Object the_cookie, Servant the_servant) System.out.println("postinvoke with ID = " + new String(oid)); } 实现伺服对象定位器
与伺服对象激活器不同: 以NO_RETAIN策略创建子POA 调用set_servant_manager()方法注册到POA的是一个伺服对象定位器而非伺服对象激活器
// 服务端的主程序 。。。 POA newPOA = rootPOA.create_POA("SLPOA", rootPOA.the_POAManager(), policies); // 创建伺服对象定位器并注册到POA ServantLocator sl = new AccountManagerLocator()._this(orb); newPOA.set_servant_manager(sl); // 创建两个不同对象标识的对象引用 newPOA.create_reference_with_id("Zhang3".getBytes(), "IDL:Bank/AccountManager:1.0"); newPOA.create_reference_with_id("Li4".getBytes(), "IDL:Bank/AccountManager:1.0"); // 激活POA管理器等待接入请求 rootPOA.the_POAManager().activate(); System.out.println("账户管理员Zhang3和Li4已就绪 ..."); orb.run(); } catch(Exception exc) { exc.printStackTrace();
// 客户端的主程序 import Bank.*; public class Client { public static void main(String[] args) { try { // 初始化ORB org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init(args, null); // 查找对象标识为Zhang3的账户管理员 System.out.println("第1次绑定对象标识Zhang3"); AccountManager mngr1 = AccountManagerHelper.bind(orb, "/SLPOA", "Zhang3".getBytes()); // 再次以同一对象标识绑定(注意此时服务端不会调用incarnate方法) System.out.println("第2次绑定对象标识Zhang3"); AccountManager mngr2 = AccountManagerHelper.bind(orb, "/SLPOA", "Zhang3".getBytes()); // 以对象标识Li4绑定会导致创建另一类型的对象实例 System.out.println("绑定对象标识Li4"); AccountManager mngr3 = AccountManagerHelper.bind(orb, "/SLPOA", "Li4".getBytes()); // 请求账户管理员找出一个指定名字的账户,无此账户则新开一个 System.out.println("David的余额:" + mngr1.open("David").getBalance()); System.out.println("Leeman的余额:" + mngr2.open("Leeman").getBalance()); System.out.println("Edward的余额:" + mngr3.open("Edward").getBalance()); } catch(Exception exc) { exc.printStackTrace(); }
5。5 适配器激活器 并不是所有CORBA程序都需要适配器激活器,如果一个服务程序在启动时就创建了所需的全部POA层次,则无需使用
5.6 纽带机制 工作原理 例子
对象实现的途径 继承:继承由IDL编译器生成的POA类(IDL框架) 纽带:不继承POA类,须声明实现生成的操作接口,服务程序创建的伺服对象实例也不再是对象实现类型,是由IDL生成的POATie类型的实例 POATie类并未提供什么新的语义,它仅仅是简单地将所收到的每一操作请求委托给它的代表对象
org.omg.portableServer. Servant 《interface》 org.omg.CORBA.Object org.omg.portableServer. Servant 《interface》 AccountOperations org.omg.portable.ObjectImpl org.omg.PortableServer. DynamicImplemantation 《interface》 Account AccountPOA 使用 _AccountStub AccountPOATie 委托 Client AccountImpl AccountDelegate