VisiBroker for Java 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”.
See also the VisiBroker for Java APIs documentation.
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:
public interface Interceptor
extends org.omg.CORBA.portable.IDLEntity, org.omg.CORBA.LocalInterface
{
public java.lang.String name ( );
public void destroy ( );
}
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 Java APIs documentation.
 
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:
1 TII 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 Java APIs documentation.
package org.omg.PortableInterceptor;
public interface ClientRequestInterceptor
extends Interceptor, org.omg.CORBA.portable.IDLEntity, org.omg.CORBA.LocalInterface
{
public void send_request(ClientRequestInfo ri) throws ForwardRequest;
public void send_poll(ClientRequestInfo ri) throws ForwardRequest;
public void receive_reply(ClientRequestInfo ri);
public void receive_exception(ClientRequestInfo ri) throws ForwardRequest;
public void receive_other(ClientRequestInfo ri) throws ForwardRequest;
}
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 Java APIs documentation.
ServerRequestInterceptor Interface:
package org.omg.PortableInterceptor;
public interface ServerRequestInterceptor
extends Interceptor, org.omg.CORBA.portable.IDLEntity, org.omg.CORBA.LocalInterface
{
public void receive_request_service_contexts(ServerRequestInfo ri)
throws ForwardRequest;
public void receive_request(ServerRequestInfo ri) throws ForwardRequest;
public void send_reply(ServerRequestInfo ri);
public void send_exception(ServerRequestInfo ri) throws ForwardRequest;
public void send_other(ServerRequestInfo ri) throws ForwardRequest;
}
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 Java APIs documentation.
package org.omg.PortableInterceptor;
public interface IORInterceptor
extends Interceptor, org.omg.CORBA.portable.IDLEntity, org.omg.CORBA.LocalInterface
{
public void establish_components(IORInfo info);
public void components_established(IORInfo info);
public void adapter_manager_state_changed(int id, short state);
public void adapter_state_changed(
ObjectReferenceTemplate[] templates, short state);
}
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 interface:
package org.omg.PortableInterceptor;
public interface Current
extends org.omg.CORBA.CurrentOperations, org.omg.CORBA.portable.IDLEntity
{
public org.omg.CORBA.Any get_slot(int id) throws InvalidSlot;

public void set_slot(int id, org.omg.CORBA.Any data) throws InvalidSlot;
}
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, see “CodecFactory”.
The Codec interface:
package org.omg.IOP;
public interface Codec
extends org.omg.CORBA.portable.IDLEntity, org.omg.CORBA.LocalInterface
{
public byte[] encode(org.omg.CORBA.Any data) throws InvalidTypeForEncoding;
public org.omg.CORBA.Any decode(byte[] data) throws FormatMismatch;
public byte[] encode_value(org.omg.CORBA.Any data) throws
InvalidTypeForEncoding;
public org.omg.CORBA.Any decode_value(byte[] data,
org.omg.CORBA.TypeCode tc)
throws FormatMismatch, TypeMismatch;
}
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 interface:
package org.omg.IOP;
public interface CodecFactory
extends org.omg.CORBA.portable.IDLEntity, org.omg.CORBA.LocalInterface
{
public Codec create_codec(Encoding enc) throws UnknownEncoding;
}
Creating a Portable Interceptor
The generic steps to create a Portable Interceptor are:
1
ClientRequestInterceptor
ServerRequestInterceptor
IORInterceptor
2
3
Example: Creating a PortableInterceptor
import org.omg.PortableInterceptor.*;

public class SampleClientRequestInterceptor extends org.omg.CORBA.LocalObject
implements ClientRequestInterceptor
{
public java.lang.String name() {
return "SampleClientRequestInterceptor";
}

public void send_request(ClientRequestInfo ri)
throws ForwardRequest {
....... // actual interceptor code here
}

public void send_poll(ClientRequestInfo ri)
throws ForwardRequest {
....... // actual interceptor code here
}

public void receive_reply(ClientRequestInfo ri) {
....... // actual interceptor code here
}

public void receive_exception(ClientRequestInfo ri)
throws ForwardRequest {
....... // actual interceptor code here
}

public void receive_other(ClientRequestInfo ri)
throws ForwardRequest {
....... // 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 interface:
package org.omg.PortableInterceptor;

public interface ORBInitializer
extends org.omg.CORBA.portable.IDLEntity, org.omg.CORBA.LocalInterface
{
public void pre_init(ORBInitInfo info);
public void post_init(ORBInitInfo info);
}
The ORBInitInfo interface:
package org.omg.PortableInterceptor;
public interface ORBInitInfo
extends org.omg.CORBA.portable.IDLEntity, org.omg.CORBA.LocalInterface
{
public java.lang.String[] arguments();
public java.lang.String orb_id();
public CodecFactory codec_factory();
public void register_initial_reference(java.lang.String id, org.omg.CORBA.Object obj)
throws InvalidName;
public void resolve_initial_references(java.lang.String id) throws InvalidName;
public void add_client_request_interceptor(ClientRequestInterceptor interceptor)
throws DuplicateName;
public void add_server_request_interceptor(ServerRequestInterceptor interceptor)
throws DuplicateName;
public void add_ior_interceptor(IORInterceptor interceptor) throws DuplicateName;
public int allocate_slot_id();
public void register_policy_factory(int type, PolicyFactory policy_factory);
}
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.
Since the register_orb_initializer( ) is a global method, it would break applet security with respect to the ORB. As a result, ORBInitializers are registered with VisiBroker ORB by using Java ORB properties instead of calling register_orb_initializer( ).
The new property names are of the form:
org.omg.PortableInterceptor.ORBInitializerClass.<Service>
where <Service> is the string name of a class which implements org.omg.PortableInterceptor.ORBInitializer.
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
Example: Registering ORBInitializer
A client-side monitoring tool written by company ABC may have the following ORBInitializer implementation:
package com.abc.Monitoring;

import org.omg.PortableInterceptor.Interceptor;
import org.omg.PortableInterceptor.ORBInitializer;
import org.omg.PortableInterceptor.ORBInitInfo;

public class MonitoringService extends org.omg.CORBA.LocalObject
implements org.omg.PortableInterceptor.ORBInitializer
{
void pre_init(ORBInitInfo 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 info)
{
// This init point is not needed.
}
}
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 interface:
package com.inprise.vbroker.PortableInterceptor;

public interface IORInfoExt extends
org.omg.CORBA.LocalInterface,
org.omg.PortableInterceptor.IORInfo,
com.inprise.vbroker.PortableInterceptor.IORInfoExtOperations,
org.omg.CORBA.portable.IDLEntity
{
public void add_server_request_interceptor(ServerRequestInterceptor interceptor)
throws DuplicateName;
public java.lang.String[] full_poa_name();
}
Inserting and extracting system exceptions
To conveniently insert and extract SystemExceptions to and from an Any, a utility helper class is provided only for VisiBroker for Java. The com.inprise.vbroker.PortableInterceptor.SystemExceptionHelper class provides the methods to insert and extract the SystemExceptions into and out of an Any respectively. You need to import the following package:
import com.inprise.vbroker.PortableInterceptor.*;
The two methods have the following signatures:
public static void insert (final org.omg.CORBA.Any any, final org.omg.CORBA.SystemException se);
public static org.omg.CORBA.SystemException extract (final org.omg.CORBA.Any any);
Limitations of VisiBroker Portable Interceptors implementation
The following are limitations of the Portable Interceptor implementation in VisiBroker.
ClientRequestInfo limitations
received_exception() and received_exception_id() will always return a CORBA::UNKNOWN exception and its respective repository id if a user exception is thrown by the application.
ServerRequestInfo limitations
exceptions() does not return any value; it will raise a CORBA::NO_RESOURCES exception in both dynamic invocations and static stub based invocation.
contexts() returns the list of contexts that are available during operation invocation.
sending_exception() returns the correct user exception only in the case of dynamic invocation (provided the user exception can be inserted into an Any or its TypeCode information is available).
arguments(), result(), contexts(), and operation_contexts() are only available for DSI invocations. For more information, see “Using the Dynamic Skeleton Interface”.
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. For more information on the definition of each interface, see the VisiBroker for Java APIs documentation.
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/vbroker/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/vbroker/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 packages for using Portable Interceptor are:
import org.omg.PortableInterceptor.*;
import org.omg.PortableInterceptor.ORBInitInfoPackage.*;
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:
public class SampleServerLoader extends org.omg.CORBA.LocalObject implements 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, see “Understanding 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(ORBInitInfo info) {
try {
info.add_client_request_interceptor
(new SampleClientInterceptor());
...
According to the OMG specification, the Java is registered via the following Java ORB property:
org.omg.PortableInterceptor.ORBInitializerClass.<Service>
where <Service> is the string name of a class which implements org.omg.PortableInterceptor.ORBInitializer. For more information, see “Developing the Client and Server Application”.
Complete implementation of the client-side interceptor loader:
// SampleClientLoader.java

import org.omg.PortableInterceptor.*;
import org.omg.PortableInterceptor.ORBInitInfoPackage.*;

public class SampleClientLoader extends org.omg.CORBA.LocalObject
implements ORBInitializer
{
public void pre_init(ORBInitInfo info) {
try {
System.out.println("=====>SampleClientLoader: Installing ...");
info.add_client_request_interceptor(new SampleClientInterceptor());
System.out.println("=====>SampleClientLoader: Interceptors loaded.");
}
catch(DuplicateName dn) {
System.out.println("=====>SampleClientLoader: " + dn.name + " already
installed.");
}
catch(Exception e) {
e.printStackTrace();
throw new org.omg.CORBA.INITIALIZE(e.toString());
}
}
public void post_init(ORBInitInfo info) {
// We do not do anything here.
}
}
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(ORBInitInfo info) {
try {
info.add_server_request_interceptor
(new SampleServerInterceptor());
...
The complete implementation of the server-side interceptor loader:
// SampleServerLoader.java

import org.omg.PortableInterceptor.*;
import org.omg.PortableInterceptor.ORBInitInfoPackage.*;

public class SampleServerLoader extends org.omg.CORBA.LocalObject

implements ORBInitializer

{

public void pre_init(ORBInitInfo info) {
try {
info.add_server_request_interceptor(new
SampleServerInterceptor());
System.out.println("=====>SampleServerLoader: Interceptors loaded");
}
catch(DuplicateName dn) {
System.out.println("Interceptor: " + dn.name + " already
installed.");
}
catch(Exception e) {
e.printStackTrace();
throw new org.omg.CORBA.INITIALIZE(e.toString());
}
}
public void post_init(ORBInitInfo info) {

// We do not do anything here.
}
}
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 String name() {
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 beforehand. On the client-side interceptor, the following request interceptor point will be triggered in relation to its events.
The void send_request(ClientRequestInfo ri) method
send_request—provides an interception point for querying request information and modifying the service context before the request is sent to the server.
public void send_request(ClientRequestInfo ri) throws ForwardRequest {
...
The void send_poll(ClientRequestInfo ri) method
send_poll—provides an interception point for querying information during a Time-Independent Invocation (TII) polling to get the reply sequence.
public void send_poll(ClientRequestInfo ri) {
...
The void receive_reply(ClientRequestInfo ri) method
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.
public void receive_reply(ClientRequestInfo ri) {
...
The void receive_exception(ClientRequestInfo ri) method
receive_exception—provides an interception point for querying the exception's information before it is raised to the client.
public void receive_exception(ClientRequestInfo ri) throws ForwardRequest {
...
The void receive_other(ClientRequestInfo ri) method
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.
public void receive_other(ClientRequestInfo ri) throws ForwardRequest {
...
The complete implementation of the client-side request interceptor follows.
// SampleClientInterceptor.java

import org.omg.PortableInterceptor.*;
import org.omg.Dynamic.*;

public class SampleClientInterceptor extends org.omg.CORBA.LocalObject
implements ClientRequestInterceptor {

public SampleClientInterceptor() {
this("SampleClientInterceptor");
}

public SampleClientInterceptor(String name) {
_name = name;
}
private String _name = null;
/**
* InterceptorOperations implementation
*/
public String name() {
return _name;
}

public void destroy() {
System.out.println("=====>SampleServerLoader: Interceptors unloaded");
}

/**
* ClientRequestInterceptor implementation
*/

/**
* This is similar to VisiBroker 4.x ClientRequestInterceptor,
*
* public void preinvoke_premarshal(org.omg.CORBA.Object target,
String operation,
* ServiceContextListHolder service_contexts_holder, Closure
closure);
*/
public void send_request(ClientRequestInfo ri) throws ForwardRequest {
System.out.println("=====> SampleClientInterceptor id " +
ri.request_id() +
" send_request => " + ri.operation() +
": target = " + ri.target());
}

/**
* There is no equivalent interface for VisiBroker 4.x
* ClientRequestInterceptor.
*/
public void send_poll(ClientRequestInfo ri) {
System.out.println("=====> SampleClientInterceptor id " +
ri.request_id() +
" send_poll => " + ri.operation() +
": target = " + ri.target());
}

/**
* This is similar to VisiBroker 4.x ClientRequestInterceptor,
*
* public void postinvoke(org.omg.CORBA.Object target,
* ServiceContext[] service_contexts, InputStream payload,
* org.omg.CORBA.Environment env, Closure closure);
*
* with env not holding any exception value.
*/
public void receive_reply(ClientRequestInfo ri) {
System.out.println("=====> SampleClientInterceptor id " +
ri.request_id() +
" receive_reply => " + ri.operation());
}

/**
* This is similar to VisiBroker 4.x ClientRequestInterceptor,
*
* public void postinvoke(org.omg.CORBA.Object target,
* ServiceContext[] service_contexts, InputStream payload,
* org.omg.CORBA.Environment env, Closure closure);
*
* with env holding the exception value.
*/
public void receive_exception(ClientRequestInfo ri) throws ForwardRequest {
System.out.println("=====> SampleClientInterceptor id " +
ri.request_id() +
" receive_exception => " + ri.operation() +
": exception = " + ri.received_exception());
}

/**
* This is similar to VisiBroker 4.x ClientRequestInterceptor,
*
* public void postinvoke(org.omg.CORBA.Object target,
* ServiceContext[] service_contexts, InputStream payload,
* org.omg.CORBA.Environment env, Closure closure);
*
* with env holding the exception value.
*/
public void receive_other(ClientRequestInfo ri) throws ForwardRequest {
System.out.println("=====> SampleClientInterceptor id " +
ri.request_id() +
" receive_reply => " + ri.operation() +
": exception = " + ri.received_exception() +
", reply status = "+ getReplyStatus(ri));
}

protected String getReplyStatus(RequestInfo ri) {
switch(ri.reply_status()) {
case SUCCESSFUL.value:
return "SUCCESSFUL";
case SYSTEM_EXCEPTION.value:
return "SYSTEM_EXCEPTION";
case USER_EXCEPTION.value:
return "USER_EXCEPTION";
case LOCATION_FORWARD.value:
return "LOCATION_FORWARD";
case TRANSPORT_RETRY.value:
return "TRANSPORT_RETRY";
default:
return "invalid reply status id";
}
}
}
Implementing the ServerRequestInterceptor for Server
On the server-side interceptor, the following request interceptor points will be triggered in relation to its events:
The void receive_request_service_contexts (ServerRequestInfo ri) method
public void receive_request_service_contexts(ServerRequestInfo ri) throws ForwardRequest {
...
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, see “Using servants and servant managers”.
The void receive_request (ServerRequestInfo ri) method
receive_request—provides an interception point for querying all the information, including operation parameters.
public void receive_request(ServerRequestInfo ri) throws ForwardRequest {
...
The void send_reply (ServerRequestInfo ri) method
public void send_reply(ServerRequestInfo 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 send_exception (ServerRequestInfo ri) method
public void send_exception(ServerRequestInfo ri) throws ForwardRequest {
...
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 send_other (ServerRequestInfo ri) method
public void send_other(ServerRequestInfo ri) throws ForwardRequest {
...
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.
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.java

import org.omg.PortableInterceptor.*;
import org.omg.Dynamic.*;
import java.io.PrintStream;

public class SampleServerInterceptor extends org.omg.CORBA.LocalObject
implements ServerRequestInterceptor {

private String _name = null;

public SampleServerInterceptor() {
this("SampleServerInterceptor");
}

public SampleServerInterceptor(String name) {
_name = name;
}
/**
* InterceptorOperations implementation
*/
public String name() {
return _name;
}

public void destroy() {
System.out.println("=====>SampleServerLoader: Interceptors unloaded");
}

/**
* ServerRequestInterceptor implementation
*/

/**
* This is similar to VisiBroker 4.x ServerRequestInterceptor,
*
* public void preinvoke(org.omg.CORBA.Object target, String operation,
* ServiceContext[] service_contexts, InputStream payload, Closure closure);
*/


public void receive_request_service_contexts(ServerRequestInfo ri)
throws ForwardRequest {
System.out.println("=====> SampleServerInterceptor id " + ri.request_id() +
" receive_request_service_contexts => " + ri.operation());
}

/**
* There is no equivalent interface for VisiBroker 4.x
* SeverRequestInterceptor.
*/
public void receive_request(ServerRequestInfo ri)
throws ForwardRequest {
System.out.println("=====> SampleServerInterceptor id " + ri.request_id() +
" receive_request =>" + ri.operation() +
": object id = " + ri.object_id() +
", adapter_id = " + ri.adapter_id());
}

/**
* There is no equivalent interface for VisiBroker 4.x
* SeverRequestInterceptor.
*/
public void send_reply(ServerRequestInfo ri) {
System.out.println("=====> SampleServerInterceptor id " + ri.request_id() +
" send_reply =>" + ri.operation());
}

/**
* This is similar to VisiBroker 4.x ServerRequestInterceptor,
*
* public void postinvoke_premarshal(org.omg.CORBA.Object target,
* ServiceContextListHolder service_contexts_holder,
* org.omg.CORBA.Environment env, Closure closure);
*
* with env holding the exception value.
*/
public void send_exception(ServerRequestInfo ri)
throws ForwardRequest {
System.out.println("=====> SampleServerInterceptor id " + ri.request_id() +
" send_exception =>" + ri.operation() +
": exception = " + ri.sending_exception() +
", reply status = " + getReplyStatus(ri));
}

/**
* This is similar to VisiBroker 4.x ServerRequestInterceptor,
*
* public void postinvoke_premarshal(org.omg.CORBA.Object target,
* ServiceContextListHolder service_contexts_holder,
* org.omg.CORBA.Environment env, Closure closure);
*
* with env holding the exception value.
*/
public void send_other(ServerRequestInfo ri) throws ForwardRequest {
System.out.print("=====> SampleServerInterceptor id " + ri.request_id() +
" send_other =>" + ri.operation() +
": exception = " + ri.sending_exception() +
", reply status = " + getReplyStatus(ri));
}
protected String getReplyStatus(RequestInfo ri) {
switch(ri.reply_status()) {
case SUCCESSFUL.value:
return "SUCCESSFUL";
case SYSTEM_EXCEPTION.value:
return "SYSTEM_EXCEPTION";
case USER_EXCEPTION.value:
return "USER_EXCEPTION";
case LOCATION_FORWARD.value:
return "LOCATION_FORWARD";
case TRANSPORT_RETRY.value:
return "TRANSPORT_RETRY";
default:
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 OMG specification has been strictly followed to implement the mappings of register_orb_initializer, which is registered using Java ORB properties. In the example, the client and server applications actually read the property files, client.properties, and server.properties containing the property
org.omg.PortableInterceptor.ORBInitializerClass.<Service>
where <Service> is the string name of a class which implements org.omg.PortableInterceptor.ORBInitializer. In this case, the two classes are SampleClientLoader and SampleServerLoader.
If you choose to write your application without reading any properties from a file, you can also use the command line option. To do so, run the application with the following parameters:
vbj -Dorg.omg.PortableInterceptor.ORBInitializerClass.SampleClientLoader=
SampleClientLoader Client
vbj -Dorg.omg.PortableInterceptor.ORBInitializerClass.SampleServerLoader=
SampleServerLoader Server
Implementing the client application
// Client.java

import org.omg.PortableServer.*;

import java.util.Properties;
import java.io.FileInputStream;

public class Client {

private static Properties property = null;

public static void main(String[] args) {
try {
property = new Properties();
property.load(new FileInputStream("client.properties"));

// Initialize the ORB.
org.omg.CORBA.ORB orb=org.omg.CORBA.ORB.init(args, property);
// Get the manager Id
byte[] AccountManagerId="BankManager".getBytes();
// Locate an account manager. Give the full POA name and servant ID.
Bank.AccountManager manager =
Bank.AccountManagerHelper.bind(orb, "/bank_client_server_poa",
AccountManagerId);
// use args[0] as the account name, or a default.
String name = null;
name = args.length > 0 ? args[0] : "Jack B. Quick";
// Request the account manager to open a named account.
Bank.Account account = manager.open(name);
// Get the balance of the account.
float balance = account.balance();
// Print out the balance.
System.out.println("The balance in " + name + "'s account is $" +
balance);
}
catch(Exception e) {
e.printStackTrace();
}
}
}
Implementing the server application
// Server.java

import org.omg.PortableServer.*;
import java.util.Properties;
import java.io.FileInputStream;

public class Server {

private static Properties property = null;

public static void main(String[] args) {
try {
property = new Properties();
property.load(new FileInputStream("server.properties"));

// Initialize the ORB.
org.omg.CORBA.ORB orb = org.omg.CORBA.ORB.init(args, property);
// get a reference to the root POA
POA rootPoa = POAHelper.narrow(orb.resolve_initial_references("RootPOA"));

// Create policies for our persistent POA
org.omg.CORBA.Policy[] policies = {
rootPoa.create_lifespan_policy(LifespanPolicyValue.PERSISTENT)
};

// Create myPOA with the right policies
POA myPOA = rootPoa.create_POA("bank_client_server_poa",
rootPoa.the_POAManager(), policies );

// Create Account servants
AccountManagerImpl managerServant = new AccountManagerImpl();
byte[] managerId = "BankManager".getBytes();
myPOA.activate_object_with_id(managerId, managerServant);
rootPoa.the_POAManager().activate();

//Announce Servants are ready
System.out.println(myPOA.servant_to_reference(managerServant) + " is
ready.");
// Wait for incoming requests
orb.run();
}
catch (Exception e) {
e.printStackTrace();
}
}
}
Compilation procedure
To compile the Java example, execute the following command:
Windows
<install_dir>\examples\vbroker\pi\client_server> vbmake
or double-click the batch file icon if the environment variable, <install_dir>\bin, has already been added to the environment variable, PATH).
UNIX
<install_dir>/examples/vbroker/pi/client_server> make -f Makefile.java
Execution or deployment of Client and Server Applications
To run the Java example with Portable Interceptor installed, start the Server and Client as follows:
Windows
Open two console windows:
<install_dir>\examples\vbroker\pi\client_server> start vbj Server (running under a new command prompt window)
<install_dir>\examples\vbroker\pi\client_server> vbj Client John (using a given name)
or
<install_dir>\examples\vbroker\pi\client_server> vbj Client(using the default name)
UNIX
Open two console shells:
<install_dir>/examples/vbroker/pi/client_server> vbj Server(in the first window)
<install_dir>/examples/vbroker/pi/client_server> vbj Client John (in the second window, using a given name)
or
<install_dir>/examples/vbroker/pi/client_server> vbj Client (in the second window, using the default name)