TAO教程之八:按需激活

按需激活

伺服(Servant)管理器

在先前的示例中,我们对使用同步方法调用的简单客户端进行了扩展,用于处理异步请求:通过使用回复处理器的异步方向调用。

在应用程序中有许多对象,没有必要在同时激活所有的对象,并且,如果同时激活所有对象会导致占用过多的内存或过多的数据库查询。为了解决这类应用程序面临的问题,POA提供了一个选项让应用程序提供伺服管理器,伺服管理器可以在每一个请求上动态的提供伺服。

伺服管理器是一个回调对象,应用程序把它和POA注册在一起。当POA试图确定与特定请求关联的伺服是,它回调应用程序的伺服管理器来找回伺服。想要把伺服管理器与POA注册在一起,就要把控制请求与伺服关系的这个RequestProcessingPolicyValue设置为USE_SERVANT_MANAGER。

根据POA是否把对象与伺服的关联是否保存在它的主动对象映射表(Active Object Map),我们把伺服管理器分为两种类型。这取决于当POA创建时为ServantRetentionPolicy设的值。如果设为 RETAIN,那么POA保留关联,如果设为NON_RETAIN,POA则不在对象和伺服中保留任何关联。

在POA是具有RETAIN 的情况下伺服管理器必须激活与对象关联的伺服。这需要伺服管理器对象支持ServantActivator 接口。在POA是具有NON_RETAIN 的情况下,我们的伺服管理器对象将能够为请求的对象找到伺服并调用它。

在本示例中,让我们使用伺服的定位器来当在象被调用时来定位与我们的对Stock_Factory对象关联的伺服。

The Stock Factory 定位器的实现

我们的Stock_Factory_Locator_i将帮助我们找到Quoter_Stock_Factory伺服。

伺服定位接口提供两个操作:调用前和调用后(preinvoke 和postinvoke)。preinvoke 操作被调用时用于找回伺服来分发请求。preinvode返回的伺服仅用于单一的请求。postinvode操作后来被调用,用于销毁被preinvode操作创建的伺服。

      #include "tao/corba.h"

class Quoter_Stock_Factory_Locator_i : public POA_PortableServer::ServantLocator
{
public:
Quoter_Stock_Factory_Locator_i (CORBA::ORB_ptr orb);

// Preinvoke function
virtual PortableServer::Servant preinvoke (const PortableServer::ObjectId &oid,
PortableServer::POA_ptr poa,
const char * operation,
void * & cookie);

// Postinvoke function
virtual void postinvoke (const PortableServer::ObjectId & oid,
PortableServer::POA_ptr poa,
const char * operation,
void * cookie,
PortableServer::Servant servant);

private:
CORBA::ORB_var orb_;
};

In the implementation of the preinvoke operation, we check if the object ID is valid and then check for the servant we want to create and create and return the requested servant.

在 preinvoke 操作的实现中,我们检查对象的ID 是否有效,然后检查我们想要创建的伺服和返回请求的伺服。

     PortableServer::Servant
Quoter_Stock_Factory_Locator_i::preinvoke (const PortableServer::ObjectId &oid,
PortableServer::POA_ptr poa,
const char * operation,
void * & cookie)
{

try {

// Get the ObjectID in string format
CORBA::String_var oid_str =
PortableServer::ObjectId_to_string (oid);

// Check if the ObjectId is valid
if (strcmp (oid_str.in (), "Quoter/Stock_Factory") != 0) {
// Create the requested servant.
PortableServer::Servant servant =
new Quoter_Stock_Factory_i ();

cookie = servant;

return servant;
}
else {
throw CORBA::OBJECT_NOT_EXIST ();
}

}catch (const CORBA::BAD_PARAM &) {
throw CORBA::OBJECT_NOT_EXIST ();
}

postinvoke 操作的实现很简单。我们仅仅是销毁在preinvoke 操作中创建的伺服。在这两个操作中的参数 Cookie IDL type帮助把preinvoke的调用和postinvoke 操作关联在一起。

      void 
Quoter_Stock_Factory_Locator_i::postinvoke (const PortableServer::ObjectId &oid,
PortableServer::POA_ptr poa,
const char * operation,
void * cookie,
PortableServer::Servant servant)
{

// Delete the servant as it is no longer needed.
PortableServer::Servant my_servant = (PortableServer::Servant) cookie;
if (servant == my_servant)
delete servant;
}
服务端的实现

第一平上从RootPOA创建一个新的POA,这个新的POA具有以下特性: RequestProcessingPolicy的值设为USE_SERVANT_MANAGER ,并且ServantRetentionPolicy的值设为NON_RETAIN。

        CORBA::PolicyList policies (3);
policies.length (3);

// Assign the polices
policies [0] =
poa->create_id_assignment_policy (PortableServer::USER_ID);

policies [1] =
poa->create_request_processing_policy
(PortableServer::USE_SERVANT_MANAGER);

policies [2] =
poa->create_servant_retention_policy (PortableServer::NON_RETAIN);

// Create the POA with these policies
PortableServer::POA_var child_poa =
poa->create_POA ("childPOA",
poa_manager.in (),
policies);

// Destroy the policy objects
for (CORBA::ULong i = 0; i != policies.length (); ++i) {
policies[i]->destroy ();
}

把策略赋值后,根据这些策略创建了childPOA,因为这些策略对象在create_POA中复制了一个拷贝,所以之后我们就不必再使用它们了,因此把它们删除。

由于我们拥有支持伺服管理器的POA,所以接下来为服务定位器对象创建伺服,激活它以找回它的引用, 然后给childPOA设置伺服管理器。

       // Create a Stock_Factory_Locator servant
Quoter_Stock_Factory_Locator_i servant_locator_i(orb.in ());

// Need to activate a servant_manager object in the Root POA
PortableServer::ServantLocator_var servant_locator =
servant_locator_i._this ();

// Set the SM with the childPOA
child_poa->set_servant_manager (servant_locator.in ());

由于我们给childPOA设置了伺服管理器,接下来通过在childPOA中创建的用户自创建ID 来创建引用,

这个childPOA使用了Quoter_Stock_Factory_Locator_i。create_reference_with_id 操作

让我们创建了需要要的对象而无须实际的创建它的伺服。应用程序提供 了ObjectID,这个对象标识在应用程序领域更具有语义。

       // Get the Object Id
PortableServer::ObjectId_var child_oid =
PortableServer::string_to_ObjectId ("childFoo");

//Create the Object without creating the servants
CORBA::Object_var stock_factory =
child_poa->create_reference_with_id (child_oid.in (),
"IDL:Quoter/Stock_Factory:1.0");

在这之后,和以前一样,我们把对角引用转为IOR字符串,并打印出来。

       // Put the object reference as an IOR string
CORBA::String_var ior = orb->object_to_string (stock_factory.in ());

// Print it out!
std::cout << ior.in () << std::endl;
练习

Modify the server.cpp in
the simple server to use servant managers and locators. Use
these files to help complete the implementation.
Stock_Factory_locator_i.h Stock_Factory_locator_i.cpp
Makefile.

解决方案

Look at the server.cpp file. It should not
be much different from yours.

测试

A client which uses request handlers is provided:
client.cpp. As before the
following files are provided.
Quoter.idl Stock_i.h Stock_i.cpp Stock_Factory_i.h
Stock_Factory_i.cpp Handler_i.h and
Handler_i.cpp.

More Reading

The

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 examples that illustrate how to use the POA policies.

你可能感兴趣的:(manager,object,String,delete,processing,reference)