# Chapter 6 The omniORBpy API

In this chapter, we introduce the omniORBpy API. The purpose of this API is to provide access points to omniORB specific functionality that is not covered by the CORBA specification. Obviously, if you use this API in your application, that part of your code is not going to be portable to run unchanged on other vendors' ORBs. To make it easier to identify omniORB dependent code, this API is defined in the ``omniORB`' module.

## 6.1 ORB initialisation options

`CORBA::ORB_init()` accepts the following standard command-line arguments:

`-ORBid omniORB3` | The identifier must be `omniORB3'.
`-ORBInitRef` <ObjectId>=<ObjectURI> | See section 4.2.
`-ORBDefaultInitRef` <Default URI> | See section 4.2.

and the following omniORB-specific arguments:

`-ORBtraceLevel` <level> | See section 6.3.
`-ORBtraceInvocations` | See section 6.3.
`-ORBstrictIIOP` | See section 6.8.
`-ORBgiopMaxMsgSize` <size in bytes> | See section 6.5.
`-ORBobjectTableSize` <number of entries> | See section 6.6.
`-ORBserverName` <string> | See section 6.4.
`-ORBno_bootstrap_agent` | See section 6.7.
`-ORBverifyObjectExistsAndType` <0 or 1> | See section 6.8.
`-ORBinConScanPeriod` <0--max integer> | See section 7.3.
`-ORBoutConScanPeriod` <0--max integer> | See section 7.3.
`-ORBclientCallTimeOutPeriod` <0--max integer> | See section 7.3.
`-ORBserverCallTimeOutPeriod` <0--max integer> | See section 7.3.
`-ORBscanGranularity` <0--max integer> | See section 7.3.
`-ORBlcdMode` | See section 6.8.
`-ORBpoa_iiop_port` <port no.> | See section 6.2.
`-ORBpoa_iiop_name_port` <hostname[:port no.]> | See section 6.2.
`-ORBhelp` | Lists all ORB command line options.

and these two obsolete omniORB-specific arguments:

`-ORBInitialHost` <string> | See section 6.7.
`-ORBInitialPort` <1--65535>] | See section 6.7.

As defined in the CORBA specification, any command-line arguments understood by the ORB will be removed from `argv` when the initialisation functions return. Therefore, an application is not required to handle any command-line arguments it does not understand.

## 6.2 Hostname and port

Normally, omniORB lets the operating system pick which port number it should use to listen for IIOP calls. Alternatively, you can specify a particular port using `-ORBpoa_iiop_port`. If you specify `-ORBpoa_iiop_port` more than once, omniORB will listen on all the ports you specify.
By default, the ORB can work out the IP address of the host machine. This address is recorded in the object references of the local objects. However, when the host has multiple network interfaces and multiple IP addresses, it may be desirable for the application to control what address the ORB should use. This can be done by defining the environment variable `OMNIORB_USEHOSTNAME` to contain the preferred host name or IP address in dot-numeric form. Alternatively, the same can be achieved using the `-ORBpoa_iiop_name_port` option. You can optionally specify a port number too. Again, you can specify more than one host name by using `-ORBpoa_iiop_name_port` more than once.
When using omniORB 2.8, these two options are named `-BOAiiop_port` and `-BOAiiop_name_port`.

## 6.3 Run-time Tracing and Diagnostic Messages

omniORB can output tracing and diagnostic messages to the standard error stream. You can vary the amount of tracing using the `-ORBtraceLevel` <level> command line argument. For instance:

    $ example_echo_srv.py -ORBtraceLevel 5

At the moment, the following trace levels are defined:

level 0 | turn off all tracing and informational messages
level 1 | informational messages only
level 2 | the above plus configuration information
level 5 | the above plus notifications when server threads are created or communication endpoints are shutdown
level 10--20 | the above plus execution and exception traces
level 25 | the above plus hex dumps of all data sent and received by the ORB via its network connections.

With omniORB 3, you can also use `-ORBtraceInvocations` to trace all operation invocations.

## 6.4 Server Name

Applications can optionally specify a name to identify the server process. At the moment, this name is only used by the host-based access control module. See section 7.5 for details. The server name can be changed by specifying the command-line option: `-ORBserverName` <string>.

## 6.5 GIOP Message Size

omniORB sets a limit on the GIOP message size that can be sent or received. The maximum size can be set with the command-line option `-ORBgiopMaxMsgSize`. The exact value is somewhat arbitrary. The reason such a limit exists is to provide some way to protect the server side from resource exhaustion. Think about the case when the server receives a rogue GIOP(IIOP) request message that contains a sequence length field set to 231. With a reasonable message size limit, the server can reject this rogue message straight away.

## 6.6 Object table size

omniORB uses a hash table to store the mapping from object keys to servant objects. Normally, it dynamically re-sizes the hash table when it becomes too full or too empty. This is the most efficient trade-off between performance and memory usage. However, since all POA operations which add or remove objects from the table can (very occasionally) cause the object table to resize, the time spent in POA operations is much less predictable than if the table size was fixed.
The `-ORBobjectTableSize` argument allows you to choose a fixed size for the object table. This prevents omniORB from resizing it. Note that omniORB uses an open hash table so you can have any number of objects active, no matter what size table you specify. If you have many more active objects than hash table entries, object look-up performance will become linear with the number of objects.

## 6.7 Obsolete Initial Object Reference Bootstrapping

Starting from 2.6.0, but superseded by the Interoperable Naming Service in omniORB 3, a mechanism is available for the ORB runtime to obtain the initial object references to CORBA services. The bootstrap service is a special object with the object key `INIT' and the following interface1:

      // IDL
      module CORBA {
        interface InitialReferences {
          Object get(in ORB::ObjectId id);
          // returns the initial object reference of the service
          // identified by <id>. For example the id for the
          // Naming service is "NameService".

          ORB::ObjectIdList list();
          // returns the list of service ids that this agent knows
       };
     };

By default, all omniORB servers contain an instance of this object and are able to respond to remote invocations. To prevent the ORB from instantiating this object, the command-line option `-ORBno_bootstrap_agent` should be specified.
In particular, the Naming Service omniNames is able to respond to a query through this interface and return the object reference of its root context. In effect, the bootstrap agent provides a level of indirection. All omniORB clients still have to be supplied with the address of the bootstrap agent. However, the information is much easier to specify than a stringified IOR! Another advantage of this approach is that it is completely compatible with JavaIDL. This makes it possible for programs written for JavaIDL to share a Naming Service with omniORB.
The address of the bootstrap agent is given by the `ORBInitialHost` and `ORBInitialPort` parameter in the omniORB configuration file (section 1.2). The parameters can also be specified as command-line options (section 6.1). The parameter `ORBInitialPort` is optional. If it is not specified, port number 900 will be used.
During initialisation, the ORB reads the parameters in the omniORB configuration file. If the parameter `NAMESERVICE` is specified, the stringified IOR is used as the object reference of the root naming context. If the parameter is absent and the parameter `ORBInitialHost` is present, the ORB contacts the bootstrap agent at the address specified to obtain the root naming context when the application calls `resolve_initial_references()`. If neither is present, `resolve_initial_references()` returns a nil object reference. Finally, the command line argument `-ORBInitialHost` overrides any parameters in the configuration file. The ORB always contacts the bootstrap agent at the address specified to obtain the root naming context.
Now we are ready to describe a simple way to set up omniNames.

1. Start omniNames for the first time on a machine (e.g. wobble):
   `$ omniNames -start 1234`
2. Add to omniORB.cfg:
   `ORBInitialHost wobble`
   `ORBInitialPort 1234`
3. All omniORB applications will now be able to contact omniNames.
   Alternatively, the command line options can be used, for example:
   `$ eg3_impl -ORBInitialHost wobble -ORBInitialPort 1234 &`
   `$ eg3_clt -ORBInitialHost wobble -ORBInitialPort 1234`

## 6.8 GIOP Lowest Common Denominator Mode

Sometimes, to cope with bugs in another ORB, it is necessary to disable various GIOP and IIOP features in order to achieve interoperability. If the command line option `-ORBlcdMode` is present, the ORB enters the so-called `lowest common denominator mode'. It bends over backwards to cope with bugs in the ORB at the other end. This is purely a transitional measure. The long term solution is to report the bugs to the other vendors and ask them to fix them expediently.
In some (sloppy) IIOP implementations, the message size value in the IIOP header can be larger than the actual body size, i.e. there is garbage at the end. As the spec does not say the message size must match the body size exactly, this is not a clear violation of the spec. omniORB's default policy is to expect incoming messages to be formatted properly. Any messages that have garbage at the end will be rejected.
`-ORBlcdMode` sets omniORB to silently skip the unread part of such invalid messages. Alternatively, you can change just this policy with a command line argument of `-ORBstrictIIOP 0`. The problem with doing this is that the header message size may actually be garbage, caused by a bug in the sender's code. The receiving thread may block forever as it tries to read more data from the connection. In this case the sender won't send any more as it thinks it has marshalled in all the data.
By default, omniORB uses the GIOP LOCATE_REQUEST message to verify the existence of an object prior to the first invocation. If another vendor's ORB is known not to be able to handle this GIOP message, you can disable this feature with the `-ORBverifyObjectExistsAndType` option, and hence achieve interoperability.

## 6.9 System Exception Handlers

By default, all system exceptions which are raised during an operation invocation, with the exception of `CORBA.TRANSIENT`, are propagated to the application code. Some applications may prefer to trap these exceptions within the proxy objects so that the application logic does not have to deal with the error condition. For example, when a `CORBA.COMM_FAILURE` is received, an application may just want to retry the invocation until it finally succeeds. This approach is useful for objects that are persistent and their operations are idempotent.
omniORBpy provides a set of functions to install exception handlers. Once they are installed, proxy objects will call these handlers when the associated system exceptions are raised by the ORB runtime. Handlers can be installed for `CORBA.TRANSIENT`, `CORBA.COMM_FAILURE` and `CORBA.SystemException`. This last handler covers all system exceptions other than the two covered by the first two handlers. An exception handler can be installed for individual proxy objects, or it can be installed for all proxy objects in the address space.

### 6.9.1 CORBA.TRANSIENT handlers

When a `CORBA.TRANSIENT` exception is raised by the ORB runtime, the default behaviour of the proxy objects is to retry indefinitely until the operation succeeds, with an exponentially increasing delay (up to a limit) between retries.
The ORB runtime will raise `CORBA.TRANSIENT` under the following conditions:

1. When a cached network connection is broken while an operation invocation is in progress. The ORB will try to open a new connection at the next invocation.
2. When the proxy object has been redirected by a location forward message by the remote object to a new location and the object at the new location cannot be contacted. In addition to the `CORBA.TRANSIENT` exception, the proxy object also resets its internal state so that the next invocation will be directed at the original location of the remote object.
3. When the remote object reports `CORBA.TRANSIENT`.

You can override the default behaviour by installing your own exception handler. The function to call has signature:

    omniORB.installTransientExceptionHandler(cookie, function [, object])

The arguments are a cookie, which is any Python object, a call-back function, and optionally an object reference. If the object reference is present, the exception handler is installed for just that object; otherwise the handler is installed for all objects with no handler of their own.
The call-back function must have the signature

    function(cookie, retries, exc) -> boolean

When a `TRANSIENT` exception occurs, the function is called, passing the cookie object, a count of how many times the operation has been retried, and the TRANSIENT exception object itself. If the function returns true, the operation is retried; if it returns false, the TRANSIENT exception is raised in the application.

### 6.9.2 CORBA.COMM_FAILURE and CORBA.SystemException

There are two other functions for registering exception handlers: one for `CORBA.COMM_FAILURE`, and one for all other exceptions. For both these cases, the default is for there to be no handler, so exceptions are propagated to the application.

    omniORB.installCommFailureExceptionHandler(cookie, function [, object])
    omniORB.installSystemExceptionHandler(cookie, function [, object])

In both cases, the call-back function has the same signature as for `TRANSIENT` handlers.

## 6.10 Dynamic importing of IDL

omniORBpy is usually used with pre-generated stubs. Since Python is a dynamic language, however, it is possible to compile and import new stubs at run-time.
Dynamic importing is achieved with `omniORB.importIDL()` and `omniORB.importIDLString()`. Their signatures are:

    importIDL(filename [, args ]) -> tuple
    importIDLString(string [, args ]) -> tuple

The first function compiles and imports the specified file; the second takes a string containing the IDL definitions. The functions work by forking omniidl and importing its output; they both take an optional argument containing a list of strings which are used as arguments for omniidl. For example, the following command runs omniidl with an include path set:

    m = omniORB.importIDL("test.idl", ["-I/my/include/path"])

Instead of specifying omniidl arguments on each import, you can set the arguments to be used for all calls using the `omniORB.omniidlArguments()` function.
Both import functions return a tuple containing the names of the Python modules which have been imported. The modules themselves can be accessed through `sys.modules`. For example:

    // test.idl
    const string s = "Hello";
    module M1 {
      module M2 {
        const long l = 42;
      };
    };
    module M3 {
      const short s = 5;
    };

From Python:

    >>> import sys, omniORB
    >>> omniORB.importIDL("test.idl")
    ('M1', 'M1.M2', 'M3', '_GlobalIDL')
    >>> sys.modules["M1.M2"].l
    42
    >>> sys.modules["M3"].s
    5
    >>> sys.modules["_GlobalIDL"].s
    'Hello'

1
  This interface was first defined by Sun's NEO and is in used in Sun's JavaIDL.