The Portable Object Adaptor
Chapter 11. The Portable Object Adaptor
The Portable Object Adaptor chapter has been updated based on CORE changes from ptc/98-09-04.
This chapter describes the Portable Object Adapter, or POA. It presents the design goals, a description of the abstract model of the POA and its interfaces, followed by a detailed description of the interfaces themselves.
Contents
This chapter contains the following sections.
Section Title
|
Page
|
“Overview”
|
11-1
|
“Abstract Model Description”
|
11-2
|
“Interfaces”
|
11-13
|
“IDL for PortableServer module”
|
11-41
|
“UML Description of PortableServer”
|
11-48
|
“Usage Scenarios”
|
11-49
|
11.1 Overview
The POA is designed to meet the following goals:
- Allow programmers to construct object implementations that are portable between different ORB products.
- Provide support for objects with persistent identities. More precisely, the POA is designed to allow programmers to build object implementations that can provide consistent service for objects whose lifetimes (from the perspective of a client holding a reference for such an object) span multiple server lifetimes.
- Provide support for transparent activation of objects.
- Allow a single servant to support multiple object identities simultaneously.
- Allow multiple distinct instances of the POA to exist in a server.
- Provide support for transient objects with minimal programming effort and overhead.
- Provide support for implicit activation of servants with POA-allocated Object Ids.
- Allow object implementations to be maximally responsible for an object’s behavior. Specifically, an implementation can control an object’s behavior by establishing the datum that defines an object’s identity, determining the relationship between the object’s identity and the object’s state, managing the storage and retrieval of the object’s state, providing the code that will be executed in response to requests, and determining whether or not the object exists at any point in time.
- Avoid requiring the ORB to maintain persistent state describing individual objects, their identities, where their state is stored, whether certain identity values have been previously used or not, whether an object has ceased to exist or not, and so on.
- Provide an extensible mechanism for associating policy information with objects implemented in the POA.
- Allow programmers to construct object implementations that inherit from static skeleton classes, generated by OMG IDL compilers, or a DSI implementation.
11.2 Abstract Model Description
The POA interfaces described in this chapter imply a particular abstract computational model. This section presents that model and defines terminology and basic concepts that will be used in subsequent sections.
This section provides the rationale for the POA design, describes some of its intended uses, and provides a background for understanding the interface descriptions.
11.2.1 Model Components
The model supported by the POA is a specialization of the general object model described in the OMA guide. Most of the elements of the CORBA object model are present in the model described here, but there are some new components, and some of the names of existing components are defined more precisely than they are in the CORBA object model. The abstract model supported by the POA has the following components:
- Client—A client is a computational context that makes requests on an object through one of its references.
- Server—A server is a computational context in which the implementation of an object exists. Generally, a server corresponds to a process. Note that client and server are roles that programs play with respect to a given object. A program that is a client for one object may be the server for another. The same process may be both client and server for a single object.
- Object—In this discussion, we use object to indicate a CORBA object in the abstract sense, that is, a programming entity with an identity, an interface, and an implementation. From a client’s perspective, the object’s identity is encapsulated in the object’s reference. This specification defines the server’s view of object identity, which is explicitly managed by object implementations through the POA interface.
- Servant—A servant is a programming language object or entity that implements requests on one or more objects. Servants generally exist within the context of a server process. Requests made on an object’s references are mediated by the ORB and transformed into invocations on a particular servant. In the course of an object’s lifetime it may be associated with (that is, requests on its references will be targeted at) multiple servants.
- Object Id—An Object Id is a value that is used by the POA and by the user-supplied implementation to identify a particular abstract CORBA object. Object Id values may be assigned and managed by the POA, or they may be assigned and managed by the implementation. Object Id values are hidden from clients, encapsulated by references. Object Ids have no standard form; they are managed by the POA as uninterpreted octet sequences.
Note that the Object Id defined in this specification is a mechanical device used by an object implementation to correlate incoming requests with references it has previously created and exposed to clients. It does not constitute a unique logical identity for an object in any larger sense. The assignment and interpretation of Object Id values is primarily the responsibility of the application developer, although the SYSTEM_ID policy enables the POA to generate Object Id values for the application. - Object Reference—An object reference in this model is the same as in the CORBA object model. This model implies, however, that a reference specifically encapsulates an Object Id and a POA identity.
Note that a concrete reference in a specific ORB implementation will contain more information, such as the location of the server and POA in question. For example, it might contain the full name of the POA (the names of all POAs starting from the root and ending with the specific POA). The reference might not, in fact, actually contain the Object Id, but instead contain more compact values managed by the ORB which can be mapped to the Object Id. This is a description of the abstract information model implied by the POA. Whatever encoding is used to represent the POA name and the Object Id must not restrict the ability to use any legal character in a POA name or any legal octet in an Object Id. - Policy—A Policy is an object associated with a POA by an application in order to specify a characteristic shared by the objects implemented in that POA. This specification defines policies controlling the POA’s threading model as well as a variety of other options related to the management of objects. Other specifications may define other policies that affect how an ORB processes requests on objects implemented in the POA.
- POA Manager—A POA manager is an object that encapsulates the processing state of one or more POAs. Using operations on a POA manager, the developer can cause requests for the associated POAs to be queued or discarded. The developer can also use the POA manager to deactivate the POAs.
- Servant Manager—A servant manager is an object that the application developer can associate with a POA. The ORB will invoke operations on servant managers to activate servants on demand, and to deactivate servants. Servant managers are responsible for managing the association of an object (as characterized by its Object Id value) with a particular servant, and for determining whether an object exists or not. There are two kinds of servant managers, called ServantActivator and ServantLocator; the type used in a particular situation depends on policies in the POA.
- Adapter Activator—An adapter activator is an object that the application developer can associate with a POA. The ORB will invoke an operation on an adapter activator when a request is received for a child POA that does not currently exist. The adapter activator can then create the required POA on demand.
11.2.2 Model Architecture
This section describes the architecture of the abstract model implied by the POA, and the interactions between various components. The ORB is an abstraction visible to both the client and server. The POA is an object visible to the server. User-supplied implementations are registered with the POA (this statement is a simplification; more detail is provided below). Clients hold references upon which they can make requests. The ORB, POA, and implementation all cooperate to determine which servant the operation should be invoked on, and to perform the invocation.
Figure 11-1 shows the detail of the relationship between the POA and the implementation. Ultimately, a POA deals with an Object Id and an active servant. By active servant, we mean a programming object that exists in memory and has been presented to the POA with one or more associated object identities. There are several ways for this association to be made.
Figure 11-1 Abstract POA Model
If the POA supports the RETAIN policy, it maintains a map, labeled Active Object Map, that associates Object Ids with active servants, each association constituting an active object. If the POA has the USE_DEFAULT_SERVANT policy, a default servant may be registered with the POA. Alternatively, if the POA has the USE_SERVANT_MANAGER policy, a user-written servant manager may be registered with the POA. If the Active Object Map is not used, or a request arrives for an object not present in the Active Object Map, the POA either uses the default servant to perform the request or it invokes the servant manager to obtain a servant to perform the request. If the RETAIN policy is used, the servant returned by a servant manager is retained in the Active Object Map. Otherwise, the servant is used only to process the one request.
In this specification, the term active is applied equally to servants, Object Ids, and objects. An object is active in a POA if the POA’s Active Object Map contains an entry that associates an Object Id with an existing servant. When this specification refers to active Object Ids and active servants, it means that the Object Id value or servant in question is part of an entry in the Active Object Map. An Object Id can appear in a POA's Active Object Map only once.
Figure 11-2 POA Architecture
11.2.3 POA Creation
To implement an object using the POA requires that the server application obtain a POA object. A distinguished POA object, called the root POA, is managed by the ORB and provided to the application using the ORB initialization interface under the initial object name “RootPOA.” The application developer can create objects using the root POA if those default policies are suitable. The root POA has the following policies.
- Thread Policy: ORB_CTRL_MODEL
- Lifespan Policy: TRANSIENT
- Object Id Uniqueness Policy: UNIQUE_ID
- Id Assignment Policy: SYSTEM_ID
- Servant Retention Policy: RETAIN
- Request Processing Policy: USE_ACTIVE_OBJECT_MAP_ONLY
- Implicit Activation Policy: IMPLICIT_ACTIVATION
The developer can also create new POAs. Creating a new POA allows the application developer to declare specific policy choices for the new POA and to provide a different adapter activator and servant manager (these are callback objects used by the POA to activate objects and nested POAs on demand). Creating new POAs also allows the application developer to partition the name space of objects, as Object Ids are interpreted relative to a POA. Finally, by creating new POAs, the developer can independently control request processing for multiple sets of objects.
A POA is created as a child of an existing POA using the create_POA operation on the parent POA. When a POA is created, the POA is given a name that must be unique with respect to all other POAs with the same parent.
POA objects are not persistent. No POA state can be assumed to be saved by the ORB. It is the responsibility of the server application to create and initialize the appropriate POA objects during server initialization or to set an AdapterActivater to create POA objects needed later.
Creating the appropriate POA objects is particularly important for persistent objects, objects whose existence can span multiple server lifetimes. To support an object reference created in a previous server process, the application must recreate the POA that created the object reference as well as all of its ancestor POAs. To ensure portability, each POA must be created with the same name as the corresponding POA in the original server process and with the same policies. (It is the user’s responsibility to create the POA with these conditions.)
A portable server application can presume that there is no conflict between its POA names and the POA names chosen by other applications. It is the responsibility of the ORB implementation to provide a way to support this behavior.
11.2.4 Reference Creation
Object references are created in servers. Once they are created, they may be exported to clients.
From this model’s perspective, object references encapsulate object identity information and information required by the ORB to identify and locate the server and POA with which the object is associated (that is, in whose scope the reference was created.) References are created in the following ways:
- The server application may directly create a reference with the create_reference and create_reference_with_id operations on a POA object. These operations collect the necessary information to constitute the reference, either from information associated with the POA or as parameters to the operation. These operations only create a reference. In doing so, they bring the abstract object into existence, but do not associate it with an active servant.
- The server application may explicitly activate a servant, associating it with an object identity using the activate_object or activate_object_with_id operations. Once a servant is activated, the server application can map the servant to its corresponding reference using the servant_to_reference or id_to_reference operations.
- The server application may cause a servant to implicitly activate itself. This behavior can only occur if the POA has been created with the IMPLICIT_ACTIVATION policy. If an attempt is made to obtain an object reference corresponding to an inactive servant, the POA may automatically assign a generated unique Object Id to the servant and activate the resulting object. The reference may be obtained by invoking POA::servant_to_reference with an inactive servant, or by performing an explicit or implicit type conversion from the servant to a reference type in programming language mappings that permit this conversion.
Once a reference is created in the server, it can be made available to clients in a variety of ways. It can be advertised through the OMG Naming and Trading Services. It can be converted to a string via ORB::object_to_string and published in some way that allows the client to discover the string and convert it to a reference using ORB::string_to_object. It can be returned as the result of an operation invocation.
Once a reference becomes available to a client, that reference constitutes the identity of the object from the client’s perspective. As long as the client program holds and uses that reference, requests made on the reference should be sent to the “same” object.
Note – The meaning of object identity and “sameness” is at present the subject of debate in the OMG. This specification does not attempt to resolve that debate in any way, particularly by defining a concrete notion of identity that is exposed to clients, beyond the existing notions of identity described in the CORBA specifications and the OMA guide.
The states of servers and implementation objects are opaque to clients. This specification deals primarily with the view of the ORB from the server’s perspective.
11.2.5 Object Activation States
At any point in time, a CORBA object may or may not be associated with an active servant.
If the POA has the RETAIN policy, the servant and its associated Object Id are entered into the Active Object Map of the appropriate POA. This type of activation can be accomplished in one of the following ways.
- The server application itself explicitly activates individual objects (via the activate_object or activate_object_with_id operations).
- The server application instructs the POA to activate objects on demand by having the POA invoke a user-supplied servant manager. The server application registers this servant manager with set_servant_manager.
- Under some circumstances (when the IMPLICIT_ACTIVATION policy is also in effect and the language binding allows such an operation), the POA may implicitly activate an object when the server application attempts to obtain a reference for a servant that is not already active (that is, not associated with an Object Id).
If the USE_DEFAULT_SERVANT policy is also in effect, the server application instructs the POA to activate unknown objects by having the POA invoke a single servant no matter what the Object Id is. The server application registers this servant with set_servant.
If the POA has the NON_RETAIN policy, for every request, the POA may use either a default servant or a servant manager to locate an active servant. From the POA’s point of view, the servant is active only for the duration of that one request. The POA does not enter the servant-object association into the Active Object Map.
11.2.6 Request Processing
A request must be capable of conveying the Object Id of the target object as well as the identification of the POA that created the target object reference. When a client issues a request, the ORB first locates an appropriate server (perhaps starting one if needed) and then it locates the appropriate POA within that server.
If the POA does not exist in the server process, the application has the opportunity to re-create the required POA by using an adapter activator. An adapter activator is a userimplemented object that can be associated with a POA. It is invoked by the ORB when a request is received for a non-existent child POA. The adapter activator has the opportunity to create the required POA. If it does not, the client receives the OBJECT_NOT_EXIST exception.
Once the ORB has located the appropriate POA, it delivers the request to that POA. The further processing of that request depends both upon the policies associated with that POA as well as the object's current state of activation.
If the POA has the RETAIN policy, the POA looks in the Active Object Map to find out if there is a servant associated with the Object Id value from the request. If such a servant exists, the POA invokes the appropriate method on the servant.
If the POA has the NON_RETAIN policy or has the RETAIN policy but didn't find a servant in the Active Object Map, the POA takes the following actions:
- If the POA has the USE_DEFAULT_SERVANT policy, a default servant has been associated with the POA so the POA will invoke the appropriate method on that servant. If no servant has been associated with the POA, the POA raises the OBJ_ADAPTER system exception.
- If the POA has the USE_SERVANT_MANAGER policy, a servant manager has been associated with the POA so the POA will invoke incarnate or preinvoke on it to find a servant that may handle the request. (The choice of method depends on the NON_RETAIN or RETAIN policy of the POA.) If no servant manager has been associated with the POA, the POA raises the OBJ_ADAPTER system exception.
- If the USE_OBJECT_MAP_ONLY policy is in effect, the POA raises the OBJECT_NOT_EXIST system exception.
If a servant manager is located and invoked, but the servant manager is not directly capable of incarnating the object, it (the servant manager) may deal with the circumstance in a variety of ways, all of which are the application’s responsibility.
Any system exception raised by the servant manager will be returned to the client in the reply. In addition to standard CORBA exceptions, a servant manager is capable of raising a ForwardRequest exception. This exception includes an object reference. The ORB will process this exception as stated below.
11.2.7 Implicit Activation
A POA can be created with a policy that indicates that its objects may be implicitly activated. This policy, IMPLICIT_ACTIVATION, also requires the SYSTEM_ID and RETAIN policies. When a POA supports implicit activation, an inactive servant may be implicitly activated in that POA by certain operations that logically require an Object Id to be assigned to that servant. Implicit activation of an object involves allocating a system-generated Object Id and registering the servant with that Object Id in the Active Object Map. The interface associated with the implicitly activated object is determined from the servant (using static information from the skeleton, or, in the case of a dynamic servant, using the _primary_interface() operation).
- The POA::servant_to_reference operation, which takes a servant parameter and returns a reference.
- The POA::servant_to_id operation, which takes a servant parameter and returns an Object Id.
- Operations supported by a language mapping to obtain an object reference or an Object Id for a servant. For example, the _this() servant member function in C++ returns an object reference for the servant.
- Implicit conversions supported by a language mapping that convert a servant to an object reference or an Object Id.
The last two categories of operations are language-mapping-dependent
If the POA has the UNIQUE_ID policy, then implicit activation will occur when any of these operations are performed on a servant that is not currently active (that is, it is associated with no Object Id in the POA's Active Object Map).
If the POA has the MULTIPLE_ID policy, the servant_to_reference and servant_to_id operations will always perform implicit activation, even if the servant is already associated with an Object Id. The behavior of language mapping operations in the MULTIPLE_ID case is specified by the language mapping. For example, in C++, the _this() servant member function will not implicitly activate a MULTIPLE_ID servant if the invocation of _this() is immediately within the dynamic context of a request invocation directed by the POA to that servant; instead, it returns the object reference used to issue the request.
Note – The exact timing of implicit activation is ORB implementation-dependent. For example, instead of activating the object immediately upon creation of a local object reference, the ORB could defer the activation until the Object Id is actually needed (for example, when the object reference is exported outside the process).
11.2.8 Multi-threading
The POA does not require the use of threads and does not specify what support is needed from a threads package. However, in order to allow the development of portable servers that utilize threads, the behavior of the POA and related interfaces when used within a multiple-thread environment must be specified.
Specifying this behavior does not require that an ORB must support being used in a threaded environment, nor does it require that an ORB must utilize threads in the processing of requests. The only requirement given here is that if an ORB does provide support for multi-threading, these are the behaviors that will be supported by that ORB. This allows a programmer to take advantage of multiple ORBs that support threads in a portable manner across those ORBs.
The POA’s processing is affected by the thread-related calls available in the ORB: work_pending, perform_work, run, and shutdown.
11.2.8.1 POA Threading Models
The POA supports two models of threading when used in conjunction with multithreaded ORB implementations; ORB controlled and single thread behavior. The two models can be used together or independently. Either model can be used in environments where a single-threaded ORB is used.
The threading model associated with a POA is indicated when the POA is created by including a ThreadPolicy object in the policies parameter of the POA’s create_POA operation. Once a POA is created with one model, it cannot be changed to the other. All uses of the POA within the server must conform to that threading model associated with the POA.
11.2.8.2 Using the Single Thread Model
Requests for a single-threaded POA are processed sequentially. In a multi-threaded environment, all upcalls made by this POA to implementation code (servants, servant managers, and adapter activators) are made in a manner that is safe for code that is multi-thread-unaware.
11.2.8.3 Using the ORB Controlled Model
The ORB controlled model of threading is used in environments where the developer wants the ORB/POA to control the use of threads in the manner provided by the ORB. This model can also be used in environments that do not support threads.
In this model, the ORB is responsible for the creation, management, and destruction of threads used with one or more POAs.
11.2.8.4 Limitations When Using Multiple Threads
There are no guarantees that the ORB and POA will do anything specific about dispatching requests across threads with a single POA. Therefore, a server programmer who wants to use one or more POAs within multiple threads must take on all of the serialization of access to objects within those threads.
There may be requests active for the same object being dispatched within multiple threads at the same time. The programmer must be aware of this possibility and code with it in mind.
11.2.9 Dynamic Skeleton Interface
The POA is designed to enable programmers to connect servants to:
- type-specific skeletons, typically generated by OMG IDL compilers, or
- dynamic skeletons.
Servants that are members of type-specific skeleton classes are referred to as typespecific servants. Servants connected to dynamic skeletons are used to implement the Dynamic Skeleton Interface (DSI) and are referred to as DSI servants.
Whether a CORBA object is being incarnated by a DSI servant or a type-specific servant is transparent to its clients. Two CORBA objects supporting the same interface may be incarnated, one by a DSI servant and the other with a type-specific servant. Furthermore, a CORBA object may be incarnated by a DSI servant only during some period of time, while the rest of the time is incarnated by a static servant.
The mapping for POA DSI servants is language-specific, with each language providing a set of interfaces to the POA. These interfaces are used only by the POA. The interfaces required are the following.
- Take a CORBA::ServerRequest object from the POA and perform the processing necessary to execute the request.
- Return the Interface Repository Id identifying the most-derived interface supported by the target CORBA object in a request.
The reason for the first interface is the entire reason for existence of the DSI: to be able to handle any request in the way the programmer wishes to handle it. A single DSI servant may be used to incarnate several CORBA objects, potentially supporting different interfaces.
The reason for the second interface can be understood by comparing DSI servants to type-specific servants.
A type-specific servant may incarnate several CORBA objects but all of them will support the same IDL interface as the most-derived IDL interface. In C++, for example, an IDL interface Window in module GraphicalSystem will generate a type-specific skeleton class called Window in namespace POA_GraphicalSystem. A type-specific servant which is directly derived from the
POA_GraphicalSystem::Window skeleton class may incarnate several CORBA objects at a time, but all those CORBA objects will support the GraphicalSystem::Window interface as the most-derived interface.
A DSI servant may incarnate several CORBA objects, not necessarily supporting the same IDL interface as the most-derived IDL interface.
In both cases (type-specific and DSI) the POA may need to determine, at runtime, the Interface Repository Id identifying the most-derived interface supported by the target CORBA object in a request. The POA should be able to determine this by asking the servant that is going to serve the CORBA object.
In the case of type-specific servants, the POA obtains that information from the typespecific skeleton class from which the servant is directly derived. In the case of DSI servants, the POA obtains that information by using the second language-specific interface above.
11.2.10 Location Transparency
The POA supports location transparency for objects implemented using the POA.Unless explicitly stated to the contrary, all POA behavior described in this specification applies regardless of whether the client is local (same process) or remote. For example, like a request from a remote client, a request from a local client may
cause object activation if the object is not active, block indefinitely if the target object's POA is in the holding state, be rejected if the target object's POA is in the discarding or inactive states, be delivered to a thread-unaware object implementation, or be delivered to a different object if the target object's servant manager raises the ForwardRequest exception. The Object Id and POA of the target object will also be available to the server via the Current object, regardless of whether the client is local or remote.
Note – The implication of these requirements on the ORB implementation is to require the ORB to mediate all requests to POA-based objects, even if the client is co-resident in the same process. This specification is not intended to change CORBAServices specifications that allow for behaviors that are not location transparent. This specification does not prohibit (nonstandard) POA extensions to support object behavior that is not location-transparent.