VisiBroker for C++ Developer’s Guide : Using Portable Interceptors

Using Portable Interceptors
This section provides an overview of Portable Interceptors. Several Portable Interceptor examples are discussed as well as the advanced features of Portable Interceptor factories.
For a complete description of Portable Interceptors, refer to the OMG Final Adopted Specification, ptc/2001-04-03, Portable Interceptors.
Portable Interceptors overview
The VisiBroker ORB provides a set of interfaces known as interceptors which provide a framework for plugging-in additional ORB behavior such as security, transactions, or logging. These interceptor interfaces are based on a callback mechanism. For example, using the interceptors, you can be notified of communications between clients and servers, and modify these communications if you wish, effectively altering the behavior of the VisiBroker ORB.
At its simplest usage, the interceptor is useful for tracing through code. Because you can see the messages being sent between clients and servers, you can determine exactly how the ORB is processing requests.
Figure 32
If you are building a more sophisticated application such as a monitoring tool or security layer, interceptors give you the information and control you need to enable these lower-level applications. For example, you can develop an application that monitors the activity of various servers and performs load balancing.
Types of interceptors
There are two types of interceptors supported by the VisiBroker ORB.
Types of Portable Interceptors
The two kinds of Portable Interceptors defined by the OMG specification are: Request Interceptors and IOR interceptors.
For additional information on using both Portable Interceptors and VisiBroker Interceptors, see “Using VisiBroker Interceptors” and the VisiBroker for C++ API Reference.
Portable Interceptor and Information interfaces
All Portable Interceptors implement one of the following base interceptor API classes which are defined and implemented by the VisiBroker ORB:
Interceptor class
All the interceptor classes listed above are derived from a common class: Interceptor. This Interceptor class has defined common methods that are available to its inherited classes.
The Interceptor class:
class PortableInterceptor::Interceptor
{
virtual char* name() = 0;
virtual void destroy() = 0;
}
Request Interceptor
A request interceptor is used to intercept the flow of a request/reply sequence at specific interception points so that services can transfer context information between clients and servers. For each interception point, the VisiBroker ORB gives an object through which the interceptor can access request information. There are two kinds of request interceptor and their respective request information interfaces:
ClientRequestInterceptor and ClientRequestInfo
ServerRequestInterceptor and ServerRequestInfo
Figure 33
For more detail information on Request Interceptors, see the VisiBroker for C++ API Reference.
ClientRequestInterceptor
ClientRequestInterceptor has its interception points implemented on the client-side. There are five interception points defined in ClientRequestInterceptor by the OMG as shown in the following table:
1TII is not implemented in the VisiBroker ORB. As a result, the send_poll( ) interception point will never be invoked.
For more information on each interception point, see the VisiBroker for C++ API Reference.
class _VISEXPORT ClientRequestInterceptor: public virtual Interceptor
{
public:
virtual void send_request(ClientRequestInfo_ptr _ri) = 0;
virtual void send_poll(ClientRequestInfo_ptr _ri) = 0;
virtual void receive_reply(ClientRequestInfo_ptr _ri) = 0;
virtual void receive_exception(ClientRequestInfo_ptr _ri) = 0;
virtual void receive_other(ClientRequestInfo_ptr _ri) = 0;
};
Client-side rules
The following are the client-side rules:
The starting interception points are: send_request and send_poll. On any given request/reply sequence, one and only one of these interception points is called.
The ending interception points are: receive_reply, receive_exception and receive_other.
An ending interception point is called if and only if send_request or send_poll runs successfully.
A receive_exception is called with the system exception BAD_INV_ORDER with a minor code of 4 (ORB has shutdown) if a request is canceled because of ORB shutdown.
A receive_exception is called with the system exception TRANSIENT with a minor code of 3 if a request is canceled for any other reason.
send_request is followed by receive_reply; a start point is followed by an end point
send_request is followed by receive_other; a start point is followed by an end point
ServerRequestInterceptor
ServerRequestInterceptor has its interception points implemented on the server-side. There are five interception points defined in ServerRequestInterceptor. The following table shows the ServerRequestInterceptor Interception points.
For more detail on each interception point, see the VisiBroker for C++ API Reference.
ServerRequestInterceptor class:
class _VISEXPORT ServerRequestInterceptor: public virtual Interceptor
{
public:
virtual void receive_request_service_contexts(ServerRequestInfo_ptr _ri) = 0;
virtual void receive_request(ServerRequestInfo_ptr _ri) = 0;
virtual void send_reply(ServerRequestInfo_ptr _ri) = 0;
virtual void send_exception(ServerRequestInfo_ptr _ri) = 0;
virtual void send_other(ServerRequestInfo_ptr _ri) = 0;
};
Server-side rules
The following are the server-side rules:
The starting interception point is: receive_request_service_contexts. This interception point is called on any given request/reply sequence.
The ending interception points are: send_reply, send_exception and send_other. On any given request/reply sequence, one and only one of these interception points is called.
The intermediate interception point is receive_request. It is called after receive_request_service_contexts and before an ending interception point.
On an exception, receive_request may not be called.
An ending interception point is called if and only if send_request or send_poll runs successfully.
A send_exception is called with the system exception BAD_INV_ORDER with a minor code of 4 (ORB has shutdown) if a request is canceled because of ORB shutdown.
A send_exception is called with the system exception TRANSIENT with a minor code of 3 if a request is canceled for any other reason.
The order of interception points: receive_request_service_contexts, receive_request, send_reply; a start point is followed by an intermediate point which is followed by an end point.
IOR Interceptor
IORInterceptor give applications the ability to add information describing the server's or object's ORB service related capabilities to object references to enable the VisiBroker ORB service implementation in the client to function properly. This is done by calling the interception point, establish_components. An instance of IORInfo is passed to the interception point. For more information on IORInfo, see the VisiBroker for C++ API Reference.
class _VISEXPORT IORInterceptor: public virtual Interceptor
{
public:
virtual void establish_components(IORInfo_ptr _info) = 0;
virtual void components_established(IORInfo_ptr _info) = 0;
virtual void adapter_manager_state_changed(
CORBA::Long _id, CORBA::Short _state) = 0;
virtual void adapter_state_changed(
const ObjectReferenceTemplateSeq& _templates,
CORBA::Short _state) = 0;
};
Portable Interceptor (PI) Current
The PortableInterceptor::Current object (hereafter referred to as PICurrent) is a table of slots that can be used by Portable Interceptors to transfer thread context information to request context. Use of PICurrent may not be required. However, if client's thread context information is required at interception point, PICurrent can be used to transfer this information.
PICurrent is obtained through a call to:
ORB->resolve_initial_references("PICurrent");
PortableInterceptor::Current class:
class _VISEXPORT Current: public virtual CORBA::Current, public virtual CORBA_Object
{
public:
virtual CORBA::Any* get_slot(CORBA::ULong _id);
virtual void set_slot(CORBA::ULong _id, const CORBA::Any& _data);
};
Codec
Codec provides a mechanism for interceptors to transfer components between their IDL data types and their CDR encapsulation representations. A Codec is obtained from CodecFactory. For more information, go to “CodecFactory”.
The Codec class:
class _VISEXPORT Codec
{
public:
virtual CORBA::OctetSequence* encode(const CORBA::Any& _data) = 0;
virtual CORBA::Any* decode(const CORBA::OctetSequence& _data) = 0;
virtual CORBA::OctetSequence* encode_value(const CORBA::Any& _data) = 0;
virtual CORBA::Any* decode_value(const CORBA::OctetSequence& _data,
CORBA::TypeCode_ptr _tc) = 0;
};
CodecFactory
This class is used to create a Codec object by specifying the encoding format, the major and minor versions. CodecFactory can be obtained with a call to:
ORB->resolve_initial_references("CodecFactory")
The CodecFactory class:
class _VISEXPORT CodecFactory
{
public:
virtual Codec_ptr create_codec(const Encoding& _enc) = 0;
};
Creating a Portable Interceptor
The generic steps to create a Portable Interceptor are:
1
ClientRequestInterceptor
ServerRequestInterceptor
IORInterceptor
2
3
Example: Creating a PortableInterceptor
#include "PortableInterceptor_c.hh"

class SampleClientRequestInterceptor: public PortableInterceptor::ClientRequestInterceptor
{
char * name() {
return "SampleClientRequestInterceptor";
}

void send_request(ClientRequestInfo_ptr _ri) {
....... // actual interceptor code here
}

void send_request(ClientRequestInfo_ptr _ri) {
....... // actual interceptor code here
}

void receive_reply(ClientRequestInfo_ptr _ri) {
....... // actual interceptor code here
}

void receive_exception(ClientRequestInfo_ptr _ri) {
....... // actual interceptor code here
}

void receive_other(ClientRequestInfo_ptr _ri) {
....... // actual interceptor code here
}
};
Registering Portable Interceptors
Portable Interceptors must be registered with the VisiBroker ORB before they can be used. To register a Portable Interceptor, an ORBInitializer object must be implemented and registered. Portable Interceptors are instantiated and registered during ORB initialization by registering an associated ORBInitializer object which implements its pre_init( ) or post_init( ) method, or both. The VisiBroker ORB will call each registered ORBInitializer with an ORBInitInfo object during the initializing process.
The ORBInitializer class:
class _VISEXPORT ORBInitializer
{
public:

virtual void pre_init(ORBInitInfo_ptr _info) = 0;
virtual void post_init(ORBInitInfo_ptr _info) = 0;
};
The ORBInitInfo class:
class _VISEXPORT ORBInitInfo
{
public:
virtual CORBA::StringSequence* arguments() = 0;
virtual char* orb_id() = 0;
virtual IOP::CodecFactory_ptr codec_factory() = 0;
virtual void register_initial_reference(const char* _id, CORBA::Object_ptr _obj) = 0;
virtual CORBA::Object_ptr resolve_initial_references(const char* _id) = 0;
virtual void add_client_request_interceptor(
ClientRequestInterceptor_ptr _interceptor) = 0;
virtual void add_server_request_interceptor(
ServerRequestInterceptor_ptr _interceptor) = 0;
virtual void add_ior_interceptor(IORInterceptor_ptr _interceptor) = 0;
virtual CORBA::ULong allocate_slot_id() = 0;
virtual void register_policy_factory(CORBA::ULong _type,
PolicyFactory_ptr _policy_factory) = 0;
};
Registering an ORBInitializer
To register an ORBInitializer, the global method register_orb_initializer is provided. Each service that implements Interceptors provides an instance of ORBInitializer. To use a service, an application:
1
calls register_orb_initializer( ) with the service's ORBInitializer; and
2
makes an instantiating ORB_Init( ) call with a new ORB identifier to produce a new ORB.
During ORB.init( ):
1
these ORB properties which begin with org.omg.PortableInterceptor.ORBInitializerClass are collected.
2
the <Service> portion of each property is collected.
3
an object is instantiated with the <Service> string as its class name.
4
the pre_init( ) and post_init( ) methods are called on that object.
5
Note
To avoid name collisions, the reverse DNS name convention is recommended. For example, if company ABC has two initializers, it could define the following properties:
org.omg.PortableInterceptor.ORBInitializerClass.com.abc.ORBInit1
org.omg.PortableInterceptor.ORBInitializerClass.com.abc.ORBInit2
The register_orb_initializer method is defined in the PortableInterceptor module as:
class _VISEXPORT PortableInterceptor {
static void register_orb_initializer(ORBInitializer *init);
}
Example: Registering ORBInitializer
A client-side monitoring tool written by company ABC may have the following ORBInitializer implementation:
#include "PortableInterceptor_c.hh"

class MonitoringService: public PortableInterceptor::ORBInitializer
{
void pre_init(ORBInitInfo_ptr _info)
{
// instantiate the service's Interceptor.
Interceptor* interceptor = new MonitoringInterceptor();

// register the Monitoring's Interceptor.
_info->add_client_request_interceptor(interceptor);
}

void post_init(ORBInitInfo_ptr _info)
{
// This init point is not needed.
}
};

MonitoringService * monitoring_service = new MonitoringService();
PortableInterceptor::register_orb_initializer(monitoring_service);
The following command may be used to run a program called MyApp using this monitoring service:
java -Dorg.omg.PortableInterceptor.ORBInitializerClass.com.abc.Monitoring.MonitoringService MyApp
VisiBroker extensions to Portable Interceptors
POA scoped Server Request Interceptors
Portable Interceptors specified by OMG are scoped globally. VisiBroker has defined “POA scoped Server Request Interceptor”, a public extension to the Portable Interceptors, by adding a new module call PortableInterceptorExt. This new module holds a local interface, IORInfoExt, which is inherited from PortableInterceptor::IORInfo and has additional methods to install POA scoped server request interceptor.
The IORInfoExt class:
#include "PortableInterceptorExt_c.hh"

class IORInfoExt: public PortableInterceptor::IORInfo
{
public:
virtual void add_server_request_interceptor(
ServerRequestInterceptor_ptr _interceptor) = 0;
virtual char* full_poa_name();
};
Limitations of VisiBroker Portable Interceptors implementation
The following are limitations of the Portable Interceptor implementation in VisiBroker.
ClientRequestInfo limitations
received_exception(): available only if typecode info is available (for example, IDL is compiled with -typecode_info and linked into program), otherwise CORBA::UNKNOWN is always returned.
ServerRequestInfo limitations
arguments(), result(), are only available for DSI invocations. For more information, go to “Using the Dynamic Skeleton Interface”
exceptions(), contexts(), operation_context(): not available, CORBA::NO_RESOURCES thrown.
sending_exception(): available only if typecode info is available (for example, IDL is compiled with -typecode_info and linked into program), otherwise CORBA::UNKNOWN is always returned.
Portable Interceptors examples
This section discusses how applications are actually written to make use of Portable Interceptors and how each request interceptor is implemented. Each example consists of a set of client and server applications and their respective interceptors written in Java and C++. For more information on the definition of each interface, see the VisiBroker for C++ API Reference. We also recommend that developers who want to make use of Portable Interceptors read the chapter on Portable Interceptors in the most recent CORBA specification.
The Portable Interceptors examples are located in the following directory:
<install_dir>/examples/vbe/pi
Each example is associated with one of the following directory names to better illustrate the objective of that example.
Example: client_server
This section provides a detailed description, explanation, the compilation procedure, and the execution or deployment of the examples in client_server.
Objective of example
This example demonstrates how easily a Portable Interceptor can be added into an existing CORBA application without altering any code. The Portable Interceptor can be added to any application, both client and server-side, through executing the related application again, together with the specified options or properties which can be configured during runtime.
The client and server application used is similar to the one found in:
<install_dir>/examples/vbe/basic/bank_agent
Portable Interceptors have been added to the entire example during runtime configuration. This provides developers, who are familiar with VisiBroker Interceptors, a fast way of coding between VisiBroker Interceptors and OMG specific Portable Interceptors.
Importing required packages
To use Portable Interceptor interfaces, inclusion of the related packages or header files is required.
Note
If you are using any Portable Interceptors exceptions, such as, DuplicateName or InvalidName, the ORBInitInfoPackage is optional.
Required header files for using Portable Interceptor are:
#include "PortableInterceptor_c.hh"
#include "IOP_c.hh"
To load a client-side request interceptor, a class that uses the ORBInitializer interface must be implemented. This is also applicable for server-side request interceptor as far as initialization is concerned. The following example shows the code for loading:
Proper inheritance of a ORBInitializer in order to load a server request interceptor:
class SampleServerLoader : public PortableInterceptor::ORBInitializer
Note
Each object that implements the interface, ORBInitializer, is also required to inherit from the object LocalObject. This is necessary because the IDL definition of ORBInitializer uses the keyword local.
For more information on the IDL keyword, local, go to “Using valuetypes”.
During the initialization of the ORB, each request Interceptor is added through the implementation of the interface, pre_init(). Inside this interface, the client request Interceptor is added through the method, add_client_request_interceptor(). The related client request interceptor is required to be instantiated before adding itself into the ORB.
Client-side request interceptor initialization and registration to the ORB
public: void pre_init(PortableInterceptor::ORBInitInfo_ptr _info) {
SampleClientInterceptor *interceptor = new SampleClientInterceptor;
try {
_info->add_client_request_interceptor(interceptor);
...
According to the OMG specification, the required application registers the respective interceptors through the method register_orb_initializer. For more information, refer to “Developing the Client and Server Application”.
VisiBroker provides an optional way of registering these interceptors through a dynamic link library (DLL). The advantage of using this method of registering is that the applications do not require changing any code, only changing the way they are executed. With an additional option during execution, the interceptors are registered and executed. The option is similar to 4.x Interceptors:
vbroker.orb.dynamicLibs=<DLL filename>
where <DLL filename>is the filename of the dynamic link library (extension .SO for UNIX or .DLL for Windows). To load more than one DLL file, separate each filename with a comma (“,”), for example:
Windows
vbroker.orb.dynamicLibs=a.dll,b.dll,c.dll
UNIX
vbroker.orb.dynamicLibs=a.so,b.so,c.so
In order to load the interceptor dynamically, the VISInit interface is used. This is similar to the one used in VisiBroker Interceptors. For more information, refer to , “Using VisiBroker Interceptors.” The registration of each interceptor loader is similar within the ORB_init implementation.
Registration of client-side ORBInitializer through DLL loading:
void ORB_init(int& argc, char* const* argv, CORBA::ORB_ptr orb)
{
if( _bind_interceptors_installed) return;

SampleClientLoader *client = new SampleClientLoader();
PortableInterceptor::register_orb_initializer(client);

...
Complete implementation of the client-side interceptor loader:
// SampleClientLoader.C

#include "PortableInterceptor_c.hh"
#include "IOP_c.hh"

#include "SampleClientInterceptor.h"

#if !defined( DLL_COMPILE )
#include "vinit.h"
#include "corba.h"
#endif

// USE_STD_NS is a define setup by VisiBroker to use the std namespace
USE_STD_NS

class SampleClientLoader :
public PortableInterceptor::ORBInitializer
{
private:
short int _interceptors_installed;

#if defined( DLL_COMPILE )
static SampleClientLoader _instance;
#endif

public:
SampleClientLoader() {
_interceptors_installed = 0;
}

void pre_init(PortableInterceptor::ORBInitInfo_ptr _info) {
if(_interceptors_installed) return;

cout << "=====>SampleClientLoader: Installing ..." << endl;

SampleClientInterceptor *interceptor = new SampleClientInterceptor;

try {
_info->add_client_request_interceptor(interceptor);

_interceptors_installed = 1;
cout << "=====>SampleClientLoader: Interceptors loaded."
<< endl;
}
catch(PortableInterceptor::ORBInitInfo::DuplicateName &e) {
cout << "=====>SampleClientLoader: "
<< e.name << " already installed!" << endl;
}
catch(...) {
cout << "=====>SampleClientLoader: other exception occurred!"
<< endl;
}
}

void post_init(PortableInterceptor::ORBInitInfo_ptr _info) {
}
};

#if defined( DLL_COMPILE )

class VisiClientLoader : VISInit
{
private:
static VisiClientLoader _instance;
short int _bind_interceptors_installed;

public:
VisiClientLoader() : VISInit(1) {
_bind_interceptors_installed = 0;
}

void ORB_init(int& argc, char* const* argv, CORBA::ORB_ptr orb) {
if( _bind_interceptors_installed) return;

try {
SampleClientLoader *client = new SampleClientLoader();
PortableInterceptor::register_orb_initializer(client);

_bind_interceptors_installed = 1;
}
catch(const CORBA::Exception& e)
{
cerr << e << endl;
}
}
};

// static instance
VisiClientLoader VisiClientLoader::_instance;

#endif
Implementing the ORBInitializer for a server-side Interceptor
At this stage, the client request interceptor should already have been properly instantiated and added. Subsequent code thereafter only provides exception handling and result display. Similarly, on the server-side, the server request interceptor is also done the same way except that it uses the, add_server_request_interceptor() method to add the related server request interceptor into the ORB.
Server-side request interceptor initialization and registration to the ORB:
public void pre_init(PortableInterceptor::ORBInitInfo_ptr _info) {
SampleServerInterceptor *interceptor = new SampleServerInterceptor;
try {
_info->add_server_request_interceptor(interceptor);
...
This method also applies similarly to loading the server-side ORBInitializer class through a DLL implementation.
Server-side request ORB Initializer loading through DLL:
void ORB_init(int& argc, char* const* argv, CORBA::ORB_ptr orb)
{
if( _poa_interceptors_installed) return;

SampleServerLoader *server = new SampleServerLoader();
PortableInterceptor::register_orb_initializer(server);
...
The complete implementation of the server-side interceptor loader:
// SampleServerLoader.C

#include "PortableInterceptor_c.hh"
#include "IOP_c.hh"
#if defined( DLL_COMPILE )
#include "vinit.h"
#include "corba.h"
#endif
#include "SampleServerInterceptor.h"
// USE_STD_NS is a define setup by VisiBroker to use the std namespace

USE_STD_NS class SampleServerLoader :

public PortableInterceptor::ORBInitializer
{
private:
short int _interceptors_installed;

public:
SampleServerLoader() {
_interceptors_installed = 0;
}
void pre_init(PortableInterceptor::ORBInitInfo_ptr _info) {

if(_interceptors_installed) return;

cout << "=====>SampleServerLoader: Installing ..." << endl;

SampleServerInterceptor *interceptor = new SampleServerInterceptor();


try {
_info->add_server_request_interceptor(interceptor);

_interceptors_installed = 1;

cout << "=====>SampleServerLoader: Interceptors loaded."
<< endl;
}
catch(PortableInterceptor::ORBInitInfo::DuplicateName &e) {
cout << "=====>SampleServerLoader: "
<< e.name << " already installed!" << endl;
}
catch(...) {
cout << "=====>SampleServerLoader: other exception occurred!"
<< endl;
}
}
void post_init(PortableInterceptor::ORBInitInfo_ptr _info) {}
};

#if defined( DLL_COMPILE ) class VisiServerLoader : VISInit

{
private:
static VisiServerLoader _instance;
short int _poa_interceptors_installed;

public:
VisiServerLoader() : VISInit(1) {
_poa_interceptors_installed = 0;
}
void ORB_init(int& argc, char* const* argv, CORBA::ORB_ptr orb) {
if( _poa_interceptors_installed) return;
try {
SampleServerLoader *server = new SampleServerLoader();
PortableInterceptor::register_orb_initializer(server);
_poa_interceptors_installed = 1;
}
catch(const CORBA::Exception& e)
{
cerr << e << endl;
}


} }; // static instance>

VisiServerLoader VisiServerLoader::_instance;

#endif
Implementing the RequestInterceptor for client- or server-side Interceptor
Upon implementation of either client- or server-side request interceptor, two other interfaces must be implemented. They are name() and destroy().
The name() is important here because it provides the name to the ORB to identify the correct interceptor that it will load and call during any request or reply. According to the CORBA specification, an interceptor may be anonymous, for example, it has an empty string as the name attribute. In this example, the name, SampleClientInterceptor, is assigned to the client-side interceptor and SampleServerInterceptor is assigned to the server-side interceptor.
Implementation of interface attribute, readonly attribute name:
public: char *name(void) {
return _name;
}
Implementing the ClientRequestInterceptor for Client
For the client request interceptor, it is necessary to implement the ClientRequestInterceptor interface for the request interceptor to work properly.
When the class implements the interface, the following five request interceptor methods are implemented regardless of any implementation:
In addition, the interface for the request interceptor must be implemented before hand. On the client-side interceptor, the following request interceptor point will be triggered in relation to its events.
send_request - provides an interception point for querying request information and modifying the service context before the request is sent to the server.
The public void send_request(ClientRequestInfo ri)interface
void send_request(PortableInterceptor::ClientRequestInfo_ptr ri) {
...
The void send_poll(ClientRequestInfo ri) interface
send_poll - provides an interception point for querying information during a Time-Independent Invocation (TII) polling to get reply sequence.
void send_poll(PortableInterceptor::ClientRequestInfo_ptr ri) {
...
The void receive_reply(ClientRequestInfo ri) interface
receive_reply - provides an interception point for querying information on a reply after it is returned from the server and before control is returned to the client.
void receive_reply(PortableInterceptor::ClientRequestInfo_ptr ri) {
...
The void receive_exception(ClientRequestInfo ri) interface
receive_exception - provides an interception point for querying the exception's information before it is raised to the client.
void receive_exception(PortableInterceptor::ClientRequestInfo_ptr ri) {
...
receive_other - provides an interception point for querying information when a request results in something other than a normal reply or an exception. For example, a request could result in a retry (for example, a GIOP Reply with a LOCATION_FORWARD status was received); or on asynchronous calls, the reply does not immediately follow the request. However, the control is returned to the client and an ending interception point is called.
void receive_other(PortableInterceptor::ClientRequestInfo_ptr ri) {
...
The complete implementation of the client-side request interceptor follows.
// SampleClientInterceptor.h

#include "PortableInterceptor_c.hh"
#include "IOP_c.hh"

// USE_STD_NS is a define setup by VisiBroker to use the std namespace
USE_STD_NS


class SampleClientInterceptor :
public PortableInterceptor::ClientRequestInterceptor
{
private:
char *_name;

void init(char *name) {
_name = new char[strlen(name)+1];
strcpy(_name, name);
}

public:
SampleClientInterceptor(char *name) {
init(name);
}

SampleClientInterceptor() {
init("SampleClientInterceptor");
}

char *name(void) {
return _name;
}

void destroy(void) {
// do nothing here
cout << "=====>SampleServerLoader: Interceptors unloaded" << endl;
}

/**
* This is similar to VisiBroker 4.x ClientRequestInterceptor,
*
* void preinvoke_premarshal(CORBA::Object_ptr target,
* const char* operation,
* IOP::ServiceContextList&servicecontexts,
* VISClosure& closure) = 0;
*/
void send_request(PortableInterceptor::ClientRequestInfo_ptr ri) {
cout << "=====> SampleClientInterceptor id " << ri->request_id()
<< " send_request => " << ri->operation()
<< ": Target = " << ri->target()
<< endl;
}

/**
* There is no equivalent interface for VisiBroker 4.x
* ClientRequestInterceptor.
*/

void send_poll(PortableInterceptor::ClientRequestInfo_ptr ri) {
cout << "=====> SampleClientInterceptor id " << ri->request_id()
<< " send_poll => " << ri->operation()
<< ": Target = " << ri->target()
<< endl;
}

/**
* This is similar to VisiBroker 4.x ClientRequestInterceptor,
*
* void postinvoke(CORBA::Object_ptr target,
* const IOP::ServiceContextList& service_contexts,
* CORBA_MarshalInBuffer& payload,
* CORBA::Environment_ptr env,
* VISClosure& closure) = 0;
*
* with env not holding any exception value.
*/
void receive_reply(PortableInterceptor::ClientRequestInfo_ptr ri){
cout << "=====> SampleClientInterceptor id " << ri->request_id()
<< " receive_reply => " << ri->operation()
<< endl;
}
/**
* This is similar to VisiBroker 4.x ClientRequestInterceptor,
*
* void postinvoke(CORBA::Object_ptr target,
* const IOP::ServiceContextList& service_contexts,
* CORBA_MarshalInBuffer& payload,
* CORBA::Environment_ptr env,
* VISClosure& closure) = 0;
*
* with env holding the exception value.
*/
void receive_exception(PortableInterceptor::ClientRequestInfo_ptr ri) {
cout << "=====> SampleClientInterceptor id " << ri->request_id()
<< " receive_exception => " << ri->operation()
<< ": Exception = " << ri->received_exception()
<< endl;
}

/**
* This is similar to VisiBroker 4.x ClientRequestInterceptor,
*
* void postinvoke(CORBA::Object_ptr target,
* const IOP::ServiceContextList& service_contexts,
* CORBA_MarshalInBuffer& payload,
* CORBA::Environment_ptr env,
* VISClosure& closure) = 0;
*
* with env holding the exception value.
*/
void receive_other(PortableInterceptor::ClientRequestInfo_ptr ri) {
cout << "=====> SampleClientInterceptor id " << ri->request_id()
<< " receive_other => " << ri->operation()
<< ": Exception = " << ri->received_exception()
<< ", Reply Status = " <<
getReplyStatus(ri->reply_status())
<< endl;
}

protected:
char *getReplyStatus(CORBA::Short status) {
if(status == PortableInterceptor::SUCCESSFUL)
return "SUCCESSFUL";
else if(status == PortableInterceptor::SYSTEM_EXCEPTION)
return "SYSTEM_EXCEPTION";
else if(status == PortableInterceptor::USER_EXCEPTION)
return "USER_EXCEPTION";
else if(status == PortableInterceptor::LOCATION_FORWARD)
return "LOCATION_FORWARD";
else if(status == PortableInterceptor::TRANSPORT_RETRY)
return "TRANSPORT_RETRY";
else
return "invalid reply status id";
}
};
On the server-side interceptor, the following request interceptor point will be triggered in relation to its events.
receive_request_service_contexts - provides an interception point for getting service context information from the incoming request and transferring it to PortableInterceptor::Current slot. This interception point is called before the Servant Manager. For more information, go to , “Using POAs.”
The void receive_request_service_contexts
(ServerRequestInfo ri) interface
void receive_request_service_contexts(PortableInterceptor::ServerRequestInfo_ptr ri) {
...
receive_request - provides an interception point for querying all the information, including operation parameters.
The void receive_request (ServerRequestInfo ri) interface
void receive_request(PortableInterceptor::ServerRequestInfo_ptr ri) {
...
send_reply - provides an interception point for querying reply information and modifying the reply service context after the target operation has been invoked and before the reply is returned to the client.
The void receive_reply (ServerRequestInfo ri)interface
void send_reply(PortableInterceptor::ServerRequestInfo_ptr ri) {
...
send_exception - provides an interception point for querying the exception information and modifying the reply service context before the exception is raised to the client.
The void receive_exception (ServerRequestInfo ri) interface
void send_exception(PortableInterceptor::ServerRequestInfo_ptr ri) {
...
send_other - provides an interception point for querying the information available when a request results in something other than a normal reply or an exception. For example, a request could result in a retry (such as, a GIOP Reply with a LOCATION_FORWARD status was received); or, on asynchronous calls, the reply does not immediately follow the request, but control is returned to the client and an ending interception point is called.
The void receive_other (ServerRequestInfo ri) interface
void send_other(PortableInterceptor::ServerRequestInfo_ptr ri) {
...
All the interception points allow both the client and server to obtain different types of information at different points of an invocation. In the example, this information is displayed as a debugging tool.
The following code example shows the complete implementation of the server-side request interceptor:
// SampleServerInterceptor.h

#include "PortableInterceptor_c.hh"
#include "IOP_c.hh"

// USE_STD_NS is a define setup by VisiBroker to use the std namespace
USE_STD_NS

class SampleServerInterceptor :
public PortableInterceptor::ServerRequestInterceptor
{
private:
char *_name;

void init(char *name) {
_name = new char[strlen(name)+1];
strcpy(_name, name);
}

public:
SampleServerInterceptor(char *name) {
init(name);
}

SampleServerInterceptor() {
init("SampleServerInterceptor");
}

char *name(void) {
return _name;
}

void destroy(void) {
// do nothing here
cout << "=====>SampleServerLoader: Interceptors unloaded" << endl;
}
/**
* This is similar to VisiBroker 4.x ClientRequestInterceptor,
*
* void preinvoke_premarshal(CORBA::Object_ptr target,
* const char* operation,
* IOP::ServiceContextList& servicecontexts,
* VISClosure& closure) = 0;
*/
void
receive_request_service_contexts(PortableInterceptor::ServerRequestInfo_ptr
ri) {
cout << "=====> SampleServerInterceptor id " << ri->request_id()
<< " receive_request_service_contexts => " << ri->operation()
<< endl;
}
/**
* There is no equivalent interface for VisiBroker 4.x
* SeverRequestInterceptor.
*/
void receive_request(PortableInterceptor::ServerRequestInfo_ptr ri)
{
cout << "=====> SampleServerInterceptor id " << ri->request_id()
<< " receive_request => " << ri->operation()
<< ": Object ID = " << ri->object_id()
<< ", Adapter ID = " << ri->adapter_id()
<< endl;
}

/**
* There is no equivalent interface for VisiBroker 4.x
* SeverRequestInterceptor.
*/
void send_reply(PortableInterceptor::ServerRequestInfo_ptr ri) {
cout << "=====> SampleServerInterceptor id " << ri->request_id()
<< " send_reply => " << ri->operation()
<< endl;
}

/**
* This is similar to VisiBroker 4.x ServerRequestInterceptor,
*
* virtual void postinvoke_premarshal(CORBA::Object_ptr _target,
* IOP::ServiceContextList&_service_contexts,
* CORBA::Environment_ptr _env,
* VISClosure& _closure) = 0;
*
* with env holding the exception value.
*/
void send_exception(PortableInterceptor::ServerRequestInfo_ptr ri) {
cout << "=====> SampleServerInterceptor id " << ri->request_id()
<< " send_exception => " << ri->operation()
<< ": Exception = " << ri->sending_exception()
<< ", Reply status = " << getReplyStatus(ri->reply_status())
<< endl;
}

/**
* This is similar to VisiBroker 4.x ServerRequestInterceptor,
*
* virtual void postinvoke_premarshal(CORBA::Object_ptr _target,
* IOP::ServiceContextList& _service_contexts,
* CORBA::Environment_ptr _env,
* VISClosure& _closure) = 0;
*
* with env holding the exception value.
*/
void send_other(PortableInterceptor::ServerRequestInfo_ptr ri) {
cout << "=====> SampleServerInterceptor id " << ri->request_id()
<< " send_other => " << ri->operation()
<< ": Exception = " << ri->sending_exception()

<< ", Reply Status = " << getReplyStatus(ri->reply_status())
<< endl;
}

protected:
char *getReplyStatus(CORBA::Short status) {
if(status == PortableInterceptor::SUCCESSFUL)
return "SUCCESSFUL";
else if(status == PortableInterceptor::SYSTEM_EXCEPTION)
return "SYSTEM_EXCEPTION";
else if(status == PortableInterceptor::USER_EXCEPTION)
return "USER_EXCEPTION";
else if(status == PortableInterceptor::LOCATION_FORWARD)
return "LOCATION_FORWARD";
else if(status == PortableInterceptor::TRANSPORT_RETRY)
return "TRANSPORT_RETRY";
else
return "invalid reply status id";
}
};
Developing the Client and Server Application
After the interceptor classes are written, you need to register them with their respective client and server applications.
The client and server register the respective ORBInitializer classes through the PortableInterceptor::register_orb_initalizer(<class_name>) method, where <class_name> is the name of the class to be registered.
In the example, we also demonstrate another way of registering the interceptor classes as a dynamic link library (DLL). The advantage of registering it this way is that while changes in the execution are required, the application does not require any code changes.
Note
This is a VisiBroker proprietary way of registration. If you wish to have full compliance with OMG, do not use the following style.
If you choose to load the interceptor classes as a DLL (using a proprietary method of VisiBroker), no additional code is required for the client and server applications. Notice that in the example a portion of the code is conditionalized out through a macro if DLL compilation and linking is not specified.
Implementation of the client application
// Client.C

#include "Bank_c.hh"

// USE_STD_NS is a define setup by VisiBroker to use the std namespace
USE_STD_NS

#if !defined( DLL_COMPILE )
#include "SampleClientLoader.C"
#endif

int main(int argc, char* const* argv)
{
try {
// Instantiate the Loader *before* the orb initialization
// if chose not to use DLL method of loading
#if !defined( DLL_COMPILE )
SampleClientLoader* loader = new SampleClientLoader;
PortableInterceptor::register_orb_initializer(loader);
#endif

// Initialize the ORB.
CORBA::ORB_var orb = CORBA::ORB_init(argc, argv);

// Get the manager Id
PortableServer::ObjectId_var managerId =
PortableServer::string_to_ObjectId("BankManager");

// Locate an account manager. Give the full POA name and the
        //servant ID.
Bank::AccountManager_var manager =
Bank::AccountManager::_bind("/bank_agent_poa", managerId);

// use argv[1] as the account name, or a default.
const char* name = argc > 1 ? argv[1] : "Jack B. Quick";

// Request the account manager to open a named account.
Bank::Account_var account = manager->open(name);

// Get the balance of the account.
CORBA::Float balance = account->balance();

// Print out the balance.
cout << "The balance in " << name << "'s account is $" << balance
<< endl;
}
catch(const CORBA::Exception& e) {
cerr << e << endl;
return 1;
}

return 0;
}
Implementation of the server application
// Server.C

#include "BankImpl.h"

// USE_STD_NS is a define setup by VisiBroker to use the std namespace
USE_STD_NS

#if !defined( DLL_COMPILE )
#include "SampleServerLoader.C"
#endif

int main(int argc, char* const* argv)
{
try {
// Instantiate an interceptor loader before initializing the orb:
#if !defined( DLL_COMPILE )
SampleServerLoader* loader = new SampleServerLoader();
PortableInterceptor::register_orb_initializer(loader);
#endif

// Initialize the ORB.
CORBA::ORB_var orb = CORBA::ORB_init(argc, argv);

// Get a reference to the root POA
CORBA::Object_var obj = orb->resolve_initial_references("RootPOA");
PortableServer::POA_var rootPOA = PortableServer::POA::_narrow(obj);

CORBA::PolicyList policies;
policies.length(1);
policies[(CORBA::ULong)0] = rootPOA->create_lifespan_policy(
PortableServer::PERSISTENT);

// get the POA Manager
PortableServer::POAManager_var poa_manager = rootPOA->the_POAManager();

// Create myPOA with the right policies
PortableServer::POA_var myPOA = rootPOA->create_POA("bank_agent_poa",
poa_manager,
policies);
// Create the servant
AccountManagerImpl managerServant;

// Decide on the ID for the servant
PortableServer::ObjectId_var managerId =
PortableServer::string_to_ObjectId("BankManager");

// Activate the servant with the ID on myPOA
myPOA->activate_object_with_id(managerId, &managerServant);

// Activate the POA Manager
poa_manager->activate();

CORBA::Object_var reference =
myPOA->servant_to_reference(&managerServant);
cout << reference << " is ready" << endl;



// Wait for incoming requests
orb->run();
}
catch(const CORBA::Exception& e) {
cerr << e << endl;
return 1;
}
return 0;
}
Compilation procedure
To compile the C++ example without using the VisiBroker propriety loading method, simply execute the following commands:
Windows
<install_dir>\examples\vbe\pi\client_server> nmake -f Makefile.cpp
UNIX
<install_dir>/examples/vbe/pi/client_server> make -f Makefile.cpp
To compile the C++ example using the VisiBroker propriety loading method, execute the following commands:
Windows
<install_dir>\examples\vbe\pi\client_server>
nmake -f Makefile.cpp dll
UNIX
<install_dir>/examples/vbe/pi/client_server>
make -f Makefile.cpp dll
Execution or deployment of Client and Server Applications
To run the C++ example without using the VisiBroker proprietary loading method, start the server and client as follows:
Windows
<install_dir>\examples\vbe\pi\client_server> start Server (running under a new command prompt window)
<install_dir>\examples\vbe\pi\client_server> Client John (using a given name)
or
<install_dir>\examples\vbe\pi\client_server> Client (using a default name)
UNIX
Open two console shells:
<install_dir>/examples/vbe/pi/client_server> Server(in the first window)
<install_dir>/examples/vbe/pi/client_server> Client John (in the second window, using a given name)
or
<install_dir>/examples/vbe/pi/client_server> Client (in the second window, using the default name)
To run the C++ example using the VisiBroker proprietary loading method, start the server and client as follows:
Windows
<install_dir>\examples\vbe\pi\client_server> start Server -Dvbroker.orb.dynamicLibs= SampleServerLoader.dll(running under a new command prompt window)
<install_dir>\examples\vbe\pi\client_server> Client John -Dvbroker.orb.dynamicLibs= SampleClientLoader.dll(using a given name)
or
<install_dir>\examples\vbe\pi\client_server> Client -Dvbroker.orb.dynamicLibs= SampleClientLoader.dll (using a default name)
UNIX
Open two console shells:
<install_dir>/examples/vbe/pi/client_server> Server
-Dvbroker.orb.dynamicLibs=./SampleServerLoader.so (in the first window)
<install_dir>/examples/vbe/pi/client_server> Client
-Dvbroker.orb.dynamicLibs=./SampleClientLoader.so John (in the second window, using a given name)