Portable Interceptors

We have revised TAO's interceptor implementation so that it conforms to the Portable Interceptor specification. The purpose of this document is to provide a transition guide for those who have used our old interceptors. The old interceptors will no longer be supported now that we have the new mechanism in place. A paper that describes TAO's portable interceptors and smart proxies is available online.


Table of Contents


Context

Interceptors allow you to interpose other CORBA services to the ORB and extend the ORB's functionalities. They are most commonly used in, but not limited to, Security Service, Transaction Service. They are also for doing accounting and debugging distributed application.

Although both CORBA 2.2 and 2.3 define an interceptor interface, the definitions are pretty much useless because it does not define how the interceptor should interact with an ORB. Therefore, OMG is currently trying to define a " Portable Interceptor" specification which will remedy the problems and allow application users to use interceptos from different venders with their ORBs.


TAO's Implementation of "Portable Interceptors"

TAO's portable interceptor implementation was developped before even a joint submission was available. There were several proposed standards which defined very different interfaces and capabilities. The old interceptor implementation provides a minimum subset of functionalities proposed in the initial submissions. This approach has allowed TAO users to explore various use cases of interceptors and prevented users from adding code that depended on the interceptor features which would not be supported when the spec gets finalized.

We have modifed TAO's interceptor interface to conform with the proposed spec. The current version of interceptors consists of support for the Dynamic module as well as the canonical interception points including (1) send_request, (2) receive_request, (3) send_reply, (4) receive_reply, (5) send_exception, (6) receive_exception, and (7) establish_components (specific to IORInterceptors). Each request interception point is passed a RequestInfo object which encapsulates the details of the operation like arguments, etc. The IOR interception point is passed an IORInfo object that encapsulates operations for adding tagged components to profiles in an IOR. Registration of all three types of interceptors (client and server request interceptors, and IOR interceptors) is now done using the interface provided by the standard ORBInitInfo object.

Details of this implementation along with benchmarking is available in the paper on Meta-programming mechanisms.

Examples on this new version of Portable Interceptors is available at $TAO_ROOT/tests/Portable_Interceptors.


Transitting from TAO's Old "Portable" Interceptor APIs to the Standard Portable Interceptor APIs

Please refer to the working draft for details on the proposed Portable Interceptor interfaces. Below is the old but now obsolete interceptor version in TAO.

// -*- IDL -*- $Id$

// This file contains the interface definitions for "Portable"
// Interceptor support.

// **********************************************************
//   Notice that the Portable Interceptor specification
//   is still under discussion in OMG and both the IDL
//   and the implementation details in TAO will eventually
//   change to conform with the PI spec in the future.
//
//   @@ Now that a working draft of the Portable Interceptors
//      is available, we will provide a compliant implementation
//      shortly.
//
//      Please see the annotation marked with "@@" in this file
//      for hints on transitting from the temporary
//      implementation to new APIs.
//
//      See $TAO_ROOT/docs/interceptors.html for more info.
// **********************************************************

// Author (currently): Nanbor Wang 
// @@ I will no longer be the author of this IDL file. ;-)

#include 
#include 

#pragma prefix "TAO"
// The prefix should be changed to "omg.org" once the spec. gets
// finallized.
// @@ The prefix will be changed to "omg.org".

module PortableInterceptor
{
  interface Cookie
    {
      // Cookie's are used to pass information among interceptors
      // within a invocation or an upcall.
      //
      // @@ Cookie will no longer be available.
      string myname ();
    };

  typedef sequence  Cookies;
  // Collections of Cookie's become Cookies'es.
  //
  // @@ Cookies will no longer be available.

  interface Interceptor
    {
      // Base interface for Interceptors.
      //
      // @@ This interface will not change.
      readonly attribute string name;
    };

  interface ServerRequestInterceptor : Interceptor
    {
      // Server side request interceptor definition.
      //
      // @@ The name of the interface will not change.

      void preinvoke (in unsigned long request_id,
                      in boolean response_expected,
                      in CORBA::Object objref,
                      in string operation_name,
                      inout IOP::ServiceContextList sc,
                      inout NVList arguments,
                      inout Cookies ck);
      // Interception pointer before invoking the servant method.
      // Currently, we don't pass NVList into the interceptor because
      // I haven't figured out how to best optimize this stuff.
      // In the future, NVList will contain all in and inout arguments
      // of the operation.
      //
      // @@ This operation will map to either
      // <receive_request_service_contexts> or <receive_request> of
      // the standard APIs.  If you are not sure, use
      // <receive_request>.
      //
      // void receive_request_service_contexts (in ServerRequestInfo ri) raises (ForwardRequest);
      // void receive_request (in ServerRequestInfo ri) raises (ForwardRequest);
      //
      // @@ Note that all arguments will be accessed thru
      // <PortableInterceptor::ServerRequestInfo> interface.

      void postinvoke (in unsigned long request_id,
                       in boolean response_expected,
                       in CORBA::Object objref,
                       in string operation_name,
                       inout IOP::ServiceContextList sc,
                       inout NVList arguments,
                       inout Cookies ck);
      // Interception pointer after invoking the servant method.
      // Currently, we don't pass NVList into the interceptor because
      // I haven't figured out how to best optimize this stuff.
      // In the future, NVList will contain all out, inout arguments
      // and the return value of the operation.
      //
      // @@ This operation will map to <send_reply>.
      // It is not clear whether oneway call will invoke <send_other>
      // operation or not.
      //
      // void send_reply (in ServerRequestInfo ri);
      // void send_other (in ServerRequestInfo ri) raises (ForwardRequest);
      //
      // @@ Note that all arguments will be accessed thru
      // <PortableInterceptor::ServerRequestInfo> interface.

      void exception_occurred (in unsigned long request_id,
                               in boolean response_expected,
                               in CORBA::Object objref,
                               in string operation_name,
                               inout Cookies ck);
      // Exception interception point.
      //
      // @@ This method will map to <send_exception> method.
      //
      // void send_exception (in ServerRequestInfo ri) raises (ForwardRequest);
      //
      // @@ Note that all arguments will be accessed thru
      // <PortableInterceptor::ServerRequestInfo> interface.
    };

  interface ClientRequestInterceptor : Interceptor
    {
      // Client side interceptor.
      //
      // @@ The name of the interface will not change.

      void preinvoke (in unsigned long request_id,
                      in boolean response_expected,
                      in CORBA::Object objref,
                      in string operation_name,
                      inout IOP::ServiceContextList sc,
                      inout NVList arguments,
                      inout Cookies ck);
      // Before remote invocation.
      // Currently, we don't pass NVList into the interceptor because
      // I haven't figured out how to best optimize this stuff.
      // In the future, NVList will contain all in and inout arguments
      // of the operation.
      //
      // @@ This operation will map to <send_request> of the standard
      // APIs.
      //
      // void send_request (in ClientRequestInfo) raises (ForwardRequest);
      //
      // @@ Note that all arguments will be accessed thru
      // <PortableInterceptor::ClientRequestInfo> interface.

      void postinvoke (in unsigned long request_id,
                       in boolean response_expected,
                       in CORBA::Object objref,
                       in string operation_name,
                       inout IOP::ServiceContextList sc,
                       inout NVList arguments,
                       inout Cookies ck);
      // After returned from remote invocation.
      // Currently, we don't pass NVList into the interceptor because
      // I haven't figured out how to best optimize this stuff.
      // In the future, NVList will contain all out, inout arguments
      // and the return value of the operation.
      //
      // @@ This operation will map to either <receive_reply> or
      // <receive_other> in the standard APIs depending on whether the
      // operation is oneway or not.
      //
      // void receive_reply (in ClientRequestInfo ri);
      // void receive_other (in ClientRequestInfo ri);
      //
      // @@ Note that all arguments will be accessed thru
      // <PortableInterceptor::ClientRequestInfo> interface.

      void exception_occurred (in unsigned long request_id,
                               in boolean response_expected,
                               in CORBA::Object objref,
                               in string operation_name,
                               inout Cookies ck);
      // Exception occurred.
      //
      // @@ This method will map to <receive_exception> method as:
      //
      //    void receive_exception (in ClientRequestInfo ri) raises (ForwardRequest);
      //
      // @@ Note that all arguments will be accessed thru
      // <PortableInterceptor::ClientRequestInfo> interface.
    };
};

#pragma prefix ""

Current Status


Future Work

  1. Add support for the ThruPOA collocation optimization to the interceptor chain; the direct collocation optimization will not go through the interceptor chain.
  2. Implement the PortableInterceptor::Current interface. Useful for passing data between interceptors.
  3. Implement the CodecFactory interface, and an accompanying CDR encapsulation Codec. Implementations of each are almost ready and should be available soon. The CDR encapsulation Codec is useful for embedding data in an octet sequence that conforms to the CDR encapsulation rules. For example, it could be used to create the octet sequence that is part of an IOP::TaggedComponent. This means that it could compliment the IOR interceptor support.
  4. Implement the remaining interception points, namely: receive_other, receive_request_service_contexts and send_other. The send_poll implementation will most likely be deferred until TII is supported in TAO.

Known Issues


References