VisiBroker for C++ Developer’s Guide : Server basics

Server basics
This section outlines the tasks that are necessary to set up a server to receive client requests.
Overview
The basic steps that you must perform in setting up your server are:
This section describes each task in a global manner to give you an idea of what you must consider. The specifics of each step are dependent on your individual requirements.
Initializing the VisiBroker ORB
As stated in the previous section, the VisiBroker ORB provides a communication link between client requests and object implementations. Each application must initialize the VisiBroker ORB before communicating with it as follows:
// Initialize the VisiBroker ORB.
CORBA::ORB_ptr orb = CORBA::ORB_init(argc, argv);
Creating the POA
Early versions of the CORBA object adapter (the Basic Object Adapter, or BOA) did not permit portable object server code. A new specification was developed by the OMG to address these issues and the Portable Object Adapter (POA) was created.
A discussion of the POA can be quite extensive. This section introduces you to some of the basic features of the POA. For detailed information, see “Using POAs” and the OMG specification.
In basic terms, the POA (and its components) determine which servant should be invoked when a client request is received, and then invokes that servant. A servant is a programming object that provides the implementation of an abstract object. A servant is not a CORBA object.
One POA (called the rootPOA) is supplied by each VisiBroker ORB. You can create additional POAs and configure them with different behaviors. You can also define the characteristics of the objects the POA controls.
The steps to setting up a POA with a servant include:
Some of these steps may be different for your application.
Obtaining a reference to the root POA
All server applications must obtain a reference to the root POA to manage objects or to create new POAs.
// get a reference to the root POA
CORBA::Object_var obj = orb->resolve_initial_references("RootPOA");
// narrow the object reference to a POA reference
PortableServer::POA_var rootPOA = PortableServer::POA::_narrow(obj);
You can obtain a reference to the root POA by using resolve_initial_references which returns a value of type CORBA::Object. You are responsible for narrowing the returned object reference to the desired type, which is PortableServer::POA in the above example.
You can then use this reference to create other POAs, if needed.
Creating the child POA
The root POA has a predefined set of policies that cannot be changed. A policy is an object that controls the behavior of a POA and the objects the POA manages. If you need a different behavior, such as different lifespan policy, you will need to create a new POA.
POAs are created as children of existing POAs using create_POA. You can create as many POAs as you think are required.
Note
Child POAs do not inherit the policies of their parent POAs.
In the following example, a child POA is created from the root POA and has a persistent lifespan policy. The POA Manager for the root POA is used to control the state of this child POA.
CORBA::PolicyList policies;
policies.length(1);
policies[(CORBA::ULong)0] = rootPOA->create_lifespan_policy(
PortableServer::PERSISTENT);
// Create myPOA with the right policies
PortableServer::POAManager_var rootManager = rootPOA->the_POAManager();
PortableServer::POA_var myPOA = rootPOA->create_POA( "bank_agent_poa",
rootManager, policies );
Implementing servant methods
IDL has a syntax similar to C++ and can be used to define modules, interfaces, data structures, and more. When you compile IDL that contains an interface, a class is generated which serves as the base class for your servant. For example, in the Bank.IDL file, there is an AccountManager interface:
module Bank{
interface Account {
float balance();
};
interface AccountManager {
Account open (in string name);
};
};
The following shows the AccountManager implementation on the server side.
class AccountManagerImpl : public POA_Bank::AccountManager {
private:
Dictionary _accounts;
public:
virtual Bank::Account_ptr open(const char* name) {
// Lookup the account in the account dictionary.
Bank::Account_ptr account = (Bank::Account_ptr) _accounts.get(name);
if(account == Bank::Account::_nil()) {
// Make up the account's balance, between 0 and 1000 dollars.
float balance = abs(rand()) % 100000 / 100.0;
// Create the account implementation, given the balance.
AccountImpl *accountServant = new AccountImpl(balance);
try {
// Activate it on the default POA which is root POA for this
servant
PortableServer::POA_var rootPOA = _default_POA();
CORBA::Object_var obj =
rootPOA->servant_to_reference(accountServant);
account = Bank::Account::_narrow(obj);
} catch(const CORBA::Exception& e) {
cerr << "_narrow caught exception: " << e << endl;
}
// Print out the new account.
cout << "Created " << name << "'s account: " << account << endl;
// Save the account in the account dictionary.
_accounts.put(name, account);
}
// Return the account.
return Bank::Account::_duplicate(account);
}
};
Creating and Activating the Servant
The AccountManager implementation must be created and activated in the server code. In this example, AccountManager is activated with activate_object_with_id, which passes the object ID to the Active Object Map where it is recorded. The Active Object Map is simply a table that maps IDs to servants. This approach ensures that this object is always available when the POA is active and is called explicit object activation.
// Create the servant

AccountManagerImpl managerServant;
// Decide on the ID for the servant
PortableServer::ObjectId_var managerId =
PortableServer::string_to_ObjectId("BankManager");
// Activate the servant with the ID on myPOA
myPOA->activate_object_with_id(managerId,&managerServant);
Activating the POA
The last step is to activate the POA Manager associated with your POA. By default, POA Managers are created in a holding state. In this state, all requests are routed to a holding queue and are not processed. To allow requests to be dispatched, the POA Manager associated with the POA must be changed from the holding state to an active state. A POA Manager is simply an object that controls the state of the POA (whether requests are queued, processed, or discarded.) A POA Manager is associated with a POA during POA creation. You can specify a POA Manager to use, or let the system create a new one for you by passing a null value as the POA Manager name in create_POA()).
// Activate the POA manager
rootPOA.the_POAManager().activate();
Activating objects
In the preceding section, there was a brief mention of explicit object activation. There are several ways in which objects can be activated:
Explicit: All objects are activated upon server start-up via calls to the POA
On-demand: The servant manager activates an object when it receives a request for a servant not yet associated with an object ID
Implicit: Objects are implicitly activated by the server in response to an operation by the POA, not by any client request
Default servant: The POA uses the default servant to process the client request
A complete discussion of object activation is in “Using POAs” For now, just be aware that there are several means for activating objects.
Waiting for client requests
Once your POA is set up, you can wait for client requests by using orb.run(). This process will run until the server is terminated.
// Wait for incoming requests
orb.run();
Complete example
The sample below shows the complete example code.
// Server.C
#include "Bank_s.hh"
#include <math.h>
class Dictionary {
private:
struct Data {
const char* name;
void* value;
};
unsigned _count;
Data* _data;
public:
Dictionary() {
_count = 0;
}
void put(const char* name, void* value) {
Data* oldData = _data;
_data = new Data[_count + 1];
for(unsigned i = 0; i < _count; i++) {
_data[i] = oldData[i];
}
_data[_count].name = strdup(name);
_data[_count].value = value;
_count++;
}
void* get(const char* name) {
for(unsigned i = 0; i < _count; i++) {
if(!strcmp(name, _data[i].name)) {
return _data[i].value;
}
}
return 0;
}
};
class AccountImpl : public POA_Bank::Account {
private:
float _balance;
public:
AccountImpl(float balance) {
_balance = balance;
}
virtual float balance() {
return _balance;
}
};
class AccountManagerImpl : public POA_Bank::AccountManager {
private:
Dictionary _accounts;
public:
virtual Bank::Account_ptr open(const char* name) {
// Lookup the account in the account dictionary.
        Bank::Account_ptr account = (Bank::Account_ptr) _accounts.get(name);
if(account == Bank::Account::_nil()) {
// Make up the account's balance, between 0 and 1000 dollars.
float balance = abs(rand()) % 100000 / 100.0;
// Create the account implementation, given the balance.
AccountImpl *accountServant = new AccountImpl(balance);
try {
// Activate it on default POA which is root POA for this servant
PortableServer::POA_var rootPOA = _default_POA();
CORBA::Object_var obj =
rootPOA->servant_to_reference(accountServant);
account = Bank::Account::_narrow(obj);
} catch(const CORBA::Exception& e) {
cerr << "_narrow caught exception: " << e << endl;
}
// Print out the new account.
cout << "Created " << name << "'s account: " << account << endl;
// Save the account in the account dictionary.
_accounts.put(name, account);
}
// Return the account.
return Bank::Account::_duplicate(account);
}
};
int main(int argc, char* const* argv) {
try {
// Initialize the ORB.
CORBA::ORB_ptr orb = CORBA::ORB_init(argc, argv);
// get a reference to the root POA
CORBA::Object_var obj = orb->resolve_initial_references("RootPOA");
// narrow the object reference to a POA reference
PortableServer::POA_var rootPOA = PortableServer::POA::_narrow(obj);
CORBA::PolicyList policies;
policies.length(1);
policies[(CORBA::ULong)0] = rootPOA->create_lifespan_policy(
PortableServer::PERSISTENT
);
// Create myPOA with the right policies
PortableServer::POAManager_var rootManager = root
                                                   POA->the_POAManager();
PortableServer::POA_var myPOA = rootPOA->create_POA( "bank_agent_poa",
rootManager, policies );
// Create the servant
AccountManagerImpl managerServant;
// Decide on the ID for the servant
PortableServer::ObjectId_var managerId =
PortableServer::string_to_ObjectId("BankManager");
// Activate the servant with the ID on myPOA
myPOA->activate_object_with_id(managerId,&managerServant);
// Activate the POA Manager
rootPOA->the_POAManager()->activate();
cout << myPOA->servant_to_reference(&managerServant) << " is ready"
        << endl;
// Wait for incoming requests
orb->run();
} catch(const CORBA::Exception& e) {
cerr << e << endl;
}
}