Java IDL: Portable Interceptors (PI)

#
Java IDL and Java RMI-IIOP Technologies:
Using Portable Interceptors (PI)

Last Update: 4/25/2002

NOTICE: This document is intended for advanced CORBA developers.

The JavaTM CORBA Object Request Broker (ORB) provides hooks, or interception points, through which ORB services can intercept the normal flow of execution of the ORB. These Portable Interceptors provide a mechanism for plugging in additional ORB behavior, or, by modifying the communications between client and server, for modifying the behavior of the ORB. The example that follows shows different ways of using Portable Interceptors.

Support for Portable Interceptors is a major recent addition to the CORBA specification. Using RequestInterceptors, one can easily write and attach portable ORB hooks that will intercept any ORB-mediated invocation. Using IORInterceptors, one can write code to annotate CORBA object references.

It is highly recommended that you read the Portable Interceptors Specification at ptc/2001-03-04 before reading this document.

The following topics are included in this document:

- Interceptor Types
- Registering `ORBInitializers` in Java
  - Notes About the Scope of Interceptors
  - Notes on Interceptor Order
  - Notes about Registering Interceptors
- Portable Interceptor Current (`PICurrent`)
  - Obtaining PICurrent
  - Obtaining PICurrent
  - Request Scope vs Thread Scope
- Portable Interceptor Example
  - Flowing Context Information between Clients and Servers
  - Avoiding Infinite Recursion During Interceptor Outcalls
  - Avoiding Recursion for Colocated Outcall References
  - Avoid recursion by using multiple ORBs
- Example Code
- Compiling and running the application

# Interceptor Types There are currently three types of interceptors that can be registered, as shown below. Examples of each are shown in the example that follows.

- `IORInterceptor`

  In some cases, a portable ORB service implementation may need to add information describing the server's or object's ORB service-related capabilities to object references in order to enable the ORB service implementation in the client to function properly. This is supported through the `IORInterceptor` and `IORInfo` interfaces. The IOR Interceptor is used to establish tagged components in the profiles within an Interoperable Object Reference (IOR).

  An example of an IOR Interceptor is shown in the file `AServiceIORInterceptor.java` in the example that follows.

- `ClientRequestInterceptor`

  A request Interceptor is designed to intercept the flow of a request/reply sequence through the ORB at specific points so that services can query the request information and manipulate the service contexts which are propagated between clients and servers. The primary use of request Interceptors is to enable ORB services to transfer context information between clients and servers.

  A `ClientRequestInterceptor` intercepts the flow of a request/reply sequence through the ORB on the client side.

An example of a `ClientRequestInterceptor` is shown in the file `LoggingServiceClientInterceptor.java` in the example that follows.

- `ServerRequestInterceptor`

  A `ServerRequestInterceptor` intercepts the flow of a request/reply sequence through the ORB on the server side.

  An example of a `ServerRequestInterceptor` is shown in the file `LoggingServiceServerInterceptor.java` in the example that follows.

# Registering `ORBInitializers` in Java

The `ORBInitializer` interface facilitates interceptor registration and ORB initialization.

Interceptors are intended to be a means by which ORB services gain access to ORB processing, effectively becoming part of the ORB. Since interceptors are part of the ORB, when `ORB.init` returns an ORB, the interceptors shall have been registered. Interceptors cannot be registered on an ORB after it has been returned by a call to `ORB.init`.

`ORBInitializers` are registered via Java ORB properties. An interceptor is registered by registering an associated `ORBInitializer` object which implements the `ORBInitializer` interface. When an ORB is initializing, it shall call each registered `ORBInitializer`, passing it an `ORBInitInfo` object which is used to register its interceptor.

The 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`

To avoid name collisions, the reverse DNS name convention should be used. For example, if company X has three initializers, it could define the following properties:

- `org.omg.PortableInterceptor.ORBInitializerClass.com.x.Init1`
- `org.omg.PortableInterceptor.ORBInitializerClass.com.x.Init2`
- `org.omg.PortableInterceptor.ORBInitializerClass.com.x.Init3`

Note: Any values associated with `ORBInitializerClass` properties are ignored.

During `ORB.init`, these ORB properties which begin with `org.omg.PortableInterceptor.ORBInitializerClass` shall be collected, the `<Service>` portion of each property shall be extracted, an object shall be instantiated with the `<Service>` string as its class name, and the `pre_init` and `post_init` methods shall be called on that object. If there are any exceptions, the ORB shall ignore them and proceed.

## Notes About the Scope of Interceptors

- Interceptors are registered on a per-ORB basis.

- To achieve virtual per-POA interceptors, instantiate each POA with a different ORB.

## Notes on Interceptor Order

- While interceptors may be ordered administratively, there is no concept of order with respect to the registration of interceptors. Request Interceptors are concerned with service contexts. Service contexts have no order, so there is no purpose for request interceptors to have an order. IOR Interceptors are concerned with tagged components. Tagged components also have no order, so there is no purpose for IOR Interceptors to have an order.

## Notes about Registering Interceptors

- Registration code should avoid using the ORB (i.e., calling `ORB.init` with the provided `orb_id`). Since registration occurs during ORB initialization, results of invocations on this ORB while it is in this state are undefined.

# Portable Interceptor Current (`PICurrent`)

The `PortableInterceptor::Current` object (hereafter referred to as `PICurrent`) is a `Current` object that is used specifically by portable Interceptors to transfer thread context information to a request context. Portable Interceptors are not required to use `PICurrent`, but if information from a client's thread context is required at an Interceptor's interception points, then `PICurrent` can be used to propagate that information. `PICurrent` allows portable service code to be written regardless of an ORB's threading model.

Note: `PICurrent` is typically NOT used directly by CORBA client or server code. Instead, it is generally used by interceptor-based service implementations as demonstrated in the `AService` example interceptor which follows.

## Obtaining PICurrent

Before an invocation is made, `PICurrent` is obtained via a call to `ORB::resolve_initial_references ( PICurrent )`. From within the interception points, the data on `PICurrent` that has moved from the thread scope to the request scope is available via the `get_slot` operation on the `RequestInfo` object. A `PICurrent` can still be obtained via `resolve_initial_references`, but that is the Interceptor's thread scope PICurrent.

## Request Scope vs Thread Scope

The thread scope `PICurrent` (TSC) is the `PICurrent` that exists within a thread's context. A request scope `PICurrent` (RSC) is the `PICurrent` associated with the request. On the client-side, the thread scope `PICurrent` is logically copied to the request scope `PICurrent` from the thread s context when a request begins and is attached to the `ClientRequestInfo` object. On the server-side, the request scope `PICurrent` is attached to the `ServerRequestInfo` and follows the request processing. It is logically copied to the thread scope `PICurrent` after the list of `receive_request_service_contexts` interception points are processed. See the Updated Interceptors specification, Section, 21.4.4.5, Flow of PICurrent between Scopes for a detailed discussion of the scope of `PICurrent`.

# Portable Interceptor Example

This section contains an example logging service application. The sample code for this application is quite complicated because it covers even subtle "corner cases". The following scenarios are covered in this sample application:

1. A logging service which logs invocations. Neither client nor server explicitly use the logging service.

2. An "empty" service which passes information from the client to the server. The client and server explicitly use this service but are not aware that it is implemented using interceptors.

Note: These examples explicitly register `ORBInitializers` to make the code easier to experiment with and setup. Typically this would not be done. Instead, this information would be passed as `-D` properties to the Java virtual machine when the applications are started. That way the applications are not coupled to the fact that either the service exists (e.g., the logging service) or that a service that they explicitly use (e.g., the `AService` interface) is implemented as an interceptor.

The purpose of the logging service example is to show how to avoid infinite recursion when making outcalls (i.e., invocations on CORBA references) from within interception points. This turns out to be quite involved when all corner cases are covered.

The purpose of the "empty" service example is to show how to implement services which flow context information from client to server and back.

## Flowing Context Information between Clients and Servers

A typical interceptor-based service will flow context information between clients and servers. The `AService` example shows how this information is flowed from the client thread into the client interceptors, across the wire into the server interceptors, to the servant thread and back.

It is important to note that neither the client nor the servant is aware that the service is implemented using interceptors. Instead, they interact with the service through local object references (the `aService` reference in this example).

`AService` diagram

Description of the steps of the `AService` diagram:

1. The client invokes `aService.begin()`.

   1.a. `aService.begin()` sets the service context information in a slot it has reserved in `PICurrent`.

2. The client invokes a method on some reference (i.e., `ref.method()`). This invocation is taking place inside the context of the service since `aService.begin()` has been invoked.

3. `send_request` is entered for the `ref.method call`.

4. `get_effective_component(s)` may be called to determine if the reference being invoked needs to interact with the service.

5. `get_slot` is called to retrieve the context set in step 1a. Slots set in `PICurrent` are logically copied and made available to `ClientRequestInfo`.

6. The service interceptor adds a service context containing the appropriate context (most likely depending on the context set in step 1a and any components retrieved in step 4). It uses `add_request_service_context` to add this context information to the request which is sent over the wire.

7. The `ref.method request` arrives at the server, activating the `receive_request_service_contexts` interception point.

8. `get_request_service_context` is used to retrieve the service context added at step 6.

9. `ServerRequestInfo.set_slot` is used to transfer the context information from the service context retrieved in step 8 to the logical thread local data.

10. `receive_request` is entered.

11. The "ref" Servant's "method" is entered.

12. The servant method invokes `aService.verify()` to interact with the service.

13. The service uses `get_slot` on `PICurrent` to retrieve the context information sent from the client side. The service may also use `set_slot` on `PICurrent` to set any return context information.

14. After the Servant completes, the `send_*` interception point is entered. If the service set any return context information, it would add a service context to the return. This is not shown in this example.

15. When the reply arrives at the client, the `receive_*` interception point is entered. If the service set any return context information, it would be retrieved at this point. This is not shown in this example.

## Avoiding Infinite Recursion During Interceptor Outcalls

Some services may need to make invocations on other CORBA object references from within interception points. When making outcalls from within interception points, steps must be taken to avoid infinite recursion since those outcalls will flow through the interception points. The `LoggingService` example illustrates this case.

The `LoggingService example` is comprised of `ClientRequestInterceptors` registered in a client program, and `ServerRequestInterceptors` registered in a server program. These interceptors send information from the client and server to a `LoggingService` implemenation which logs this information.

However, since the `LoggingService` implementation is itself a CORBA server, we must ensure that we do not log calls to the logger. The following diagrams illustrate the steps taken to avoid infinite recursion.

The following diagram shows the simplest case of avoiding recursion when calling an external logger from within interceptors. These steps are useful for the case where the client ORB only contains `ClientRequestInterceptors`, the server ORB only contains `ServerRequestInterceptors`, and the `LoggingService` is external to both the client and server ORBs.

`LoggingService` diagram

Description of the steps of the `LoggingService` diagram:

1. The client invokes a method on some reference.

2. The client interceptor's `send_request` method is entered for the method invoked in step 1.

3. A slot reserved for indicating an outcall is set to `true` on `PICurrent`.

4. The same slot is checked on `ClientRequestInfo` via `get_slot`. This value will not be set since it represents the client's thread state at step 1. Therefore a call to the logger will be made.

5. `send_request` is recursively entered for the logger invocation made in step 4.

6. A slot reserved for indicating an outcall is set to `true` on `PICurrent`. Note, this slot is always unconditionally set. This is necessary when there are 2 or more interceptors doing outcalls. Since interceptors do not know about the existence of other interceptors we always set the `PICurrent` slot.

7. The slot is checked on `ClientRequestInfo` via `get_slot`. This time the value is set (from step 3). Therefore we do not log this call (which is the call to the logger itself). The `send_request` point that entered at step 5 finishes.

8. The ORB sends the log invocation made at step 4 to the logging service.

9. The `send_request` point for step 2 finishes. The ORB sends the initial client invocation made in step 1 to the server for the appropriate reference.

10. The server's `receive_request_service_contexts` point is entered. It logs the incoming request. A server which does not contain client interceptors which make outcalls and which does not contain the implementation of the logger itself does not need to set recursion avoidance slots. That is what this diagram represents.

11. - 13. Therefore all the server side interception points are entered with no further checking and the response from the method initially invoked by the client is returned to the client ORB.

12. The client's `receive_*` point is entered. Steps similar to steps 2 through 9 will occur if this point needs to make an outcall.

## Avoiding Recursion for Colocated Outcall References

The following diagram illustrates the case where the `LoggingService` may be colocated in the same ORB as the reference being invoked by the client. In general, it is not possible to know that a particular object reference is NOT colocated with any other objects hosted by that ORB. Therefore, to cover all corner cases, more steps must be taken.

This diagram shows only the server side. The client side steps are identical to those in the preceding diagram.

`LoggingServiceColocated` diagram

Description of the steps of the `LoggingServiceColocated` diagram:

1. The request from the client ORB arrives, activating the `receive_request_service_contexts` interception point.

2. A slot reserved for indicating an outcall is set to `true` on `PICurrent`.

3. `ServerRequestInfo.get_request_service_context` is used to check for the presence of a service context indicating an outcall. The service context is not present so the logger is invoked from within the interception point.

4. The `send_request` interception point is entered for the logger request.

5. `get_slot` checks for the outcall indicator.

6. The outcall indicator slot has been set (from step 2), therefore `add_request_service_context` is used to a service context indicating an outcall. This is necessary since there is no logical relationship between client and server threads.

7. The logger invocation arrives at `receive_request_service_contexts`.

8. A slot reserved for indicating an outcall is set to `true` on `PICurrent`.

9. `ServerRequestInfo.get_request_service_context` is used to check for the presence of a service context indicating an outcall. The service context is present so no further action is taken. `receive_request_service_contexts` exits.

10. The logger request proceeds to `receive_request`. Steps similar to those taken inside `receive_request_service_context` are necessary if the logger is called at the `receive_request point` (this is not shown in the diagram (although the example code logs all points)).

11. The logger request arrives at the `LoggingService` Servant, which logs the initial client request (not invocation of the logger).

12. The logger request proceeds to `ServerRequestInterceptor.send_*` (most likely `send_reply`).

13. The logger request proceeds to `ClientRequestInterceptor.receive_*` (most likely `receive_reply`).

    After Step 13, the original request that left off at Step 3 would be serviced.

The main point illustrated in this example is the necessity of using both client and server interceptors in conjunction with `PICurrent` slots and service contexts to indicate an outcall.

## Avoid recursion by using multiple ORBs

A simpler way to avoid recursion is to ensure that the outcall references are associated with a different ORB that does not have the logging interceptors registered. That way the outcall invocations never go through interceptors.

This seems like a simple solution, but, in general, interceptors are registered via properties passed to the VM during startup. This means that all ORBs created in that VM will contain all interceptors so this solution will not work.

This solution will only work where interceptors are explicitly registered in client code during `ORB.init`. However, that is neither a typical nor a recommended way to register interceptor-based services.

# Example Code

The following files contain the code which the above diagrams illustrate. Instructions for compiling and executing these examples follow the code. The files included in this example are:

- `serviceexample.idl`
- `LoggingServiceClientORBInitializer.java`
- `LoggingServiceClientInterceptor.java`
- `LoggingServiceServerORBInitializer.java`
- `LoggingServiceServerInterceptor.java`
- `LoggingServiceImpl.java`
- `AServiceORBInitializer.java`
- `AServiceImpl.java`
- `AServiceInterceptor.java`
- `AServiceIORInterceptor.java`
- `ArbitaryObjectImpl.java`
- `Client.java`
- `ColocatedServers.java`

## `serviceexample.idl`

This is the Interface Definition Language (IDL) file that contains definitions of an arbitrary object on which to make invocations and two services which will service calls to the arbitrary object.

    // serviceexample.idl
    // Copyright and License

    module pi
    {
    module serviceexample
    {

        // Create some arbitrary object to call.  Those calls
        // will be serviced by the service implemented using interceptors.

        exception ArbitraryObjectException { string reason; };

        interface ArbitraryObject
        {
                 string         arbitraryOperation1 ( in string a1 );

            oneway void         arbitraryOperation2 ( in long a1 );

    	       void         arbitraryOperation3 ( in string a1 )
    	                        raises (ArbitraryObjectException);
        };

        // This would typically be in a file separate from the "ArbitraryObject"
        // and probably unknown to it.

        interface LoggingService
        {
    	void log ( in string a1 );
        };

        // This would also typically be in a file of its own.
        // IMPORTANT: the interface should be a local object to avoid
        // unnecessary overhead.

        /*local*/ interface AService
        {
    	void begin();
    	void end();
    	void verify();
        };

        // Tagged component for adding to an IOR to indicate that
        // the AService must be in effect when invocations are made
        // on the object containing this tagged component.

        // Note: we explicitly declare the tag type rather than using
        // the IOP typedef (commented out) to simplify compiling this
        // example (i.e., to avoid includes and make include path directives).
        //const IOP::ComponentId TAG_ASERVICE_COMPONENT = 2345;
        const unsigned long TAG_ASERVICE_COMPONENT = 2345;

        struct ASERVICE_COMPONENT {
            boolean requiresAService;
        };

    }; // module serviceexample

    }; // module pi

## `LoggingServiceClientORBInitializer.java`

This file creates and registers the logging service interceptor used by object clients.

    // LoggingServiceClientORBInitializer.java
    // Copyright and License

    package pi.serviceexample;

    import org.omg.CosNaming.*;
    import org.omg.CosNaming.NamingContextPackage.*;
    import org.omg.PortableInterceptor.Current;
    import org.omg.PortableInterceptor.CurrentHelper;
    import org.omg.PortableInterceptor.ORBInitInfo;

    public class LoggingServiceClientORBInitializer
        extends org.omg.CORBA.LocalObject
        implements org.omg.PortableInterceptor.ORBInitializer
    {
        public void pre_init(ORBInitInfo info)
        {
        }

        public void post_init(ORBInitInfo info)
        {
    	try {

    	    // Get a reference to the LoggingService object.

    	    NamingContext nameService =
    		NamingContextHelper.narrow(
                        info.resolve_initial_references("NameService"));

    	    NameComponent path[] =
    	        { new NameComponent("LoggingService", "") };
    	    LoggingService loggingService =
    		LoggingServiceHelper.narrow(nameService.resolve(path));

    	    // Get a reference to TSC PICurrent.

    	    Current piCurrent =
    		CurrentHelper.narrow(
    	            info.resolve_initial_references("PICurrent"));

    	    // Allocate a slot id to use for the interceptor to indicate
    	    // that it is making an outcall.  This is used to avoid
    	    // infinite recursion.

    	    int outCallIndicatorSlotId = info.allocate_slot_id();

    	    // Create (with the above data) and register the client
    	    // side interceptor.

    	    LoggingServiceClientInterceptor interceptor =
    		new LoggingServiceClientInterceptor(loggingService,
    						    piCurrent,
    						    outCallIndicatorSlotId);

    	    info.add_client_request_interceptor(interceptor);
    	} catch (Throwable t) {
    	    System.out.println("Exception handling not shown.");
    	}
        }
    }

## `LoggingServiceClientInterceptor.java`

This interceptor logs client side interception points. It illustrates how to make invocations on other objects from within an interceptor and how to avoid infinite recursion during those "outcall" invocations.

    // LoggingServiceClientInterceptor.java
    // Copyright and License

    package pi.serviceexample;

    import org.omg.CORBA.Any;
    import org.omg.CORBA.ORB;
    import org.omg.CORBA.TCKind;
    import org.omg.IOP.ServiceContext;
    import org.omg.PortableInterceptor.ClientRequestInterceptor;
    import org.omg.PortableInterceptor.ClientRequestInfo;
    import org.omg.PortableInterceptor.Current;
    import org.omg.PortableInterceptor.InvalidSlot;

    public class LoggingServiceClientInterceptor
        extends org.omg.CORBA.LocalObject
        implements ClientRequestInterceptor
    {
        private LoggingService loggingService;
        private Current piCurrent;
        private int outCallIndicatorSlotId;

        public LoggingServiceClientInterceptor(LoggingService loggingService,
    					   Current piCurrent,
    					   int outCallIndicatorSlotId)
        {
    	this.loggingService = loggingService;
    	this.piCurrent = piCurrent;
    	this.outCallIndicatorSlotId = outCallIndicatorSlotId;
        }

        //
        // Interceptor operations
        //

        public String name()
        {
    	return "LoggingServiceClientInterceptor";
        }

        public void destroy()
        {
        }

        //
        // ClientRequestInterceptor operations
        //

        public void send_request(ClientRequestInfo ri)
        {
    	log(ri, "send_request");
        }

        public void send_poll(ClientRequestInfo ri)
        {
    	log(ri, "send_poll");
        }

        public void receive_reply(ClientRequestInfo ri)
        {
    	log(ri, "receive_reply");
        }

        public void receive_exception(ClientRequestInfo ri)
        {
    	log(ri, "receive_exception");
        }

        public void receive_other(ClientRequestInfo ri)
        {
    	log(ri, "receive_other");
        }

        //
        // Utilities.
        //

        public void log(ClientRequestInfo ri, String point)
        {
    	// IMPORTANT: Always set the TSC out call indicator in case
    	// other interceptors make outcalls for this request.
    	// Otherwise the outcall will not be set for the other interceptor's
    	// outcall resulting in infinite recursion.

    	Any indicator = ORB.init().create_any();
    	indicator.insert_boolean(true);
    	try {
    	    piCurrent.set_slot(outCallIndicatorSlotId, indicator);
    	} catch (InvalidSlot e) { }

    	try {
    	    indicator = ri.get_slot(outCallIndicatorSlotId);

    	    // If the RSC out call slot is not set then log this invocation.
    	    // If it is set that indicates the interceptor is servicing the
    	    // invocation of loggingService itself.  In that case do
    	    // nothing (to avoid infinite recursion).

    	    if (indicator.type().kind().equals(TCKind.tk_null)) {
    		loggingService.log(ri.operation() + " " + point);
    	    }
    	} catch (InvalidSlot e) {
    	    System.out.println("Exception handling not shown.");
    	}
        }
    }

## `LoggingServiceServerORBInitializer.java`

This file creates and registers the logging service interceptor used by object servers. Even though this interceptor is meant to only log server-side interception points, it is both a client and server interceptor. The code illustrates how to avoid infinite recursion in the case where the object being called is colocated in the same ORB in which the interceptors are registered.

    // LoggingServiceServerORBInitializer.java
    // Copyright and License

    package pi.serviceexample;

    import org.omg.CosNaming.*;
    import org.omg.CosNaming.NamingContextPackage.*;
    import org.omg.PortableInterceptor.Current;
    import org.omg.PortableInterceptor.CurrentHelper;
    import org.omg.PortableInterceptor.ORBInitInfo;

    public class LoggingServiceServerORBInitializer
        extends org.omg.CORBA.LocalObject
        implements org.omg.PortableInterceptor.ORBInitializer
    {
        public void pre_init(ORBInitInfo info)
        {
        }

        public void post_init(ORBInitInfo info)
        {
    	try {

    	    // Create and register the logging service interceptor.
    	    // Give that interceptor references to the NameService and
    	    // PICurrent to avoid further lookups (i.e., optimization).
    	    // More importantly, allocate and give the interceptor
    	    // a slot id which is will use to tell itself not to
    	    // log calls that the interceptor makes to the logging process.

    	    NamingContext nameService =
    		NamingContextHelper.narrow(
                        info.resolve_initial_references("NameService"));

    	    Current piCurrent =
    		CurrentHelper.narrow(
    	            info.resolve_initial_references("PICurrent"));

    	    int outCallIndicatorSlotId = info.allocate_slot_id();

    	    LoggingServiceServerInterceptor interceptor =
    		new LoggingServiceServerInterceptor(nameService,
    						    piCurrent,
    						    outCallIndicatorSlotId);

    	    info.add_client_request_interceptor(interceptor);
    	    info.add_server_request_interceptor(interceptor);
    	} catch (Throwable t) {
    	    System.out.println("Exception handling not shown.");
    	}
        }
    }

## `LoggingServiceServerInterceptor.java`

This interceptor logs server side interception points, and is implemented as both a `ClientRequestInterceptor` and a `ServerRequestInterceptor` to illustrate the need to set some "out call" service context data (in addition to setting an out call slot) to avoid infinite recursion for the case noted in the description of `LoggingServiceServerORBInitializer.java`.

    // LoggingServiceServerInterceptor.java
    // Copyright and License

    package pi.serviceexample;

    import org.omg.CosNaming.*;
    import org.omg.CosNaming.NamingContextPackage.*;
    import org.omg.CORBA.Any;
    import org.omg.CORBA.BAD_PARAM;
    import org.omg.CORBA.ORB;
    import org.omg.CORBA.TCKind;
    import org.omg.IOP.ServiceContext;
    import org.omg.PortableInterceptor.ClientRequestInterceptor;
    import org.omg.PortableInterceptor.ClientRequestInfo;
    import org.omg.PortableInterceptor.Current;
    import org.omg.PortableInterceptor.InvalidSlot;
    import org.omg.PortableInterceptor.ServerRequestInterceptor;
    import org.omg.PortableInterceptor.ServerRequestInfo;

    public class LoggingServiceServerInterceptor
        extends org.omg.CORBA.LocalObject
        implements ClientRequestInterceptor,
    	       ServerRequestInterceptor
    {
        private NamingContext nameService;
        private LoggingService loggingService;
        private Current piCurrent;
        private int outCallIndicatorSlotId;
        private static final int serviceContextId = 100001;
        private static final byte[] serviceContextData = {1};

        // Returns a reference to the logging process.

        private LoggingService loggingService()
        {
    	if (loggingService == null) {
    	    NameComponent path[] =
    	        { new NameComponent("LoggingService", "") };
    	    try {
    		loggingService =
    		    LoggingServiceHelper.narrow(nameService.resolve(path));
    	    } catch (Throwable t) {
    		System.out.println("Exception handling not shown.");
    	    }
    	}
    	return loggingService;
        }

        public LoggingServiceServerInterceptor(NamingContext nameService,
    					   Current piCurrent,
    					   int outCallIndicatorSlotId)
        {
    	this.nameService = nameService;
    	this.piCurrent = piCurrent;
    	this.outCallIndicatorSlotId = outCallIndicatorSlotId;
        }

        //
        // Interceptor operations
        //

        public String name()
        {
    	return "LoggingServiceServerInterceptor";
        }

        public void destroy()
        {
        }

        //
        // ClientRequestInterceptor operations
        //

        public void send_request(ClientRequestInfo ri)
        {

    	// If the server interceptor sets the recursion slot then
    	// put in the service context so the server doesn't make
    	// the call again in the case where the server side interceptor
    	// is colocated in the same ORB as the object being invoked.

    	try {
    	    Any indicator = ri.get_slot(outCallIndicatorSlotId);
    	    if (indicator.type().kind().equals(TCKind.tk_boolean)) {
    		ServiceContext serviceContext =
    		    new ServiceContext(serviceContextId, serviceContextData);
    		ri.add_request_service_context(serviceContext, false);
    	    }
    	} catch (InvalidSlot e) {
    	    System.out.println("Exception handling not shown.");
    	}
        }

        public void send_poll(ClientRequestInfo ri)
        {
        }

        public void receive_reply(ClientRequestInfo ri)
        {
        }

        public void receive_exception(ClientRequestInfo ri)
        {
        }

        public void receive_other(ClientRequestInfo ri)
        {
        }

        //
        // ServerRequestInterceptor operations
        //

        public void receive_request_service_contexts(ServerRequestInfo ri)
        {
    	log(ri, "receive_request_service_contexts");
        }

        public void receive_request(ServerRequestInfo ri)
        {
    	log(ri, "receive_request");
        }

        public void send_reply(ServerRequestInfo ri)
        {
    	log(ri, "send_reply");
        }

        public void send_exception(ServerRequestInfo ri)
        {
    	log(ri, "send_exception");
        }

        public void send_other(ServerRequestInfo ri)
        {
    	log(ri, "send_other");
        }

        //
        // Utilities.
        //

        public void log(ServerRequestInfo ri, String point)
        {
    	// This is only relevant for the colocated example.
    	// Do not attempt to log until the logging service object
    	// has been bound in naming.  Otherwise the attempt to call
    	// rebind on naming will call log which will fail.
    	if (! ColocatedServers.colocatedBootstrapDone) {
    	    return;
    	}

    	// IMPORTANT:
    	// The conditional logging of the invocation is only necessary
    	// if there is a chance that the object being invoked is colocated
    	// in the same ORB as this interceptor.  Otherwise the outcall to
    	// the logging service can be made unconditionally.

    	// Always set the recursion slot.

    	Any indicator = ORB.init().create_any();
    	indicator.insert_boolean(true);
    	try {
    	    piCurrent.set_slot(outCallIndicatorSlotId, indicator);
    	} catch (InvalidSlot e) {
    	    System.out.println("Exception handling not shown.");
    	}

    	// Make the out call if you have not already done so.

    	try {

    	    // Only the presence of the service context counts.
    	    // The data is ignored.

    	    ri.get_request_service_context(serviceContextId);
    	} catch (BAD_PARAM e) {
    	    // Recursion indicator not set so make the call.
    	    loggingService().log(ri.operation() + " " + point);
    	}
        }
    }

## `LoggingServiceImpl.java`

This file is the implementation of the logging object to which the logging service interceptors send their data.

    //
    // Copyright and License

    package pi.serviceexample;

    import org.omg.CORBA.ORB;
    import org.omg.CosNaming.*;
    import org.omg.CosNaming.NamingContextPackage.*;
    import org.omg.PortableServer.POAHelper;

    import java.util.Properties;

    class LoggingServiceImpl
        extends LoggingServicePOA
    {
        public static ORB orb;

        //
        // The IDL operations.
        //

        public void log(String a1)
        {
    	System.out.println(a1);
        }

        //
        // The server.
        //

        public static void main(String[] av)
        {
    	try {
    	    if (orb == null) {
    		orb = ORB.init(av, null);
    	    }

    	    POA rootPOA =  POAHelper.narrow( orb.resolve_initial_references("RootPOA"));
    	    rootPOA.the_POAManager().activate();

    	    byte[] objectId =
    		rootPOA.activate_object(new LoggingServiceImpl());
    	    org.omg.CORBA.Object ref = rootPOA.id_to_reference(objectId);

    	    NamingContext nameService =
    		NamingContextHelper.narrow(
                        orb.resolve_initial_references("NameService"));
    	    NameComponent path[] =
    	        { new NameComponent("LoggingService", "") };
    	    nameService.rebind(path, ref);

    	    // Only relevant for colocated example.
    	    ColocatedServers.colocatedBootstrapDone = true;

    	    System.out.println("LoggingService ready.");

    	    orb.run();

            } catch (Exception e) {
    	    e.printStackTrace();
    	    System.exit(-1);
            }
    	System.exit(0);
        }
    }

## `AServiceORBInitializer.java`

The file creates and registers the `AServiceInterceptor` as both a client and server interceptor, creates and registers the `AServiceIORInterceptor` which puts a TaggedComponent into IORs, and creates a local object to be used by applications to explicitly control the services offered by `AService`. This local object is registered as an initial service with the ORB such that it can be obtained by clients using `org.omg.CORBA.ORB.resolve_initial_references`.

    // AServiceORBInitializer.java
    // Copyright and License

    package pi.serviceexample;

    import org.omg.IOP.Codec;
    import org.omg.IOP.CodecFactory;
    import org.omg.IOP.CodecFactoryHelper;
    import org.omg.IOP.Encoding;
    import org.omg.PortableInterceptor.Current;
    import org.omg.PortableInterceptor.CurrentHelper;
    import org.omg.PortableInterceptor.ORBInitInfo;

    public class AServiceORBInitializer
        extends org.omg.CORBA.LocalObject
        implements org.omg.PortableInterceptor.ORBInitializer
    {
        private AServiceImpl aServiceImpl;
        private AServiceInterceptor aServiceInterceptor;

        public void pre_init(ORBInitInfo info)
        {
    	try {
    	    int id = info.allocate_slot_id();

    	    aServiceInterceptor = new AServiceInterceptor(id);

    	    info.add_client_request_interceptor(aServiceInterceptor);
    	    info.add_server_request_interceptor(aServiceInterceptor);

    	    // Create and register a reference to the service to be
    	    // used by client code.

    	    aServiceImpl = new AServiceImpl(id);

    	    info.register_initial_reference("AService", aServiceImpl);

    	} catch (Throwable t) {
    	    System.out.println("Exception handling not shown.");
    	}
        }

        public void post_init(ORBInitInfo info)
        {
    	try {

    	    Current piCurrent =
    		CurrentHelper.narrow(
    		    info.resolve_initial_references("PICurrent"));
    	    aServiceImpl.setPICurrent(piCurrent);

    	    CodecFactory codecFactory =
    		CodecFactoryHelper.narrow(
    	            info.resolve_initial_references("CodecFactory"));
    	    Encoding encoding = new Encoding((short)0, (byte)1, (byte)2);
    	    Codec codec = codecFactory.create_codec(encoding);
    	    aServiceInterceptor.setCodec(codec);

    	    AServiceIORInterceptor aServiceIORInterceptor =
    		new AServiceIORInterceptor(codec);
    	    info.add_ior_interceptor(aServiceIORInterceptor);

    	} catch (Throwable t) {
    	    System.out.println("Exception handling not shown.");
    	}
        }

    }

## `AServiceImpl.java`

This file contains an object that is explicitly used by client and servant code to communicate with the service. When the client calls `begin()` on the service, the service causes a `ServiceID` specific to the service to be put in the TSC `PICurrent` slot reserved by this service. When the client calls `end()` on the service, it sets the TSC slot to a non-valid value to indicate that the service is not in effect. Servants use the `verify()` method to determine whether the `ServiceID` was passed from the client side to the server side.

    //
    // Copyright and License

    package pi.serviceexample;

    import org.omg.CORBA.Any;
    import org.omg.CORBA.TCKind;
    import org.omg.CORBA.LocalObject;
    import org.omg.CORBA.ORB;
    import org.omg.PortableInterceptor.Current;
    import org.omg.PortableInterceptor.InvalidSlot;

    class AServiceImpl
        extends LocalObject
        implements AService
    {
        private int slotId;

        private int currentServiceId = 0;

        private Current piCurrent;

        private Any NOT_IN_EFFECT;

        public AServiceImpl(int slotId)
        {
    	this.slotId = slotId;
    	NOT_IN_EFFECT = ORB.init().create_any();
        }

        // Package protected so the AService ORBInitializer can access this
        // non-IDL defined method.
        void setPICurrent(Current piCurrent)
        {
    	this.piCurrent = piCurrent;
        }

        public void begin()
        {
    	Any any = ORB.init().create_any();
    	any.insert_long(++currentServiceId);
    	setSlot(any);
        }

        public void end()
        {
    	setSlot(NOT_IN_EFFECT);
        }

        public void verify()
        {
    	try {
    	    Any any = piCurrent.get_slot(slotId);
    	    if (any.type().kind().equals(TCKind.tk_long)) {
    		System.out.println("Service present: " + any.extract_long());
    	    } else {
    		System.out.println("Service not present");
    	    }
    	} catch (InvalidSlot e) {
    	    System.out.println("Exception handling not shown.");
    	}
        }

        // Synchronized because two threads in the same ORB could be
        // sharing this object.
        synchronized private void setSlot(Any any)
        {
    	try {
    	    piCurrent.set_slot(slotId, any);
    	} catch (InvalidSlot e) {
    	    System.out.println("Exception handling not shown.");
    	}
        }
    }

## `AServiceInterceptor.java`

This interceptor is responsible for arranging to pass the client side `AService` information to the service side.

On the client side, if `AService.begin()` has been called, the `send_request(ri)` point will see the service id in the RSC slot. In this case, it inserts the value of that service id into an `org.omg.CORBA.ServiceContext` and adds that service context to the data to be passed along with the invocation.

On the server side, `receive_request_service_context(ri)` looks for the presence of that service context. When present, it extracts the service id value from the `ServiceContext` and sets the RSC slot to that value. When the servant is executing, the value of that RSC slot is available in the TSC slot.

    // AServiceInterceptor.java
    // Copyright and License

    package pi.serviceexample;

    import org.omg.CORBA.Any;
    import org.omg.CORBA.BAD_PARAM;
    import org.omg.CORBA.ORB;
    import org.omg.CORBA.TCKind;
    import org.omg.IOP.Codec;
    import org.omg.IOP.CodecPackage.FormatMismatch;
    import org.omg.IOP.CodecPackage.TypeMismatch;
    import org.omg.IOP.ServiceContext;
    import org.omg.IOP.TaggedComponent;
    import org.omg.PortableInterceptor.ClientRequestInterceptor;
    import org.omg.PortableInterceptor.ClientRequestInfo;
    import org.omg.PortableInterceptor.InvalidSlot;
    import org.omg.PortableInterceptor.ServerRequestInterceptor;
    import org.omg.PortableInterceptor.ServerRequestInfo;

    public class AServiceInterceptor
        extends org.omg.CORBA.LocalObject
        implements ClientRequestInterceptor, ServerRequestInterceptor
    {
        private int slotId;
        private Codec codec;

        private static final int serviceContextId = 1234;

        public AServiceInterceptor(int slotId)
        {
    	this.slotId = slotId;
        }

        void setCodec(Codec codec)
        {
    	this.codec = codec;
        }

        //
        // Interceptor operations
        //

        public String name()
        {
    	return "AServiceInterceptor";
        }

        public void destroy()
        {
        }

        //
        // ClientRequestInterceptor operations
        //

        public void send_request(ClientRequestInfo ri)
        {
    	//
    	// See if the target object contains an ASERVICE_COMPONENT.
    	//

    	try {
    	    TaggedComponent taggedComponent =
    		ri.get_effective_component(TAG_ASERVICE_COMPONENT.value);

    	    Any sAny = null;
    	    try {
    		sAny = codec.decode_value(taggedComponent.component_data,
    					  ASERVICE_COMPONENTHelper.type());
    	    } catch (TypeMismatch e) {
    		System.out.println("Exception handling not shown.");
    	    } catch (FormatMismatch e) {
    		System.out.println("Exception handling not shown.");
    	    }

    	    ASERVICE_COMPONENT aServiceComponent =
    		ASERVICE_COMPONENTHelper.extract(sAny);

    	    //
    	    // Only send the service context if the target object requires it.
    	    //

    	    if (aServiceComponent.requiresAService) {
    		try {
    		    Any any = ri.get_slot(slotId);
    		    if (any.type().kind().equals(TCKind.tk_long)) {
    			int serviceId = any.extract_long();
    			byte[] serviceContextData = {
    			    // Little endian to make it
    			    // easier to see in debugger.
    			    (byte)((serviceId >>>  0) &  0xFF),
    			    (byte)((serviceId >>>  8) &  0xFF),
    			    (byte)((serviceId >>> 16) &  0xFF),
    			    (byte)((serviceId >>> 24) &  0xFF)
    			};
    			ri.add_request_service_context(
    			    new ServiceContext(serviceContextId,
    					       serviceContextData),
    			    false);
    		    }
    		} catch (InvalidSlot e) {
    		    System.out.println("Exception handling not shown.");
    		}
    	    }
    	} catch (BAD_PARAM e) {
    	    // If it is not present, do nothing.
    	    ;
    	}
        }

        public void send_poll(ClientRequestInfo ri)
        {
        }

        public void receive_reply(ClientRequestInfo ri)
        {
        }

        public void receive_exception(ClientRequestInfo ri)
        {
        }

        public void receive_other(ClientRequestInfo ri)
        {
        }

        //
        // ServerRequestInterceptor operations
        //

        public void receive_request_service_contexts(ServerRequestInfo ri)
        {
    	try {
    	    ServiceContext serviceContext =
    		ri.get_request_service_context(serviceContextId);
    	    byte[] data = serviceContext.context_data;
    	    int b1, b2, b3, b4;
    	    b4 = (data[0] <<  0) & 0x000000FF;
    	    b3 = (data[1] <<  8) & 0x0000FF00;
    	    b2 = (data[2] << 16) & 0x00FF0000;
    	    b1 = (data[3] << 24) & 0xFF000000;
    	    int serviceId = (b1 | b2 | b3 | b4);
    	    Any any = ORB.init().create_any();
    	    any.insert_long(serviceId);
    	    ri.set_slot(slotId, any);
    	} catch (BAD_PARAM e) {
    	    // Not present means service is not in effect.
    	    // Do nothing.
    	    ;
    	} catch (InvalidSlot e) {
    	    System.out.println("Exception handling not shown.");
    	}
        }

        public void receive_request(ServerRequestInfo ri)
        {
        }

        public void send_reply(ServerRequestInfo ri)
        {
        }

        public void send_exception(ServerRequestInfo ri)
        {
        }

        public void send_other(ServerRequestInfo ri)
        {
        }
    }

## `AServiceIORInterceptor.java`

This file adds a `TaggedComponent` to IORs.

    // AServiceIORInterceptor.java
    // Copyright and License

    package pi.serviceexample;

    import org.omg.CORBA.Any;
    import org.omg.CORBA.LocalObject;
    import org.omg.CORBA.ORB;
    import org.omg.IOP.TaggedComponent;
    import org.omg.IOP.Codec;
    import org.omg.IOP.CodecPackage.InvalidTypeForEncoding;
    import org.omg.PortableInterceptor.IORInfo;
    import org.omg.PortableInterceptor.IORInterceptor;

    public class AServiceIORInterceptor
        extends org.omg.CORBA.LocalObject
        implements IORInterceptor
    {
        private Codec codec;

        public AServiceIORInterceptor(Codec codec)
        {
    	this.codec = codec;
        }

        //
        // Interceptor operations
        //

        public String name()
        {
    	return "AServiceInterceptor";
        }

        public void destroy()
        {
        }

        //
        // IOR Interceptor operations
        //

        public void establish_components(IORInfo info)
        {
    	//
    	// Note: typically, rather than just inserting a tagged component
    	// this interceptor would check info.get_effective_policy(int)
    	// to determine if a tagged component reflecting that policy
    	// should be added to the IOR.  That is not shown in this example.
    	//

    	ASERVICE_COMPONENT aServiceComponent = new ASERVICE_COMPONENT(true);
    	Any any = ORB.init().create_any();
    	ASERVICE_COMPONENTHelper.insert(any, aServiceComponent);
    	byte[] value = null;
    	try {
    	    value = codec.encode_value(any);
    	} catch (InvalidTypeForEncoding e) {
    	    System.out.println("Exception handling not shown.");
    	}
    	TaggedComponent taggedComponent =
    	    new TaggedComponent(TAG_ASERVICE_COMPONENT.value, value);
    	info.add_ior_component(taggedComponent);
        }

    }

## `ArbitaryObjectImpl.java`

This file is an implementation and server for the `ArbitraryObject` IDL interface. The implementations of the IDL interface operations explicitly call the `AServiceImpl.verify()` method to illustrate the end-to-end passing of data from the client (via `AService.begin()`) to the servant.

    // ArbitaryObjectImpl.java
    // Copyright and License

    package pi.serviceexample;

    import org.omg.CORBA.ORB;
    import org.omg.CORBA.ORBPackage.InvalidName;
    import org.omg.CosNaming.*;
    import org.omg.CosNaming.NamingContextPackage.*;
    import org.omg.PortableServer.POAHelper;

    import java.util.Properties;

    class ArbitraryObjectImpl
        extends ArbitraryObjectPOA
    {
        public static ORB orb;

        private AService aService;

        //
        // The IDL operations.
        //

        public String arbitraryOperation1(String a1)
        {
    	verifyService();
    	return "I got this from the client: " + a1;
        }

        public void arbitraryOperation2 (int a1)
        {
    	verifyService();
        }

        public void arbitraryOperation3(String a1)
    	throws ArbitraryObjectException
        {
    	verifyService();
    	if (a1.equals("throw exception")) {
    	    throw new ArbitraryObjectException("because you told me to");
    	}
        }

        private void verifyService()
        {
    	getAService().verify();
        }

        private AService getAService()
        {
    	// Only look up the service once, then cache it.

    	if (aService == null) {
    	    try {
    		aService =
    		    AServiceHelper.narrow(
    	                orb.resolve_initial_references("AService"));
    	    } catch (InvalidName e) {
    		System.out.println("Exception handling not shown.");
    	    }
    	}
    	return aService;
        }

        //
        // The server.
        //

        public static void main(String[] av)
        {
    	try {
    	    if (orb == null) {
    		Properties props = new Properties();
    		props.put("org.omg.PortableInterceptor.ORBInitializerClass."
    			  + "pi.serviceexample.AServiceORBInitializer",
    			  "");
    		props.put("org.omg.PortableInterceptor.ORBInitializerClass."
    			  + "pi.serviceexample.LoggingServiceServerORBInitializer",
    			  "");
    		orb = ORB.init(av, props);
    	    }

    	    POA rootPOA =  POAHelper.narrow( orb.resolve_initial_references("RootPOA"));
    	    // Create a POA so the IOR interceptor executes.
    	    POA childPOA = rootPOA.create_POA("childPOA", null, null);
    	    childPOA.the_POAManager().activate();

    	    byte[] objectId =
    		childPOA.activate_object(new ArbitraryObjectImpl());
    	    org.omg.CORBA.Object ref = childPOA.id_to_reference(objectId);

    	    NamingContext nameService =
    		NamingContextHelper.narrow(
                        orb.resolve_initial_references("NameService"));
    	    NameComponent path[] =
    	        { new NameComponent("ArbitraryObject", "") };
    	    nameService.rebind(path, ref);

    	    System.out.println("ArbitaryObject ready.");

    	    orb.run();

            } catch (Exception e) {
    	    e.printStackTrace();
    	    System.exit(-1);
            }
    	System.exit(0);
        }
    }

## `Client.java`

This is a client that calls methods on `ArbitraryObject`. It makes some of those calls within the context of `AService` and some outside of its context. It is unaware of the existence of the logging interceptor (except that it explicitly registers the `LoggingServerClientORBInitializer` as noted above).

    // Client.java
    // Copyright and License

    package pi.serviceexample;

    import org.omg.CORBA.ORB;
    import org.omg.CosNaming.*;
    import org.omg.CosNaming.NamingContextPackage.*;

    import java.util.Properties;

    public class Client
    {
        public static void main(String av[])
        {
            try {
    	    Properties props = new Properties();
    	    props.put("org.omg.PortableInterceptor.ORBInitializerClass."
    		      + "pi.serviceexample.AServiceORBInitializer",
    		      "");
    	    props.put("org.omg.PortableInterceptor.ORBInitializerClass."
    		      + "pi.serviceexample.LoggingServiceClientORBInitializer",
    		      "");
    	    ORB orb = ORB.init(av, props);

    	    //
    	    // The client obtains a reference to a service.
    	    // The client does not know the service is implemented
    	    // using interceptors.
    	    //

    	    AService aService =
    		AServiceHelper.narrow(
    	            orb.resolve_initial_references("AService"));

    	    //
    	    // The client obtains a reference to some object that
    	    // it will invoke.
    	    //

    	    NamingContext nameService =
    		NamingContextHelper.narrow(
                        orb.resolve_initial_references("NameService"));
    	    NameComponent arbitraryObjectPath[] =
    	        { new NameComponent("ArbitraryObject", "") };
    	    ArbitraryObject arbitraryObject =
    		ArbitraryObjectHelper.narrow(nameService.resolve(arbitraryObjectPath));

    	    //
    	    // The client begins the service so that invocations of
    	    // any object will be done with that service in effect.
    	    //

    	    aService.begin();

    	    arbitraryObject.arbitraryOperation1("one");
    	    arbitraryObject.arbitraryOperation2(2);

    	    //
    	    // The client ends the service so that further invocations
    	    // of any object will not be done with that service in effect.
    	    //

    	    aService.end();

    	    // This invocation is not serviced by aService since
    	    // it is outside the begin/end.
    	    arbitraryObject.arbitraryOperation3("just return");

    	    aService.begin();
    	    try {
    		arbitraryObject.arbitraryOperation3("throw exception");
    		throw new RuntimeException("should not see this");
    	    } catch (ArbitraryObjectException e) {
    		// Expected in this example, so do nothing.
    	    }
    	    aService.end();

            } catch (Exception e) {
                e.printStackTrace();
    	    System.exit(-1);
            }
    	System.out.println("Client done.");
    	System.exit(0);
        }
    }

## `ColocatedServers.java`

This is a server which runs both `ArbitraryObject` and `LoggingService` in the same ORB. This means that these objects are colocated.

The server is created this way in order to exercise the code in `LoggingServiceServerInterceptor` that illustrates when interceptors make out calls to objects colocated in the same ORB extra steps must be taken to avoid infinite recursion.

    // ColocatedServers.java
    // Copyright and License

    package pi.serviceexample;

    import org.omg.CORBA.ORB;
    import java.util.Properties;

    public class ColocatedServers
    {
        public static ORB orb;

        public static boolean colocatedBootstrapDone = false;

        public static void main (String[] av)
        {
    	try {

    	    //
    	    // Share an ORB between objects servers.
    	    //

    	    Properties props = new Properties();
    	    props.put("org.omg.PortableInterceptor.ORBInitializerClass."
    		      + "pi.serviceexample.AServiceORBInitializer",
    		      "");
    	    props.put("org.omg.PortableInterceptor.ORBInitializerClass."
    		      + "pi.serviceexample.LoggingServiceServerORBInitializer",
    		      "");
    	    ORB orb = ORB.init(av, props);
    	    ArbitraryObjectImpl.orb = orb;
    	    LoggingServiceImpl.orb = orb;

    	    //
    	    // Start both object servers.
    	    //

    	    ServerThread ServerThread = new ServerThread(av);
    	    ServerThread.start();
    	    ArbitraryObjectImpl.main(av);
    	} catch (Exception e) {
    	    e.printStackTrace();
    	    System.exit(-1);
    	}
        }
    }

    class ServerThread extends Thread
    {
        String[] av;
        ServerThread (String[] av)
        {
    	this.av = av;
        }
        public void run ()
        {
    	LoggingServiceImpl.main(av);
        }
    }

# Compiling and running the application

The example code, which contains the logging example and the service example, may be compiled and run using a Makefile such as that shown below:

    # Makefile for the Example Files
    # Copyright and License

    JAVA_HOME=/path_to_J2SE_installation

    CLASSPATH=.

    JAVAC=$(JAVA_HOME)/bin/javac
    JAVA=$(JAVA_HOME)/bin/java

    ORB_INITIAL_PORT=1050

    IDLJ=$(JAVA_HOME)/bin/idlj
    IDLJ_FLAGS=-fall -td $(CLASSPATH) -verbose

    ORBD=${JAVA_HOME}/bin/orbd -ORBInitialPort ${ORB_INITIAL_PORT}

    build:
            $(IDLJ) $(IDLJ_FLAGS) serviceexample.idl
            $(JAVAC) -d $(CLASSPATH) *.java
            $(JAVAC) pi/serviceexample/*.java

    runorbd:
            $(ORBD)

    runloggingservice:
            $(JAVA) -classpath $(CLASSPATH) pi.serviceexample.LoggingServiceImpl \
                    -ORBInitialPort ${ORB_INITIAL_PORT}

    runarbitraryobject:
            $(JAVA) -classpath $(CLASSPATH) pi.serviceexample.ArbitraryObjectImpl \
                    -ORBInitialPort ${ORB_INITIAL_PORT}

    runcolocatedservers:
            $(JAVA) -classpath $(CLASSPATH) pi.serviceexample.ColocatedServers \
                    -ORBInitialPort ${ORB_INITIAL_PORT}

    runclient:
            $(JAVA) -classpath $(CLASSPATH) pi.serviceexample.Client \
                    -ORBInitialPort ${ORB_INITIAL_PORT}

    clean:
            rm -rf pi
            rm -rf orb.db

    # Order of steps:
    # Build:     clean build
    # Remote:    runorbd runloggingservice runarbitraryobjectimpl runclient
    # Colocated: runorbd runcolocatedservers runclient

The following steps show how to build and run the example on the Solaris operating system using the above Makefile. From the command prompt, run these commands as shown. The `%` symbol is used as a reminder that these are commands that are to be run from the command prompt.

1. `% make clean`
2. `% make build`
3. `% make runorbd &`
4. `% make runloggingservice &`
5. `% make runarbitraryobject &`
6. `% make runclient`

   After this step, you will see output such as this:

       resolve send_request
       resolve receive_reply
       arbitraryOperation1 send_request
       Service present: 1
       arbitraryOperation1 receive_reply
       arbitraryOperation2 send_request
       Service present: 1
       arbitraryOperation2 receive_other
       arbitraryOperation3 send_request
       Service not present
       arbitraryOperation3 receive_reply
       arbitraryOperation3 send_request
       Service present: 2
       arbitraryOperation3 receive_exception
       Client done.

7. `% jobs`

   After this step, you will see output such as this:

       [1]   Running                 make runorbd &
       [2]-  Running                 make runloggingservice &
       [3]+  Running                 make runarbitraryobject &

8. `% kill %2 %3`
9. `% make runcolocatedservers &`
10. `% make runclient`

    After this step, you will see output such as this:

        log receive_request_service_contexts
        log receive_request
        resolve send_request
        log send_reply
        log receive_request_service_contexts
        log receive_request
        resolve receive_reply
        log send_reply
        log receive_request_service_contexts
        log receive_request
        arbitraryOperation1 send_request
        log send_reply
        arbitraryOperation1 receive_request_service_contexts
        arbitraryOperation1 receive_request
        Service present: 1
        arbitraryOperation1 send_reply
        log receive_request_service_contexts
        log receive_request
        arbitraryOperation1 receive_reply
        log send_reply
        log receive_request_service_contexts
        log receive_request
        arbitraryOperation2 send_request
        log send_reply
        arbitraryOperation2 receive_request_service_contexts
        arbitraryOperation2 receive_request
        log receive_request_service_contexts
        Service present: 1
        arbitraryOperation2 send_reply
        log receive_request
        arbitraryOperation2 receive_other
        log send_reply
        log receive_request_service_contexts
        log receive_request
        arbitraryOperation3 send_request
        log send_reply
        arbitraryOperation3 receive_request_service_contexts
        arbitraryOperation3 receive_request
        Service not present
        arbitraryOperation3 send_reply
        log receive_request_service_contexts
        log receive_request
        arbitraryOperation3 receive_reply
        log send_reply
        log receive_request_service_contexts
        log receive_request
        arbitraryOperation3 send_request
        log send_reply
        arbitraryOperation3 receive_request_service_contexts
        arbitraryOperation3 receive_request
        Service present: 2
        arbitraryOperation3 send_exception
        log receive_request_service_contexts
        log receive_request
        arbitraryOperation3 receive_exception
        log send_reply
        Client done.

11. `% jobs`

    After this step, you will see output such as this:

        [1]-  Running                 make runorbd &
        [4]+  Running                 make runcolocatedservers &

12. `% kill %1 %4`
13. `% make clean`

See Also:
  `ORBInitInfo`
  `org.omg.PortableInterceptor` package.
  Portable Interceptors Specification at ptc/2001-03-04

Send questions or comments to: JavaIDL@eng.sun.com or consult the Java Developer's Forum on Distributed Computing at http://forum.java.sun.com/.