The POA mapping

The POA interface

The POA interface is rather big but simple:

module PortableServer {
// lots of useless stuff here
	interface POA {

	// Object activation functions
	ObjectId activate_object (in Servant p_servant)
		raises ServantAlreadyActive, WrongPolicy);
	void activate_object_with_id   (in ObjectId,
					in Servant p_servant)
		raises (ServantAlreadyActive, ObjectAlreadyActive, 
			WrongPolicy);
	void deactivate_object (in ObjectId id) 
		raises (ObjectNotActive, WrongPolicy);

	// Reference creation functions
	Object create_reference (in CORBA::RepositoryId repid)
		raises (WrongPolicy);
	Object create_reference_with_id (in ObjectId id,
					in CORBA::RepositoryId repid)
		raises (WrongPolicy);

	// Identity Mapping functions
	ObjectId servant_to_id (in Servant p_servant)
		raises (ServantNotActive, WrongPolicy);
	Object servant_to_reference (in Servant p_servant)
		raises (ServantNotActive, WrongPolicy);
	Servant reference_to_servant (in Object reference)
		raises (ObjectNotActive, WrongAdapter, WrongPolicy);
	ObjectId reference_to_id (in Object reference)
		raises (WrongAdapter, WrongPolicy);
	Servant id_to_servant (in ObjectId oid)
		raises (ObjectNotActive, WrongPolicy);
	Object id_to_reference (in ObjectId oid)
		raises (ObjectNotActive, WrongPolicy);


	};
};

What you see here is an excerpt of the real POA interface: i removed all the exception definitions and many other function definitions which are not relevant here. The functions i made disappear will be discussed in the last part of this chapter.

Now, let's look at these functions and their use:

Table 4-1. The POA interface

Function NameFunction Use
activate_objectThis function will register the object implementation represented by the Servant object against the POA and will return the ObjectId which can then be used with the id_to_reference function to get the object reference associated with this interface implementation.
activate_object_with_idThis function will register the object implementation represented by the Servant object against the POA and will associate it the id parameter as an ObjectId. The ObjectId could be generated with a call to create_reference, then reference_to_id .
deactivate_objectThis function will unregister an object specified by its ObjectId (obtained through the reference_to_id or servant_to_id function).
create_referenceThis function will create an Object reference from the object implementation (The Servant object).
create_reference_with_idThis function should be used only for well known objects whose ObjectId is well known...
servant_to_idThis function's signature makes things rather obvious. However, it is interesting to note that if the Servant was not activated, it will return a ServantNotActive exception which means that this function cannot be called before activating the object with one of activate_object or activate_object_with_id.
servant_to_referenceThis function's signature makes things rather obvious. However, it is interesting to note that if the Servant was not activated, it will return a ServantNotActive exception which means that this function cannot be called before activating the object with one of activate_object or activate_object_with_id.
id_to_servantThis function's signature makes things rather obvious. However, it is interesting to note that if the object associated to the ObjectId was not activated, it will return an ObjectNotActivated exception which means that this function cannot be called before activating the object with one of activate_object or activate_object_with_id.
id_to_referenceThis function's signature makes things rather obvious. However, it is interesting to note that if the object associated to the ObjectId was not activated, it will return an ObjectNotActivated exception which means that this function cannot be called before activating the object with one of activate_object or activate_object_with_id.
reference_to_servantThis function's signature makes things rather obvious. However, it is interesting to note that if the object associated to the object reference was not activated, it will return an ObjectNotActivated exception which means that this function cannot be called before activating the object with one of activate_object or activate_object_with_id.
reference_to_idThis function's signature makes things rather obvious. This function is different from all the other precedent functions: it will not throw any NotActivated exception which means that it may be used after a call to create_reference to generate the correct ObjectId to use for the activate_object_with_id functions.

Here is some sample code using these functions:

/* sample code using activate_object */
ObjectId obj_id;
CORBA_Object obj;
obj_id = PortableServer_POA_activate_object (poa, servant, &ev);
/* now, we can register this CORBA_Object 
* in the Naming Service or with an ior string
*/
obj = PortableServer_POA_id_to_reference (poa, obj_id, &ev);

/* sample code using activate_object_with_id */
CORBA_Object obj;
/* note that PortableServer_string_to_id's use 
* is detailed a later. suffice it to say that 
* it returns an ObjectId
*/
PortableServer_POA_activate_object_with_id (poa,
	PortableServer_string_to_id ("my_small_servant", &ev),
	servant, 
	&ev);

obj = Portable_Server_POA_servant_to_reference (poa, servant, &ev);
/* now, we can register this CORBA_Object 
* in the Naming Service or with an ior string
*/

Servants

All these functions show how a servant is registered against the POA. Servants are language dependent. Their structure and their use is completely mapping dependent. As we allready explained it sooner, we only show the C-mapping in this introduction which is why we will look only at the C way of creating POAs.

The idea is to pass some initialization function a data structure which holds the list of function pointers for the implementation of the object's methods. Such a data structure is called an EPV (entry point vector). The Servant data structure holds such an EPV.

Here is for example the data structure which would be generated for the following interface definition:

// idl interface
module FruitsBasket {
	interface Apple {
		void EatMe ();
		void ThrowMe ();
	};
};
typedef struct {
	void *_private; /* ORB specific data */
	void (*EatMe) (PortableServer_Servant servant, CORBA_Environment * ev);
	void (*ThrowMe) (PortableServer_Servant servant, CORBA_Environment * ev);
} POA_FruitsBasket_Apple__epv;

typedef struct {
	PortableServer_ServantBase__epv *_base_epv;
	POA_FruitsBasket_Apple__epv *FruitsBasket_Apple_epv;
} POA_FruitsBasket_Apple__vepv;

typedef struct {
	void *_private; /* ORB specific data */
	POA_FruitsBasket_Apple__vepv *vepv;
} POA_FruitsBasket_Apple;

extern void POA_FruitsBasket_Apple__init(POA_FruitsBasket_Apple servant,
	CORBA_Environment * ev);
extern void POA_FruitsBasket_Apple__fini(POA_FruitsBasket_Apple servant,
	CORBA_Environment * ev);

A servant is thus nothing more than a structure which holds an EPV specific to the object implementation and a generic EPV called the _base_epv. The specific EPV is rather self explanatory: function pointers are listed there, waiting to be filled. The base EPV was not shown there: it is used to hold some information specific to the servant itself (in fact, a servant may be responsible for more than one object implementation but it would be overkill to care about this).

Now, here is the PortableServer_ServantBase__epv structure:

typedef struct PortableServer_ServantBase__epv {
void *private;  /* ORB specific data */
/* finalization routine called 
* to destroy any Servant data 
*/
void (*finalize) (PortableServer_Servant, CORBA_Environment *);
/* The POA used by this Servant */
PortableServer_POA (*default_POA) (PortableServer_Servant, 
	CORBA_Environment *);
} PortableServant_ServantBase__epv;

If the finalize and default_poa members are NULL when the Servant is passed to the POA_FruitsBasket_Apple__init, the ORB will initialize them with standard default values. default_POA is defaulted to the "RootPOA", the POA returned by CORBA_ORB_resolve_initial_reference (orb, "RootPOA", &ev) . Otherwise, the ORB will assume the application initialized these fields correctly.

Typically, such a set of data structures would be initialized as follows:

void MyEatMe (PortableServer_Servant servant, 
	CORBA_Environment * ev)
{
/* here is your own code which 
* corresponds to the object implementation 
*/
}
void MyThrowMe (PortableServer_Servant servant, 
	CORBA_Environment * ev)
{
/* here is your own code which 
* corresponds to the object implementation 
*/
}

PortableServer_ServantBase__epv base_epv {
	NULL, /* ORB specific data */
	NULL, /* finalize method */
	NULL  /* default POA */
}

POA_FruitsBasket_Apple__epv Apple_epv {
	NULL,    /* ORB specific data */
	MyEatMe,
	MyThrowMe
};

POA_FruitsBasket_Apple__vepv Apple_vepv {
	&base_epv,
	&Apple_epv
};

POA_FruitsBasket_Apple Apple_servant = {
	NULL,
	&Apple_vpev
};

Then, the only thing left to do is to call POA_FruitsBasket_Apple__init ( Apple_servant, &ev). Now, the Servant is registered against the POA but we still need to activate this object implementation, get a valid object reference back and register it against the Name Service. Here is the complete sample code:

#include <orb/orbit.h>
#include <ORBitservices/CosNaming.h>

void MyEatMe (PortableServer_Servant servant, 
CORBA_Environment * ev)
{
/* 
	here is your own code which 
	corresponds to the object 
	implementation 
*/
}
void MyThrowMe (PortableServer_Servant servant, 
CORBA_Environment * ev)
{
/* 
	here is your own code which 
	corresponds to the object 
	implementation 
*/
}

PortableServer_ServantBase__epv base_epv {
	NULL, /* ORB specific data */
	NULL, /* finalize method */
	NULL  /* default POA */
}

POA_FruitsBasket_Apple__epv Apple_epv {
	NULL,    /* ORB specific data */
	MyEatMe,
	MyThrowMe
};

POA_FruitsBasket_Apple__vepv Apple_vepv {
	&base_epv,
	&Apple_epv
};

POA_FruitsBasket_Apple Apple_servant = {
	NULL,
	&Apple_vpev
};

int main (int argc, char **argv)
{
CORBA_Environment ev;
CORBA_ORB orb;
PortableServer_POA root_poa;
ObjectId *obj_id;
CORBA_Object obj;
CosNaming_NamingContext *root_name;
CosNaming_NameComponent name_component[1] = { {"MyApple", "server"} };
CosNaming_Name name = {1, 1, name_component, CORBA_FALSE};


CORBA_exception_init (&ev);
orb = CORBA_ORB_init (&argc, argv, 
	"orbit-local-orb", 
	&ev);

POA_FruitsBasket_Apple__init (orb, 
	Apple_servant, 
	&ev);
if (ev->_major != CORBA_NO_EXCEPTION) {
	fprintf (stderr, 
		"Error: exception during Servant initialization: %s\n", 
		CORBA_exception_id(&ev));
	CORBA_exception_free (&ev);
	exit 1;
}

root_poa = CORBA_ORB_resolve_initial_references (orb, 
	"RootPOA", 
	&ev);
if (ev->_major != CORBA_NO_EXCEPTION) {
	fprintf (stderr, 
		"Error: exception during RootPOA initialization: %s\n", 
		CORBA_exception_id(&ev));
	CORBA_exception_free (&ev);
	exit 1;
}

/* activate object */
obj_id = PortableServer_POA_activate_object (root_poa,
	&Apple_servant,
	&ev);
/* get an object reference */
obj = PortableServer_POA_id_to_reference (poa,
	obj_id,
	&ev);

/* register the object against the naming service */
root_name = CORBA_ORB_resolve_initial_service (orb, 
	"NameService", 
	&ev);
if (ev->_major != CORBA_NO_EXCEPTION) {
	fprintf (stderr, 
		"Error: could not get name service: %s\n", 
		CORBA_exception_id(&ev));
	exit 1;
}
CosNaming_NamingContext_bind (root_amp, 
	&name, 
	obj, 
	&ev);
if (ev->_major != CORBA_NO_EXCEPTION) {
	fprintf (stderr, 
		"Error: could not register object: %s\n", 
		CORBA_exception_id(&ev));
	exit 1;
}
CORBA_free (root_poa);
CORBA_exception_free (&ev);
exit 0;
}

pfew !! This was tough !! ... However, you are just beginning to get into CORBA hard stuff. This code has simplifications over real things. Here, we assumed that the Po was already ready to run, and we used the RootPOA for simplification which is not a good idea if you have hundreds of objects: they would all use the same POA which would induce great performance problems.

More functions

Before getting into the real hard stuff, here is a small but useful API which is specific to the C mapping: it is useful when dealing with ObjectId structures. Their signatures are enough to understand their use so...

PortableServer_ObjectId   * PortableServer_string_to_ObjectId (CORBA_Char *string, 
	CORBA_Environment *ev);

CORBA_Char                * PortableServer_string_to_ObjectId (PortableServer_ObjectId *obj, 
	CORBA_Environment *ev);