Chapter 7: Handling Events

VisiBroker transparently manages networking and communication issues for you, but there may be times when your client applications and object implementations need to define their own error and recovery processing. VisiBroker provides a set of event handling mechanisms for notifying clients and object implementations of system events. Event handing can be used to implement accounting, tracing, debugging, logging, security or encryption features. This chapter includes the following major sections:

Event Handler Concepts

Client Event Handlers

Implementation Event Handlers

Event Handler Concepts

Event handlers objects allow client application and object implementations to define methods that the ORB will invoke to handle events such as the success or failure of a bind request or the failure of an object implementation. Two different event handler classes are provided because the types of events that can be handled are different for clients and object implementations. However, the procedure for using an event handler is similar for clients and object implementations.

  1. Derive an event handler class for your object, defining the event methods you wish to handle.
  2. Provide Implementations for the event methods you wish to handle.
  3. Add code to the client or object implementation to register the event handler.
The following section is a summary of the events that can be handled by client applications and object implementations.

Client-side Events

Bind succeeded

Bind Failed

Server aborted

Rebind succeeded

Rebind failed

Implementation-side Events

Bind request received

Unbind request received

Client aborted

Pre-method

Post-method

Client Event Handlers

Client applications can register an event handler with the ORB to handle events for a particular ORB object. The client can also globally register an event handler to handle events for all ORB objects the client uses.

The following example shows a portion of the pmcext.h include file that contains the class definition for the ClientEventHandler class.


class PMC_EXT

{

struct ConnectionInfo {

CORBA::String_var hostname;

CORBA::UShort port;

CORBA::Long fd;

...

};

class ClientEventHandler

{

public:

virtual void bind_succeeded(CORBA::Object_ptr,

const ConnectionInfo&);

virtual void bind_failed(CORBA::Object_ptr);

virtual void server_aborted(CORBA::Object_ptr);

virtual void rebind_succeeded(CORBA::Object_ptr,

const ConnectionInfo&);

virtual void rebind_failed(CORBA::Object_ptr);

...

};

...

};

The ConnectionInfo Structure

This structure represents all the information needed for a connection. It includes the host name where the object implementation resides, the port number and the file descriptor used for the connection. This structure is modified when the connection to the object implementation is lost and a re-bind operation is attempted.

ClientEventHandler Methods

When an event handler object has been registered for a particular ORB object, the ORB will call the ClientEventHandler methods when a specific event occurs. If the event handler is registered as a global event handler, the ClientEventHandler methods will be called for any event related to any object the client uses.

The bind_succeeded method is called by the ORB when the client's request to bind to the ORB object has completed successfully. A pointer to the object that has been bound is provided as a parameter as well as the connection information.

The bind_failed method is called if the client's bind request fails. A pointer to the object to which the event is related is provided as a parameter.

The server_aborted method is called if the connection to the object implementation is lost. A pointer to the object to which the event is related is provided as a parameter.

The rebind_succeeded method is called when an attempt to re-connect to an object implementation succeeds. A pointer to the object that has been re-bound is provided as a parameter as well as the new connection information.

The rebind_failed method is called when an attempt to re-connect to an object implementation fails. A pointer to the object to which the event is related is provided as a parameter.

Creating a Client Event Handler

To implement an event handler for your client application, you must derive your own event handler class for the class you wish to monitor. You will need to implement only those event handler methods you wish to override. If you do not override an event handler method, no special processing will occur and no performance overhead will be added to the application.

The following example shows how you would define an event handler for the library client, introduced in Chapter 2. Only three of the possible five methods offered by ClientEventHandler have been overridden.


class LibraryClientHandler : public PMC_EXT::ClientEventHandler

{

...

public:

void bind_succeeded(CORBA::Object_ptr, const ConnectionInfo&);

void bind_failed(CORBA::Object_ptr);

void server_aborted(CORBA::Object_ptr);

};

The following example shows simple implementations for these methods.


void LibraryClientHandler::bind_succeeded(CORBA::Object_ptr obj,

const ConnectionInfo&)

{

cout << "Event Handler bind_succeeded for: "

<< obj->_interface_name() << endl;

}

void LibraryClientHandler::bind_failed(CORBA::Object_ptr obj)

{

cout << "Event Handler bind_failed for: "

<< obj->_interface_name() << endl;

}

void LibraryClientHandler::server_aborted(CORBA::Object_ptr obj)

{

cout << "Event Handler server_aborted for: "

<< obj->_interface_name() << endl;

}

The Handler Registry

You can use the static method HandlerRegistry::instance to obtain a pointer to the registry and then invoke the methods for registering and un-registering various types of event handlers.


class HandlerRegistry{

...

public:

...

static HandlerRegistry_ptr instance();

void reg_obj_client_handler(CORBA::Object_ptr obj,

ClientEventHandler_ptr handler);

void reg_glob_client_handler(ClientEventHandler_ptr handler);

void unreg_obj_client_handler(CORBA::Object_ptr obj);

void unreg_glob_client_handler();

void reg_obj_impl_handler(CORBA::Object_ptr obj,

ImplEventHandler_ptr handler);

void reg_glob_impl_handler(ImplEventHandler_ptr handler);

void unreg_obj_impl_handler(CORBA::Object_ptr obj);

void unreg_glob_impl_handler();

...

};

HandlerRegistry Methods for Clients Applications

The reg_obj_client_handler method can be called by your client application to register an event handler for a specific object. The parameters passed to this method are a reference to the object and a pointer to the object's ClientEventHandler. If the object reference is not valid, an InvalidObject exception will be raised. If an event handler has already been registered for the specified object, a HandlerExists exception will be raised. You can use the unreg_obj_client_handler method to un-register a previously registered event handler.

The reg_glob_client_handler method can be called by your client application to register an event handler for all object the client uses. The parameter passed to this method is a pointer to the object's ClientEventHandler. If a global handler has already been registered, a HandlerExists exception will be raised. You can use the unreg_glob_client_handler method to un-register a previously registered global event handler.

Note: If both an object event handler and a global event handler are registered, the object event handler will take precedence for events that occur which are related to its object. All other events will be handled by the global event handler.

The unreg_obj_client_handler method can called by your client application to un-register an event handler for a specific object. A reference to the object whose event handler is to be removed is passed as a parameter. If the object reference is not valid, an InvalidObject exception will be raised. If no event handler has been registered for the specified object, a NoHandler exception will be raised.

The unreg_glob_client_handler method can called by your client application to unregister a global event handler. If no global event handler has been registered, a
NoHandler exception will be raised.

Registering Client Event Handlers

There are methods for registering both global and per-object event handlers. In either case, the client uses the PCM_EXT::HandlerRegistry::instance method to obtain a pointer to the ORB's event handler registry. The following example shows the registration process for a global event handler and shows how to register a per-object event handler. Both examples assume that the LibraryClientHandler class has been defined and implemented, as shown in the previous examples.

The following example shows how to register a global client event handler.


#include <fstream.h>

#include <lib_client.hh>

main(int argc, char *const *argv)

{

CORBA::Boolean ret;

// Initialize the ORB

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

// Parse arguments

...

// Declare the library object

library_var *library_object;

// Declare the library event handler

LibraryClientHandler client_handler;

// Obtain a handle to the ORB's registry

PCM_EXT::HandlerRegistery_ptr registry_handle =

PCM_EXT::HandlerRegistry::instance();

try {

// Register the global event handler

registry_handle->reg_glob_client_handler(&client_handler);

}

catch(const PMC_EXT::HandlerExists& excep) {

cout << "A global handler was already registered" << endl;

}

// Bind to the library object and invoke methods

...

try {

// Un-register the global event handler

registry_handle->unreg_glob_client_handler();

}

catch(const PMC_EXT::NoHandler& excep) {

cout << "No global handler was registered" << endl;

}

return(1);

}

The following example shows how to register a per-object client event handler.


#include <fstream.h>

#include <lib_client.hh>

main(int argc, char *const *argv)

{

CORBA::Boolean ret;

// Initialize the ORB

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

// Parse arguments

...

// Declare the library object

library_var *library_object;

// Bind to the library object

...

// Declare the library event handler

LibraryClientHandler client_handler;

// Obtain a handle to the ORB's registry

PCM_EXT::HandlerRegistery_ptr registry_handle =

PCM_EXT::HandlerRegistry:::instance();

try {

// Register the library event handler

registry_handle->reg_obj_client_handler(library_object,

&client_handler);

}

catch(const PMC_EXT::HandlerExists& excep) {

cout << "A handler was already registered" << endl;

}

// Invoke methods on library object

...

try {

// Un-register the library event handler

registry_handle->unreg_obj_client_handler(library_object);

}

catch(const PMC_EXT::NoHandler& excep) {

cout << "No handler was registered" << endl;

}

catch(const PMC_EXT::InvalidObject& excep) {

cout << "Invalid object reference" << endl;

}

return(1);

}

Implementation Event Handlers

Like client applications, object implementations can register an event handler with the ORB to handle events for a particular ORB object. The implementation can also globally register an event handler to handle events for all ORB objects implemented. Implementation-side event handling can be used for a variety of purposes. For example, the implementation may refuse a client connection request, based on the caller's identity.

The ImplEventHandler Class

The following example shows the ImplEventHandler class you will use to derive an implementation event handler. All of the methods shown make use of the ConnectionInfo structure, discussed previously.


class PCM_EXT

{

...

class ImplEventHandler

{

public:

virtual void bind(const ConnectionInfo&,

CORBA::Principal_ptr, CORBA::Object_ptr);

virtual void unbind(const ConnectionInfo&,

CORBA::Principal_ptr, CORBA::Object_ptr);

virtual void client_aborted(const ConnectionInfo&,

CORBA::Principal_ptr, CORBA::Object_ptr);

virtual void pre_method(const ConnectionInfo&,

CORBA::Principal_ptr, CORBA::Object_ptr,

const char *, CORBA::Object_ptr);

virtual void post_method(const ConnectionInfo&,

CORBA::Principal_ptr, CORBA::Object_ptr,

const char *, CORBA::Object_ptr);

};

...

};

In the preceding example, CORBA::Principal_ptr allows clients to send information to the server that can retrieve this data and, as the implementor, you can determine if the server allows the action (like a bind) to be performed.

ImplEventHandler Methods

The bind method will be called every time a client wishes to connect to this object. This method allow your object implementation to do any special processing before the bind request is processed. Once this method returns, the BOA will proceed with the normal binding process. The parameters passed to this method are the connection information, the Principal value associated with the client and a pointer to the ORB object requested. This method may choose to reject the bind, based on the requestor's identity, by raising a CORBA::NO_PERMISSION exception.

The unbind method will be called every time a client application calls the CORBA::release method for a previously bound object. The BOA will pass control to this method before the un-bind occurs. The connection information and the object reference are passed to this method.

The client_aborted method will be called if the connection to a client application is lost. The connection information and the object reference are passed to this method.

The pre_method method will be called every time a client application invokes a method on the object for which the handler is registered. After this method returns, the BOA will proceed with the method invocation. The connection information, Principal of the client, method name and a pointer to the object are all passed to this method.

The post_method method will be called after every invocation of a method by a client on the object being traced. After this method returns, the results of the method invocation will be returned to the client. The connection information, Principal of the client, method name and a pointer to the object are all passed to this method.

Note: If the method invoked by the client raises an exception, post_method will not be called.

Creating Implementation Event Handlers

The following example shows how you can create an implementation event handler for the Library object by deriving your own class from the ImplEventHandler class.


class LibraryImplHandler : public PMC_EXT::ImplEventHandler

{

public:

void bind(const ConnectionInfo&, CORBA::Principal_ptr,

CORBA::Object_ptr);

void unbind(const ConnectionInfo&, CORBA::Principal_ptr,

CORBA::Object_ptr);

};

The following example shows the implementation for the LibraryImplHandler methods defined. You only need to define and provide method implementations for those events you wish to handle.


void LibraryImplHandler::bind(const ConnectionInfo&,

CORBA::Principal_ptr, CORBA::Object_ptr obj)

{

cout << "Bind request arrived for " << obj->_interface_name << endl;

...

};

void LibraryImplHandler::unbind(const ConnectionInfo&,

CORBA::Principal_ptr, CORBA::Object_ptr obj)

{

cout << "Un-Bind request arrived for " << obj->_interface_name << endl; ...

};

Using the Handler Registry

As with client applications, the HandlerRegistry is used to register implementation event handlers. The HandlerRegistry class is show in a previous example.

HandlerRegistry Methods for Object Implementations

The reg_obj_impl_handler method can be called by your object implementation to register an event handler with the BOA for a specific object. The parameters passed to this method are a reference to the object and a pointer to the object's ImplEventHandler. If the object reference is not valid, an InvalidObject exception will be raised. If an event handler has already been registered for the specified object, a HandlerExists exception will be raised. You can use the unreg_obj_impl_handler method to un-register a previously registered event handler.

The reg_glob_impl_handler method can be called by your object implementation to register an event handler with the BOA for all objects contained in the implementation. The parameter passed to this method is a pointer to the object's ImplEventHandler. If a global handler has already been registered for this implementation, a HandlerExists exception will be raised. You can use the unreg_glob_impl_handler method to un-register a previously registered global event handler.

Note: If both an object event handler and a global event handler are registered, the object event handler will take precedence for events that occur which are related to its object. All other events will be handled by the global event handler.

The unreg_obj_impl_handler method can be called by your object implementation to un-register an event handler for a specific object. A reference to the object whose event handler is to be removed is passed as a parameter. If the object reference is not valid, an InvalidObject exception will be raised. If no event handler has been registered for the specified object, a NoHandler exception will be raised.

The unreg_glob_impl_handler method can be called by your object implementation to un-register a global event handler. If no global event handler has been registered, a NoHandler exception will be raised.

Registering Implementation Event Handlers

Like client applications, your object implementations will use similar procedures for registering both global and per-object event handler. In both cases, the client uses the PCM_EXT::HandlerRegistry::instance method to obtain a pointer to the BOA's event handler registry. The following example shows the registration process for a global event handler. . The example assumes that the LibraryImplHandler class has been defined and implemented, as shown in a previous example.


#include <lib_server.hh>

int main(int argc, char **argv)

{

// Initialize ORB and Basic Object Adaptor (BOA)

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

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

// Instantiate the Library object

Library *library_obj = new Library("Harvard");

// Define the impl_handler and registry instance

LibraryImplHandler impl_handler;

PMC_EXT::HandlerRegistry_ptr registry_handle;

registry_handle = PMC_EXT::HandlerRegistry::instance();

try {

// Register a global event handler

registry_handle->reg_glob_impl_handler(&impl_handler);

}

catch(const PMC_EXT::HandlerExists& excep) {

cout << "Global handler already defined" << endl;

}

// Instantiate Library Class, activate object and implementation

...

try {

registry_handle->unreg_glob_impl_handler();

}

catch(const PMC_EXT::NoHandler& excep) {

cout << "Removal of global event handler failed" << endl;

}

...

}

The following example shows how to register a per-object event handler. The example assumes that the LibraryImplHandler class has been defined and implemented, as shown in a previous example.


#include <lib_server.hh>

int main(int argc, char **argv)

{

// Initialize ORB and Basic Object Adaptor (BOA)

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

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

// Instantiate the Library object

Library *library_obj = new Library("Harvard");

// Define the impl_handler and registry instance

LibraryImplHandler impl_handler;

PMC_EXT::HandlerRegistry_ptr registry_handle;

registry_handle = PMC_EXT::HandlerRegistry::instance();

try {

// Register a global event handler

registry_handle->reg_obj_impl_handler(library_obj, &impl_handler);

}

catch(const PMC_EXT::HandlerExists& excep) {

cout << "Handler already defined for " <<

library_obj->_instance_name << endl;

}

// Instantiate Library Class, activate object and implementation

...

try {

registry_handle->unreg_obj_impl_handler(library_obj);

}

catch(const PMC_EXT::NoHandler& excep) {

cout << "Removal of event handler failed for " <<

library_obj->_instance_name << endl;

}

...

}


[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]