VisiBroker for .NET Developer’s Guide : Using Portable Object Adapters

Using Portable Object Adapters
What is a Portable Object Adapter?
The Portable Object Adapter (POA) is a service used to take incoming requests from clients and map those requests to the appropriate object implementations. For J2EE developers, it might be useful to think of a POA as being similar to an EJB Container in that it is responsible for mapping invocations to the set of objects it logically contains.
As with any container, you can think of the POA as having an external perspective and an internal perspective. The internal model of the POA is in terms of Servant objects: these are the objects that implement the user's business logic. The external model of the POA is in terms of Object References, which are references that can be used in distributed system invocations (for example, these Object References are analogous to instances of java.rmi.Remote in RMI/J2EE terminology, CORBA Object References in CORBA terminology, or instances of MarshalByRefObject in .NET Remoting terminology). The task of the POA is to map between external Object References and internal Servant objects.
The POA is an intermediary between the implementation of an object and the ORB. In its role as an intermediary, a POA routes requests to Servants and, as a result may cause Servants to run and create child POAs if necessary.
Servers can support multiple POAs. At least one POA must be present, which is called the Root POA. The Root POA is created automatically for you. The set of POAs is hierarchical; all POAs have the Root POA as their ancestor.
Servant Managers locate and assign Servants to objects for the POA. When an Object Reference is assigned to a Servant, it is called an active object and the Servant is said to incarnate the active object. Every POA has one Active Object Map which keeps track of the object IDs of active objects and their associated active Servants.
POA terminology
Contained in the following table are definitions of some terms with which you should become more familiar as you read through this section.
Steps for creating and using POAs
Although the exact process can vary, the basic steps that occur during a POA life cycle are:
1
2
3
4
5
6
Depending on your needs, some of these steps may be optional. For example, you only have to activate the POA if you want it to process requests.
POA policies
Each POA has a set of policies that define its characteristics. When creating a new POA, you can use the default set of policies or use different values to suit your requirements. You can only set the policies when creating a POA; you can not change the policies of an existing POA. POAs do not inherit the policies from their parent POA.
The following sections list the POA policies, their values, and the default value (used by the Root POA).
Thread policy
The thread policy specifies the threading model to be used by the POA. The valid values for the thread policy are described in the following table.
Calls are processed on a distinguished main thread. Requests for all main-thread POAs are processed sequentially. In a multi-threaded environment, all calls processed by all POAs with this policy are thread-safe. The application programmer designates the main thread by calling ORB.Run() or ORB.PerformWork(). For more information about these methods, see “Activating objects”.
Lifespan policy
The lifespan policy specifies the lifespan of the objects implemented in the POA. The valid values for the lifespan policy are listed in the following table.
(Default) A transient object activated by a POA cannot outlive the POA that created it. Once the POA is deactivated, an OBJECT_NOT_EXIST exception occurs if an attempt is made to use any object references generated by the POA.
Object ID Uniqueness policy
The Object ID Uniqueness policy allows a single Servant to be shared by many Object References. The valid values for the Object ID Uniqueness policy are listed in the following table.
ID Assignment policy
The ID assignment policy specifies whether object IDs are generated by server applications or by the POA. The valid values for the ID Assignment policy are listed in the following table.
(Default) Objects are assigned object IDs by the POA. If the PERSISTENT policy is also set, object IDs must be unique across all instantiations of the same POA.
Typically, USER_ID is for persistent objects, and SYSTEM_ID is for transient objects. If you want to use SYSTEM_ID for persistent objects, you can extract them from the Servant or Object Reference.
Servant Retention policy
The Servant Retention policy specifies whether the POA retains active Servants in the Active Object Map. The valid values for the Servant Retention policy are listed in the following table.
(Default) The POA tracks Object Reference activations in the Active Object Map. RETAIN is usually used with ServantActivators or explicit activation methods on POA.
The POA does not retain active Servants in the Active Object Map. NON_RETAIN must be used with ServantLocators.
ServantActivators and ServantLocators are types of Servant Managers. For more information on Servant Managers, see “Using Servants and Servant Managers”.
Request Processing policy
The Request Processing policy specifies how requests are processed by the POA. The valid values for the Request Processing policy are listed in the following table.
(Default) If the Object ID is not listed in the Active Object Map, an OBJECT_NOT_EXIST exception is returned. The POA must also use the RETAIN policy with this value.
If the Object ID is not listed in the Active Object Map or the NON_RETAIN policy is set, the request is dispatched to the default Servant. If no default Servant has been registered, an OBJ_ADAPTER exception is returned. The POA must also use the MULTIPLE_ID policy with this value.
If the Object ID is not listed in the Active Object Map or the NON_RETAIN policy is set, the Servant Manager is used to obtain a Servant.
Implicit Activation policy
The Implicit Activation policy specifies whether the POA supports implicit activation of Servants. The valid values for the Implicit Activation policy are listed in the following table.
Converting them to an Object Reference with PortableServer.POA.ServantToReference().
Invoking This_() on the Servant.
The POA must also use the SYSTEM_ID and RETAIN policies with this value.
Bind Support policy
The Bind Support policy (a VisiBroker-specific policy) controls the registration of POAs and active objects with the VisiBroker Smart Agent (osagent). If you have several thousands objects, it is not feasible to register all of them with the osagent. Instead, you can register the POA with the osagent. When a client request is made, the POA name and the object ID is included in the bind request so that the osagent can correctly forward the request. The valid values for the Bind Support policy are listed in the following table.
Note:
The Root POA is created with the NONE activation policy.
Creating POAs
To implement objects using the POA, at least one POA object must exist on the server. To ensure that a POA exists, a Root POA is provided during the ORB initialization. This POA uses the default POA policies described earlier in this section.
Once the Root POA is obtained, you can create child POAs that implement a specific server-side policy set.
POA naming convention
Each POA keeps track of its name and its full POA name (the full hierarchical path name.) The hierarchy is indicated by a slash (/). For example, /A/B/C means that POA C is a child of POA B, which in turn is a child of POA A. The first slash indicates the Root POA. If the BindSupport:BY_POA policy is set on POA C, then /A/B/C is registered and the client binds with /A/B/C.
If your POA name contains escape characters or other delimiters, VisiBroker for .NET precedes these characters with a double back slash (\\) when recording the names internally.
Obtaining the Root POA
The following code sample illustrates how a server application can obtain its Root POA.
// Initialize the ORB.
CORBA.ORB orb = CORBA.ORB.Init(args);
// get a reference to the Root POA
PortableServer.POA rootPOA =
POAHelper.Narrow(orb.ResolveInitialReferences("RootPOA"));
Note:
The ResolveInitialReferences method 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 previous example.
Setting the POA policies
Policies are not inherited from the parent POA. If you want a POA to have a specific characteristic, you must identify all the policies that are different from the default value. For more information about POA policies, see “POA policies”.
CORBA.Policy[] policies = {
rootPOA.CreateLifespanPolicy(LifespanPolicyValue.PERSISTENT),
rootPOA.CreateRequestProcessingPolicy(
RequestProcessingPolicyValue.USE_DEFAULT_SERVANT),
rootPOA.CreateIdUniquenessPolicy(IdUniquenessPolicyValue.MULTIPLE_ID)
};
Creating and activating the POA
A POA is created using CreatePOA on its parent POA. You can name the POA anything you like; however, the name must be unique with respect to all other POAs with the same parent. If you attempt to give two POAs the same name, a CORBA exception (AdapterAlreadyExists) is raised.
To create a new POA, use CreatePOA as follows:
CreatePOA(“ThePOAName”, thePOAManager, thePolicyList);
The POA manager (<POAManager>) controls the state of the POA (for example, whether it is processing requests). If null is passed to CreatePOA as the POA manager name, a new POA manager object is created and associated with the POA. Typically, you will want to have the same POA manager for all POAs. For more information about the POA manager, see “Managing POAs with the POA manager”.
POA managers (and POAs) are not automatically activated once created. Use Activate() to activate the POA manager associated with your POA.
The following code sample is an example of creating a POA and activating the POA manager.
// Create policies for our persistent POA
CORBA.Policy[] policies = {
rootPOA.CreateLifespanPolicy(LifespanPolicyValue.PERSISTENT)
};
// Create myPOA with the right policies
PortableServer.POA myPOA =
rootPOA.CreatePOA("bank_agent_poa",
rootPOA.ThePOAManager, policies);
// Activate the POA manager
rootPOA.ThePOAManager.Activate();
Activating objects
When Object References are associated with an active Servant, if the POA's Servant Retention Policy is RETAIN, the associated object ID is recorded in the Active Object Map and the object is activated. Activation can occur in one of several ways:
Explicit activation—The server application itself explicitly activates objects by calling ActivateObject or ActivateObjectWithId.
On-demand activation—The server application instructs the POA to activate objects through a user-supplied Servant Manager. The Servant Manager must first be registered with the POA through SetServantManager.
Implicit activation—The server activates objects solely by in response to certain operations. If a Servant is not active, there is nothing a client can do to make it active (for example, requesting for an inactive object does not make it active.)
Default Servant—The POA uses a single Servant to implement all of its objects.
Activating objects explicitly
By setting IdAssignmentPolicy.SYSTEM_ID on a POA, objects can be explicitly activated without having to specify an object ID. The server invokes ActivateObject on the POA which activates, assigns and returns an object ID for the object. This type of activation is most common for transient objects. No Servant Manager is required since neither the object nor the Servant is needed for very long.
Objects can also be explicitly activated using object IDs. A common scenario is during server initialization where the user invokes ActivateObjectWithId to activate all the objects managed by the server. No Servant Manager is required since all the objects are already activated. If a request for a non-existent object is received, an OBJECT_NOT_EXIST exception is raised. This has obvious negative effects if your server manages large numbers of objects.
This code sample is an example of explicit activation using ActivateObjectWithId.
// Create the account manager Servant.
Servant managerServant = new AccountManagerImpl(rootPoa);
// Activate the newly created Servant.
byte[] managerId = orb.StringToObjectId(“BankManager”);
testPoa.ActivateObjectWithId(managerId, managerServant);
// Activate the POAs
testPoa.ThePOAManager.Activate();
Activating objects on demand
On-demand activation occurs when a client requests an object that does not have an associated Servant. After receiving the request, the POA searches the Active Object Map for an active Servant associated with the object ID. If none is found, the POA invokes Incarnate on the Servant Manager which passes the object ID value to the Servant Manager. The Servant Manager can do one of three things:
Raise an OBJECT_NOT_EXIST exception that is returned to the client.
The POA policies determine any additional steps that may occur. For example, if RequestProcessingPolicy.USE_SERVANT_MANAGER and ServantRetentionPolicy.RETAIN are enabled, the Active Object Map is updated with the Servant and object ID association. if RequestProcessingPolicy.USE_SERVANT_MANAGER and ServantRetentionPolicy.RETAIN are enabled, the Active Object Map is updated with the Servant and object ID association.
Activating objects implicitly
A Servant can be implicitly activated by certain operations if the POA has been created with ImplicitActivationPolicy.IMPLICIT_ACTIVATION, IdAssignmentPolicy.SYSTEM_ID, and ServantRetentionPolicy.RETAIN. Implicit activation can occur with:
This_() Servant method
If the POA has IdUniquenessPolicy.UNIQUE_ID set, implicit activation can occur when any of the above operations are performed on an inactive Servant.
If the POA has IdUniquenessPolicy.MULTIPLE_ID set, ServantToReference and ServantToId operations always perform implicit activation, even if the Servant is already active.
Activating with the default Servant
Use the RequestProcessing.USE_DEFAULT_SERVANT policy to have the POA invoke the same Servant no matter what the object ID is. This is useful when little data is associated with each object.
This is an example of activating all objects with the same Servants
using System;
using System.IO;
using PortableServer;
using CORBA;
public class Server {
static void Main(string [] args) {
try {
// initialize the ORB
ORB orb = ORB.Init(args);
// get a reference to the root POA
POA rootPOA =
POAHelper.Narrow(orb.ResolveInitialReferences("RootPOA"));
// create policies for our persistent POA
Policy[] policies = {
rootPOA.CreateLifespanPolicy(
LifespanPolicyValue.PERSISTENT),
rootPOA.CreateRequestProcessingPolicy(
RequestProcessingPolicyValue.USE_DEFAULT_SERVANT),
rootPOA.CreateIdUniquenessPolicy(
IdUniquenessPolicyValue.MULTIPLE_ID)
};
// create myPOA with the right policies
POA myPOA = rootPOA.CreatePOA("bank_default_servant_poa",
rootPOA.ThePOAManager,
policies );
// create the servant
AccountManagerImpl managerServant = new AccountManagerImpl();
myPOA.SetServant(managerServant);
// Activate the POA manager
rootPOA.ThePOAManager.Activate();
// Generate the reference and write it out. One for each
// Checking and Savings account type. Note that we are not
// creating any servants here and just manufacturing a
// reference which is not yet backed by a servant.
// Write out checking object ID
try {
CORBA.Object objref = myPOA.CreateReferenceWithId(
orb.StringToObjectId("CheckingAccountManager"),
"IDL:Bank/AccountManager:1.0");
StreamWriter writer = new StreamWriter("cref.dat");
writer.WriteLine(orb.ObjectToString(objref));
writer.Close();
}
catch (Exception e) {
Console.WriteLine("Error writing the IOR for
CheckingAccountManager to file");
Console.WriteLine(e);
}
try {
// Write out savings object ID
CORBA.Object objref = myPOA.CreateReferenceWithId(
orb.StringToObjectId("SavingsAccountManager"),
"IDL:Bank/AccountManager:1.0");
StreamWriter writer = new StreamWriter("sref.dat");
writer.WriteLine(orb.ObjectToString(objref));
writer.Close();
}
catch (Exception e) {
Console.WriteLine("Error writing the IOR for
SavingsAccountManager to file");
Console.WriteLine(e);
}
Console.WriteLine("DefaultServantServer is ready.");
// Wait for incoming requests
orb.Run();
}
catch(Exception e) {
Console.WriteLine(e);
}
}
}
Deactivating objects
A POA can remove a Servant from its Active Object Map. This may occur, for example, as a form of garbage-collection scheme. When the Servant is removed from the map, it is deactivated. You can deactivate an object using DeactivateObject(). When an object is deactivated, it doesn't mean this object is lost forever. It can always be reactivated at a later time.
Using Servants and Servant Managers
Servant Managers perform two types of operations: find and return a Servant, and deactivate a Servant. They allow the POA to activate objects when a request for an inactive object is received. Servant Managers are optional. For example, Servant Managers are not needed when your server loads all objects at startup. Servant Managers may also inform clients to forward requests to another object using the ForwardRequest exception.
A Servant is an active instance of an implementation. The POA maintains a map of the active Servants and the object IDs of the Servants. When a client request is received, the POA first checks this map to see if the object ID (embedded in the client request) has been recorded. If it exists, then the POA forwards the request to the Servant. If the object ID is not found in the map, the Servant Manager is asked to locate and activate the appropriate Servant. This is only an example scenario; the exact scenario depends on what POA policies you have in place.
There are two types of Servant Managers: Servant Activator and Servant Locator. The type of policy already in place determines which type of Servant Manager is used. For more information on POA policy, see “POA policies”. Typically, a Servant Activator activates persistent objects and a Servant Locator activates transient objects.
To use Servant Managers, RequestProcessingPolicy.USE_SERVANT_MANAGER must be set as well as the policy which defines the type of Servant Manager (ServantRetentionPolicy.RETAIN for Servant Activator or ServantRetentionPolicy.NON_RETAIN for Servant Locator.)
ServantActivators
ServantActivators are used when ServantRetentionPolicy.RETAIN and RequestProcessingPolicy.USE_SERVANT_MANAGER are set.
Servants activated by this type of Servant Manager are tracked in the Active Object Map.
The following events occur while processing requests using Servant Activators:
1
2
3
If the object ID is not found in the Active Object Map, the POA invokes Incarnate on a Servant Manager. Incarnate passes the object ID and the POA in which the object is being activated.
4
5
Note:
The Etherealize and Incarnate method implementations are user-supplied code.
At a later date, the Servant can be deactivated. This may occur from several sources, including the DeactivateObject operation, deactivation of the POA manager associated with that POA, and so forth. More information on deactivating objects is described in “Deactivating objects”.
The following is the implementation of the ServantActivator.
using System;
using System.Threading;
using System.Collections;
public class
AccountManagerActivator : PortableServer.ServantActivator {
private Hashtable _objectMap = new Hashtable();
public AccountManagerActivator() {
Console.WriteLine("AccountManagerActivator() called.");
// Populate the Object Map.
_objectMap.Add("SavingsAccountManager",
new SavingsAccountManagerImpl());
_objectMap.Add("CheckingAccountManager",
new CheckingAccountManagerImpl());
}
public PortableServer.Servant Incarnate(byte[] oid,
PortableServer.POA adapter) {
try {
Console.WriteLine(
"AccountManagerActivator.Incarnate() called.");
string accountType = CORBA.ORB.Init().ObjectIdToString(oid);
Console.WriteLine("\nAccountManagerActivator.Incarnate()
called with ID = " + accountType);
new ObjectDeactivator(adapter, oid);
return (PortableServer.Servant) _objectMap[accountType];
}
catch (Exception e) {
Console.WriteLine(e);
}
return null;
}
public void Etherealize(byte[] oid,
PortableServer.POA adapter,
PortableServer.Servant serv,
bool cleanupInProgress,
bool remainingActivations) {
Console.WriteLine("Etheralize() called.");
try {
string accountType = CORBA.ORB.Init().ObjectIdToString(oid);
Console.WriteLine("\nAccountManagerActivator.Etherealize()
called with ID = " + accountType);
}
catch (Exception e) {
Console.WriteLine(e);
}
}
private const int ONE_SECOND = 1000;
private class ObjectDeactivator {
private PortableServer.POA _adapter;
private byte[] _oid;
public ObjectDeactivator(PortableServer.POA adapter, byte[] oid) {
_adapter = adapter;
_oid = oid;
new Thread(new ThreadStart(Deactivate)).Start();
}
public void Deactivate() {
Console.WriteLine("Deactivate() called.");
try {
Thread.Sleep(ONE_SECOND * 15);
Console.WriteLine("\nDeactivating the object with ID = " +
CORBA.ORB.Init().ObjectIdToString(_oid));
_adapter.DeactivateObject(_oid);
}
catch (Exception e) {
Console.WriteLine(e);
}
}
}
}
The following is a server implementation similar to the code example in “Activating with the default Servant”. In this example we highlight the differences for activating Servants with the ServantActivator.
// create policies for our persistent POA
CORBA.Policy[] policies = {
rootPOA.CreateLifespanPolicy(
LifespanPolicyValue.PERSISTENT),
rootPOA.CreateRequestProcessingPolicy(
RequestProcessingPolicyValue.USE_SERVANT_MANAGER)
};
// create myPOA with the right policies
POA myPOA =
rootPOA.CreatePOA("bank_servant_activator_poa",
rootPOA.ThePOAManager,
policies );
// Create the servant activator servant and get its
// reference
ServantActivator sa = new AccountManagerActivator(orb);
// Set the servant activator on our POA
myPOA.SetServantManager(sa);
// Activate the POA manager
rootPOA.ThePOAManager.Activate();
ServantLocators
In many situations, the POA's Active Object Map could become quite large and consume memory. To reduce memory consumption, a POA can be created with RequestProcessingPolicy.USE_SERVANT_MANAGER and ServantRetentionPolicy.NON_RETAIN, meaning that the Servant-to-object association is not stored in the Active Object Map. Since no association is stored, Servant Locator Servant Managers are invoked for each request.
The following events occur while processing requests using Servant Locators:
1
2
Since ServantRetentionPolicy.NON_RETAIN is used, the POA does not search the Active Object Map for the object ID.
3
The POA invokes Preinvoke on a Servant Manager. Preinvoke passes the object ID, the POA in which the object is being activated, and a few other parameters.
4
5
6
The POA invokes Postinvoke on the Servant Manager.
Note:
The Preinvoke and Postinvoke method implementations are user-supplied code.
The following is the implementation of the ServantLocator.
using System;
using CORBA;
using PortableServer;
using PortableServer.ServantLocatorNS;
public class AccountManagerLocator : ServantLocator {
private ORB _orb;
public AccountManagerLocator(ORB orb) {
_orb = orb;
}
public Servant Preinvoke (byte[] oid, POA adapter,
string operation, out object theCookie) {
string accountType = _orb.ObjectIdToString(oid);
theCookie = null;
Console.WriteLine("\nAccountManagerLocator.preinvoke
called with ID = {0}\n", accountType);
if (accountType.Equals("SavingsAccountManager")) {
return new SavingsAccountManagerImpl();
}
return new CheckingAccountManagerImpl();
}
public void Postinvoke (byte[] oid,
POA adapter,
string operation,
object theCookie,
Servant theServant) {
string id = _orb.ObjectIdToString(oid);
Console.WriteLine("\nAccountManagerLocator.postinvoke
called with ID = {0}\n", id);
}
}
The following is a server implementation similar to the code example in “Activating with the default Servant”. This example highlights the differences for activating Servants using the ServantLocator.
// Create policies for our POA. We need persistence life
// span, use servant manager request processing policies
// and non retain retention policy. This non retain policy
// will let us use the servant locator instead of servant
// activator
CORBA.Policy[] policies = {
rootPOA.CreateLifespanPolicy(
LifespanPolicyValue.PERSISTENT),
rootPOA.CreateServantRetentionPolicy(
ServantRetentionPolicyValue.NON_RETAIN),
rootPOA.CreateRequestProcessingPolicy(
RequestProcessingPolicyValue.USE_SERVANT_MANAGER)
};
// create myPOA with the right policies
POA myPOA = rootPOA.CreatePOA("bank_servant_locator_poa",
rootPOA.ThePOAManager, policies);
// Create the servant locator servant and get its
// reference
ServantLocator sl = new AccountManagerLocator(orb);
// Set the servant activator on our POA
myPOA.SetServantManager(sl);
// Activate the POA manager
rootPOA.ThePOAManager.Activate();
Managing POAs with the POA manager
A POA manager controls the state of the POA (whether requests are queued or discarded), and can deactivate the POA. Each POA is associated with a POA manager object. A POA manager can control one or several POAs.
A POA manager is associated with a POA when the POA is created. You can specify the POA manager to use, or specify null to have a new POA manager created.
The following is an example of naming the POA and its POA manager:
POA myPOA = rootPOA.CreatePOA("MyPOA",
rootPOA.ThePOAManager, policies);
POA myPOA = rootPOA.CreatePOA("MyPOA", null, policies);
A POA manager is “destroyed” when all its associated POAs are destroyed.
A POA manager can have the following four states:
These states in turn determine the state of the POA. They are each described in detail in the following sections.
Getting the current state
To get the current state of the POA manager, use
State state = manager.GetState();
Holding state
By default, when a POA manager is created, it is in the Holding state. When the POA manager is in the Holding state, the POA queues all incoming requests.
Requests that require an adapter activator are also queued when the POA manager is in the Holding state.
To change the state of a POA manager to Holding, use
manager.HoldRequests(waitForCompletion);
waitForCompletion is Boolean. If false, this operation returns immediately after changing the state to Holding. If true, this operation returns only when all requests started prior to the state change have completed or when the POA manager is changed to a state other than Holding. AdapterInactive is the exception raised if the POA manager was in the Inactive state prior to calling this operation.
Note:
POA managers in the Inactive state cannot change to the Holding state.
Any requests that have been queued but not yet started will continue to be queued during the Holding state.
Active state
When the POA manager is in the Active state, its associated POAs process requests.
To change the POA manager to the Active state, use
manager.Activate();
AdapterInactive is the exception raised if the POA manager was in the Inactive state prior to calling this operation.
Note:
POA managers currently in the Inactive state can not change to the Active state.
Discarding state
When the POA manager is in the Discarding state, its associated POAs discard all requests that have not yet started. In addition, the adapter activators registered with the associated POAs are not called. This state is useful when the POA is receiving too many requests. You need to notify the client that their request has been discarded and to resend their request. There is no inherent behavior for determining if and when the POA is receiving too many requests. It is up to you to set up thread monitoring if so desired.
To change the POA manager to the Discarding state, use
manager.DiscardRequests(waitForCompletion);
The waitForCompletion option is Boolean. If false, this operation returns immediately after changing the state to Holding. If true, this operation returns only when all requests started prior to the state change have completed or when the POA manager is changed to a state other than Discarding. AdapterInactive is the exception raised if the POA manager was in the Inactive state prior to calling this operation.
Note:
POA managers currently in the Inactive state can not change to the Discarding state.
Inactive state
When the POA manager is in the Inactive state, its associated POAs reject incoming requests. This state is used when the associated POAs are to be shut down.
Note:
POA managers in the Inactive state cannot change to any other state.
To change the POA manager to the Inactive state, use
manager.Deactivate(etherealizeObjects, waitForCompletion);
After the state changes, if etherealizeObjects is true, then all associated POAs that have ServantRetentionPolicy.RETAIN and RequestProcessingPolicy.USE_SERVANT_MANAGER set call Etherealize on the Servant Manager for all active objects. If etherealizeObjects is false, then Etherealize is not called. The waitForCompletion option is Boolean. If false, this operation returns immediately after changing the state to Inactive. If true, this operation returns only when all requests started prior to the state change have completed or Etherealize has been called on all associated POAs (that have ServantRetentionPolicy.RETAIN and RequestProcessingPolicy.USE_SERVANT_MANAGER). AdapterInactive is the exception raised if the POA manager was in the Inactive state prior to calling this operation.
Listening and Dispatching: Server Engines, Server Connection Managers, and their properties
Note:
Policies that cover listener and dispatcher features are not supported by POAs. In order to provide these features, a VisiBroker for .NET-specific policy (ServerEnginePolicy) can be used.
VisiBroker for .NET provides a very flexible mechanism to define and tune endpoints for VisiBroker for .NET servers. An endpoint in this context is a destination for a communication channel for clients to communicate with servers. A Server Engine is a virtual abstraction for connection endpoint provided as a configurable set of properties.
A Server Engine abstraction can provide control in terms of:
Server Engine and POAs
A POA on VisiBroker for .NET can have many-to-many relationship with a Server Engine. A POA can be associated with many Server Engines and vice-versa. The manifestation of this fact is that a POA, and hence the Object References on the POA, can support multiple communication channels.
The simplest case is where POAs have their own unique single server engine. Here, requests for different POAs arrive on different ports. A POA can also have multiple server engines. In this scenario, a single POA supports requests coming from multiple input ports.
Notice that POAs can share server engines. When server engines are shared, the POAs listen to the same port. Even though the requests for (multiple) POAs arrive at the same port, they are dispatched correctly because of the POA name embedded in the request. This scenario occurs, for example, when you use a default server engine and create multiple POAs (without specifying a new server engine during the POA creation).
Server Engines are identified by a name and is defined the first time its name is introduced. By default VisiBroker for .NET defines three Server Engine names. They are:
iiop_tp: TCP transport with thread pool dispatcher
iiop_ts: TCP transport with thread per session dispatcher
iiop_tm: TCP transport with main thread dispatcher
Associating a POA with a Server Engine
The default Server Engine associated with POA can be changed by using the property vbroker.se.default. For example, setting
vbroker.se.default=MySE
defines a new server engine with the name MySE. The Root POA and all child POAs created will be associated with this Server Engine by default.
A POA can also be associated with a particular ServerEngine explicitly by using the SERVER_ENGINE_POLICY_TYPE POA policy. For example:
// create ServerEngine policy value
Any seAny = orb.CreateAny();
StringSequenceHelper.Insert(seAny, new String [] {"mySE"});
Policy sePolicy = orb.CreatePolicy(
PortableServerExt.SERVER_ENGINE_POLICY_TYPE.Value, seAny);
// create POA policies
Policy [] policies = {
rootPOA.CreateLifespanPolicy(LifespanPolicyValue.PERSISTENT),
sePolicy
};
// create POA with policies
POA myPOA = rootPOA.CreatePOA("bank_se_policy_poa",
rootPOA.ThePOAManager,
policies);
The POA has an IOR template, profiles for which, are obtained from the Server Engines associated with it.
If you don't specify a server engine policy, the POA assumes a server engine name of iiop_tp and uses the following default values:
vbroker.se.iiop_tp.host=null
vbroker.se.iiop_tp.proxyHost=null
vbroker.se.iiop_tp.scms=iiop_tp
To change the default server engine policy, enter its name using the vbroker.se.default property and define the values for all the components of the new server engine. For example:
vbroker.se.default=abc,def
vbroker.se.abc.host=cob
vbroker.se.abc.proxyHost=null
vbroker.se.abc.scms=cobscm1,cobscm2
vbroker.se.def.host=gob
vbroker.se.def.proxyHost=null
vbroker.se.def.scms=gobscm1
Defining Hosts for Endpoints for the Server Engine
Since Server Engines help define a connection's endpoints, the following properties are provided to specify their hosts:
vbroker.se.<se-name>.host=<host-URL> (vbroker.se.mySE.host=host.borland.com, for example. )
vbroker.se.<se-name>.proxyHost=<proxy-host-URL-or-IP-address> (vbroker.se.mySE.proxyHost=proxy.borland.com, for example.)
The proxyHost property can also take an IP address as its value. Doing so replaces the default hostname in the IOR with this IP address.
The endpoint abstraction of a Server Engine is further fine-grained in terms of configurable set of entities referred to as Server Connection Managers (SCM). A Server Engine can have multiple SCMs. SCMs are not shareable between Server Engines. SCMs are also identified using a name and are defined for a Server Engine using:
vbroker.se.<se-name>.scms=<SCM-name>[,<SCM-name>,...]
Server Connection Managers
The Server Connection Manager defines the configurable components of an endpoint. Its responsibilities are connection resource management, listening for requests, and dispatching requests to its associated POA. Three logical entities, defined through property groups, are provided by the SCM to fulfill these responsibilities:
Each SCM has one Manager, Listener, and Dispatcher. All three, when defined, form a single endpoint definition allowing clients to contact servers.
Manager
Manager is a set of properties defining the configurable portions of a connection resource. VisiBroker for .NET provides a manager of type Socket.
vbroker.se.<se-name>.scm.<scm-name>.manager.type=Local|Socket
You can specify the maximum number of concurrent connections acceptable to the server endpoint using the connectionMax property:
vbroker.se.<se-name>.scm.<scm-name>.manager.connectionMax=<integer>
Setting connectionMax to 0 (zero) indicates that there is no restriction on the number of connections, which is the default setting.
You specify the maximum number of idle seconds using the connectionMaxIdle property:
vbroker.se.<se-name>.scm.<scm-name>.manager.connectionMaxIdle=<seconds>
Setting connectionMaxIdle to 0 (zero) indicates that there is no timeout, which is the default setting.
Garbage collection time can also be specified for the Manager to garbage-collect idled connections. (Connections can idle after the connectionMaxIdle time until they are garbage-collected.) You can use the garbageCollectTimer property to specify the period of garbage collection in seconds:
vbroker.se.<se-name>.scm.<scm-name>.manager.garbageCollectTimer=<seconds>
Garbage collection time is specified through the following property:
vbroker.orb.gcTimeout=<seconds>
A value of 0 (zero) means that the connection will never be garbage collected.
Listener
The Listener is the SCM component that determines how and where the SCM listens for messages. Like the Manager, the Listener is also a set of properties. VisiBroker for .NET defines a IIOP listener for the TCP connections.
Since listeners are close to the actual underlying transport mechanism, their properties are not portable across listener types. Each listener type has its own set of properties, defined below.
IIOP listener properties
IIOP listeners need to define a port and (if desired) a proxy port in conjunction with their hosts. These are set using the port and proxyPort properties, as follows:
vbroker.se.<se-name>.scm.<scm-name>.listener.port=<port>
vbroker.se.<se-name>.scm.<scm-name>.listener.proxyPort=<proxy-port>
Note:
If you do not set the port property (or set it to 0 [zero]), a random port will be selected. A 0 value for the proxyPort property means that the IOR will contain the actual port (defined by the listener.port property or selected by the system randomly). If it is not required to advertise the actual port, set the proxy port to a non-zero (positive) value.
Setting properties to define standard TCP socket options is also supported for send|receive buffer sizes, socket lingering time, and whether or not to keep inactive sockets alive. The following properties are provided for these mechanisms:
vbroker.se.<se-name>.scm.<scm-name>.listener.rcvBuffSize=<bytes>
vbroker.se.<se-name>.scm.<scm-name>.listener.sendBuffSize=<bytes>
vbroker.se.<se-name>.scm.<scm-name>.listener.socketLinger=<seconds>
vbroker.se.<se-name>.scm.<scm-name>.listener.keepAlive=true|false
If for any reason you wish to simply use your system's defaults for the TCP socket properties, simply set the appropriate property to a value of 0 (zero).
VisiBroker for .NET additionally supports a property allowing you to specify your GIOP version:
vbroker.se.<se-name>.scm.<scm-name>.listener.giopVersion=<version>
Dispatcher
The Dispatcher defines a set of properties that determine how the SCM dispatches requests to threads. Three types of dispatchers are provided: ThreadPool, ThreadSession, and MainThread. You set the dispatcher type with the type property:
vbroker.se.<se-name>.scm.<scm-name>.dispatcher.type=ThreadPool|ThreadSession|MainThread
Further control is provided through the SCM for the ThreadPool dispatcher type. The ThreadPool defines the minimum and maximum number of threads that can be created in the thread pool, as well as the maximum time in seconds after which an idled thread is destroyed. These values are controlled with the following properties:
vbroker.se.<se-name>.scm.<scm-name>.dispatcher.threadMin=<integer>
vbroker.se.<se-name>.scm.<scm-name>.dispatcher.threadMax=<integer>
vbroker.se.<se-name>.scm.<scm-name>.dispatcher.threadMaxIdle=<seconds>
When to use these properties
There are many times where you need to change some of the server engine properties. The method for changing these properties depends on what you need. For example, suppose you want to change the port number. You could accomplish this by:
Changing the default listener.port property
Changing the default listener.port property is the simplest method, but this affects all POAs that use the default server engine. This may or may not be what you want.
If you want to change the port number on a specific POA, then you'll have to create a new server engine, define the properties for this new server engine, and then reference the new server engine when creating the POA.
The previous sections show how to update the server engine properties. The following code shows how to create a POA with a user-defined server engine policy:
using System;
using System.IO;
using PortableServer;
using CORBA;
public class Server {
static void Main(string [] args) {
try {
// initialize the ORB
ORB orb = ORB.Init(args);
// get a reference to the root POA
POA rootPOA =
POAHelper.Narrow(orb.ResolveInitialReferences("RootPOA"));
// Create our server engine policy
Any seAny = orb.CreateAny();
StringSequenceHelper.Insert(seAny, new String [] {"mySe"});
Policy sePolicy = orb.CreatePolicy(
PortableServerExt.SERVER_ENGINE_POLICY_TYPE.Value, seAny);
// create policies for our persistent POA
Policy [] policies = {
rootPOA.CreateLifespanPolicy(
LifespanPolicyValue.PERSISTENT), sePolicy
};
// create myPOA with the right policies
POA myPOA = rootPOA.CreatePOA("bank_se_policy_poa",
rootPOA.ThePOAManager, policies);
// create the servant
AccountManagerImpl managerServant = new AccountManagerImpl();
// Decide on the ID for the servant
byte [] managerId = orb.StringToObjectId("BankManager");
// Activate the servant
myPOA.ActivateObjectWithId(managerId, managerServant);
// Obtain the reference
CORBA.Object objRef = myPOA.ServantToReference(managerServant);
// Now write out the IOR
try {
StreamWriter writer = new StreamWriter("ior.dat");
writer.WriteLine(orb.ObjectToString(objRef));
writer.Close();
}
catch (Exception e) {
Console.WriteLine("Error writing the IOR to file ior.dat");
Console.WriteLine(e);
}
// Activate the POA manager
rootPOA.ThePOAManager.Activate();
Console.WriteLine("{0} is ready.", objRef);
// Wait for incoming requests
orb.Run();
}
catch(Exception e) {
Console.WriteLine(e);
}
Console.ReadLine();
}
}
Adapter activators
Adapter activators are associated with POAs and provide the ability to create child POAs on-demand. This can be done during the FindPOA operation, or when a request is received that names a specific child POA.
An adapter activator supplies a POA with the ability to create child POAs on demand, as a side-effect of receiving a request that names the child POA (or one of its children), or when FindPOA is called with an activate parameter value of true. A server that creates all its needed POAs at the beginning of execution does not need to use or provide an adapter activator; it is necessary only for the case in which POAs need to be created during request processing.
While a request from the POA to an adapter activator is in progress, all requests to objects managed by the new POA (or any descendant POAs) will be queued. This serialization allows the adapter activator to complete any initialization of the new POA before requests are delivered to that POA.
Processing requests
Requests contain the Object ID of the target object and the POA that created the target object reference. When a client sends a request, the ORB first locates the appropriate server, or starts the server if needed. It then locates the appropriate POA within that server.
Once the ORB has located the appropriate POA, it delivers the request to that POA. How the request is processed at that point depends on the policies of the POA and the object's activation state. For information about object activation states, see “Activating objects”.
If the POA has ServantRetentionPolicy.RETAIN, the POA looks at the Active Object Map to locate a Servant associated with the Object ID from the request. If a Servant exists, the POA invokes the appropriate method on the Servant.
If the POA has ServantRetentionPolicy.NON_RETAIN or has ServantRetentionPolicy.RETAIN but did not find the appropriate Servant, the following may take place:
If the POA has RequestProcessingPolicy.USE_DEFAULT_SERVANT, the POA invokes the appropriate method on the default Servant.
If the POA has RequestProcessingPolicy.USE_SERVANT_MANAGER, the POA invokes Incarnate or Preinvoke on the Servant Manager.
If the POA has RequestProcessingPolicy.USE_OBJECT_MAP_ONLY, an exception is raised.
If a Servant Manager has been invoked but can not incarnate the object, the Servant Manager can raise a ForwardRequest exception.