Chapter 4: Object and Implementation Activation

This chapter discusses how objects are implemented and made available to client applications. It includes the following major sections:

Object Implementation

The Basic Object Adaptor

Object Activation Daemon

Unregistering Implementations

ORB Interface to the OAD

Activating Objects Directly

Activating Objects with the BOA

Object and Implementation Deactivation

Object Implementation

An object implementation provides the state and processing activities for the ORB objects used by client applications. An ORB object is created when its implementation class is instantiated in C++ by an implementation process or server. An object implementation uses the Basic Object Adaptor, or BOA, to activate its ORB objects so that they can be used by client applications. ORB objects fall into two categories: transient and persistent.

Transient Objects

Objects that are only available during the lifetime of the process that created them are called transient objects. Transient objects are not registered with VisiBroker's directory service. Only those entities that possess an explicit object reference to a transient object may invoke its methods. Figure 4-1 shows you how to modify the library application so that library_server is created as a transient object. The scope must be set prior to instantiating the object.


#include <lib_srv.h>

int main(int argc, char **argv)

{

// Initialize ORB and Basic Object Adaptor (BOA)

CORBA::ORB_var orb = CORBA::ORB_init(argc, argv);

CORBA::BOA_var boa = orb->BOA_init(argc, argv);

// Set local registration scope

boa->scope(CORBA::BOA::SCOPE_LOCAL);

// Instantiate the Library class as a transient object

Library library_server();

// Since Library object is transient, it won't get

// registered with the directory service

boa->obj_is_ready(&library_server);

...

};

Handling Transient Object References

Clients can only access objects of transient objects when passed as an argument, as defined by the IDL; for instance, object_to_string will fail.

Persistent Objects

An object that remains valid beyond the lifetime of the process that created it is called a persistent object. These objects have a global scope and are registered with VisiBroker's directory service, which allow them to be located and used by client applications. Persistent objects may also be registered with the Object Activation Daemon, enabling the servers that implement them to be activated on demand. You can use persistent objects to implement long-running servers that provide long-term tasks. Figure 4-2 shows the creation and registration of a persistent object.

Note: Registration is handled by the boa::obj_is_ready method.

The following example shows the creating and activating of a persistent object.


#include <lib_srv.h>

int main(int argc, char **argv)

{

// Initialize ORB and Basic Object Adaptor (BOA)

CORBA::ORB_var orb = CORBA::ORB_init(argc, argv);

CORBA::BOA_var boa = orb->BOA_init(argc, argv);

// Instantiate the Library class

Library library_server();

// Or

// Library * library_server = new Library;


// Register the Library object with directory service

boa->obj_is_ready(&library_server);


// Server is ready to receive requests

boa->impl_is_ready();

Note: You do not have to set the scope of a persistent object because the default scope is global, or persistent.

Checking for Persistent Objects

Figure 4-3 shows a method your client application can use to determine whether a persistent or transient object implementation is associated with a given object reference. It is important to know whether or not an object is persistent because some methods for
manipulating object references will fail if the object is transient. The _is_persistent method returns 1 if the object is persistent and 0 if the object is transient.

The following example shows the method for checking for persistent object implementations.


class Object {

...

Boolean _is_persistent() const;

...

};

Object Registration

Once a server has instantiated the ORB objects that it offers, the BOA must be notified when the objects have been initialized. Lastly, the BOA is notified when the server is ready to receive requests from client applications.

The obj_is_ready method notifies the BOA that a particular ORB object is ready to receive requests from client applications. If your server offers more than one ORB object, it must make a call to obj_is_ready for each object, passing the object reference as an argument.

If the object reference passed to obj_is_ready represents a persistent object, the BOA will register the object with VisiBroker's directory service. If the object is transient, no such registration will occur.

Note: When obj_is_ready is not called and a client attempts to call _bind, the exception NO_IMPLEMENT is raised.

Once all of the objects have been instantiated and all the calls to obj_is_ready have been made, the server must call impl_is_ready to enter an event loop and await client requests. Chapter 7 in this guide discusses event handling in detail.

The Basic Object Adaptor

VisiBroker's BOA provides several important functions to client applications and the object implementations they use. It is important to realize that an object may reside in the same process as its client application or it may reside in a separate processes called servers. Servers may contain and offer a single object or multiple objects. Furthermore, servers may be activated by the BOA on demand or they may be started by some entity external to the BOA.

Object Server Activation Policies

The CORBA specification defines four activation policies that describe the way in which an object implementation is started and the manner in which it may be accessed by a client application. These activation policies only apply to persistent objects, not transient objects.

Shared Server Policy

When the shared server policy is specified, only one server is launched regardless of the number of clients; the clients share the server. Along with persistent servers, shared servers are the most common types of servers.

Persistent Server Policy

This policy describes servers that, like shared servers, implement multiple objects. Persistent servers are started by some entity outside of the Basic Object Adaptor, but they still register their objects and receive requests using the BOA.

Unshared Server Policy

Unshared servers are processes that implement a single object. A client application causes this type of server to be activated. Once that client exits, the unshared server will exit.

Server-Per-Method Policy

This activation policy requires a server process to be started for each method that is invoked. After the method has been completed, the server will exit. Subsequent method invocations on the same object will require a new server process to be started.

Object Activation Daemon

You can register an object implementation with VisiBroker's Object Activation Daemon to automatically activate the implementation when a client requests a bind to the object. Object implementations can be registered using a command-line interface or programmatically with the BOA::create method. There is also an ORB interface to the OAD, described in "ORB Interface to the OAD" on page 4-14. In each case, the interface name, object name, the activation policy, and the executable program representing the implementation must be specified.

The Implementation Repository

All object implementations registered with the OAD are stored in an implementation repository, maintained by the OAD. By default, the implementation repository data are stored in a file named impl_rep. This file's path name is dependent on where VisiBroker was installed on your system. If VisiBroker was installed in /usr/local/visibroker/, then the path to this file would be /usr/local/visibroker/adm/impl_dir/impl_rep. These defaults can be overridden using OAD environment variables, described in the VisiBroker for C++ Reference Guide.

OAD Registration with regobj

The regobj command can be used to register an object implementation from the command line or from within a script. The required parameters are the interface name, object name and path name. If the activation policy is not specified, the default policy of shared server will be used. For complete information on using this command, see the VisiBroker for C++ Reference Guide.

Note: The implementation of your object does not need to be modified in order for you to use regobj. You may write an implementation and start it manually during the development and testing phases. When your implementation is ready to be deployed, you can simply use regobj to register your implementation with the OAD.

Note: When registering an object implementation, use the same object name as is used when the implementation object is contructed.

The following example shows the use of regobj for UNIX users. For more information, see the VisiBroker for C++ Reference Guide.

regobj -o library,Harvard -p shared -f /home/user/dir/libsrv -a arg1 -e env1 -
r refdata

For information about the Windows implementation of regobj, see the "Commands" chapter of the VisiBroker for C++ Reference Guide.

OAD Registration using BOA::create

Instead of using the regobj command manually or in a script, VisiBroker allows applications written in C++ to use the BOA::create method to register one or more objects with the activation daemon. Using this method results in an object implementation being registered with the OAD and the VisiBroker directory service. The OAD will store the information in the implementation repository, allowing the object implementation to be located and activated when a client attempts to bind to the object.

The following example shows the BOA::create method and its parameters.


class CORBA {

...

typedef OctetSequence ReferenceData;

...

class BOA {

virtual Object_ptr create(

const ReferenceData& ref_data,

InterfaceDef_ptr inf_ptr,

ImplementationDef_ptr impl_ptr) = 0;

...

};

...

};

Reference Data Parameter

You can use the ref_data parameter to distinguish between multiple instances of the same object. The value of the reference data is chosen by the implementation at object creation time and remains constant during the lifetime of the object. The ReferenceData typedef is portable across platforms and ORBs.

Note: VisiBroker does not use the inf_ptr, defined by the CORBA specification to identify the interface of the object being created. Applications created with VisiBroker should always specify a NULL value for this parameter.

Implementation Definition Parameter

The impl_ptr parameter supplies the information that the BOA needs to register an ORB object. The ImplementationDef class defines the interface name, object name, and reference id properties used by the BOA. Figure 4-6 shows the methods for querying and setting these properties.


class ImplementationDef

{

public:

static ImplementationDef_ptr _duplicate(

ImplementationDef_ptr obj);

static void _release(

ImplementationDef_ptr obj);

static ImplementationDef_ptr _nil();

const char *interface_name() const;

void interface_name(const char *val);

const char *object_name() const;

void object_name(const char *val);

ReferenceData_ptr id() const;

void id(const ReferenceData_ptr& data);

...

protected:

String_var _interface_name;

String_var _object_name;

ReferenceData _id;

...

};

The _interface_name property represents the name specified in the object's IDL specification. The _object_name property is the name of this object, provided by the implementor or the person installing the object. The _id property is chosen by the implementation and has no meaning to the BOA or the OAD. The implementor may use the _id property as they chose.

Creation Definition

The ImplementationDef class, as defined by the CORBA specification, does not supply all the information that the OAD needs to activate an object implementation when a client attempts to bind to the object. The CreationImplDef class is derived from ImplementationDef and adds the properties the OAD requires.The properties added are _path_name, _policy, _args and _env. Methods for setting and querying their values are also provided. These additional properties are used by the OAD to activate an ORB object. Figure 4-7 shows the CreationImplDef class, its properties and methods.

The _path_name property specifies the exact path name of the executable program that implements the object. The _policy property represents the server's activation policy, discussed in "Object Server Activation Policies" on page 4-5. The _args and _env properties represent optional arguments and environment settings to be passed to the server.


enum Policy {

SHARED_SERVER,

UNSHARED_SERVER,

SERVER_PER_METHOD

};

class CreationImplDef: public ImplementationDef

{

public:

CreationImplDef();

CreationImplDef(const char *interface_name,

const char *object_name,

const RefereneData& i d,

const char *path_name,

const StringSequence& args,

const StringSequence& env);

~CreationImplDef() {};

static CreationImplDef_ptr _duplicate(CreationImplDef_ptr obj);

static void _release(CreationImplDef_ptr obj);

static CreationImplDef_ptr _nil();

static CreationImplDef_ptr _narrow(ImplementationDef_ptr ptr);

Policy activation_policy() const;

void activation_policy(Policy p);

const char *path_name() const;

void path_name(const char *val);

StringSequence *args() const;

void *args(const StringSequence& val);

StringSequence *env() const;

void env(const StringSequence& val);

...

protected:

String_val _path_name;

Policy _policy;

StringSequence _args;

StringSequence _env;

};

BOA::create Example

The following figure shows how to use the CreationImplDef class and the BOA::create method to create an ORB object and register it with the OAD.


#include "libsrv.h"

void main(int argc, char * const * argv)

{

CORBA::Object_ptr obj;

// Initialize the ORB and BOA

CORBA::ORB_var orb = CORBA::ORB_init(argc, argv);

CORBA::BOA_var boa = orb->BOA_init(argc, argv);

// Optional reference data

ReferenceData id;

CORBA::CreationImplDef impl_def("library", "Harvard", id,

"/usr/home/dir/libsrv",

NULL /* no args */, NULL /* no envs */);

obj = boa->create(id, NULL, &impl_def);

if (obj != NULL)

cout << "ORB object created successfully"

exit (1);

}

Note: If the impl_def parameter passed to BOA::create cannot be narrowed to a CreationImplDef reference, the create will fail and a CORBA::BAD_PARAM exception will be raised.

Changing an ORB Implementation

Figure 4-9 shows the BOA::change_implementation method which can be used to dynamically change an object's implementation. You can use this method to change the object's activation policy, path name, arguments and environment variables.

If the impl parameter cannot be narrowed to a CreationImplDef, this method will fail and a CORBA::BAD_PARAM exception will be raised.

The following example shows the change_implementation method.


class BOA {

...

virtual void change_implementation(

const Object &obj,

const ImplementationDef& impl);

...

};

Caution: Though you can change an object's implementation name and object name with the this method, you should exercise caution. Doing so will prevent client applications from locating the object with the old name.

Unregistering Implementations

When the services offered by an object are no longer available or temporarily suspended, the object should be unregistered with the OAD. When an ORB object is unregistered, it is removed from the OAD's list of objects. The object is also removed from the directory service and from the implementation repository. Once an object is unregistered, client applications will no longer be able to locate or use it. In addition, the BOA::change_implementation method will no longer be able to be used to change the object's implementation. As with the registration process, unregistering may be done with a command line or programmatically. There is also an ORB object interface to the OAD, described in "ORB Interface to the OAD" on page 4-14.

Unregistering with unregobj

Figure 4-10 shows the unregobj command, which can be used to unregister an object implementation from the command line or from within a script. If the interface name is specified by itself, all objects instances associated with that interface name will be unregistered. You can specify both the interface and object name if you only wish to unregister a specific object within an interface. For complete information on using this command, see the VisiBroker for C++ Reference Guide.

The following example shows the use of unregobj for UNIX users. For more information, see the VisiBroker for C++ Reference Guide.

unregobj -i library,Harvard 
For information about the Windows implementation of unregobj, see the "Commands" chapter of the VisiBroker for C++ Reference Guide.

Unregistering with the BOA::dispose Method

An object's implementation can use the BOA::dispose method to unregister an ORB object. Any connections that might exist between a client application and the object will be terminated as soon as the object is unregistered.

The following example shows the use of the BOA::dispose method.


class CORBA {

class BOA {

...

virtual void dispose(Object_ptr);

...

};

};

The listimpl Command

You can use the listimpl command to list the contents of a particular implementation repository. For each implementation in the repository the listimpl command lists all the object instance names, the path name of the executable program, the activation mode and the reference data. Any arguments or environment variables that are to be passed to the executable program are also listed. For complete details on using this command see the VisiBroker for C++ Reference Guide.

The following example shows the use of listimpl for UNIX users. For more information, see the VisiBroker for C++ Reference Guide.

listimpl -i interface
For information about the Windows implementation of listimpl, see the "Commands" chapter of the VisiBroker for C++ Reference Guide.

ORB Interface to the OAD

The Object Activation Daemon is implemented as an ORB object. Figure 4-13 shows the IDL interface specification for the OAD. You can create a client application that binds to the OAD and uses this interface to query the status of objects that have been registered.

The following example shows the OAD interface specification.


// IDL

module Activation

{

enum State {

ACTIVE,

INACTIVE,

WAITING_FOR_ACTIVATION

};

struct ObjectStatus {

long process_id;

State activation_state;

Object objRef;

};

typedef sequence<ObjectStatus> ObjectStatusList;

struct ImplementationStatus {

CORBA::CreationImplDef impl;

ObjectStatusList status;

};

typedef sequence<ImplementationStatus> ImplStatusList;

exception NotRegistered {};

...


interface OAD {

// Internal methods are not shown here.

...

// Get status info for a given implementation

ImplementationStatus get_status(

in string interface_name,

in string object_name)

raises (NotRegistered);

// Get status of all implementations for a given interface

ImplStatusList get_status_interface(

in string interface_name)

raises (NotRegistered);

// Get list of all registered interfaces.

ImplStatusList get_status_all();

...

Activating Objects Directly

In the library example introduced in Chapter 2, the Library object was activated directly by the server. Direct activation of an object involves instantiating all the C++ implementation classes, invoking the boa::obj_is_ready method for each object and then invoking BOA::impl_is_ready to begin receiving requests. Figure 4-14 shows how this processing would occur for a server offering two Library objects; one with the object name of "Stanford" and the other named "Harvard." Once the objects have been instantiated and activated, the server invokes BOA::impl_is_ready to begin receiving client requests.

Note: The BOA::obj_is_ready must be called for each object offered by the implementation.

The following example shows a server activating two objects and the implementation.


#include <lib_server.hh>

int main(int argc, char * const * argv)

{

// Initialize ORB and Basic Object Adaptor (BOA)

CORBA::ORB_var orb = CORBA::ORB_init(argc, argv);

CORBA::BOA_var boa = orb->BOA_init(argc, argv);

// Instantiate Harvard Library Class

Library harvard_lib("Harvard");

boa->obj_is_ready(&harvard_lib);

// Instantiate Stanford Library Class

Library stanford_lib("Stanford");

boa->obj_is_ready(&stanford_lib);

// Begin event loop of receiving messages

boa->impl_is_ready();

return(1);

}

Activating Objects with the BOA

When you design your object implementation, you may want to defer the activation of one or more ORB objects until a client requests them. The BOA::obj_is_ready and BOA::impl_is_ready methods may be used with the ActivationImplDef class to instantiate objects upon receipt of a client request.


class CORBA {

class BOA {

...

virtual void obj_is_ready(Object_ptr,

ImplementationDef_ptr impl=NULL) = 0;

virtual void impl_is_ready(ImplementationDef_ptr impl=NULL) = 0;

...

};

};

In previous examples, the obj_is_ready method was only passed an object reference. The impl_is_ready was passed no parameters at all. It is possible to pass an ActivationImplDef pointer to the obj_is_ready method, which can be used to override the activation and deactivation methods used by the BOA. Figure 4-16 shows the ActivationImplDef class, which adds an Activator pointer and provides methods for setting and retrieving that pointer. Note that this class is derived from ImplementationDef.


class ActivationImplDef: public ImplementationDef

{

public:

ActivationImplDef();

ActivationImplDef(const char *interface_name,

const char *object_name,

const ReferenceData& id,

Activator_ptr act);

~ActivationImplDef();

static ActivationImplDef_ptr _duplicate(ActivationImplDef_ptr obj);

static ActivationImplDef_ptr _nil();

static ActivationImplDef_ptr _narrow(ImplementationDef_ptr ptr);

Activator_ptr activator_obj();

void activator_obj(Activator_ptr val);

protected:

Activator_ptr _activator;

...

};

The Activator Class

The following figure shows the Activator class, which provides the two methods used by the BOA to activate and deactivate an ORB object.


class Activator {

public:

Activator();

~Activator();

static Activator_ptr _duplicate(Activator_ptr obj);

static void _release(Activator_ptr);

static Activator_ptr _nil();

virtual Object_ptr activate(ImplementationDef impl) = 0;

virtual void deactivate(Object_ptr,

ImplementationDef_ptr impl);

};

Deriving your own class from the Activator class lets you to override the activate and deactivate methods that the ORB will use for the Library object. This allows you to delay the instantiation of the Library object until the BOA activates the ORB object. It also allows you to provide clean-up processing when the ORB deactivates the object. Figure 4-18 shows how to create an Activator for the Library class.

The following example shows deriving the LibraryActivator class, implementing the activate and deactivate methods.


class LibraryActivator : CORBA::Activator {

public:

virtual CORBA::Object_ptr activate(

CORBA::ImplementationDef_ptr impl);

virtual void deactivate(CORBA::Object_ptr,

CORBA::ImplementationDef_ptr impl);

};

CORBA::Object_ptr LibraryActivator::activate(

CORBA::ImplementationDef_ptr impl)

{

// When the BOA activates us, instantiate the Library object.

return new Library(impl->object_name());

}

void LibraryActivator::deactivate(CORBA::Object_ptr obj,

CORBA::ImplementationDef_ptr impl)

{

// When the BOA deactivates us, release the Library object.

obj->release();

}

Putting it All Together

The following example shows how to use the ActivationImplDef class the LibraryActivator class, to defer the activation of the Library object until a client request is received. The instantiation of the Library object no longer appears in the main routine. Instead, the Library object will be instantiated when the BOA receives a client request and invokes the activate method.

In this example, the invocation of BOA::obj_is_ready is passed a NULL object reference as well as an ActivationImplDef reference. The creation of the Library object named "Harvard" will now be deferred until the first client request for that object is received.


void main(int argc, char * const * argv)

{

// Initialize ORB and Basic Object Adaptor (BOA)

CORBA::ORB_var orb = CORBA::ORB_init(argc, argv);

CORBA::BOA_var boa = orb->BOA_init(argc, argv);

CORBA::ReferenceData id;

CORBA::ActivationImplDef impl("library", "Harvard", id,

(CORBA::Activator_ptr) new LibraryActivator);

// obj_is_ready is passed an ActivationImplDef object to override

// the activation of the Library object.

boa->obj_is_ready(NULL, &impl);

// activate other objects

...

// Begin event loop of receiving requests

boa->impl_is_ready();

return(1);

};

If an implementation has only one object, then the impl_is_ready method can be called with the ActivationImplDef reference to activate both the object and the implementation. Since impl_is_ready can accept only one object's implementation, this approach cannot be used if multiple objects reside in the same implementation. Figure 4-20 shows the use of a one invocation of the impl_is_ready method.

The following example shows the use of a single impl_is_ready method.


void main(int argc, char * const * argv)

{

// Initialize ORB and Basic Object Adaptor (BOA)

CORBA::ORB_var orb = CORBA::ORB_init(argc, argv);

CORBA::BOA_var boa = orb->BOA_init(argc, argv);

CORBA::ReferenceData id;

CORBA::ActivationImplDef impl("library", "Harvard", id,

(CORBA::Activator_ptr) new LibraryActivator);

// impl_is_ready is passed an ActivationImplDef object to override

// the activation of the Library object.

boa->impl_is_ready(&impl);

return(1);

};

Object and Implementation Deactivation

The correct approach to deactivating objects and implementations depends on how the object and implementation were activated. Objects and their implementations can be activated manually, through C++ instantiation, by the OAD, or by the BOA.

Deactivating a Manually Started Implementation

An implementation that is started manually can be considered deactivated when the implementation exits. VisiBroker will automatically unregister the objects within that implementation from the list maintained by the directory service.

Deactivating C++ Instantiated Objects

If an object was created by instantiating its C++ class, call CORBA::release(Object_ptr) on the object to unregister the object from the list of objects maintained by the directory service. This also calls the destructor if no other references to the object exist. Calling delete on the object is not recommended since the object could be deleted prematurely.

Deactivating Implementations Started by the OAD

Implementations started by the OAD can be deactivated by calling the BOA::deactivate_impl method. Once this method is called, the implementation will not be available to service client requests. The implementation can only be re-activated if it is restarted or if it again calls the impl_is_ready method.

Deactivating Objects Activated by the BOA

The BOA::deactivate_obj method is provided to deactivate objects activated by the BOA. After this method is called, the object will be removed from the directory service list of objects offered by that implementation. Figure 4-21shows the definition of the deactivate_obj method.


class CORBA {

class BOA {

...

virtual void deactivate_obj(Object_ptr);

...

};

};


[Preface] [Chapter 1] [Chapter 2] [Chapter 3] [Chapter 4] [Chapter 5] [Chapter 6]
[Chapter 7] [Chapter 8] [Chapter 9] [Chapter 10] [Chapter 11] [Chapter 12] [Appendix A]