Interceptors

# Chapter 10 Interceptors

omniORB supports interceptors that allow the application to insert processing in various points along the call chain, and in various other locations. It does not (yet) support the standard Portable Interceptors API.

The interceptor interfaces are defined in a single header, `include/omniORB4/omniInterceptors.h`. Each interception point consists of a singleton object with `add()` and `remove()` methods, and the definition of an ‘interceptor info’ class. For example:

class omniInterceptors { ... class clientSendRequest_T { public: class info_T { public: GIOP_C& giop_c; IOP::ServiceContextList service_contexts; info_T(GIOP_C& c) : giop_c(c), service_contexts(5) {} private: info_T(); info_T(const info_T&); info_T& operator=(const info_T&); }; typedef CORBA::Boolean (*interceptFunc)(info_T& info); void add(interceptFunc); void remove(interceptFunc); }; ... };

You can see that the interceptors themselves are functions that take the `info_T` object as their argument and return boolean. Interceptors are called in the order they are registered; normally, all interceptor functions return true, meaning that processing should continue with subsequent interceptors. If an interceptor returns false, later interceptors are not called. You should only do that if you really know what you are doing.

Notice that the `info_T` contains references to omniORB internal data types. The definitions of these types can be found in other header files within `include/omniORB4` and `include/omniORB4/internal`.

## 10.1 Interceptor registration

All the interceptor singletons are registered within another singleton object of class `omniInterceptors`. You retrieve a pointer to the object with the `omniORB::getInterceptors()` function, which must be called after the ORB has been initialised with `CORBA::ORB_init()`, but before the ORB is used. The code to register an interceptor looks, for example, like:

omniInterceptors* interceptors = omniORB::getInterceptors(); interceptors->clientSendRequest.add(myInterceptorFunc);

## 10.2 Available interceptors

The following interceptors are available:

encodeIOR
  Called when encoding an IOR to represent an object reference. This interception point allows the application to insert extra profile components into IORs. Note that you must understand and adhere to the rules about data stored in IORs, otherwise the IORs created may be invalid. omniORB itself uses this interceptor to insert various items, so you can see an example of its use in the `insertSupportedComponents()` function defined in `src/lib/omniORB/orbcore/ior.cc`.
decodeIOR
  Called when decoding an IOR. The application can use this to get out whatever information they put into IORs with encodeIOR. Again, see `extractSupportedComponents()` in `src/lib/omniORB/orbcore/ior.cc` for an example.
clientOpenConnection
  Called as a client opens a new connection to a server, after the connection is opened but before it is used to send a request. The interceptor function can set the `info_T`’s `reject` member to true to cause the client to immediately close the new connection and throw CORBA::TRANSIENT to the calling code. In that case, the interceptor function can also set the `why` member to provide a message that is logged.
clientSendRequest
  Called just before a request header is sent over the network. The application can use it to insert service contexts in the header. See `setCodeSetServiceContext()` in `src/lib/omniORB/orbcore/cdrStream.cc` for an example of its use.
clientReceiveReply
  Called as the client receives a reply, just after unmarshalling the reply header. Called for normal replies and exceptions.
serverAcceptConnection
  Called when a server accepts a new incoming connection, but before it reads any data from it. The interceptor function can set the `info_T`’s `reject` member to true to cause the server to immediately close the new connection. In that case, the interceptor function can also set the `why` member to provide a message that is logged.
serverReceiveRequest
  Called when the server receives a request, just after unmarshalling the request header. See the `getCodeSetServiceContext()` function in `src/lib/omniORB/orbcore/cdrStream.cc` for an example.
serverSendReply
  Called just before the server marshals a reply header.
serverSendException
  Called just before the server marshals an exception reply header.
createIdentity
  Called when the ORB is about to create an ‘identity’ object to represent a CORBA object. It allows application code to provide its own identity implementations. It is very unlikely that an application will need to do this.
createORBServer
  Used internally by the ORB to register different kinds of server. At present, only a GIOP server is registered. It is very unlikely that application code will need to do this.
createThread
  Called whenever the ORB creates a thread. The `info_T` class for this interceptor is
  class info_T { public: virtual void run() = 0; };

  The interceptor function is called in the context of the newly created thread. The function must call the `info_T`’s `run()` method, to pass control to the thread body. `run()` returns just before the thread exits. This arrangement allows the interceptor to initialise some per-thread state before the thread body runs, then release it just before the thread exits.

assignUpcallThread
  The ORB maintains a general thread pool, from which threads are drawn for various purposes. One purpose is for performing upcalls to application code, in response to incoming CORBA calls. The assignUpcallThread interceptor is called when a thread is assigned to perform upcalls. In the thread per connection model, the thread stays assigned to performing upcalls for the entire lifetime of the underlying network connection; in the thread pool model, threads are assigned for upcalls on a per call basis, so this interceptor is triggered for every incoming call1. As with the createThread interceptor, the interceptor function must call the `info_T`’s `run()` method to pass control to the upcall.

  When a thread finishes its assignment of processing upcalls, it returns to the pool (even in thread per connection mode), so the same thread can be reassigned to perform more upcalls, or reused for a different purpose.

  Unlike the other interceptors, the interceptor functions for createThread and assignUpcallThread have no return value. Interceptor chaining is performed by calls through the `info_T::run()` method, rather than by visiting interceptor functions in turn.

1
  Except that with the threadPoolWatchConnection parameter set true, a thread can perform multiple upcalls even when thread pool mode is active.