改进服务端之通过POA策略实现持久化的对象引用
介绍-改进服务器
在本节中,我们将改进之前写的简单服务器(第二篇)。我们要利用POA策略来创建具有持久化对象引用的对象。
在创建POA时为其指定策略可以用于控制POA的特性。POA的策回略都具有相同的形式:在创建时使用枚举类型为它指定值。在我们的示例中,我们要使用LifeSpanPolicy这个策略控制对象引用的生命期和创建它的对象的POA的生命期之间的关系;我们还要使用IdAssignmentPolicy,它可以控制如何给对象ID赋值。
CORBA对象存在的进程如果与创建它或激活它的进程无关,我们称这种对象为持久化的对象。同样地,如果CORBA对象的生命期被绑定在创建它的POA所在的进程中,这种对象被称为暂时对象。注意,这一点与对象的状态没有关系:一个应用程序可以创建暂时对象来访问在数据库中维护的持久化的信息。例如,有这样的对象可以用来表示不同的连接会话或数据的交易视图。类似的,有的持久化对象可能没有状态或持久的状态。例如,因为日志设备是持久化的,所以它总有效,但它可以不必维护状态或只是简单的为当前的活动缓存一些状态而已。总而言之,具有持久化状态的对象总是通过持久化对象的引用来访问的。
RootPOA的标准生命期策略是短暂的(TRANSIEN)。这意味着如果应用程序试图支持持久化对象必须至少创建另外一个支持持久生命期策略的POA。在我们的例子中,我们将为子POA创建两个策略。一个策略是LifeSpanPolicy,它会被设为持久化的(PERSISTENT)。习惯上,创建持久对象引用的应用程序还会设置IdAssignmentPolicy,所以这些应用程序可以以一种可预测的方式分配对象ID,与服务端的激活一致。使系统ID具有持久化对象引用虽然也是可以的,但这样用非常少见。
子POA的创建
和以前一样,我们先初始化ORB,再为RootPOA找回引用。
CORBA::ORB_var orb = CORBA::ORB_init (argc, argv); CORBA::Object_var poa_object = orb->resolve_initial_references ("RootPOA"); PortableServer::POA_var poa = PortableServer::POA::_narrow (poa_object.in ());
接下来我们找回RootPOA的POA管理器好用它来激活RootPOA。
PortableServer::POAManager_var poa_manager = poa->the_POAManager (); poa_manager->activate ();
然后我们用PERSISTENT来创建LifeSpanPolicy 对象。
// Create a PERSISTENT LifespanPolicy object PortableServer::LifespanPolicy_var lifespan = poa->create_lifespan_policy (PortableServer::PERSISTENT);
and next we create an IdAssignmentPolicy
object with the USER_ID
value:
// Create a USER_ID IdAssignmentPolicy object PortableServer::IdAssignmentPolicy_var idassignment = poa->create_id_assignment_policy (PortableServer::USER_ID);
再一步,我们初始化策略的序列:
CORBA::PolicyList polices (2); policies.length (2); policies[0] = PortableServer::IdAssignmentPolicy::_duplicate (idassignment); policies[1] = PortableServer::LifespanPolicy::_duplicate (lifespan);
在父POA上使用create_POA操作创建子POA。
PortableServer::POA_var child_poa = poa->create_POA ("childPOA", poa_manager.in (), policies);
传给create_POA操作的参数是:子POA的名称、子POA的管理器和CORBA策略列表(CORBA::PolicyList)。我们能够通过传递空引用(nil reference)创建一个被新的POA管理器(POAManager)控制的子POA,但通常情况下使用父POA的POA管理器。
最后一步,我们可以销毁生命期策略和ID分配策略,因为我们不必在用它们了。create_POA操作将在策略列表中复制对象,并且新创建POA将引用传递给create_POA的对象的拷贝。
idassignment->destroy (); lifespan->destroy ();
激活在子POA的对象
既然我们已经创建了新的POA,那让我们所用这个POA来激活股票对象。第一步将要创建股票工厂实现的实例。
// Create a servant of class Quoter_Stock_Factory_i Quoter_Stock_Factory_i stock_factory_i;
可以使用activate_object_with_id () 显示的激活对象。这个对象有两个输入参数:对象的ID和实现它的伺服代码的指针。
PortableServer::ObjectId_var oid = PortableServer::string_to_ObjectId ("Stock_Factory");
第二步,我们可以激活“股票工厂”对象:
child_poa->activate_object_with_id (oid.in (), &stock_factory_i);
这个操作并不返回新对象的对象引用,但我们可以用id_to_reference
操作找该对象的引用:
CORBA::Object_var stock_factory = child_poa->id_to_reference (oid.in ());
与之前一样,我们把对象引用转换成IOR字符串以便客户端可以使用它。
CORBA::String_var ior = orb->object_to_string (stock_factory.in ()); std::cout << ior.in () << std::endl;
我们已经知道了,在能处理客户端的请求的最后一步是要运行ORB事件循环。直到中止时析构时最后我们销毁POA。
orb->run (); // Destroy the POA poa->destroy (1,1); orb->destroy ();
练习
修改在简单服务器中的 server.cpp 文件来创建持久化的子POA。你还可以使用相同的Quoter.idl Stock_i.h Stcok_i.cpp Stock_Factory_i.h Stock_Factory_i.cpp 文件和使用MPC file文件。
解决方案
你的文件和server.cpp 文件作比较.
测试
你可以使用client.cpp 来检查结果,如下操作:
$ ./server -ORBEndPoint iiop://localhost:12345 > server.ref &
正常地,ORB随机的选择侦听的终端。这一点对于具有持久化对象引用的应用程序就不适合了。这是因为如果服务器重启会选择一个新的侦听端口,原来的引用就变为无效了。在TAO中,我们可以使用 -ORBEndPoint选项来控制侦听的端口。比如,对于IIOP协议,终端信息包括了主机的机器名字或IP地址和一个可用的TCP端口号。在下一节中,我们将学习使用实现仓库,它和持久化的对象一起工作,这样就不必显示地设置侦听的端口了。
客户端还是和以前那样执行:
$ ./client file://server.ref MSFT RHAT
为了测试POA的持久化,让我们关掉服务器,然后将对象引用转化为新的foo.ref。
$ kill %1 $ ./server -ORBEndPoint iiop://localhost:12345 > foo.ref & [2] 6941
如果我们再次运行客户端,我们必定会从服务器得到与先前一样的结果。
$ ./client file://server.ref MSFT RHAT
如果我们不告之服务器在相同的端口上侦听会发生什么呢?让我们和之前一样来运行新的服务端:
$ ./server > server.ref & [1] 23897 $ ./client file://server.ref MSFT RHAT The price of a stock in "RedHat, Inc." is $210 The price of a stock in "Microsoft, Inc." is $91 $ kill %1 $ ./server > foo.ref & [2] 23908 $ ./client file://server.ref MSFT RHAT CORBA exception raised!TRANSIENT (IDL:omg.org/CORBA/TRANSIENT:1.0)
一个CORBA TRANSIENT 异常抛出来了。这表明执行请求必须的某些资源不可用。在这种情况下客户端的ORB不能在期望的端口号上找到服务端。没有实现仓库,客户端ORB不能在新的端口里定位到服务器。必须假设服务端会临时关掉或在后来重启,这都会引发TRANSIENT异常。
More Reading
The Henning and Vinoski CORBA book discusses POA policies in detail. Likewise, the Schmidt and Vinoski columns in C++ Report also include several articles about the POA. Finally, the TAO distribution includes several examples that illustrate how to use the POA policies.