Netscape Internet Service Broker for C++ Programmer's Guide

[Contents] [Previous] [Next]

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 ( 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 ISB for C++'s directory service. Only those entities that possess an explicit object reference to a transient object may invoke its methods. The following code example shows you how to modify a library application so that library_server is created as a transient object. The scope must be set prior to instantiating the object.

NOTE: 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.
Creating a transient 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);

...
};

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 ISB for C++'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. The following code example shows the creation and registration of a persistent object.

Creating and activating a persistent object.

// MsgService.cpp
#include "HelloImpl.cpp"
#include <iostream.h>
#include <NameUtil.hpp>

int main(int argc, char* const* argv) {
try {
// Initialize the ORB and the BOA.
CORBA::ORB_var orb = CORBA::ORB_init(argc, argv);
CORBA::BOA_var boa = orb->BOA_init(argc, argv);
HelloImpl* hi = new HelloImpl();
WAIReturnType_t rc;
char *objectName = "Howdy";
char *hostAndPort = "mikelee:80";
rc = registerObject(hostAndPort, objectName, hi);
boa->obj_is_ready(hi);
cerr << "Ready for client requests." << endl;
boa->impl_is_ready();
} catch (CORBA::SystemException& e) {
cerr << e << endl;
return(1);
}
return(0);
}
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

The following code listing shows a method a 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 method for checking for persistent object implementations.

class Object {
...
Boolean _is_persistent() const;
...
};

Object Registration

Once a server has instantiated the service 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 service object is ready to receive requests from client applications. If a server offers more than one service object, it must call 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 ISB for C++'s directory service. If the object is transient, no such registration will occur.

NOTE: If a client tries to bind to a service and obj_is_ready has not been called, the exception NO_IMPLEMENT is raised.
When 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. The Handling Events chapter in this guide discusses event handling in detail.

The Basic Object Adaptor

ISB for C++'s BOA provides several important functions to client applications and the object implementations they use. An object may reside in the same process as its client application or it may reside in a separate process called a server. 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 ISB for C++'s Object Activation Daemon (OAD) to automatically activate the implementation when a client binds 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. 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 depends on where ISB for C++ was installed on your system. The default value can be overridden using OAD environment variables, described in the Netscape Internet Service Broker 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 program code. 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 Netscape Internet Service Broker for C++ Reference Guide.

NOTE: The implementation of your object does not need to be modified in order for you to use regobj. You can write an implementation and start it manually during the development and testing phases. When your implementation is ready to be deployed, 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.
Figure 4.1    The regobj command

For information about the Windows implementation of regobj, see the "Commands" chapter of the Netscape Internet Service Broker for C++ Reference Guide.

OAD Registration using BOA::create

Instead of using the regobj command manually or in code, ISB for C++ provides the BOA::create method to register one or more objects with the OAD and the ISB for C++ 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 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: ISB for C++ does not use the inf_ptr, defined by the CORBA specification to identify the interface of the object being created. Applications created with ISB for C++ 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. The following code listing shows the methods for querying and setting these properties.

The ImplementationDef class.

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 getting and setting their values are also provided. These additional properties are used by the OAD to activate an ORB object. The code listing below 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. The _args and _env properties represent optional arguments and environment settings to be passed to the server.

The CreationImplDef class.

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& id,
                          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);
     ...
     pro

BOA::create Example

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

Creating an ORB object and registering 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" << endl;
}
NOTE: If the impl_def parameter passed to BOA::create cannot be narrowed to a CreationImplDef reference, create will fail and a CORBA::BAD_PARAM exception will be raised.

Changing an ORB Implementation

The following code listing 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 change_implementation method.

class BOA {
...
virtual void change_implementation(const Object &obj,
const ImplementationDef& impl);
...
};
Caution Changing an object's implementation name and object name using this method 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. When an object is unregistered, client applications cannot locate or use it. In addition, the BOA::change_implementation method cannot 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.

Unregistering with unregobj

The unregobj command can be used to unregister an object implementation from the command line or from within code. 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 Netscape Internet Service Broker for C++ Reference Guide.

Figure 4.2    The unregobj command.

For information about the Windows implementation of unregobj, see the "Commands" chapter of the Netscape Internet Service Broker 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 exist between a client application and the object will be terminated as soon as the object is unregistered.

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 Netscape Internet Service Broker for C++ Reference Guide.

Figure 4.3    The listimpl command.

 

For information about the Windows implementation of listimpl, see the "Commands" chapter of the Netscape Internet Service Broker for C++ Reference Guide.

ORB Interface to the OAD

The Object Activation Daemon is implemented as an ORB object. The code listing below 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 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

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. The following code example 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.
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

An object server may want to defer activating 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.

The BOA::obj_is_ready and BOA::impl_is_ready methods.

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. The following code listing shows the ActivationImplDef class, which adds an Activator pointer and provides methods for setting and retrieving that pointer. This class is derived from ImplementationDef.

The ActivationImplDef class.

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 code listing below shows the Activator class, which provides the two methods used by the BOA to activate and deactivate an ORB object.

The Activator class.

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 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. The following code listing shows how to create an Activator for the Library class.

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 code example below shows how to use the ActivationImplDef class with 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 and an ActivationImplDef reference. The Library object named "Harvard" will not be created until the first client request for that object is received.

Using the ActivationImplDef class with the BOA::obj_is_ready method.

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);

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, impl_is_ready 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. The following code example shows one invocation of impl_is_ready.

The use of a single impl_is_ready method.

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);
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 approach to deactivating objects and implementations depends on how they were activated, as shown in the following table.

Activation Method

Deactivation Method

Manual

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

C++ instantiation

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 because the object could be deleted prematurely.

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.

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.


[Contents] [Previous] [Next]

Last Updated: 02/03/98 15:30:18


Copyright © 1997 Netscape Communications Corporation

Any sample code included above is provided for your use on an "AS IS" basis, under the Netscape License Agreement - Terms of Use