\documentclass[11pt,twoside,onecolumn]{book}
\usepackage[]{fontenc}
\usepackage{palatino}
\usepackage{a4}
\addtolength{\oddsidemargin}{-0.2in}
\addtolength{\evensidemargin}{-0.6in}
\addtolength{\textwidth}{0.5in}

\pagestyle{headings}
\setcounter{secnumdepth}{3}
\setcounter{tocdepth}{3}
\begin{document}

\pagenumbering{roman}
\pagestyle{empty}


\begin{center}

\vfill

{ \Huge
The omniORB2 version 2.7.1\\[4mm]
User's Guide
}

\vfill

{ \Large
Sai-Lai Lo\\
{\normalsize ({\it email: slo@uk.research.att.com})}\\
David Riddoch\\
{\normalsize ({\it email: djr@uk.research.att.com})}\\
AT\&T Laboratories Cambridge\\
}


\vfill
\vfill
22nd February, 1999
\vfill

\end{center}

\pagebreak

{\Large \bf \sf Changes and Additions, 22nd February 1999}

\begin{itemize}
\item Chapter 11 - expanded and updated
\end{itemize}


\cleardoublepage
\tableofcontents
\cleardoublepage
\pagestyle{headings}

\pagenumbering{arabic}

\mainmatter

%\input{intro.tex}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\chapter{Introduction}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

OmniORB2 is an Object Request Broker (ORB) that implements the 2.0
specification of the Common Object Request Broker Architecture
(CORBA)~\cite{corba2-spec}\footnote{The DynAny implmentation introduced in
version 2.6.0 implements the facility in the 2.2 specification. Other parts
of the 2.2 specification are also implemented where they do not clash
with the 2.0 specification.}.
This user guide tells you how to use omniORB2 to develop CORBA applications.
It assumes a basic understanding of CORBA. 

In this chapter, we give an overview of the main features of omniORB2 and
what you need to do to setup your environment to run omniORB2.

\section{Features}

\subsection{CORBA 2 compliant}

OmniORB2 implements the Internet Inter-ORB Protocol (IIOP).
This protocol provides omniORB2 the means of achieving interoperability
with the ORBs implemented by other vendors. In fact, this is the
native protocol used by omniORB2 for the communication amongst its objects
residing in different address spaces. Moreover, the IDL to C++ language
mapping provided by omniORB2 conforms to the latest revision of the CORBA
specification. Type Any and TypeCode are now supported (introduced in version
2.5.0). DynAny is supported since 2.6.0. The Dynamic Invocation Interface
and Dynamic Skeleton Interface are supported since 2.7.0.

\subsection{Multithreading}

OmniORB2 is fully multithreaded. To achieve low IIOP call overhead,
unnecessary call-multiplexing is eliminated. At any time, there is at most
one call in-flight in each communication channel between two address
spaces. To do so without limiting the level of concurrency, new channels
connecting the two address spaces are created on demand and cached when
there are more concurrent calls in progress. Each channel is served by a
dedicated thread. This arrangement provides maximal concurrency and
eliminates any thread switching in either of the address spaces to process
a call. Furthermore, to maximise the throughput in processing large call
arguments, large data elements are sent as soon as they are processed while
the other arguments are being marshalled.

\subsection{Portability}

At AT\&T Laboratories, the ability to target a single source tree to
multiple platforms is
very important. This is difficult to achieve if the IDL to C++ mapping for
these platforms are different. We avoid this problem by making sure that
only one IDL to C++ mapping is used. We run several flavours of Unices, Windows
NT, Windows 95 and our in-house developed systems for our own
hardware. OmniORB2 have been ported to all these platforms. {\bf The IDL to
C++ mapping for these targets are all the same}.

OmniORB2 uses real C++ exceptions and nested classes. We stay with the
CORBA specification's standard mapping as much as possible and do not use
the alternative mappings for C++ dialects. The only exception is the
mapping of {\bf modules}.

Starting with 2.6.0, the code generated by the IDL compiler of omniORB2 can
be compiled using {\bf C++ classes} or {\bf namespaces} to represent IDL
{\bf modules} depending on the availability of namespace support in the
compiler.

OmniORB2 relies on the native thread libraries to provide the
multithreading capability. A small class library (omnithread~\cite{tjr96a})
is used to encapsulated the (possibly different) APIs of the native thread
libraries. In the application code, it is recommended but not mandatory to
use this class library for thread management. It should be easy to port
omnithread to any platform that either supports the POSIX thread standard
or has a thread package that supports similar capabilities.

\subsection{Missing features}

OmniORB2 is not (yet) a complete implementation of the CORBA core. 
The following is a list of the missing features. 

\begin{itemize}

\item The BOA only support the persistent server activation policy. Other
dynamic activation and deactivation policies are not supported.
\item OmniORB2 does not has its own Interface Repository.
\end{itemize}

\sloppy{These features may be implemented in the short to medium term. It is
best to check out the latest status on the omniORB2 home page
({\tt http://www.uk.research.att.com/omniORB/omniORB.html}).}


\section{Setting Up Your Environment}
\label{setup}

\sloppy{At AT\&T Laboratories Cambridge, you should use the OMNI Development
Environment (ODE)~\cite{tjr96b}
and the OMNI tree version 5.0 or above to compile your programs. If this is
the case, there is no extra setup you have to do other than those described
in the ODE documentation.}

If you are running omniORB2 at other sites, you (or your system
administrator) should install omniORB2 by following the instructions in the
installation notes. 

\begin{itemize}

\item On Unix platforms, the omniORB2 runtime looks for the environment
variable {\tt OMNIORB\_CONFIG}. If this variable is defined, it contains
the pathname of the omniORB2 configuration file. If the variable is not
set, omniORB2 will use the compiled-in pathname to locate the file.

\item On ARM/ATMos, the omniORB2 runtime looks for configuration
information in the file {\tt omniORB.cfg}.

\item On Win32 platforms (Windows NT, Windows '95), omniORB2 first checks the 
environment variable ({\tt OMNIORB2\_CONFIG}) to obtain the pathname of the 
configuration file. If this is not set, it then attempts to obtain 
configuration data in the system registry. It searches for the data under 
the key {\tt HKEY\_LOCAL\_MACHINE$\backslash$SOFTWARE$\backslash$ORL$\backslash$omniORB$\backslash$2.0}

\end{itemize}

The configuration file is used to obtain an object reference for the
COSS Naming Service. The entry in the configuration file should be specified
in the following form:

{\tt NAMESERVICE <stringified IOR for the COSS Naming Service>}

Comments in the configuration file should be prefixed with a \#.

On Win32 platforms, the stringified IOR can be placed in the system registry, 
in the (string) value {\tt NAMESERVICE}, under the key 
{\tt HKEY\_LOCAL\_MACHINE$\backslash$SOFTWARE$\backslash$ORL$\backslash$omniORB$\backslash$2.0}.

Since 2.6.0, two other entries are supported:

\begin{verbatim}
   ORBInitialHost <hostname string>
   ORBInitialPort <port number (1-65535)>
\end{verbatim}

The corresponding entries under the Win32 system registry is the key with
name {\tt ORBInitialHost} and {\tt ORBInitialPort}.

The two entries provide information to the ORB to locate a bootstrap
service at runtime. The bootstrap service is able to return the initial
object reference for the COSS Naming Service and others. This is now the
recommended way to configure omniORB2. More details are provided in
section~\ref{bootstrap}.



\section{Platform specific variables}

To compile omniORB2 programs correctly, several C++ preprocessor defines
{\bf must} be specified to identify the target platform.

\begin{flushleft}
\begin{tabular}{|l|l|}
\hline
Platform & CPP defines \\
\hline
Sun Solaris 2.5  & \verb|__sparc__  __sunos__  __OSVERSION__=5| \\
\hline
Digital Unix 3.2 & \verb|__alpha__  __osf1__   __OSVERSION__=3| \\
\hline
HPUX 10.x & \verb|__hppa__  __hpux__   __OSVERSION__=10| \\
\hline
IBM AIX 4.x & \verb|__aix__  __powerpc__   __OSVERSION__=4| \\
\hline
Linux 2.0 (x86)  & \verb|__x86__    __linux__  __OSVERSION__=2| \\
\hline
Linux 2.0 (alpha)  & \verb|__alpha__    __linux__  __OSVERSION__=2| \\
\hline
Windows/NT 3.5   & \verb|__x86__    __NT__     __OSVERSION__=3  __WIN32__| \\
\hline
Windows/NT 4.0   & \verb|__x86__    __NT__     __OSVERSION__=4  __WIN32__| \\
\hline
Windows/95   & \verb|__x86__ __WIN32__| \\
\hline
OpenVMS 6.x (alpha) & \verb|__alpha__    __vms     __OSVERSION__=6 | \\
\hline
OpenVMS 6.x (vax)   & \verb|__vax__    __vms     __OSVERSION__=6 | \\
\hline
SGI Irix 6.2 & \verb|__mips__    __irix__     __OSVERSION__=6 | \\
\hline
Reliant Unix 5.43 & \verb|__mips__    __SINIX__     __OSVERSION__=5 | \\
\hline
ATMos 4.0        & \verb|__arm__    __atmos__  __OSVERSION__=4| \\
\hline
NextStep 3.x & \verb|__m68k__  __nextstep__   __OSVERSION__=3| \\
\hline
\end{tabular}
\end{flushleft}

The preprocessor defines for new platform ports not listed above can be
found in the corresponding platform configuration files. For instance, the 
platform configuration file for Sun Solaris 2.6 is in {\tt
mk/platforms/sun4\_sosV\_5.6.mk}. The preprocess defines to identify a
platform is the value of the make variable {\tt IMPORT\_CPPFLAGS}.

In a single source multi-target environment, you can put the preprocessor
defines as the command-line arguments for the compiler. Alternately, you could
create a sitedef.h file in the same directory as {\tt
omniORB2/CORBA.h}. Write into the file the appropriate set of preprocessor
defines and add {\tt \#include <omniORB2/sitedef.h>} at the beginning of {\tt
omniORB2/CORBA\_sysdep.h}.

%\input{basic.tex}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\chapter{The Basics}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\label{ch_basic}

In this chapter, we go through three examples to illustrate the practical
steps to use omniORB2. By going through the source code of each example,
the essential concepts and APIs are introduced. If you have no previous
experience with using CORBA, you should study this chapter in detail. There
are pointers to other essential documents you should be familiar with.

If you have experience with using other ORBs, you should still go through
this chapter because it provides important information about the features
and APIs that are necessarily omniORB2 specific. For instance, the object
implementation skeleton is covered in section~\ref{stubobjimpl}.

\section{The Echo Object Example}

Our example is an object which has only one method. The method simply echos
the argument string. We have to:

\begin{enumerate}

\item define the object interface in IDL;
\item use the IDL compiler to generate the stub code\footnote{The stub code
is the C++ code that provides the object mapping as defined in the CORBA 2.0
specification.};
\item provide the object implementation;
\item write the client code.

\end{enumerate}

The source code of this example is included in the last section of this
chapter. A makefile written to be used under the OMNI Development
Environment (ODE)~\cite{tjr96b} is also included.

\section{Specifying the Echo interface in IDL}

We define an object interface, called Echo, as follows:

{\small
\begin{verbatim}

interface Echo {
    string echoString(in string mesg);
};

\end{verbatim}
}

If you are new to IDL, you can learn about its syntax in Chapter 3 of the
CORBA specification 2.0~\cite{corba2-spec}.

For the moment, you only need to know that the interface consists of a
single operation, echoString, which takes a string as an argument and
returns a copy of the same string.

The interface is written in a file, called {\tt echo.idl}. If you are
using ODE, all IDL files should have the same
extension- {\tt.idl} and should be placed in the {\tt idl} directory of
your export tree. This is done so that the stub code will be generated
automatically and kept up-to-date with your IDL file.

For simplicity, the interface is defined in the global IDL namespace. This
practice should be avoided for the sake of object reusuability. If every
CORBA developer defines their interfaces in the global IDL namespace, there
is a danger of name clashes between two independently defined
interfaces. Therefore, it is better to qualify your interfaces by defining
them inside {\tt module} names. Of course, this does not eliminate the
chance of a name clash unless some form of naming convention is agreed
globally. Nevertheless, a well-chosen module name can help a lot.

\section{Generating the C++ stubs}

From the IDL file, we use the IDL compiler to produce the C++ mapping of
the interface. The IDL compiler for omniORB2 is called {\tt
omniidl2}. Given the IDL file, {\tt omniidl2} produces two stub files: a
C++ header file and a C++ source file. For example, from the file {\tt
echo.idl}, the following files are produced:

\begin{itemize}
\item {\tt echo.hh}
\item {\tt echoSK.cc}
\end{itemize}

If you are using ODE, you don't need to invoke omniidl2 explicitly. In
the example file {\tt dir.mk}, we have the following line:

{\small
\begin{verbatim}

CORBA_INTERFACES = echo

\end{verbatim}
}

That is all we need to instruct ODE to generate the stubs. Remember, you
won't find the stubs in your working directory because all stubs are written
into the {\tt stub} directory at the top level of your build tree. 

\section{A Quick Tour of the C++ stubs}

The C++ stubs conform to the mapping defined in the CORBA 2.0 specification
(chapter 16-18). It is important to understand the mapping before you start
writing any serious CORBA applications.

Before going any further, it is worth knowing what the mapping looks like.

\subsection{Object Reference}

The use of an object interface denotes an object reference. For the
example interface Echo, the C++ mapping for its object reference is {\tt
Echo\_ptr}. The type is defined in echo.hh. The relevant section of the
code is reproduced below:

{\small
\begin{verbatim}

class Echo;
typedef Echo* Echo_ptr;

class Echo : public virtual omniObject, public virtual CORBA::Object {
public:

  virtual char *  echoString ( const char *  mesg ) = 0;
  static Echo_ptr _nil();
  static Echo_ptr _duplicate(Echo_ptr);
  static Echo_ptr _narrow(CORBA::Object_ptr);

  ... // methods generated for internal use
};

\end{verbatim}
}

In a compliant application, the operations defined in an object interface
should {\bf only} be invoked via an object reference. This is done by using
arrow (``$\rightarrow$'') on an object reference. For example, the call to the
operation {\tt echoString} would be written as {\tt obj$\rightarrow$echoString(mesg)}. 

It should be noted that the concrete type of an object reference is opaque,
i.e. you must not make any assumption about how an object reference is
implemented. In our example, even though {\tt Echo\_ptr} is implemented as
a pointer to the class {\tt Echo}, it should not be used as a C++ pointer,
i.e. conversion to void*, arithmetic operations, and relational operations,
including test for equality using {\bf operation==} must not be performed
on the type.

In addition to {\tt echoString}, the mapping also defines three static
member functions in the class Echo: {\tt \_nil}, {\tt \_duplicate}, and 
{\tt \_narrow}. Note that these are operations on an object reference. 

The {\tt \_nil} function returns a nil object reference of the Echo interface. The
following call is guaranteed to return TRUE:

{\small
\begin{verbatim}

CORBA::Boolean true_result = CORBA::is_nil(Echo::_nil());

\end{verbatim}
}

Remember, {\tt CORBA::is\_nil()} is the only compliant way to check if an
object reference is nil. You should not use the equality operator==.

The {\tt \_duplicate} function returns a new object reference of the Echo
interface. The new object reference can be used interchangeably with the old
object reference to perform an operation on the same object.


\sloppy{All CORBA objects inherit from the generic object {\tt CORBA::Object}.
{\tt CORBA::Object\_ptr} is the object reference for {\tt CORBA::Object}.
Any object reference is therefore conceptually inherited from 
{\tt CORBA::Object\_ptr}. In other words, an object reference
such as {\tt Echo\_ptr} can be used in places where a {\tt
CORBA::Object\_ptr} is expected.}

The {\tt \_narrow} function takes an argument of the type {\tt
CORBA::Object\_ptr} and returns a new object reference of the Echo
interface.  If the actual (runtime) type of the argument object reference
can be widened to {\tt Echo\_ptr}, {\tt \_narrow} will return a valid object
reference. Otherwise it will return a nil object reference.

To indicate that an object reference will no longer be accessed, you can
call the {\tt CORBA::release} operation. Its signature is as follows:

{\small
\begin{verbatim}

class CORBA {
   static void release(CORBA::Object_ptr obj);
   ... // other methods
};
\end{verbatim}
}

You should not use an object reference once you have called {\tt
CORBA::release}. This is because the associated resources may have been
deallocated. Notice that we are referring to the resources associated with
the object reference and {\bf not the object implementation}. Here is a
concrete example, if the implementation of an object resides in a different
address space, then a call to {\tt CORBA::release} will only caused the
resources associated with the object reference in the current address space
to be deallocated. The object implementation in the other address space is
unaffected.

As described above, the equality operator== should not be used on object
references. To test if two object references are equivalent, the member
function {\tt \_is\_equivalent} of the generic object {\tt CORBA::Object}
can be used. Here is an example of its usage:

{\small
\begin{verbatim}

Echo_ptr A;
...            // initialised A to a valid object reference 
Echo_ptr B = A;
CORBA::Boolean true_result = A->_is_equivalent(B); 
// Note: the above call is guaranteed to be TRUE

\end{verbatim}
}

You have now been introduced to most of the operations that can be invoked
via {\tt Echo\_ptr}. The generic object {\tt CORBA::Object} provides a few more
operations and all of them can be invoked via {\tt Echo\_ptr}. These operations
deal mainly with CORBA's dynamic interfaces. You do not have to understand
them in order to use the C++ mapping provided via the stubs. For details,
please read the CORBA specification~\cite{corba2-spec} chapter 17.

Since object references must be released explicitly, their usage is prone
to error and can lead to memory leakage. The mapping defines the {\bf
object reference variable} type to make life easier. In our example, the
variable type {\tt Echo\_var} is defined\footnote{In omniORB2, all object
reference variable types are instantiated from the template type
\_CORBA\_ObjRef\_Var.}.

The {\tt Echo\_var} is more convenient to use because it will automatically
release its object reference when it is deallocated or when assigned a new
object reference. For many operations, mixing data of type {\tt Echo\_var} and
{\tt Echo\_ptr} is possible without any explicit operations or castings
\footnote{However, the implementation of the type conversion operator()
between Echo\_var and Echo\_ptr varies slightly among different C++
compilers, you may need to do an explicit casting when the compiler
complains about the conversion being ambiguous.}. For instance, the
operation {\tt echoString} can be called using the arrow
(``$\rightarrow$'') on a {\tt Echo\_var}, as one can do with a {\tt Echo\_ptr}.

The usage of {\tt Echo\_var} is illustrated below:

{\small
\begin{verbatim}

Echo_var a;
Echo_ptr p = ...     // somehow obtain an object reference

a = p;               // a assumes ownership of p, must not use p anymore

Echo_var b = a;      // implicit _duplicate

p = ...              // somehow obtain another object reference

a = Echo::_duplicate(p);     // release old object reference
                             // a now holds a copy of p.
\end{verbatim}
}

\subsection{Object Implementation}
\label{stubobjimpl}

Unlike the client side of an object, i.e. the use of object references, the
CORBA specification 2.0 deliberately leave many of the necessary
functionalities to implement an object unspecified. As a consequence, it is
very unlikely the implementation code of an object on top of two different
ORBs can be identical. However, most of the code are expected to be
portable. In particular, the body of an operation implementation can
normally be ported with no or little modification.

OmniORB2 uses C++ inheritance to provide the skeleton code for 
object implementation. For each object interface, a skeleton class is
generated. In our example, the skeleton class {\tt \_sk\_Echo} is generated for
the Echo IDL interface. An object implementation can be written by creating
an implementation class that derives from the skeleton class. 

The skeleton class {\tt \_sk\_Echo} is defined in {\tt echo.hh}. The
relevant section of the code is reproduced below. 

{\small
\begin{verbatim}

class _sk_Echo :  public virtual Echo {
public:
  _sk_Echo(const omniORB::objectKey& k);
  virtual char *  echoString ( const char *  mesg ) = 0;
  Echo_ptr        _this();
  void            _obj_is_ready(BOA_ptr);
  void            _dispose();
  BOA_ptr         _boa();
  omniORB::objectKey _key();  
  ... // methods generated for internal use
};

\end{verbatim}
}

The code fragment shows the only member functions that can be used in the
object implementation code. Other member functions are generated for
internal use only. {\bf Unless specified otherwise, the description below
is omniORB2 specific.}  The functions are:

\begin{description}

\item[echoString] it is through this abstract function that an
implementation class provides the implementation of the {\tt echoString}
operation. Notice that its signature is the same as the {\tt echoString}
function that can be invoked via the {\tt Echo\_ptr} object reference.
{\bf The signature of this function is specified by the CORBA specification}.

\item[\_this] this function returns an object reference for the target
object. The returned value must be deallocated via {\tt CORBA::release}.
See~\ref{objeg1} for an example of how this function is used.

\item[\_obj\_is\_ready] this function tells the Basic Object
Adaptor\footnote{The interface of a BOA is described in chapter 8 of the
CORBA specification.} (BOA) that the object is ready to serve. Until this
function is called, the BOA would not serve any incoming calls to this
object. See~\ref{objeg1} for an example of how this function is used.

\item[\_dispose] this function tells the BOA to dispose of the object.
The BOA will stop serving incoming calls of this object and remove any
resources associated with it.
See~\ref{objeg1} for an example of how this function is used.

\item[\_boa] this function returns a reference to the BOA that serves this
object.

\item[\_key] this function returns the key that the ORB used to identify
this object. The type {\tt omniORB::objectKey} is opaque to application
code. The function {\tt omniORB::keyToOctetSequence} can be used to
convert the key to a sequence of octets.

\end{description}

\section{Writing the object implementation}
\label{objimpl}

You define an implementation class to provide the object
implementation. There is little constraint on how you design your
implementation class except that it has to inherit from the stubs' skeleton
class and to implement all the abstract functions defined in the skeleton
class. Each of these abstract functions corresponds to an operation of the
interface. They are hooks for the ORB to perform upcalls to your
implementation.

Here is a simple implementation of the Echo object.

{\small
\begin{verbatim}
class Echo_i : public virtual _sk_Echo {
public:
  Echo_i() {}
  virtual ~Echo_i() {}
  virtual char * echoString(const char *mesg);
};

char *
Echo_i::echoString(const char *mesg) {
  char *p = CORBA::string_dup(mesg);
  return p;
}
\end{verbatim}
}

There are three points to note here:
\begin{description}
\item[Storage Responsibilities] A string, which is used as an IN argument
and the return value of {\tt echoString}, is a variable size data
type. Other examples of variable size data types include sequences, type
``any'', etc. For these data types, you must be clear about who's
responsibility to allocate and release their associated storage. As a rule
of thumb, the client (or the caller to the implementation functions) owns
the storage of all IN arguments, the object implementation (or the callee)
must copy the data if it wants to retain a copy. For OUT arguments and
return values, the object implementation allocates the storage and passes
the ownership to the client. The client must release the storage when the
variables will no longer be used.  For details, please refer to Table 24-27
of the CORBA specification.

\item[Multi-threading] As omniORB2 is fully multithreaded, multiple threads
may perform the same upcall to your implementation concurrently. It is up
to your implementation to synchronise the threads' accesses to shared data.
In our simple example, we have no shared data to protect so no
thread synchronisation is necessary.

\item[Instantiation] You must not instantiate an implementation as
automatic variables. Instead, you should always instantiate an
implementation using the new operator, i.e. its storage is allocated on the
heap. The reason behind this restriction will become clear in
section~\ref{objeg1}.

\end{description}

\section{Writing the client}

Here is an example of how a {\tt Echo\_ptr} object reference is used.

{\small
\begin{verbatim}
void
hello(CORBA::Object_ptr obj)
{
  Echo_var e = Echo::_narrow(obj);                // line 1

  if (CORBA::is_nil(e)) {                         // line 2
    cerr << "hello: cannot invoke on a nil object reference.\n" << endl;
    return;
  }

  CORBA::String_var src = (const char*) "Hello!";  // line 3
  CORBA::String_var dest;                          // line 4

  dest = e->echoString(src);                       // line 5

  cerr << "I said,\"" << src << "\"."
       << " The Object said,\"" << dest <<"\"" << endl;
}
\end{verbatim}
}

Briefly, the function {\tt hello} accepts a generic object reference. The
object reference ({\tt obj}) is narrowed to {\tt Echo\_ptr}. If the object
reference returned by {\tt Echo::\_narrow} is not nil, the operation {\tt
echoString} is invoked. Finally, both the argument to and the return value of
{\tt echoString} are printed to cerr.

The example also illustrates how T\_var types are used. As it was explained
in the previous section, T\_var types take care of storage allocation and
release automatically when variables of the type are assigned to or when
the variables go out of scope. 

In line 1, the variable {\tt e} takes over the storage responsibility of
the object reference returned by {\tt Echo::\_narrow}. The object reference
is released by the destructor of {\tt e}. It is called automatically when
the function returns. Line 2 and 5 shows how a {\tt Echo\_var} variable is
used. As said earlier, {\tt Echo\_var} type can be used interchangeably with
{\tt Echo\_ptr} type.

The argument and the return value of {\tt echoString} are stored in {\tt
CORBA::String\_var} variable {\tt src} and {\tt dest} respectively. The
strings managed by the variables are deallocated by the destructor of
{\tt CORBA::String\_var}. It is called automatically when the function
returns. Line 5 shows how {\tt CORBA::String\_var} variables are used. They
can be used in place of a string (for which the mapping is {\tt char*
})\footnote{A conversion operator() of CORBA::String\_var converts a
CORBA::String\_var to a char*.}. As used in line 3, assigning a constant
string ({\tt const char*}) to a {\tt CORBA::String\_var} causes the string
to be copied. On the otherhand, assigning a {\tt char*} to a {\tt
CORBA::String\_var}, as used in line 5, causes the latter to assume
the ownership of the string\footnote{Please refer to the CORBA
specification 16.7 for the details of the String\_var mapping. Other T\_var
types are also covered in chapter 16.}. 

Under the C++ mapping, T\_var types are provided for all the non-basic data
types.  It is obvious that one should use automatic variables whenever
possible both to avoid memory leak and to maximise performance. However,
when one has to allocate data items on the heap, it is a good practice to
use the T\_var types to manage the heap storage.

\section{Example 1 - Colocated Client and Implementation}
\label{objeg1}

Having introduced the client and the object implementation, we can now
describe how to link up the two via the ORB. In this section, we describe
an example in which both the client and the object implementation are in
the same address space. In the next two sections, we shall describe the
case where the two are in different address spaces.

The code for this example is reproduced below:

{\small
\begin{verbatim}
int
main(int argc, char **argv)
{
  CORBA::ORB_ptr orb = CORBA::ORB_init(argc,argv,"omniORB2");   // line 1
  CORBA::BOA_ptr boa = orb->BOA_init(argc,argv,"omniORB2_BOA"); // line 2

  Echo_i *myobj = new Echo_i();                                 // line 3
  myobj->_obj_is_ready(boa);                                    // line 4

  boa->impl_is_ready(0,1);                                      // line 5

  Echo_ptr myobjRef = myobj->_this();                           // line 6
  hello(myobjRef);                                              // line 7
  CORBA::release(myobjRef);                                     // line 8

  myobj->_dispose();                                            // line 9
  return 0;
}
\end{verbatim}
}

The example illustrates several important interactions among the ORB, the
object implementation and the client. Here are the details:

\subsection{ORB/BOA initialisation}

\begin{description}

\item[line 1] The ORB is initialised by calling the {\tt CORBA::ORB\_init} function. The function uses the 3rd argument to determine which ORB should be
returned. To use omniORB2, this argument must either be ``omniORB2'' or
NULL. If it is NULL, there must be an argument, -ORBid ``omniORB2'', in
{\tt argv}. Like any command-line arguments understood by the ORB, it will
be removed from argv when {\tt CORBA::ORB\_init} returns. Therefore, an
application is not required to handle any command-line arguments it does
not understand. If the ORB identifier is not ``omniORB2'', the
initialisation will fail and a nil {\tt ORB\_ptr} will be returned. If
supplied, omniORB2 also reads the configuration file {\tt
omniORB.cfg}. Among other things, the file provides a list of initial
object references. One example of these object references is the naming
service. Its use will be discussed in section~\ref{resolveinit}. If any
error occurs during the processing of the configuration file, the system
exception CORBA::INITIALIZE is raised.


\item[line 2] The BOA is initialised by calling the ORB's {\tt BOA\_init}.
The 3rd argument must either be ``omniORB2\_BOA'' or NULL. If it
is NULL, then {\tt argv} must contain an argument, -BOAid
``omniORB2\_BOA''. If the BOA identifier is not ``omniORB2\_BOA'', the
initialisation will fail and a nil BOA\_ptr will be returned. Like
{\tt ORB\_init}, any command-line arguments understood by {\tt BOA\_init}
will be removed from {\tt argv}.

\end{description}

\subsection{Object initialisation}

\begin{description}
\item[line 3] An instance of the Echo object is initialised using the {\tt
new} operator.
\item[line 4] The object's {\tt \_obj\_is\_ready} is called. 
This function informs the BOA that this object is ready to serve. Until
this function is called, the BOA will not accept any invocation on the
object and will not perform any upcall to the object.
\item[line 5] The BOA's {\tt impl\_is\_ready} is called. This function tells
the BOA the implementation is ready. After this call, the BOA will accept
IIOP requests from other address spaces. There are 2 points to note here:
\begin{enumerate}
\item {\tt boa$\rightarrow$impl\_is\_ready} can be called any time after
{\tt BOA\_init} is called (line 2). In other words, object instances can be
initialised and advertised to the BOA before or after this function is
called. 
\item The 2nd argument\footnote{The 1st argument is a pointer to the
implementation definition and is always ignored by omniORB2.} to {\tt
impl\_is\_ready} tells the ORB whether this call should be
non-blocking. The default value of this argument is FALSE(0) and the call
will block indefinitely within the ORB. If there are more things the main
thread should do after it calls {\tt impl\_is\_ready}, as it is the case in
this example, the non-blocking option (TRUE=1) should be specified. Whether
the main thread blocks in this call or not, the ORB is not affected because
its functions are provided by other threads spawned internally.  Notice
that the signature of {\tt impl\_is\_ready} in the CORBA specification does
not have the 2nd argument\footnote{The CORBA specification does not specify
when {\tt impl\_is\_ready} should return. Many ORB vendors choose to
implement {\tt impl\_is\_ready} as blocking until a certain time-out value
is exceeded. In a single threaded implementation this is necessary to give
the ORB the time to serve incoming requests.}. Therefore, calling
{\tt impl\_is\_ready} with the non-blocking option is omniORB2 specific.
\end{enumerate}
\end{description}

\subsection{Client invocation}

\begin{description}

\item[line 6] The object reference is obtained from the implementation by
calling {\tt \_this}. Like any object reference, the return value of \_this
must be released by {\tt CORBA::release} when it is no longer needed.
\item[line 7] Call {\tt hello} with this object reference. The argument is
widened implicitly to the generic object reference {\tt CORBA::Object\_ptr}.
\item[line 8] Release the object reference.
\end{description}

One of the important characteristic of an object reference is that it is
completely location transparent. A client can invoke on the object using
its object reference without any need to know whether the object is
colocated in the same address space or resided in a different address
space. 

In case of colocated client and object implementation, omniORB2 is able to
short-circuit the client calls to direct calls on the
implementation methods. The cost of an invocation is reduced to that of a
function call. This optimisation is applicable {\bf not only} to object
references returned by the \_this function but to any object references
that are passed around within the same address space or received from other
address spaces via IIOP calls.

\subsection{Object disposal}

\begin{description}

\item[line 9] To dispose of an object implementation and release all the
resources associated with it, the {\tt \_dispose} function is called.  In
fact, this is the {\bf only} clean way to get rid of an object
implementation. Even though the object is created using the new operator in
the application code, the application should never call the delete operator
on the object directly.

\end{description}

Once an application calls {\tt \_dispose} on an object implementation, the
pointer to the object should not be used any more. At the time the {\tt
\_dispose} call is made, there may be other threads invoking on the object,
omniORB2 ensures that all these calls are completed before removing the
object from its internal tables and releasing the resources associated with
it. The storage associated with the object is released by omniORB2
using the delete operator. This is why all object implementation should be
initialised using the new operator (section~\ref{objimpl}).

The disposal of an object implementation by omniORB2 may also be deferred
when {\bf colocated} clients continue to hold on to copies of the object's
reference\footnote{Object references held by clients in other address
spaces will not prevent the object implementation from being disposed
of. If these clients invoke on the object after it is disposed, the system
exception INV\_OBJREF is raised.}. This behavior is to prevent the
short-circuited calls from the clients to fail unpredictably.

To summarise, an application can make no assumption as to when the object
is disposed by omniORB2 after the {\tt \_dispose} call returns. If it is
necessary to have better control on when to stop serving incoming
requests, the work should be done by the object implementation itself, such
as by keeping track of the current serving state.

\section{Example 2 - Different Address Spaces}

In this example, the client and the object implementation reside in two
different address spaces. The code of this example is almost the same as the
previous example. The only difference is the extra work need to be done to
pass the object reference from the object implementation to the client.

The simplest (and quite primitive) way to pass an object reference between
two address spaces is to produce a stringified version of the object
reference and to pass this string to the client as a command-line argument.
The string is then converted by the client into a proper object reference.
This method is used in this example. In the next example, we shall
introduce a better way of passing the object reference using the COS Naming
Service.

\subsection{Object Implementation: Generating a Stringified Object Reference}

The {\tt main} function of the object implementation side is reproduced
below. The full listing ({\tt eg2\_impl.cc}) can be found at the end of
this chapter.

{\small
\begin{verbatim}
int
main(int argc, char **argv)
{
  CORBA::ORB_ptr orb = CORBA::ORB_init(argc,argv,"omniORB2");
  CORBA::BOA_ptr boa = orb->BOA_init(argc,argv,"omniORB2_BOA");

  Echo_i *myobj = new Echo_i();
  myobj->_obj_is_ready(boa);

  {
    Echo_var myobjRef = myobj->_this();
    CORBA::String_var p;

    p = orb->object_to_string(myobjRef);            //line 1

    cerr << "'" << (char*)p << "'" << endl;
  }

  boa->impl_is_ready();    // block here indefinitely
                           // See the explanation in example 1
  return 0;
}
\end{verbatim}
}

The stringified object reference is obtained by calling the ORB's function
{\tt \_object\_to\_string} (line 1). This is a sequence starting with the
signature ``IOR:'' and followed by a hexadecimal string. All CORBA 2.0
compliant ORBs are able to convert the string into its internal
representation of a so-called Interoperable Object Reference (IOR). The IOR
contains the location information and a key to uniquely identify the object
implementation in its own address space\footnote{Notice that the
object key is not globally unique across address spaces.}. From the IOR, an
object reference can be constructed.

\subsection{Client: Using a Stringified Object Reference}
\label{clnt2}

The stringified object reference is passed to the client as a command-line
argument. The client uses the ORB's function {\tt string\_to\_object} to
convert the string into a generic object reference ({\tt
CORBA::Object\_ptr}). The relevant section of the code is reproduced
below. The full listing ({\tt eg2\_clt.cc}) can be found at the end of this
chapter.

{\small
\begin{verbatim}
try {
  CORBA::Object_var obj = orb->string_to_object(argv[1]);
  hello(obj);
}
catch(CORBA::COMM_FAILURE& ex) {
  ... // code to handle communication failure
}
\end{verbatim}
}

\subsection{Catching System Exceptions}

When omniORB2 detects an error condition, it may raise a system exception.
The CORBA specification defines a series of exceptions covering most of the
error conditions that an ORB may encounter. The client may choose to catch
these exceptions and recover from the error condition\footnote{If a system
exception is not caught, the C++ runtime will call the {\tt terminate}
function. This function is defaulted to abort the whole process and on some
system will cause a core file to be produced.}. For instance, the code
fragment, shown in section~\ref{clnt2}, catches the system exception
COMM\_FAILURE which indicates that communication with the object
implementation in another address space has failed. 

All system exceptions inherit from the class
{\tt CORBA::SystemException}. With compilers that support RTTI\footnote{Run Time
Type Identification}\footnote{A noticeable exception is the GNU C++
compiler (version 2.7.2). It doesn't support RTTI unless the
compilation flag -frtti is specified. The omniORB2 runtime is not compiled
with the -frtti flag. It is said that RTTI will be properly supported in
the upcoming version 2.8.}, a single catch {\tt CORBA::SystemException} will
catch all the different system exceptions thrown by omniORB2. 

When omniORB2 detects an internal inconsistency that is most likely to be
caused by a bug in the runtime, it raises the exception {\tt
omniORB::fatalException}.  When this exception is raised, it is not
sensible to proceed with any operation that involves the ORB's runtime. It
is best to exit the program immediately. The exception structure carries by
{\tt omniORB::fatalException} contains the exact location (the file name
and the line number) where the exception is raised. You are strongly
encourage to file a bug report and point out the location.

\subsection{Lifetime of an Object Implementation}

It may be obvious but it has to stated that an object implementation exists
only for the duration of the process's lifetime. When the same program is
run again, a different instance of the object implementation is
created. More significantly, {\bf the IOR, and hence the object reference,
of this instance is different from that of the previous run}.

For instance, if you look at the stringified object reference produced by
the program {\tt eg2\_impl} in different runs, they are all
different. The implication is that you cannot store away the stringified
object reference and expect to be able to use it again later when the
original program run has terminated.

For system services and other applications, it may be desirable to have
``persistent'' object implementations.  The objects are ``persistent'' in
the sense that they can be contacted using the same IOR when they are
instantiated in different program runs. To provide this functionality,
omniORB2 needs to be provided with two pieces of information: the (network)
location and the object key. The details of how this can be done will be
described in the later part of this manual.

Alternatively, an indirection from textual pathnames to object references
can be used. Applications can register object implementations at runtime to
a naming service and bind them to fixed pathnames. Clients can bind to the
object implementations at runtime by asking the naming service to resolve
the pathnames to the object references. CORBA defines a naming service,
which is a component of the Common Object Services
(COS)~\cite{corbaservices}, that can be used for this purpose. The next
section describes an example of how to use the COS Naming Service.

\section{Example 3 - Using the COS Naming Service}

In this example, the object implementation uses the COS Naming
Service~\cite{corbaservices} to
pass on the object reference to the client.  This method is by-far more
practical than using stringified object references. The full listing of
the object implementation ({\tt eg3\_impl.cc}) and the client ({\tt
eg3\_clt.cc}) can be found at the end of this chapter.

The object reference is bound to the pathname ``{\bf
test}/{\bf Echo}''\footnote{A pathname, or in the Naming Service's
terminology- a {\it compound name}, is a sequence of textual names. Each
name component except the last one is bound to a naming context. A naming
context is analogous to a directory in a filing system, it can contain
names of object references or other naming contexts. The last name
component is bound to an object reference. Note: '/' is purely a notation
to separate two components in the pathname. It does not appear in the {\it
compound name} that is registered with the Naming Service.}. The pathname
consists of the context {\bf test} and the object name {\bf Echo}. Both the
context and the object name has an attribute {\bf kind}. This attribute is
a string that is intended to be used to describe the name in a
syntax-independent way. The naming service does not interpret, assign, or
manage these values. However both the name and the kind attribute must
match for a name lookup to succeed. In this example, the {\bf kind} values
for {\bf test} and {\bf Echo} are chosen to be ``my\_context'' and
``Object'' respectively. This is an arbitrary choice for there is no
standardised set of kind values.

\subsection{Obtaining the Root Context Object Reference}
\label{resolveinit}

The initial contact with the Naming Service can be established via what we
called the {\bf root} context. The object reference to the root context is
provided by the ORB and can be obtained by calling
{\tt resolve\_initial\_references}. The following code fragment shows how
it is used:

{\small
\begin{verbatim}

CORBA::ORB_ptr orb = CORBA::ORB_init(argc,argv,"omniORB2");

CORBA::Object_var initServ;
initServ = orb->resolve_initial_references("NameService");

CosNaming::NamingContext_var rootContext;
rootContext = CosNaming::NamingContext::_narrow(initServ);

\end{verbatim}
}

Remember, omniORB2 constructs its internal list of initial references at
initialisation time using the information provided in the configuration
file {\tt omniORB.cfg}. If this file is not present, the internal list will
be empty and {\tt resolve\_initial\_references} will raise a 
CORBA::ORB::InvalidName exception. 

\subsection{The Naming Service Interface}

It is beyond the scope of this chapter to describe in detail the Naming
Service interface. You should consult the CORBAservices
specification~\cite{corbaservices} (chapter 3). The
code listed in {\tt eg3\_impl.cc} and {\tt eg3\_clt.cc} are good examples
of how the service can be used. Please spend time to study the examples
carefully.

\section{Example 4 - Using tie implementation templates}

Since 2.6.0, a new command-line option ({\tt -t}) has been added to {\tt
omniidl2}. When this flag is specified, {\tt omniidl2} generates an extra
template class for each interface. This template class can be used to
tie a C++ class to the skeleton class of the interface. 

The source code in {\tt eg3\_tieimpl.cc} at the end of this chapter
illustrates how the template class can be used. The code is almost
identical to {\tt eg3\_impl.cc} with only a few changes.

Firstly, the implementation class {\tt Echo\_i} does not inherit from any
stub classes. This is the main benefit of using the template class because
there are applications in which it is difficult to require every
implementation class to subclass from CORBA classes.

Secondly, the instantiation of a CORBA object now involves creating an
instance of the implementation class {\bf and} an instance of the template.
Here is the relevant code fragment:

{\small
\begin{verbatim}
    class Echo_i { ... };
   
    Echo_i *myimpl = new Echo_i();
    _tie_Echo<Echo_i,1> *myobj = new _tie_Echo<Echo_i,1>(myimpl);
    myobj->_obj_is_ready(boa);
\end{verbatim}
}

For interface {\tt Echo}, the name of its tie implementation template is
{\tt \_tie\_Echo}. The first template parameter is the implementation class
that contains an implementation of each of the operations defined in the
interface. The second template parameter is a boolean flag. When the flag
is TRUE (1), as it is in this example, the ORB would call {\tt delete} on
the implementation object ({\tt myimpl}) when {\tt \_dispose} is invoked on
{\tt myobj}. When the flag is FALSE (0), {\tt delete} would not be called.
Instantiating this template with the flag set to FALSE is useful when the
same implementation class is used to implement multiple interfaces. In this
situation, the same implementation would be used as the argument to a
number of tie template instantiations. Provided that only one of the
instantiation has the flag set to TRUE, the object implementation would not
be deleted more than once!

\newpage
\section{Source Listing}

{\small
\subsection{echo\_i.cc}
\begin{verbatim}
// echo_i.cc - This source code demonstrates an implmentation of the
//             object interface Echo. It is part of the three examples
//             used in Chapter 2 "The Basics" of the omniORB2 user guide.
//
#include <string.h>
#include "echo.hh"

class Echo_i : public virtual _sk_Echo {
public:
  Echo_i() {}
  virtual ~Echo_i() {}
  virtual char * echoString(const char *mesg);
};

char *
Echo_i::echoString(const char *mesg) {
  char *p = CORBA::string_dup(mesg);
  return p;
}
\end{verbatim}
\newpage

\subsection{greeting.cc}
\begin{verbatim}
// greeting.cc - This source code demonstrates the use of an object
//               reference by a client to perform an operation on an 
//               object. It is part of the three examples used
//               in Chapter 2 "The Basics" of the omniORB2 user guide.
//
#include <iostream.h>
#include "echo.hh"

void
hello(CORBA::Object_ptr obj)
{
  Echo_var e = Echo::_narrow(obj);

  if (CORBA::is_nil(e)) {
    cerr << "hello: cannot invoke on a nil object reference.\n" << endl;
    return;
  }

  CORBA::String_var src = (const char*) "Hello!";  
  CORBA::String_var dest;

  dest = e->echoString(src);

  cerr << "I said,\"" << src << "\"."
       << " The Object said,\"" << dest <<"\"" << endl;
}
\end{verbatim}
\newpage

\subsection{eg1.cc}
\begin{verbatim}
// eg1.cc - This is the source code of example 1 used in Chapter 2 
//          "The Basics" of the omniORB2 user guide.
//
//          In this example, both the object implementation and the 
//          client are in the same process.
//
// Usage: eg1
//
#include <iostream.h>
#include "echo.hh"

#include "echo_i.cc"
#include "greeting.cc"

int
main(int argc, char **argv)
{
  CORBA::ORB_ptr orb = CORBA::ORB_init(argc,argv,"omniORB2");
  CORBA::BOA_ptr boa = orb->BOA_init(argc,argv,"omniORB2_BOA");

  Echo_i *myobj = new Echo_i();
  // Note: all implementation objects must be instantiated on the
  // heap using the new operator.

  myobj->_obj_is_ready(boa);
  // Tell the BOA the object is ready to serve.
  // This call is omniORB2 specific.
  //
  // This call is equivalent to the following call sequence:
  //     Echo_ptr myobjRef = myobj->_this();
  //     boa->obj_is_ready(myobjRef);
  //     CORBA::release(myobjRef);

  boa->impl_is_ready(0,1);
  // Tell the BOA we are ready and to return immediately once it has
  // done its stuff. It is omniORB2 specific to call impl_is_ready()
  // with the extra 2nd argument- CORBA::Boolean NonBlocking,
  // which is set to TRUE (1) in this case.

  Echo_ptr myobjRef = myobj->_this();
  // Obtain an object reference.
  // Note: always use _this() to obtain an object reference from the
  //       object implementation.

  hello(myobjRef);

  CORBA::release(myobjRef);
  // Dispose of the object reference.

  myobj->_dispose();
  // Dispose of the object implementation.
  // This call is omniORB2 specific.
  // Note: *never* call the delete operator or the dtor of the object
  //       directly because the BOA needs to be informed.
  //
  // This call is equivalent to the following call sequence:
  //     Echo_ptr myobjRef = myobj->_this();
  //     boa->dispose(myobjRef);
  //     CORBA::release(myobjRef);

  return 0;
}
\end{verbatim}
\newpage

\subsection{eg2\_impl.cc}
\begin{verbatim}
// eg2_impl.cc - This is the source code of example 2 used in Chapter 2
//               "The Basics" of the omniORB2 user guide.
//
//               This is the object implementation.
//
// Usage: eg2_impl
//
//        On startup, the object reference is printed to cerr as a
//        stringified IOR. This string should be used as the argument to 
//        eg2_clt.
//
#include <iostream.h>
#include "omnithread.h"
#include "echo.hh"

#include "echo_i.cc"

int
main(int argc, char **argv)
{
  CORBA::ORB_ptr orb = CORBA::ORB_init(argc,argv,"omniORB2");
  CORBA::BOA_ptr boa = orb->BOA_init(argc,argv,"omniORB2_BOA");

  Echo_i *myobj = new Echo_i();
  myobj->_obj_is_ready(boa);

  {
    Echo_var myobjRef = myobj->_this();
    CORBA::String_var p = orb->object_to_string(myobjRef);
    cerr << "'" << (char*)p << "'" << endl;
  }

  boa->impl_is_ready();
  // Tell the BOA we are ready. The BOA's default behaviour is to block
  // on this call indefinitely.

  return 0;
}
\end{verbatim}
\newpage

\subsection{eg2\_clt.cc}
\begin{verbatim}
// eg2_clt.cc - This is the source code of example 2 used in Chapter 2
//              "The Basics" of the omniORB2 user guide.
//
//              This is the client. The object reference is given as a
//              stringified IOR on the command line.
//
// Usage: eg2_clt <object reference>
//
#include <iostream.h>
#include "echo.hh"

#include "greeting.cc"

extern void hello(CORBA::Object_ptr obj);

int
main (int argc, char **argv) 
{
  CORBA::ORB_ptr orb = CORBA::ORB_init(argc,argv,"omniORB2");
  CORBA::BOA_ptr boa = orb->BOA_init(argc,argv,"omniORB2_BOA");

  if (argc < 2) {
    cerr << "usage: eg2_clt <object reference>" << endl;
    return 1;
  }

  try {
    CORBA::Object_var obj = orb->string_to_object(argv[1]);
    hello(obj);
  }
  catch(CORBA::COMM_FAILURE& ex) {
    cerr << "Caught system exception COMM_FAILURE, unable to contact the "
         << "object." << endl;
  }
  catch(omniORB::fatalException& ex) {
    cerr << "Caught omniORB2 fatalException. This indicates a bug is caught "
         << "within omniORB2.\nPlease send a bug report.\n"
         << "The exception was thrown in file: " << ex.file() << "\n"
         << "                            line: " << ex.line() << "\n"
         << "The error message is: " << ex.errmsg() << endl;
  }
  catch(...) {
    cerr << "Caught a system exception." << endl;
  }

  return 0;
}
\end{verbatim}
\newpage

\subsection{eg3\_impl.cc}
\begin{verbatim}
// eg3_impl.cc - This is the source code of example 3 used in Chapter 2
//               "The Basics" of the omniORB2 user guide.
//
//               This is the object implementation.
//
// Usage: eg3_impl
//
//        On startup, the object reference is registered with the 
//        COS naming service. The client uses the naming service to
//        locate this object.
//
//        The name which the object is bound to is as follows:
//              root  [context]
//               |
//              text  [context] kind [my_context]
//               |
//              Echo  [object]  kind [Object]
//

#include <iostream.h>
#include "omnithread.h"
#include "echo.hh"

#include "echo_i.cc"

static CORBA::Boolean bindObjectToName(CORBA::ORB_ptr,CORBA::Object_ptr);

int
main(int argc, char **argv)
{
  CORBA::ORB_ptr orb = CORBA::ORB_init(argc,argv,"omniORB2");
  CORBA::BOA_ptr boa = orb->BOA_init(argc,argv,"omniORB2_BOA");

  Echo_i *myobj = new Echo_i();
  myobj->_obj_is_ready(boa);

  {
    Echo_var myobjRef = myobj->_this();
    if (!bindObjectToName(orb,myobjRef)) {
      return 1;
    }
  }

  boa->impl_is_ready();
  // Tell the BOA we are ready. The BOA's default behaviour is to block
  // on this call indefinitely.

  return 0;
}


static
CORBA::Boolean
bindObjectToName(CORBA::ORB_ptr orb,CORBA::Object_ptr obj)
{
  CosNaming::NamingContext_var rootContext;
  
  try {
    // Obtain a reference to the root context of the Name service:
    CORBA::Object_var initServ;
    initServ = orb->resolve_initial_references("NameService");

    // Narrow the object returned by resolve_initial_references()
    // to a CosNaming::NamingContext object:
    rootContext = CosNaming::NamingContext::_narrow(initServ);
    if (CORBA::is_nil(rootContext))
      {
        cerr << "Failed to narrow naming context." << endl;
        return 0;
      }
  }
  catch(CORBA::ORB::InvalidName& ex) {
    cerr << "Service required is invalid [does not exist]." << endl;
    return 0;
  }


  try {
    // Bind a context called "test" to the root context:

    CosNaming::Name contextName;
    contextName.length(1);
    contextName[0].id   = (const char*) "test";    // string copied
    contextName[0].kind = (const char*) "my_context"; // string copied    
    // Note on kind: The kind field is used to indicate the type
    // of the object. This is to avoid conventions such as that used
    // by files (name.type -- e.g. test.ps = postscript etc.)

    CosNaming::NamingContext_var testContext;
    try {
      // Bind the context to root, and assign testContext to it:
      testContext = rootContext->bind_new_context(contextName);
    }
    catch(CosNaming::NamingContext::AlreadyBound& ex) {
      // If the context already exists, this exception will be raised.
      // In this case, just resolve the name and assign testContext
      // to the object returned:
      CORBA::Object_var tmpobj;
      tmpobj = rootContext->resolve(contextName);
      testContext = CosNaming::NamingContext::_narrow(tmpobj);
      if (CORBA::is_nil(testContext)) {
        cerr << "Failed to narrow naming context." << endl;
        return 0;
      }
    } 

    // Bind the object (obj) to testContext, naming it Echo:
    CosNaming::Name objectName;
    objectName.length(1);
    objectName[0].id   = (const char*) "Echo";   // string copied
    objectName[0].kind = (const char*) "Object"; // string copied


    // Bind obj with name Echo to the testContext:
    try {
      testContext->bind(objectName,obj);
    }
    catch(CosNaming::NamingContext::AlreadyBound& ex) {
      testContext->rebind(objectName,obj);
    }
    // Note: Using rebind() will overwrite any Object previously bound 
    //       to /test/Echo with obj.
    //       Alternatively, bind() can be used, which will raise a
    //       CosNaming::NamingContext::AlreadyBound exception if the name
    //       supplied is already bound to an object.

    // Amendment: When using OrbixNames, it is necessary to first try bind
    // and then rebind, as rebind on it's own will throw a NotFoundexception if
    // the Name has not already been bound. [This is incorrect behaviour -
    // it should just bind].
  }
  catch (CORBA::COMM_FAILURE& ex) {
    cerr << "Caught system exception COMM_FAILURE, unable to contact the "
         << "naming service." << endl;
    return 0;
  }
  catch (omniORB::fatalException& ex) {
    throw;
  }
  catch (...) {
    cerr << "Caught a system exception while using the naming service."<< endl;
    return 0;
  }
  return 1;
}
\end{verbatim}
\newpage

\subsection{eg3\_clt.cc}
\begin{verbatim}
// eg3_clt.cc - This is the source code of example 3 used in Chapter 2
//              "The Basics" of the omniORB2 user guide.
//
//              This is the client. It uses the COSS naming service
//              to obtain the object reference.
//
// Usage: eg3_clt
//
//
//        On startup, the client lookup the object reference from the
//        COS naming service.
//
//        The name which the object is bound to is as follows:
//              root  [context]
//               |
//              text  [context] kind [my_context]
//               |
//              Echo  [object]  kind [Object]
//

#include <iostream.h>
#include "echo.hh"

#include "greeting.cc"

extern void hello(CORBA::Object_ptr obj);

static CORBA::Object_ptr getObjectReference(CORBA::ORB_ptr orb);

int
main (int argc, char **argv) 
{
  CORBA::ORB_ptr orb = CORBA::ORB_init(argc,argv,"omniORB2");
  CORBA::BOA_ptr boa = orb->BOA_init(argc,argv,"omniORB2_BOA");

  try {
    CORBA::Object_var obj = getObjectReference(orb);
    hello(obj);
  }
  catch(CORBA::COMM_FAILURE& ex) {
    cerr << "Caught system exception COMM_FAILURE, unable to contact the "
         << "object." << endl;
  }
  catch(omniORB::fatalException& ex) {
    cerr << "Caught omniORB2 fatalException. This indicates a bug is caught "
         << "within omniORB2.\nPlease send a bug report.\n"
         << "The exception was thrown in file: " << ex.file() << "\n"
         << "                            line: " << ex.line() << "\n"
         << "The error message is: " << ex.errmsg() << endl;
  }
  catch(...) {
    cerr << "Caught a system exception." << endl;
  }

  return 0;
}

static 
CORBA::Object_ptr
getObjectReference(CORBA::ORB_ptr orb)
{
  CosNaming::NamingContext_var rootContext;
  
  try {
    // Obtain a reference to the root context of the Name service:
    CORBA::Object_var initServ;
    initServ = orb->resolve_initial_references("NameService");

    // Narrow the object returned by resolve_initial_references()
    // to a CosNaming::NamingContext object:
    rootContext = CosNaming::NamingContext::_narrow(initServ);
    if (CORBA::is_nil(rootContext)) 
      {
        cerr << "Failed to narrow naming context." << endl;
        return CORBA::Object::_nil();
      }
  }
  catch(CORBA::ORB::InvalidName& ex) {
    cerr << "Service required is invalid [does not exist]." << endl;
    return CORBA::Object::_nil();
  }


  // Create a name object, containing the name test/context:
  CosNaming::Name name;
  name.length(2);

  name[0].id   = (const char*) "test";       // string copied
  name[0].kind = (const char*) "my_context"; // string copied
  name[1].id   = (const char*) "Echo";
  name[1].kind = (const char*) "Object";
  // Note on kind: The kind field is used to indicate the type
  // of the object. This is to avoid conventions such as that used
  // by files (name.type -- e.g. test.ps = postscript etc.)

  
  CORBA::Object_ptr obj;
  try {
    // Resolve the name to an object reference, and assign the reference 
    // returned to a CORBA::Object:
    obj = rootContext->resolve(name);
  }
  catch(CosNaming::NamingContext::NotFound& ex)
    {
      // This exception is thrown if any of the components of the
      // path [contexts or the object] aren't found:
      cerr << "Context not found." << endl;
      return CORBA::Object::_nil();
    }
  catch (CORBA::COMM_FAILURE& ex) {
    cerr << "Caught system exception COMM_FAILURE, unable to contact the "
         << "naming service." << endl;
    return CORBA::Object::_nil();
  }
  catch(omniORB::fatalException& ex) {
    throw;
  }
  catch (...) {
    cerr << "Caught a system exception while using the naming service."<< endl;
    return CORBA::Object::_nil();
  }
  return obj;
}
\end{verbatim}
\newpage

\subsection{eg3\_tieimpl.cc}
\begin{verbatim}
// eg3_tieimpl.cc - This example is similar to eg3_impl.cc except that
//                  the tie implementation skeleton is used.
//
//               This is the object implementation.
//
// Usage: eg3_tieimpl
//
//        On startup, the object reference is registered with the 
//        COS naming service. The client uses the naming service to
//        locate this object.
//
//        The name which the object is bound to is as follows:
//              root  [context]
//               |
//              text  [context] kind [my_context]
//               |
//              Echo  [object]  kind [Object]
//

#include <iostream.h>
#include "omnithread.h"
#include "echo.hh"


// Real implementation, notice that it does not inherit from any stub class
class Echo_i {
public:
  Echo_i() {}
  virtual ~Echo_i() {}
  virtual char * echoString(const char *mesg);
};

char *
Echo_i::echoString(const char *mesg) {
  char *p = CORBA::string_dup(mesg);
  return p;
}


static CORBA::Boolean bindObjectToName(CORBA::ORB_ptr,CORBA::Object_ptr);

int
main(int argc, char **argv)
{
  CORBA::ORB_ptr orb = CORBA::ORB_init(argc,argv,"omniORB2");
  CORBA::BOA_ptr boa = orb->BOA_init(argc,argv,"omniORB2_BOA");

  Echo_i *myimpl = new Echo_i();
  _tie_Echo<Echo_i,1> *myobj = new _tie_Echo<Echo_i,1>(myimpl);
  myobj->_obj_is_ready(boa);

  {
    Echo_var myobjRef = myobj->_this();
    if (!bindObjectToName(orb,myobjRef)) {
      return 1;
    }
  }

  boa->impl_is_ready();
  // Tell the BOA we are ready. The BOA's default behaviour is to block
  // on this call indefinitely.

  return 0;
}


static
CORBA::Boolean
bindObjectToName(CORBA::ORB_ptr orb,CORBA::Object_ptr obj)
{
  CosNaming::NamingContext_var rootContext;
  
  try {
    // Obtain a reference to the root context of the Name service:
    CORBA::Object_var initServ;
    initServ = orb->resolve_initial_references("NameService");

    // Narrow the object returned by resolve_initial_references()
    // to a CosNaming::NamingContext object:
    rootContext = CosNaming::NamingContext::_narrow(initServ);
    if (CORBA::is_nil(rootContext)) 
      {
        cerr << "Failed to narrow naming context." << endl;
        return 0;
      }
  }
  catch(CORBA::ORB::InvalidName& ex) {
    cerr << "Service required is invalid [does not exist]." << endl;
    return 0;
  }


  try {
    // Bind a context called "test" to the root context:

    CosNaming::Name contextName;
    contextName.length(1);
    contextName[0].id   = (const char*) "test";    // string copied
    contextName[0].kind = (const char*) "my_context"; // string copied    
    // Note on kind: The kind field is used to indicate the type
    // of the object. This is to avoid conventions such as that used
    // by files (name.type -- e.g. test.ps = postscript etc.)

    CosNaming::NamingContext_var testContext;
    try {
      // Bind the context to root, and assign testContext to it:
      testContext = rootContext->bind_new_context(contextName);
    }
    catch(CosNaming::NamingContext::AlreadyBound& ex) {
      // If the context already exists, this exception will be raised.
      // In this case, just resolve the name and assign testContext
      // to the object returned:
      CORBA::Object_var tmpobj;
      tmpobj = rootContext->resolve(contextName);
      testContext = CosNaming::NamingContext::_narrow(tmpobj);
      if (CORBA::is_nil(testContext)) {
        cerr << "Failed to narrow naming context." << endl;
        return 0;
      }
    } 

    // Bind the object (obj) to testContext, naming it Echo:
    CosNaming::Name objectName;
    objectName.length(1);
    objectName[0].id   = (const char*) "Echo";   // string copied
    objectName[0].kind = (const char*) "Object"; // string copied


    // Bind obj with name Echo to the testContext:
    try {
      testContext->bind(objectName,obj);
    }
    catch(CosNaming::NamingContext::AlreadyBound& ex) {
      testContext->rebind(objectName,obj);
    }
    // Note: Using rebind() will overwrite any Object previously bound 
    //       to /test/Echo with obj.
    //       Alternatively, bind() can be used, which will raise a
    //       CosNaming::NamingContext::AlreadyBound exception if the name
    //       supplied is already bound to an object.

    // Amendment: When using OrbixNames, it is necessary to first try bind
    // and then rebind, as rebind on it's own will throw a NotFoundexception if
    // the Name has not already been bound. [This is incorrect behaviour -
    // it should just bind].
  }
  catch (CORBA::COMM_FAILURE& ex) {
    cerr << "Caught system exception COMM_FAILURE, unable to contact the "
         << "naming service." << endl;
    return 0;
  }
  catch (omniORB::fatalException& ex) {
    throw;
  }
  catch (...) {
    cerr << "Caught a system exception while using the naming service."<< endl;
    return 0;
  }
  return 1;
}

\end{verbatim}
\newpage
\subsection{dir.mk}
\begin{verbatim}
# dir.mk - This is the makefile to compile all the example programs used in
#          Chapter 2 The Basics.
#          This makefile is to be used under the OMNI development environment.
#
CXXSRCS = greeting.cc eg1.cc \
          eg2_impl.cc eg2_clt.cc \
          eg3_impl.cc eg3_clt.cc

DIR_CPPFLAGS = $(CORBA_CPPFLAGS)

CORBA_INTERFACES = echo

eg1        = $(patsubst %,$(BinPattern),eg1)
eg2_impl   = $(patsubst %,$(BinPattern),eg2_impl)
eg2_clt    = $(patsubst %,$(BinPattern),eg2_clt)
eg3_impl   = $(patsubst %,$(BinPattern),eg3_impl)
eg3_clt    = $(patsubst %,$(BinPattern),eg3_clt)

all:: $(eg1) $(eg2_impl) $(eg2_clt)  $(eg3_impl) $(eg3_clt)

clean::
        $(RM) $(eg1) $(eg2_impl) $(eg2_clt) $(eg3_impl) $(eg3_clt)

$(eg1): eg1.o $(CORBA_STUB_OBJS) $(CORBA_LIB_DEPEND)
        @(libs="$(CORBA_LIB)"; $(CXXExecutable))

$(eg2_impl): eg2_impl.o $(CORBA_STUB_OBJS) $(CORBA_LIB_DEPEND)
        @(libs="$(CORBA_LIB)"; $(CXXExecutable))

$(eg2_clt): eg2_clt.o $(CORBA_STUB_OBJS) $(CORBA_LIB_DEPEND)
        @(libs="$(CORBA_LIB)"; $(CXXExecutable))

$(eg3_impl): eg3_impl.o $(CORBA_STUB_OBJS) $(CORBA_LIB_DEPEND)
        @(libs="$(CORBA_LIB)"; $(CXXExecutable))

$(eg3_clt): eg3_clt.o $(CORBA_STUB_OBJS) $(CORBA_LIB_DEPEND)
        @(libs="$(CORBA_LIB)"; $(CXXExecutable))

\end{verbatim}
}


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\chapter{IDL to C++ Language Mapping}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Now that you are familiar with the basics, it is important to
familiar yourselves with the IDL to C++ language. The mapping is described
in detail in~\cite{corba2-spec}. If you have not done so, you should obtain
a copy of the document and use that as the programming guide to
omniORB2.

%\input{api.tex}


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\chapter{The omniORB2 API}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\label{omniorb2api}

In this chapter, we introduce the omniORB2 API. The purpose
of this API is to provide access points to omniORB2 specific
functionalities that are 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 omniORB2 dependent code, this API is defined
under the name space ``omniORB''\footnote{omniORB is a class name if the
C++ compiler does not support the namespace keyword.}.

\section{ORB and BOA initialisation options}
\label{omniorbapioptions}

{\tt CORBA::ORB\_init} accepts the following command-line arguments:

\begin{description}

\item[\tt -ORBid ``omniORB2''] The identifier supplied must be ``omniORB2''.
\item[\tt -ORBtraceLevel <level>] See section~\ref{rttrace}.
\item[\tt -ORBserverName <string>] See section~\ref{sec_servername}.
\item[\tt -ORBtcAliasExpand <0 or 1>] See section~\ref{anyOmniORB2}.
\item[\tt -ORBgiopMaxMsgSize <size in bytes>] See section~\ref{giopmsg}.
\item[\tt -ORBInitialHost <string>] See section~\ref{bootstrap}.
\item[\tt -ORBInitialPort <1-65535>] See section~\ref{bootstrap}.
\item[\tt -ORBdiiThrowsSysExceptions <0 or 1>] See section~\ref{dii_invoke}.
\item[\tt -ORBinConScanPeriod <0-65535>] See section~\ref{sec_shut}.
\item[\tt -ORBoutConScanPeriod <0-65535>] See section~\ref{sec_shut}.
\end{description}

{\tt BOA\_init} accepts the following command-line arguments:

\begin{description}

\item[\tt -BOAid ``omniORB2\_BOA''] The identifier supplied must be ``omniORB2\_BOA''.
\item[\tt -BOAiiop\_port <port number>] This option tells the BOA which
TCP/IP port to use to accept IIOP calls. If this option is not specified,
the BOA will use an arbitrary port assigned by the operating system.
\item[\tt -BOAno\_bootstrap\_agent] See section~\ref{bootstrap}.
\end{description}

By default, the BOA 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 BOA should use. This can be done by defining the environment variable
{\tt OMNIORB\_USEHOSTNAME} to contain the preferred host name or IP
address in dot-numeric form.


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

\section{Run-time Tracing and Diagnostic Messages}
\label{rttrace}

OmniORB2 uses the C++ iostream {\tt cerr} to output any tracing and
diagnostic messages. Some or all of these messages can be turned-{on/off} by
setting the variable {\tt omniORB::traceLevel}. The type definition of
the variable is:

{\small
\begin{verbatim}
CORBA::ULong omniORB::traceLevel = 1;  // The default value is 1
\end{verbatim}
}

At the moment, the following trace levels are defined:

\begin{description}

\item[level 0] turn off all tracing and informational messages
\item[level 1] informational messages only
\item[level 2] the above plus configuration information
\item[level 5] the above plus notifications when server threads are created
or communication endpoints are shutdown
\item[level 10-20] the above plus execution traces

\end{description}

The variable can be changed by assignment inside your applications. It can
also be changed by specifying the command-line option: {\tt -ORBtraceLevel
<level>}. For instance:

{\small
\begin{verbatim}
$ eg2_impl -ORBtraceLevel 5
\end{verbatim}
}

%$

\section{Server Name}
\label{sec_servername}

Applications can optionally specified a name to identify the server
process. At the moment, this name is only used by the host-based access
control module. See section~\ref{sec_accept} for details.

The name is stored in the variable {\tt omniORB::serverName}.

{\small
\begin{verbatim}
CORBA::String_var omniORB::serverName;
\end{verbatim}
}

The variable can be changed by assignment inside your applications. It can
also be changed by specifying the command-line option: {\tt -ORBserverName
<string>}.
 
\section{Object Keys}

OmniORB2 uses a data type {\tt omniORB::objectKey} to uniquely
identify each object implementation. This is an opaque data type and 
can only be manipulated by the following functions:

{\small
\begin{verbatim}
void omniORB::generateNewKey(omniORB::objectKey &k);
\end{verbatim}
}

{\tt omniORB::generateNewKey} returns a new {\tt objectKey}. The return
value is guaranteed to be unique among the keys generated during this program
run. On the platforms that have a realtime clock and unique process
identifiers, a stronger assertion can be made, i.e. the keys are guaranteed
to be unique among all keys ever generated on the same machine.

{\small
\begin{verbatim}
const unsigned int omniORB::hash_table_size;
int omniORB::hash(omniORB::objectKey& k);
\end{verbatim}
}

{\tt omniORB::hash} returns the hash value of an {\tt objectKey}. The value
returned by this function is always between 0 and {\tt
omniORB:hash\_table\_size - 1} inclusively.

{\small
\begin{verbatim}
omniORB::objectKey omniORB::nullkey();
\end{verbatim}
}

{\tt omniORB::nullkey} always returns the same {\tt objectKey} value. This
key is guaranteed to hash to 0.

{\small
\begin{verbatim}
int operator==(const omniORB::objectKey &k1,const omniORB::objectKey &k2);
int operator!=(const omniORB::objectKey &k1,const omniORB::objectKey &k2);
\end{verbatim}
}

{\tt ObjectKeys} can be tested for equality using the overloaded {\tt
operator==} and {\tt operator!=}.

{\small
\begin{verbatim}
omniORB::seqOctets*
omniORB::keyToOctetSequence(const omniORB::objectKey &k1);

omniORB::objectKey
omniORB::octetSequenceToKey(const omniORB::seqOctets& seq);
\end{verbatim}
}

{\tt omniORB::keyToOctetSequence} takes an {\tt objectKey} and returns its
externalised representation in the form of a sequence of octets. The same
sequence can be converted back to an {\tt objectKey} using {\tt
omniORB::octetSequenceToKey}. If the supplied sequence is not an {\tt
objectKey}, {\tt omniORB::octetSequenceToKey} raises a {\tt CORBA::MARSHAL}
exception.


\section{GIOP Message Size}
\label{giopmsg}

omniORB2 sets a limit on the GIOP message size that can be sent or
received. The value can be obtained by calling:
{\small
\begin{verbatim}
size_t omniORB::MaxMessageSize();
\end{verbatim}
}
\noindent and can be changed by:

{\small
\begin{verbatim}
void omniORB::MaxMessageSize(size_t newvalue);
\end{verbatim}
}

\noindent or by the command-line option {\tt -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 2**31. With a reasonable
message size limit, the server can reject this rogue message straight away.

\section{Initial Object Reference Bootstrapping}
\label{bootstrap}

Starting from 2.6.0, a new mechanism is available for the ORB runtime to
obtain the initial object references to CORBA services. Previously, it is
necessary to write the IOR string of these services in the configuration
file (section~\ref{setup}). Now the object references can be obtained from
a bootstrap service. The bootstrap service is a special object with the
object key 'INIT' and the following interface\footnote{This interface is
first defined by Sun's NEO and is in used in Sun's JavaIDL}.:

{
\small
\begin{verbatim}
     // 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 COSS
            // Naming service is "NameService".

            ORB::ObjectIdList list();
            // returns the list of service id that this agent knows of
            // their initial object reference.
        };
     };
\end{verbatim}
}

By default, all omniORB2 servers, i.e. those applications with the BOA
initialised, contains an instance of this object and is able to responds to
remote invocations. To prevent the ORB from instantiating this object, the
command-line option {\tt -BOAno\_bootstrap\_agent} should be specified.

In particular, the Naming Service omniNames is able to respond to a query
through this interface and returns the object reference of its root
context. In effect, the bootstrap agent provides a level of indirection.
All omniORB2 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 compatiable with JavaIDL. This makes it possible for a client
written in JavaIDL to share with a omniORB2 server the same Naming Service.

The address of the bootstrap agent is given by the {\tt ORBInitialHost} and
{\tt ORBInitialPort} parameter in the omniORB configuration file
(section~\ref{setup}). The parameters can also be specified as command-line
options (section~\ref{omniorbapioptions}). {\tt ORBInitialHost} is the host
name and {\tt ORBInitialPort} is the TCP/IP port number. The parameter {\tt
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 {\tt NAMESERVICE} is specified, the
stringified IOR would be used as the object reference of the root naming
context. If the parameter is absent and the parameter {\tt ORBInitialHost}
is present, the ORB would contact the bootstrap agent at the address
specified to obtain the root naming context when the application calls {\tt
resolve\_initial\_reference()}. If neither the {\tt NAMESERVICE} nor {\tt
ORBInitialHost} is present, a call to {\tt resolve\_initial\_reference()}
returns a nil object. Finally, the command line argument {\tt
-ORBInitialHost} overrides any parameters in the configuration file. The
ORB would always contact 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.

\begin{enumerate}
\item Start omniNames for the first time on a machine (e.g. wobble):

{\tt \$ omniNames -start 1234}

\item Add to omniORB.cfg:

{\tt ORBInitialHost wobble}

{\tt ORBInitialPort 1234}

\item All omniORB2 applications will now be able to contact omniNames.

\end{enumerate}

Alternatively, the command line options can be used, for example:

{\tt \$ eg3\_impl -ORBInitialHost wobble -ORBInitialPort 1234 \&}

{\tt \$ eg3\_clt -ORBInitialHost wobble -ORBInitialPort 1234}


\section{Trapping omniORB2 Internal Errors}

{\small
\begin{verbatim}
class fatalException {
public:
    const char *file() const;
    int line() const;
    const char *errmsg() const;
};
\end{verbatim}
}

When omniORB2 detects an internal inconsistency that is most likely to be
caused by a bug in the runtime, it raises the exception {\tt
omniORB::fatalException}.  When this exception is raised, it is not
sensible to proceed with any operation that involves the ORB's runtime. It
is best to exit the program immediately. The exception structure carries by
{\tt omniORB::fatalException} contains the exact location (the file name
and the line number) where the exception is raised. You are strongly
encourage to file a bug report and point out the location.


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\chapter{The Basic Object Adaptor (BOA)}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

This chapter describes the BOA implementation in omniORB2. The CORBA
specification defines the Basic Object Adaptor as the entity that mediates
between object implementations and the ORB. Unfortunately, the BOA
specification is incomplete and does not address the multi-threading issues
appropriately. The end result is that different ORB vendors implement
different extensions to their BOAs. Worse, the implementation of the operations
defined in the specification are different in different ORBs. Recently, a new
Object Adaptor specification (the Portable Object Adaptor- POA) has been
adopted and will replace the BOA as the standard Object Adaptor in
CORBA. The new specification recognises the compatibility problems of BOA
and recommends that all BOAs should be considered propriety extensions.
OmniORB2 will support POA in future releases. Until then, you have to
use the BOA to attach object implementations to the ORB. 

The rest of this chapter describes the interface of the BOA in detail. It
is important to recognise that the interface described below is omniORB2
specific and hence the code using this interface is unlikely to be portable
to other ORBs.

Unless it is stated otherwise, the term ``object'' will be used below to
refer to object implementations. This should not be confused with ``object
references'' which are handles held by clients.

\section{BOA Initialisation}

It takes two steps to put the BOA into service. The BOA has to be
initialised using {\tt BOA\_init} and activated using {\tt
impl\_is\_ready}.


\noindent {\tt BOA\_init} is a member of the {\tt CORBA::ORB} class. Its signature is:

{\small
\begin{verbatim}
BOA_ptr BOA_init(int & argc,
                 char ** argv,
                 const char * boa_identifier);
\end{verbatim}
}

\noindent Typically, it is used in the startup code as follows:

{\small
\begin{verbatim}
CORBA::ORB_ptr orb = CORBA::ORB_init(argc,argv,"omniORB2");   // line 1
CORBA::BOA_ptr boa = orb->BOA_init(argc,argv,"omniORB2_BOA"); // line 2
\end{verbatim}
}

The {\tt argv} parameters may contain BOA options. These options will be
removed from the {\tt argv} list when {\tt BOA\_init} returns. Other
parameters in {\tt argv} will remain. The supported options are:

\begin{description}

\item[-BOAiiop\_port {\tt <port number (0-65535)>}] Use the port number to receive
IIOP requests. This option can be specified multiple times in the command
line and the BOA would be initialised to listen on all of the ports.

\item[-BOAid {\tt <id (string)>}] If this option is used the id must be
``omniORB2\_BOA''. 

\end{description}

If the third argument of {\tt BOA\_init} is non-nil, it must be the string
constant ``omniORB2\_BOA''. If the argument is nil, -BOAid must be present
in {\tt argv}.

If there is any problem in the initialisation process, a {\tt
CORBA::INITIALIZE} exception would be raised.

To register an object with the BOA, the method
{\tt \_obj\_is\_ready} should be called with the return value of {\tt
BOA\_init} as the argument.

{\tt BOA\_init} is thread-safe. It can be called multiple times and the
same {\tt BOA\_ptr} will be returned. However, only the {\tt argv} in the
first call will be scanned, the argument is ignored in subsequent calls.

{\tt BOA\_init} returns a pseudo object of type {\tt
CORBA::BOA\_ptr}. Similar to {\tt CORBA::Object\_ptr}, the pointer can be
managed using {\tt CORBA::BOA\_var}, {\tt BOA::\_duplicate} and {\tt
CORBA::release}. The pointer can be tested using {\tt CORBA::is\_nil} which
returns true if the pointer is equivalent to the return value of {\tt
BOA::\_nil}. 

After {\tt BOA\_init} is called, objects can be registered. However,
incoming IIOP requests would not be despatched until {\tt impl\_is\_ready}
is called.

{\small
\begin{verbatim}
class BOA {
public:
   impl_is_ready(CORBA::ImplementationDef_ptr p = 0,
                 CORBA::Boolean NonBlocking = 0);
};
\end{verbatim}
}

One of the common pitfall in using the BOA is to forget to call
impl\_is\_ready. Until this call returns, there is no thread listening on
the port from which IIOP requests are received. The remote client may hang
because of this.

When {\tt impl\_is\_ready} is called with no argument. The calling thread
would be blocked indefinitely in the function until {\tt impl\_shutdown}
(see below) is called. The thread that is calling {\tt impl\_is\_ready}
is not used by the BOA to perform its internal functions. The BOA has its
own set of threads to process incoming requests and general
housekeeping. Therefore, it is not necessary to have a thread blocked in
the call if it can be put into use elsewhere. For example, the main thread
may call {\tt impl\_is\_ready} once in non-blocking mode (see below) and
then enter the event loop to handle the GUI frontend.

If non-blocking behaviour is needed, the {\tt NonBlocking} argument should be
set to 1. For instance, if you creates a callback object, you might call
impl\_is\_ready in non-blocking mode to tell the BOA to start receiving
IIOP requests before sending the callback object to the remote object. The
first argument {\tt ImplementationDef\_ptr} is ignored by the BOA. Just set
the argument to nil.

{\tt impl\_is\_ready} is thread safe and can be called multiple
times. Multiple threads can be blocked in {\tt impl\_is\_ready}.

\section{Object Registration}

Once the BOA is initialised, objects can be registered. The
purpose of object registration is to let the BOA know of the existence of
the object and to dispatch requests for the object as upcalls into the
object. 

To register an object, the {\tt \_obj\_is\_ready} function should be
called. {\tt \_obj\_is\_ready} is a member function of the implementation
skeleton class. The function should be called only once for each object.
The call should be made only after the object is fully initialised.

The member function {\tt obj\_is\_ready} of the BOA may also be used to
register an object. However, this function has been superseded by {\tt
\_obj\_is\_ready} and should not be used in new application code.

\section{Object Disposal}

Once an object is registered, it is under the
management of the BOA. To remove the object from the BOA and to delete it
(when it is safe to do so), the {\tt \_dispose} function should be called.
{\tt \_dispose} is a member function of the implementation skeleton class.
The function should be called only once for each object.

Notice the asymmetry in object instantiation and destruction. To instantiate
an object, the application code has to call the {\bf new}
operator. To remove the object, the application should never
call the delete operator on the object directly.

At the time the {\tt \_dispose} call is made, there may be other threads
invoking on the object, the BOA ensures that all these calls are completed
before removing the object from its internal tables and calling the
{\bf delete} operator.

Internally, the BOA keeps a reference count on each object. Initially, the
reference count is 0. After a call to {\tt \_obj\_is\_ready}, the reference
count is 1. The BOA increases the reference count by 1 before
an upcall into the object is made. The count is decreased by 1 when the
upcall returns.  {\tt \_dispose} decreases the reference count by 1, if
the reference count is 0, the delete operator is called. If the count is
non-zero, the object is marked as disposed. The object will be deleted when
the reference count eventually goes to zero.

The reference count is also increased by 1 for each object reference held
in the same address space. Hence, the {\bf delete} operator will not be
called when there are outstanding object references in the same address
space. To ensure that an object is deleted, all its object references in
the same address space should be released using {\tt CORBA::release}.

Unlike colocated object references, references held by clients in other
address spaces would not prevent the deletion of objects. If these clients
invoke on the object after it is disposed, the system exception INV\_OBJREF
would be raised. The difference in semantics is an undesirable side-effect
of the current BOA implementation. In future, colocated references will
have the same semantics as remote references, i.e. their presence will not
delay the deletion of the objects.

Instead of {\tt \_dispose}, it may be useful to have a method to deactivate
the object but not deleting it. This feature is not supported in the
current BOA implementation.

\section{BOA Shutdown}

The BOA can be withdrawn from service using member functions {\tt
impl\_shutdown} and {\tt destroy}.

{\small
\begin{verbatim}
class BOA {
public:
   void impl_shutdown();
   void destroy();
};
\end{verbatim}
}

{\tt impl\_shutdown} and {\tt destroy} are the inverse of {\tt
impl\_is\_ready} and {\tt BOA\_init} respectively.

{\tt impl\_shutdown} deactivates the BOA. When the call returns, all the
internal threads and network connections will be shutdown. Any thread
blocking in {\tt impl\_is\_ready} would be unblocked. After the call, no
request from other address spaces will be processed. In other words, the
BOA will be in the same state as it was in before {\tt impl\_is\_ready} was
called. For example, a remote client may hang if it tries to connect to the
server after {\tt impl\_shutdown} was called because no thread is listening
on the IIOP port. 

{\tt impl\_shutdown} does not wait for incoming requests to complete before
it closes the network connections. The remote clients will see the network
connections shutdown and the replies may not  reach them even if the
upcalls have been completed. Therefore, if the application is to define an
operation in an IDL interface to shutdown the BOA,  the operation should be
defined as an oneway operation.

{\tt impl\_shutdown} is thread-safe and can be called multiple times. The
call is silently ignored if the BOA has already been shutdown. After {\tt
impl\_shutdown} is called, the BOA can be reactivated by another call to
{\tt impl\_is\_ready}.

It should be noted that {\tt impl\_shutdown} does not affect outgoing
network connections. That is, clients in the same address space will
still be able to make calls to objects in other address spaces.

While remote requests are not delivered after {\tt impl\_shutdown} is
called, the current implementation does not stop colocated clients from
calling the objects. In future, colocated clients will exhibit the same
behaviour as remote clients.

{\tt destroy} permanently removed the BOA. This function will call {\tt
impl\_shutdown} implicitly if it has not been called. When this call
returns, the IIOP port(s) held by the BOA will be freed. Remote clients
will see their requests refused by the operating system when they try to
open a connection to the IIOP port(s). 

After {\tt destroy} is called, the BOA should not be used. If there is any
objects still registered with the BOA, the objects should not be invoked
afterwards. The objects are not disposed. Invoking on the objects after
{\tt destroy} would result in undefined behaviour. Initialisation of
another BOA using {\tt BOA\_init} is not supported. The behaviour of {\tt
BOA\_init} after this call is undefined.

\section{Unsupported functions}

The following member functions are not implemented. Calling these functions
do not have any effect.

\begin{itemize}
\item {\tt Object\_ptr create(...)}
\item {\tt ReferenceData* get\_id(Object\_ptr)}
\item {\tt Principal\_ptr get\_principal(Object\_ptr,Environment\_ptr)}
\item {\tt void change\_implementation(Object\_ptr, ImplementationDef\_ptr)}
\item {\tt void deactivate\_impl(ImplementationDef\_ptr)}
\item {\tt void deactivate\_obj(Object\_ptr)}
\end{itemize}


\section{Loading Objects On Demand}
\label{load_on_demand}

Since 2.5.0, there is limited support for loading objects on demand. 
An application can register a handler for loading objects dynamically. The
handler should have the signature {\tt omniORB::loader::mapKeyToObject\_t}:

{\small
\begin{verbatim}
  namespace omniORB {
    ...
    class loader {
    public:
      typedef CORBA::Object_ptr (*mapKeyToObject_t) (const objectKey& key);
      static void set(mapKeyToObject_t NewKeyToObject);
    };
  };
\end{verbatim}
}


When the ORB cannot locate the target object in this address space, it
calls the handler with the object key of the target. The handler is expected
to instantiate the object, either in this address space or in another
address space, and returns the object reference to the newly instantiated
object. The ORB will then reply with a LOCATION\_FORWARD message to instruct
the client to retry using the object reference returned by the handler.
When the handler returns, the ORB assumes ownership of the returned
value. It will call CORBA::release() on the returned value when it has
finished with it.
                                                                      
The handler may be called concurrently by multi-threads. Hence it  
must be thread-safe.                                               
                                                                      
If the handler cannot load the target object, it should return     
CORBA::Object::\_nil(). The object will be treated as non-existing. 
                                                                      
The application registers the handler with the ORB at runtime      
using omniORB::loader::set(). This function is not thread-safe.    
Calling this function again will replace the old handler with      
the new one.                                                       


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\chapter{Interface Type Checking}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\label{ch_intf}

This chapter describes the mechanism used by omniORB2 to ensure type safety
when object references are exchanged across the network. This mechanism is
handled completely within the ORB. There is no programming interface
visible at the application level. However, for the sake of diagnosing the
problem when there is a type violation, it is useful to understand the
underlying mechanism in order to interpret the error conditions reported by
the ORB.

\section{Introduction}

In GIOP/IIOP, an object reference is encoded as an Interoperable Object
Reference (IOR) when it is sent across a network connection. The IOR
contains a Repository ID (REPOID) and one or more communication profiles. The
communication profiles describe where and how the object can be
contacted. The REPOID is a string which uniquely identifies the
IDL interface of the object. 

Unless the {\bf ID} pragma is specified in the IDL, the ORB generates the
REPOID string in the so-called OMG IDL Format\footnote{For further details
of the repository ID formats, see section 6.6 in the CORBA
specification.}. For instance, the REPOID for the {\tt Echo} interface used
in the examples of chapter~\ref{ch_basic} is {\tt IDL:Echo:1.0}.

When interface inheritance is used in the IDL, the ORB always sends the
REPOID of the most derived interface. For example:

{\small
\begin{verbatim}
// IDL
   interface A {
     ...
   };
   interface B : A {
     ...
   };
   interface C {
      void op(in A arg);
   };

// C++
   C_ptr server;
   B_ptr objB;
   A_ptr objA = objB;
   server->op(objA);      // Send B as A
\end{verbatim}
}

In the example, the operation C::op accepts an object reference of type
A. The real type of the reference passed to C::op is B, which inherits from
A. In this case, the REPOID of B, and not that of A, is sent across the
network.

The GIOP/IIOP specification allows an ORB to send a null string in the
REPOID field of an IOR. It is up to the receiving end to work out the real
type of the object. OmniORB2 never sends out null strings as
REPOID. However, it may receive null REPOID from other ORBs. In that case,
it will use the mechanism described below to ensure type safety.

\section{Basic Interface Type Checking}
\label{sec_intf}

The ORB is provided with the interface information by the stubs via the
proxyObjectFactory class. For an interface A, the stub of A contains a
A\_proxyObjectFactory class. This class is derived from the
proxyObjectFactory class. The proxyObjectFactory is an abstract class which
contains 3 virtual functions.

{\small
\begin{verbatim}

class proxyObjectFactory {
public:

  virtual const char *irRepoId() const = 0;

  virtual _CORBA_Boolean  is_a(const char *base_repoId) const = 0;
       
  virtual CORBA::Object_ptr newProxyObject(Rope *r,
                                           CORBA::Octet *key,
                                           size_t keysize,
                                           IOP::TaggedProfileList
                                           *profiles,
                                           CORBA::Boolean release) = 0;

};

\end{verbatim}
}

\begin{itemize}
\item {\tt irRepoId} returns the REPOID of the interface.
\item {\tt is\_a} returns true(1) if the argument is the REPOID of the
interface itself or it is that of its base interfaces.
\item {\tt newProxyObject} returns an object reference based on the
information supplied in the arguments.
\end{itemize}

A single instance of every *\_proxyObjectFactory is instantiated at runtime.
The instances are entered into a list inside the ORB. The list constitutes
all the interface information known to the ORB.

When the ORB receives an IOR from the network, it unmarshals and
extracts the REPOID from the IOR. At this point, the ORB has two pieces of
information in hand:

\begin{enumerate}
\item The REPOID of the object reference received from the network.
\item The REPOID the ORB is expecting. This comes from the unmarshal
      function that tells the ORB to receive the object reference.
\end{enumerate}

Using the REPOID received, the ORB searches its proxyObjectFactory list for
an exact match. If there is an exact match, all is well because the runtime
can use the {\tt is\_a} method of the proxyFactory to check if the expected
REPOID is the same as the received REPOID or if it is that of its base
interfaces. If the answer is positive, the IOR passes the type checking
test and the ORB can proceed to create an object reference in its own
address space to represent the IOR.

However, the ORB may fail to find a match in its proxyObjectFactory
list. This means that the ORB has no local knowledge of the REPOID.
There are three possible causes:

\begin{enumerate}
\item The remote end is another ORB and it sends a null string as the REPOID.
\item The ORB is expecting an object reference of interface A. The remote
      end sends the REPOID of B which is an interface that inherits from A.
      The stubs of A is linked into the executable but the stubs of B is
      not.
\item The remote end has sent a duff IOR.
\end{enumerate}

To handle this situation, the ORB must find out the type information
dynamically. This is explained in the next section.

\section{Interface Inheritance}

When the ORB receives an IOR of interface type B when it expects the type to
be A, it must find out if B inherits from A. When the ORB has no local
knowledge of the type B, it must work out the type of B dynamically.

The CORBA specification defines an Interface Repository (IR) from which IDL
interfaces can be queried dynamically. In the above situation, the ORB
could contact the IR to find out the type of B. However, this approach
assumes that an IR is always available and contains the up-to-date
information of all the interfaces used in the domain. This assumption may
not be valid in many applications.

An alternative is to use the {\tt \_is\_a} operation to
work out the actual type of an object. This approach is simpler
and more robust than the previous one because no 3rd party is involved. 

{\small
\begin{verbatim}
class Object{
    CORBA::Boolean _is_a(const char* type_id);
};
\end{verbatim}
}

The {\tt \_is\_a} operation is part of the {\tt CORBA::Object} interface
and must be implemented by every object. The input argument is a
REPOID. The function returns true(1) if the object is really an instance of
that type, including if that type is a base type of the most derived type
of that object.

In the situation above, the ORB would invoke the {\tt \_is\_a}
operation on the object and ask if the object is of type A {\bf before}
it processes any application invocation on the object.

Notice that the {\tt \_is\_a} call is {\bf not} performed when the IOR is
unmarshalled. It is performed just prior to the first application
invocation on the object. This leads to some interesting failure mode if
B reports that it is not an A. Consider the following example:

{\small
\begin{verbatim}

\\ IDL
   interface A { ... };
   interface B : A { ... };
   interface D { ... };
   interface C {
     A      op1();
     Object op2();
   };

\\ C++

   C_ptr objC;
   A_ptr objA;
   CORBA::Object_ptr objR;

   objA =  objC->op1();              // line 1
   (void) objA->_non_existent();     // line 2

   objR =  objC->op2();              // line 3
   objA =  A::_narrow(objR);         // line 4

\end{verbatim}
}

\noindent If the stubs of A,B,C,D are linked into the executable and:

\begin{description}
\item[Case 1] {\tt C::op1} and {\tt C::op2} returns a B. Line 1-4 complete successful. The
remote object is only contacted at line 2.
\item[Case 2] {\tt C::op1} and {\tt C::op2} returns a D. This condition only occurs if the
runtime of the remote end is buggy. The ORB raises a CORBA::Marshal
exception at line 1 because it knows it has received an interface of the
wrong type.
\end{description}

\noindent If only the stub of A is linked into the executable and:

\begin{description}
\item[Case 1] C::op1 and C::op2 returns a B. Line 1-4 completes successful. When
line 2 and 4 is executed, the object is contacted to ask if it is a A.
\item[Case 2] C::op1 and C::op2 returns a D. This condition only occurs if the
runtime of the remote end is buggy. Line 1 completes and no exception is
raised. At line 2, the object is contacted to ask if it is a A. If the
answer is no, a CORBA::INV\_OBJREF exception is raised. The application will
also see a CORBA::INV\_OBJREF at line 4.
\end{description}


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\chapter{Connection Management}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\label{ch_conn}


This chapter describes how omniORB2 manages network connections.

\section{Background}

In CORBA, the ORB is the ``middleware'' that allows a client to invoke an
operation on an object without regard to its implementation or location. In
order to invoke an operation on an object, a client needs to ``bind'' to
the object by acquiring its object reference. Such a reference may be
obtained as the result of an operation on another object (such as a naming
service) or by conversion from a stringified representation previously
generated by the same ORB. If the object is in a different address space,
the binding process involves the ORB building a proxy object in the
client's address space. The ORB arranges for invocations on the proxy
object to be transparently mapped to equivalent invocations on the
implementation object.

For the sake of interoperability, CORBA mandates that all ORBs should
support IIOP as the means to communicate remote invocations over a TCP/IP
connection. IIOP is asymmetric with respect to the roles of the parties at
the two ends of a connection. At one end is the client which can only
initiate remote invocations. At the other end is the server which can only
receive remote invocations.

Notice that in CORBA, as in most distributed systems, remote bindings are
established implicitly without application intervention. This provides the
illusion that all objects are local, a property known as ``location
transparency''. CORBA does not specify when such bindings should be
established or how they should be multiplexed over the underlying network
connections. Instead, ORBs are free to implement implicit binding by a
variety of means. 

The rest of this chapter describes how omniORB2 manages network
connections and the programming interface to fine tune the management
policy. 

\section{The Model}

OmniORB2 is designed from the ground up to be fully multi-threaded. The
objective is to maximise the degree of concurrency and at the same time
eliminate any unnecessary thread overhead. Another objective is to minimise
the interference by the activities of other threads on the progress of a
remote invocation. In other words, thread ``cross-talk'' should be
minimised within the ORB. To achieve these objectives, the degree of
multiplexing at every level is kept to a minimum.

On the client side of a connection, the thread that invokes on a proxy
object drives the IIOP protocol directly and blocks on the connection to
receive the reply. On the server side, a dedicated thread blocks on the
connection. When it receives a request, it performs the up-call to the
object and sends the reply when the upcall returns. There
is no thread switching along the call chain.

With this design, there is at most one call in-flight at any time in a
connection. If there is only one connection, concurrent invocations to the
same remote address space would have to be serialised. To eliminate this
limitation, omniORB2 implements a dynamic policy- multiple connections to
the same remote address space are created on demand and cached when there
are concurrent invocations in progress.

To be more precise, a network connection to another address space is only
established when a remote invocation is about to be made. Therefore, there
may be one or more object references in one address space that refers to
objects in a different address space but unless the application invokes on
these objects, no network connection is made. The maximum number of
connections opened to another address space is 5 by default. Since 2.6.0,
this parameter can be changed by setting the variable {\tt
omniORB::maxTcpConnectionPerServer} {\bf before} calling {\tt ORB\_init}.

It is wasteful to leave a connection opened when it has been left unused
for a considerable time. Too many idle connections could block out new
connections to a server when it runs out of spare communication
channels. For example, most unix platforms has a limit on the number of
file handles a process can open. 64 is the usual default limit. The
value can be increased to a maximum of a thousand or more by changing the
``ulimit'' in the shell.

\section{Idle Connection Shutdown}
\label{sec_shut}

Inside the ORB, two separate threads are dedicated to scan for idle
connections. One thread is responsible for outgoing connections and the
other looks after incoming connections. The thread for incoming connections
is only created when the BOA is initialised because only then will there be
any incoming connections.

The threads scan all opened connections once every ``scan period''. If a
connection is found to be idle for two consecutive periods, it will be
closed. The threads use mark-and-swipe to detect if a connection is idle.
When a connection is checked, a status flag attached to the connection is
set. Every remote invocation using that connection would clear the flag. So
if a connection's status flag is found to be set in two consecutive scans,
the connection has been idled during the  scan period.

The scan period for incoming and outgoing connections can be individually
controlled by the following API:

{\small
\begin{verbatim}

class omniORB {

public:

  enum idleConnType { idleIncoming, idleOutgoing };

  static void idleConnectionScanPeriod(idleConnType direction,
                                       CORBA::ULong sec);

  static CORBA::ULong idleConnectionScanPeriod(idleConnType direction);

};

\end{verbatim}
}

The current value of the scan period (in seconds) is returned by the
read-only {\tt idleConnectionScanPeriod}. The scan period can be changed by
the write-only {\tt idleConnectionScanPeriod}. The scan period can be changed
at any time but the write function is non-thread safe. Concurrent calls to this
function could result in undefined behaviour.
The scan periods may also be specified on the command-line by using the
options {\tt -ORBinConScanPeriod} and {\tt -ORBoutConScanPeriod}. See
section~\ref{omniorbapioptions}.

The default value for both incoming and outgoing connections is 30 seconds.
The scan can be disabled completely by setting the scan period to 0.

\section{Interoperability Considerations}

The IIOP specification allows both the client and the server to shutdown a
connection unilaterally. When one end is about to shutdown a connection,
it should send a closeConnection message to the other end. It should also make
sure that the message will reach the other end before it proceeds to
shutdown the connection. 

The client should distinguish between an orderly and an abnormal connection
shutdown. When a client receives a closeConnection message before the
connection is closed, the condition is an orderly shutdown. If the message
is not received, the condition is an abnormal shutdown. In an abnormal
shutdown, the ORB should raise a {\tt COMM\_FAILURE} exception whereas in
an orderly shutdown, the ORB should {\bf not} raise an exception and should
try to re-establish a new connection transparently.

OmniORB2 implements this semantics completely. However, it is known that
some ORBs are not (yet) able to distinguish between an orderly and an
abnormal shutdown. Usually this is manifested as the client in these ORBs
seeing a {\tt COMM\_FAILURE} occasionally when connected to an omniORB2
server. The workaround is either to catch the exception in the application
code and retries or to turn off the idle connection shutdown inside the
omniORB2 server.


\section{Connection Acceptance}
\label{sec_accept}

OmniORB2 provides the hook to implement a connection acceptance
policy. Inside the ORB runtime, a thread is dedicated to receive new
connections. When the thread is given the handle of a new connection by
the operating system, it calls the policy module to decide if the
connection can be accepted. If the answer is yes, the ORB will start
serving requests coming in from that connection. Otherwise, the connection
is shutdown immediately.

There can be a number of policy module implementations. The basic one is a
dummy module which just accepts every connection. 

In addition, a host-based access control module is available on unix
platforms. The module uses the IP address of the client to decide if the
connection can be accepted. The module is implemented using {\em
tcp\_wrappers 7.6}. The access control policy can be defined as rules in
two access control files: {\tt hosts.allow} and {\tt hosts.deny}. The
syntax of the rules is described in the manual page {\tt hosts\_access(5)}
which can be found in appendix A. The syntax defines a simple access
control language that is based on client (host name/address, user name),
and server (process name, host name/address) patterns. When searching for a
match on the server process name, the ORB uses the value of {\tt
omniORB::serverName}. {\tt ORB\_init} uses the argument {\tt argv[0]} to
set the default value of this variable. This can be overridden by the
application by passing the option: {\tt -ORBserverName <string>} to {\tt
ORB\_init}.

The default location of the access control files is {\tt /etc}. This can be
overridden by the extra options in {\tt omniORB.cfg}. For instance:

{\small
\begin{verbatim}
# omniORB configuration file - extra options
#

GATEKEEPER_ALLOWFILE   /project/omni/var/hosts.allow

GATEKEEPER_DENYFILE    /project/omni/var/hosts.deny

\end{verbatim}
}

As each policy module is implemented as a separate library, the choice of
policy module is determined at program linkage time.

For instance, if the host-based access control module is in use:

{\small
\begin{verbatim}
% eg1 -ORBtraceLevel 2
omniORB2 gateKeeper is tcpwrapGK 1.0 - based on tcp_wrappers_7.6 
I said,"Hello!". The Object said,"Hello!"
\end{verbatim}
}

Whereas if the dummy module is in use:

{\small
\begin{verbatim}
% eg1 -ORBtraceLevel 2
omniORB2 gateKeeper is not installed. All incoming are accepted.
I said,"Hello!". The Object said,"Hello!"
\end{verbatim}
}


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\chapter{Proxy Objects}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

When a client acquires a reference to an object in another address space,
omniORB2 creates a local representation of the object and returns a pointer
to this object as its object reference. The local representation is known
as the proxy object. 

The proxy object maps each IDL operation into a method to deliver
invocations to the remote object. The method implements argument
marshalling using the ORB runtime. When the ORB runtime detects an error
condition, it may raise a system exception. These exceptions will normally be
propagated by the proxy object to the application code. However, there may
be applications that prefer to have the system exceptions trapped in the
proxy object. For these applications, it is possible to install exception
handlers for individual proxy object or all proxy objects. The API to do
this will be explained in this chapter.


As described in section~\ref{sec_intf}, proxy objects are created by
instances of the proxyObjectFactory class. For each IDL interface A, the
stubs of A contains a derived class of proxyObjectFactory
(A\_proxyObjectFactory). This derived class is responsible for creating
proxy objects for A. This process is completely transparent to the
application. However, there may be applications that require greater
control on the creation of proxy objects or even want to change the
behavior of the proxy objects. To cater for this requirement, applications
can override the default proxyObjectFactories and install their own
versions of proxyObjectFactories. The way to do this will be explained in
this chapter.


\section{System Exception Handlers}

By default, all system exceptions, with the exception of CORBA::TRANSIENT,
are propagated by the proxy objects 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.

OmniORB2 provides a set of functions to install exception handlers. Once
they are installed, proxy objects will call these handlers when the target
system exceptions are raised by the ORB runtime. Exception handlers can be
installed for CORBA::TRANSIENT, CORBA::COMM\_FAILURE and
CORBA::SystemException. The 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 object or it can be installed for all proxy
objects in the address space.


\subsection{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. Successive retries will be delayed progressively by multiples of
{\tt omniORB::defaultTransientRetryDelayIncrement}. The delay will be
limited to a maximum specified by {\tt
omniORB::defaultTransientRetryDelayMaximum}. The unit of both values are in
seconds.

The ORB runtime will raised CORBA::TRANSIENT under the following
conditions:

\begin{enumerate}

\item When a {\bf cached} network connection is broken while an invocation
is in progress. The ORB will try to open a new connection at the next
invocation. 

\item 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.

\item When the remote object reports CORBA::TRANSIENT. 

\end{enumerate}

Applications can override the default behaviour by installing their own
exception handler. The API to do so is summarised below:

{\small
\begin{verbatim}

class omniORB {

public:
  
typedef CORBA::Boolean (*transientExceptionHandler_t)(void* cookie,
                                                CORBA::ULong n_retries,
                                                const CORBA::TRANSIENT& ex);

static void installTransientExceptionHandler(void* cookie,
                                             transientExceptionHandler_t fn);

static void installTransientExceptionHandler(CORBA::Object_ptr obj,
                                             void* cookie,
                                             transientExceptionHandler_t fn);
  
static CORBA::ULong defaultTransientRetryDelayIncrement;
static CORBA::ULong defaultTransientRetryDelayMaximum;

}

\end{verbatim}
}

The overloaded functions {\tt installTransientExceptionHandler}
can be used to install the exception handlers for CORBA::TRANSIENT.

Two overloaded forms are available. The first form install an
exception handler for all object references except for those which
have an exception handler installed by the second form, which takes
an addition argument to identify the target object reference.
The argument {\tt cookie} is an opaque pointer which will be passed
on by the ORB when it calls the exception handler.

An exception handler will be called by proxy objects with three
arguments. The {\tt cookie} is the opaque pointer registered by
{\tt installTransientExceptionHandler}. The argument {\tt n\_retries} is
the number of times the proxy has called this handler for the same
invocation. The argument {\tt ex} is the value of the exception caught.
The exception handler is expected to do whatever is appropriate and returns
a boolean value. If the return value is TRUE(1), the proxy object would
retry the operation again. If the return value is FALSE(0), the
CORBA::TRANSIENT exception would be propagated into the application code.

The following sample code installs a simple exception handler for all
objects and for a specific object:

{\small
\begin{verbatim}

CORBA::Boolean my_transient_handler1 (void* cookie,
                                      CORBA::ULong retries,
                                      const CORBA::TRANSIENT& ex)
{
   cerr << ''transient handler 1 called.'' << endl;
   return 1;           // retry immediately.
}
 
CORBA::Boolean my_transient_handler2 (void* cookie,
                                      CORBA::ULong retries,
                                      const CORBA::TRANSIENT& ex)
{
   cerr << ''transient handler 2 called.'' << endl;
   return 1;           // retry immediately.
}


static Echo_ptr myobj;

void installhandlers()
{
   omniORB::installTransientExceptionHandler(0,my_transient_handler1);
   // All proxy objects will call my_transient_handler1 from now on.

   omniORB::installTransientExceptionHandler(myobj,0,my_transient_handler2);
   // The proxy object of myobj will call my_transient_handler2 from now on.
}


\end{verbatim}
}


\subsection{CORBA::COMM\_FAILURE}

When the ORB runtime fails to establish a network connection to the remote
object and none of the conditions listed above for raising a
CORBA::TRANSIENT is applicable, it raises a CORBA::COMM\_FAILURE exception.

The default behaviour of the proxy objects is to propagate this exception
to the application.

Applications can override the default behaviour by installing their own
exception handlers. The API to do so is summarised below:

{\small
\begin{verbatim}

class omniORB {

public:

typedef CORBA::Boolean (*commFailureExceptionHandler_t)(void* cookie,
                                                CORBA::ULong n_retries,
                                                const CORBA::COMM_FAILURE& ex);

static void installCommFailureExceptionHandler(void* cookie,
                                             commFailureExceptionHandler_t fn);

static void installCommFailureExceptionHandler(CORBA::Object_ptr obj,
                                             void* cookie,
                                             commFailureExceptionHandler_t
                                             fn);
}
\end{verbatim}
}


The functions are equivalent to their counterparts for CORBA::TRANSIENT. 



\subsection{CORBA::SystemException}


To report an error condition, the ORB runtime may raise other
SystemExceptions. If the exception is neither CORBA::TRANISENT nor
CORBA::COMM\_FAILURE, the default behaviour of the proxy objects is to
propagate this exception to the application.

Application can override the default behaviour by installing their own
exception handlers. The API to do so is summarised below:


{\small
\begin{verbatim}

class omniORB {

public:

typedef CORBA::Boolean (*systemExceptionHandler_t)(void* cookie,
                                            CORBA::ULong n_retries,
                                            const CORBA::SystemException& ex);

static void installSystemExceptionHandler(void* cookie,
                                          systemExceptionHandler_t fn);

static void installSystemExceptionHandler(CORBA::Object_ptr obj,
                                          void* cookie,
                                          systemExceptionHandler_t fn);
}
\end{verbatim}
}

The functions are equivalent to their counterparts for CORBA::TRANSIENT. 


\section{Proxy Object Factories}

This section describes how an application can control the creation or
change the behaviour of proxy objects.


\subsection{Background}

For each interface A, its stub contains a proxy factory class- {\tt
A\_proxyObjectFactory}. This class is derived from {\tt proxyObjectFactory}
and implements three virtual functions:

{\small
\begin{verbatim}

class A_proxyObjectFactory : public virtual proxyObjectFactory {
public:

  virtual const char *irRepoId() const;

  virtual _CORBA_Boolean  is_a(const char *base_repoId) const;
       
  virtual CORBA::Object_ptr newProxyObject(Rope *r,
                                           CORBA::Octet *key,
                                           size_t keysize,
                                           IOP::TaggedProfileList
                                           *profiles,
                                           CORBA::Boolean release);

};

\end{verbatim}
}

As described in chapter~\ref{ch_intf}, the functions allow the ORB runtime
to perform type checking. The function {\tt newProxyObject} creates a proxy
object for A based on its input arguments. The return value is a pointer to
the class {\tt \_proxy\_A} which is automatically re-casted into a {\tt
CORBA::Object\_ptr}.  {\tt \_proxy\_A} implements the proxy object for A:

{\small
\begin{verbatim}
class _proxy_A :  public virtual A {
public:

  _proxy_A (Rope *r,
            CORBA::Octet *key,
            size_t keysize,IOP::TaggedProfileList *profiles,
            CORBA::Boolean release);
  virtual ~_proxy_A();

  // plus other internal functions.

};
\end{verbatim}
}

The stub of A guarantees that exactly {\bf one} instance of
{\tt A\_proxyObjectFactory} is instantiated when an application is
executed. The constructor of {\tt A\_proxyObjectFactory}, via its
base class {\tt proxyObjectFactory} links the instance into the ORB's
proxy factory list. 

Newly instantiated proxy object factories are always entered at the front
of the ORB's proxy factory list. Moreover, when the ORB searches for a
match on the type, it always stops at the first match. In other words, when
additional instances of {\tt A\_proxyObjectFactory} or derived classes of
it are created, the last instantiation will override earlier instantiations
to be the proxy factory selected to create proxy objects of A. This
property can be used by an application to install its
own proxy object factories.

\subsection{An Example}

Using the {\tt Echo} example in chapter~\ref{ch_basic} as the basis, one
can tell the ORB to use a modified proxy object class to create proxy
objects. The steps involved are as follows:

\subsubsection{Define a new proxy class}

We define a new proxy class to cache the result of the last
invocation of {\tt echoString}.

{\small
\begin{verbatim}
class _new_proxy_Echo : public virtual _proxy_Echo {
public:
  _new_proxy_Echo (Rope *r,
                  CORBA::Octet *key,
                  size_t keysize,IOP::TaggedProfileList *profiles,
                  CORBA::Boolean release) 
         : _proxy_Echo(r,key,keysize,profiles,release),
           omniObject(Echo_IntfRepoID,r,key,keysize,profiles,release) 
   {
     // You have to look at the _proxy_Echo class and copy from its
     // ctor all the explicit ctor calls to its base member.
   }
   virtual ~_new_proxy_Echo() {}


   virtual char* echoString(const char* mesg) {
     //
     // Only calls the remote object if the argument is different from the
     // last invocation.

     omni_mutex_lock sync(lock);
     if ((char*)last_arg) {
       if (strcmp(mesg,(char*)last_arg) == 0) {
          return CORBA::string_dup(last_result);
       }
     }
     char* res = _proxy_Echo::echoString(mesg);
     last_arg = mesg;
     last_result = (const char*) res;
     return res;
   }

private:
  omni_mutex        lock;
  CORBA::String_var last_arg;
  CORBA::String_var last_result;
};
\end{verbatim}
}

\subsubsection{Define a new proxy factory class}

Next, we define a new proxy factory class to instantiate {\tt
\_new\_proxy\_Echo} as proxy objects for {\tt Echo}.

{\small
\begin{verbatim}
class _new_Echo_proxyObjectFactory : public virtual Echo_proxyObjectFactory
{
public:
   _new_Echo_proxyObjectFactory () {}
   virtual ~_new_Echo_proxyObjectFactory() {}

   // Only have to override newProxyObject
   virtual CORBA::Object_ptr newProxyObject(Rope *r,
                                            CORBA::Octet *key,
                                            size_t keysize,
                                            IOP::TaggedProfileList *profiles,
                                            CORBA::Boolean release) {
      _new_proxy_Echo *p = new _new_proxy_Echo(r,key,keysize,profiles,release);
      return p;
   }
};
\end{verbatim}
}

Finally, we have to instantiate a single instance of the new proxy factory
in the application code.

{\small
\begin{verbatim}
int main(int argc, char** argv)
{
   // Other initialisation steps

   _new_Echo_proxyObjectFactory* f =  new _new_Echo_proxyObjectFactory;

   // Use the new operator to instantiate the proxy factory and never
   // call the delete operator on this instance.

   // From this point onwards, _new_proxy_Echo will be used to create
   // proxy objects for Echo.

}
\end{verbatim}
}

\subsection{Further Considerations}

Notice that the ORB may call {\tt newProxyObject} multiple times to create
proxy objects for the same remote object. In other words, the ORB does not
guarantee that only one proxy object is created for each remote
object. For applications that require this guarantee, it is necessary to
check within {\tt newProxyObject} whether a proxy object has already been
created for the current request. If the argument {\tt Rope* r} points to
the same structure and the content of the sequence {\tt CORBA::Octet* key} is
the same, then an existing proxy object can be returned to satisfy the
current request. Do not forget to call {\tt CORBA::duplicate()} before
returning the object reference.

{\tt newProxyObject} may be called concurrently by different threads within
the ORB. Needless to say, the function must be thread-safe.


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\chapter{Type Any and TypeCode}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\label{ch_any}

The CORBA specification provides for a type that can hold the value of any 
OMG IDL type. This type is known as type Any. The OMG also specifies a 
pseudo-object, TypeCode, that can encode a description of any type specifiable
in OMG IDL.

In this chapter, an example demonstrating the use of type Any is presented. 
This is followed by sections describing the behaviour of type Any and TypeCode 
in omniORB2. 
For further information on type Any, refer to the C++ Mapping section of the 
CORBA 2 specification~\cite{corba2-spec}, and for more information on 
TypeCode, refer to the Interface Repository chapter in the CORBA core section 
of the CORBA 2 specification. 

\section{Example using type Any}

Before going through this example, you should make sure that you have read 
and understood the examples in chapter~\ref{ch_basic}.
The source code for this example is included in the omniORB2 distribution,
in the directory src/examples/anyExample. A listing of the source code is
provided at the end of this chapter.

\subsection{Type Any in IDL}
Type Any allows one to delay the decision on the type used in an operation 
until run-time. To use type any in IDL, use the keyword {\tt any}, as in the 
following example:
{\small
\begin{verbatim}

// IDL

interface anyExample {
  any testOp(in any mesg);
};

\end{verbatim}
}

The operation {\tt testOp()} in this example can now take any value 
expressible in OMG IDL as an argument, and can also return any type 
expressible in OMG IDL.

Type Any is mapped into C++ as the type {\tt CORBA::Any}. When passed as
an argument or as a result of an operation, the following rules apply:

{\small
\begin{tabular}{llll}
{\bf In }                & {\bf InOut }       & {\bf Out }           & 
{\bf Return }                                                   \\ \hline
{\tt const CORBA::Any\& }& {\tt CORBA::Any\& }& {\tt CORBA::Any*\& } & 
{\tt CORBA::Any* }
\end{tabular}
}

\vspace{7mm}
So, the above IDL would map to the following C++

{\small
\begin{verbatim}

// C++

class anyExample_i : public virtual _sk_anyExample {
public:
  anyExample_i() { }
  virtual ~anyExample_i() { }
  virtual CORBA::Any* testOp(const CORBA::Any& a);
};

\end{verbatim}
}
     


\subsection{Inserting and Extracting Basic Types from an Any}

The question now arises as to how values are inserted into and removed from
an Any. This is achieved using two overloaded operators: {\tt <<= and >>= }.

Two insert a value into an Any, the {\tt <<= }operator is used, as in this 
example:

{\small
\begin{verbatim}

// C++
 
CORBA::Any an_any;
CORBA::Long l = 100;
an_any <<= l;

\end{verbatim}
}


Note that the overloaded {\tt <<= }operator has a return type of {\tt void}.

To extract a value, the {\tt >>= }operator is used, as in this example (where
the Any contains a long):

{\small
\begin{verbatim}

// C++

CORBA::Long l;
an_any >>= l;

cout << "This is a long: " << l << endl;

\end{verbatim}
}


The overloaded {\tt >>= }operator returns a CORBA::Boolean. If an attempt is 
made to extract a value from an Any when it contains a different value (e.g. 
an attempt to extract a long from an Any containing a double), the overloaded 
{\tt >>= }operator will return False; otherwise it will return True. Thus, a 
common tactic to extract values from an Any is as follows:
\pagebreak

{\small
\begin{verbatim}

// C++


CORBA::Long l;
CORBA::Double d;
char* str;

if (an_any >>= l) {
    cout << "Long: " << l << endl;
}
else if (an_any >>= d) {
    cout << "Double: " << d << endl;
}
else if (an_any >>= str) {
    cout << "String: " << str << endl;
}
else {
    cout << "Unknown value." << endl;
}

\end{verbatim}
}


\subsection{Inserting and Extracting Constructed Types from an Any}

It is also possible to insert and extract constructed types and object
references from an Any. {\tt omniidl2 }will generate insertion and extraction 
operators for the constructed type. Note that it is necessary to specify
the {\tt -a} command-line flag when running omniidl2 in order to generate
these operators. The following example illustrates the use of constructed types
with type Any:

{\small
\begin{verbatim}

// IDL

struct testStruct {
  long l;
  short s;
};


interface anyExample {
  any testOp(in any mesg);
};

\end{verbatim}
}

Upon compiling the above IDL with {\tt omniidl2 -a}, the following overloaded 
operators are generated: 

\begin{enumerate}
\item {\tt void operator<<=(CORBA::Any\&, const testStruct\& ) }
\item {\tt void operator<<=(CORBA::Any\&, testStruct* ) }
\item {\tt CORBA::Boolean operator>>=(const CORBA::Any\&, testStruct*\&) }
\end{enumerate}

Operators of this form are generated for all constructed types, and for 
interfaces.

The first operator, {\em (1) }, copies the constructed type, and inserts it 
into the Any. The second operator, {\em (2) }, inserts the constructed type 
into the Any, and then manages it. Note that if the second operator is used,
the Any consumes the constructed type, and the caller should not used the
pointer to access the data after insertion. The following is an example of how
to insert a value into an Any using operator {\em (1) }:
{\small
\begin{verbatim}

// C++

CORBA::Any an_any;

testStruct t;
t.l = 456;
t.s = 8;

an_any <<= t;

\end{verbatim}
}


The third operator, {\em (3) }, is used to extract the constructed type 
from the Any, and can be used as follows:

{\small
\begin{verbatim}

testStruct* tp;

if (an_any >>= tp) {
    cout << "testStruct: l: " << tp->l << endl;
    cout << "            s: " << tp->s << endl;
}
else {
    cout << "Unknown value contained in Any." << endl;
}

\end{verbatim}
}

As with basic types, if an attempt is made to extract a type
from an Any that does not contain a value of that type, the extraction 
operator returns False. If the Any does contain that type, the extraction
operator returns True. If the extraction is successful, the caller's pointer 
will point to memory managed by the Any. The caller must not delete or 
otherwise change this storage, and should not use this storage after the
contents of the Any are replaced (either by insertion or assignment), or
after the Any has been destroyed \footnote{It is unclear in the CORBA 
specification whether or not object references should be managed by an Any. 
The omniORB2 implementation leaves management of an extracted object reference
to the caller. Therefore, the programmer should release object references and 
TypeCodes that have been extracted from an Any.}. In particular, management of
the pointer should not be assigned to a {\tt \_var} type.

If the extraction fails, the caller's pointer will be set to point to null.

Note that there are special rules for inserting and extracting arrays (using 
{\tt \_forany} types), and for inserting and extracting booleans, octets,
chars, and bounded strings. Please refer to section 16.14 of the C++ Mapping 
section of the CORBA 2 specification~\cite{corba2-spec} for further 
information. 


\section{Type Any in omniORB2}
\label{anyOmniORB2}

This section contains some notes on the use and behaviour of type Any in 
omniORB2.

\paragraph*{Generating Insertion and Extraction Operators.}
To generate type Any insertion and extraction operators for constructed 
types and interfaces, the {\tt -a }command line flag should be specified when 
running {\tt omniidl2}. 

\paragraph*{TypeCode comparison when extracting from an Any.}
When an attempt is made to extract a type from an Any, the TypeCode of the 
type is checked for equality with the TypeCode of the type stored by the 
Any. omniORB2 will ignore any alias TypeCodes ({\tt tk\_alias}) when 
making this comparison. Examples:

{\small
\begin{verbatim}

// IDL 1

typedef double Double1;

struct Test1 {
Double1 a;
};


------


// IDL 2

typedef double Double2;

struct Test1 {
  Double2 a;
};

\end{verbatim}
}
    
If an attempt is made to extract the type {\tt Test1 }defined in IDL 1 from an
Any containing the {\tt Test1 }defined in IDL 2, this will succeed (and 
vice-versa), as the two types differ only by an alias. 

\paragraph*{Object references.}
Note that type Any does not manage object reference types - it is unclear in 
the CORBA specification whether this is required or not. Therefore, the 
programmer should release object references and pseudo-objects (such as 
TypeCode) that have been extracted from an Any. Type Any will, however, manage
constructed types (as per the CORBA 2 specification) - constructed types
extracted from an Any should not be deleted, as they will be deleted by the 
Any when it is destroyed.

\paragraph*{Top-level aliases.}
When a type is inserted into an Any, the Any stores both the value of the type
and the TypeCode for that type. If there are any top-level {\tt tk\_alias} 
TypeCodes in the TypeCode, they will be removed from the TypeCode stored in 
the Any. Note that this does not affect the {\tt \_tc\_ }TypeCode generated to 
represent the type (see section on TypeCode, below). This behaviour is 
necessary, as two types that differ only by a top-level alias can use the 
same insertion and extraction operators. If the {\tt tk\_alias} is not 
removed, one of the types could be transmitted with an incorrect 
{\tt tk\_alias} TypeCode. Example:

{\small
\begin{verbatim}

// IDL 3

typedef sequence<double> seqDouble1;
typedef sequence<double> seqDouble2;

\end{verbatim}
}

If either seqDouble1 or seqDouble2 is inserted into a TypeCode, the TypeCode
stored will be for a {\tt sequence<double>}, and not for an alias to a 
{\tt sequence<double>}.

\paragraph*{Removing aliases from TypeCodes.}
Some ORBs (e.g. Orbix) will not accept TypeCodes containing {\tt tk\_alias} 
TypeCodes. When using type Any while interoperating with these ORBs, it is 
necessary to remove {\tt tk\_alias} TypeCodes from throughout the TypeCode 
representing a constructed type. 

While omniORB2 will always remove top-level aliases, it doesn't remove aliases 
contained in a constructed type (for example, {\tt Double1} in the struct 
{\tt Test1} in example 1, above). To remove all {\tt tk\_alias} 
TypeCodes from TypeCodes stored in Anys, supply the {\tt -ORBtcAliasExpand 1 }
command-line flag when running an omniORB2 executable. There will be some 
(small) performance penalty when inserting values into an Any. 

Note that the {\tt \_tc\_ }TypeCodes generated for all constructed types will 
contain the complete TypeCode for the type (including any {\tt tk\_alias} 
TypeCodes), regardless of whether the {\tt -ORBtcAliasExpand} flag is set to 1
or not. 

\paragraph*{Recursive TypeCodes.}
omniORB2 does not yet support recursive TypeCodes. This means that types such 
as the following can not be inserted or extracted from an Any:
{\small
\begin{verbatim}
   
// IDL 4

struct Test4 {
  sequence<Test4> a;
};

\end{verbatim}
}
If these types are specified in IDL, omniidl2 will not generate Any insertion/
extraction operators, so an attempt to insert/extract them will result in 
compile-time errors. Similarly, it won't generate a {\tt \_tc\_} TypeCode for
the type. If another type contains a type which is recursive, operators won't 
be generated for that type either, and so on. Recursive TypeCodes will be 
supported in a future release of omniORB2.

\paragraph*{Type-unsafe construction and insertion.}
If using the type-unsafe Any constructor, or the {\tt CORBA::Any::replace()} 
member function, ensure that the value returned by the 
{\tt CORBA::Any::value()} member function and the TypeCode returned by the 
{\tt CORBA::Any::type()} member function are used as arguments to the 
constructor or function. Using other values or TypeCodes may result in a 
mismatch, and is undefined behaviour.

Note that a non-CORBA 2 function, 
{\small
\begin{verbatim}
   CORBA::ULong CORBA::Any::NP_length() const
\end{verbatim}
}
is supplied. This member function returns the length of the value returned 
by the {\tt CORBA::Any::value() }member function. It may be necessary to use 
this function if the Any's value is to be stored in a file.

\paragraph*{Threads and type Any.}
Inserting and extracting simultaneously from the same Any (in 2 different 
threads) is undefined behaviour.

Extracting simultaneously from the same Any (in 2 or more different threads)
may result in a memory leak if the type being extracted is a constructed type.
It was decided not to mutex the Any, as this condition should rarely arise, 
and adding a mutex would lead to performance penalties.


\section{TypeCode in omniORB2}

This section contains some notes on the use and behaviour of TypeCode in 
omniORB2

\paragraph*{TypeCodes in IDL.}
When using TypeCodes in IDL, note that they are defined in the CORBA scope.
Therefore, CORBA::TypeCode should be used. Example:
{\small
\begin{verbatim}
// IDL 5

struct Test5 {
  long length;
  CORBA::TypeCode desc;
};
\end{verbatim}
}

\paragraph*{orb.idl}
Inclusion of the file {\tt orb.idl }in IDL using CORBA::TypeCode is optional.
An empty orb.idl file is provided for compatibility purposes.

\paragraph*{Generating TypeCodes for constructed types.}
To generate a TypeCode for constructed types, specify the {\tt -a}
command-line flag when running omniidl2. This will generate a {\tt \_tc\_} 
TypeCode describing the type, at the same scope as the type (as per the 
CORBA 2 specification). Example:

{\small
\begin{verbatim}
// IDL 6

struct Test6 {
 double a;
 sequence<long> b;
};
\end{verbatim}
}

A TypeCode, {\tt \_tc\_Test6}, will be generated to describe the struct 
{\tt Test6}. The operations defined in the TypeCode interface (see 
section 6.7.1 of the CORBA 2 specification~\cite{corba2-spec} ) can be used to
query the TypeCode about the type it represents.


\paragraph*{TypeCode equality.}
The {\tt CORBA::TypeCode::equal()} member function will return true only if 
the two TypeCodes are exactly the same. {\tt tk\_alias} TypeCodes are included
in this comparison, unlike the comparison made when values are extracted from 
an Any (see section on Any, above). 

If one of the TypeCodes being checked is a {\tt tk\_struct}, {\tt tk\_union},
{\tt tk\_enum}, or {\tt tk\_alias}, and has an empty repository ID parameter,
then the repository ID parameter will be ignored when checking for equality. 
Similarly, if the {\tt name }or {\tt member\_name }parameters of a TypeCode are
empty strings, they will be ignored for equality checking purposes. This is 
because a CORBA 2 ORB does not have to include these parameters in a TypeCode 
(see section 12.3.4 of the Interoperability section of the CORBA 2 
specification~\cite{corba2-spec}). Note that these (optional) parameters are 
included in TypeCodes generated by omniORB2.


\newpage
\section{Source Listing}
{\small
\subsection{anyExample\_impl.cc}
\begin{verbatim}
// anyExample_impl.cc - This is the source code of the example used in 
//                      Chapter 9 "Type Any and TypeCode" of the omniORB2 
//                      users guide.
//
//               This is the object implementation.
//
// Usage: anyExample_impl
//
//        On startup, the object reference is registered with the 
//        COS naming service. The client uses the naming service to
//        locate this object.
//
//        The name which the object is bound to is as follows:
//              root  [context]
//               |
//              text  [context] kind [my_context]
//               |
//              anyExample  [object]  kind [Object]
//

#include <iostream.h>

#include "anyExample.hh"


static CORBA::Boolean bindObjectToName(CORBA::ORB_ptr,CORBA::Object_ptr);


class anyExample_i : public virtual _sk_anyExample {
public:
  anyExample_i() { }
  virtual ~anyExample_i() { }
  virtual CORBA::Any* testOp(const CORBA::Any& a);
};


CORBA::Any* 
anyExample_i::testOp(const CORBA::Any& a) {

  cout << "Any received, containing: " << endl;
  
#ifndef NO_FLOAT
  CORBA::Double d;
#endif

  CORBA::Long l;
  char* str;

  testStruct* tp;


  if (a >>= l) {
    cout << "Long: " << l << endl;
  }
#ifndef NO_FLOAT
  else if (a >>= d) {
    cout << "Double: " << d << endl;
  }
#endif
  else if (a >>= str) {
    cout << "String: " << str << endl;
  }
  else if (a >>= tp) {
    cout << "testStruct: l: " << tp->l << endl;
    cout << "            s: " << tp->s << endl;
  }
  else {
    cout << "Unknown value." << endl;
  }

  CORBA::Any* ap = new CORBA::Any;
  
  *ap <<= (CORBA::ULong) 314;

  cout << "Returning Any containing: ULong: 314\n" << endl;
  return ap;
}


int
main(int argc, char **argv)
{
  CORBA::ORB_ptr orb = CORBA::ORB_init(argc,argv,"omniORB2");
  CORBA::BOA_ptr boa = orb->BOA_init(argc,argv,"omniORB2_BOA");

  anyExample_i *myobj = new anyExample_i();
  myobj->_obj_is_ready(boa);

  {
    anyExample_var myobjRef = myobj->_this();
    if (!bindObjectToName(orb,myobjRef)) {
      return 1;
    }
  }

  boa->impl_is_ready();
  // Tell the BOA we are ready. The BOA's default behaviour is to block
  // on this call indefinitely.

  return 0;
}


static
CORBA::Boolean
bindObjectToName(CORBA::ORB_ptr orb,CORBA::Object_ptr obj)
{
  CosNaming::NamingContext_var rootContext;
  
  try {
    // Obtain a reference to the root context of the Name service:
    CORBA::Object_var initServ;
    initServ = orb->resolve_initial_references("NameService");

    // Narrow the object returned by resolve_initial_references()
    // to a CosNaming::NamingContext object:
    rootContext = CosNaming::NamingContext::_narrow(initServ);
    if (CORBA::is_nil(rootContext)) 
      {
        cerr << "Failed to narrow naming context." << endl;
        return 0;
      }
  }
  catch(CORBA::ORB::InvalidName& ex) {
    cerr << "Service required is invalid [does not exist]." << endl;
    return 0;
  }


  try {
    // Bind a context called "test" to the root context:

    CosNaming::Name contextName;
    contextName.length(1);
    contextName[0].id   = (const char*) "test";    // string copied
    contextName[0].kind = (const char*) "my_context"; // string copied    
    // Note on kind: The kind field is used to indicate the type
    // of the object. This is to avoid conventions such as that used
    // by files (name.type -- e.g. test.ps = postscript etc.)

    CosNaming::NamingContext_var testContext;
    try {
      // Bind the context to root, and assign testContext to it:
      testContext = rootContext->bind_new_context(contextName);
    }
    catch(CosNaming::NamingContext::AlreadyBound& ex) {
      // If the context already exists, this exception will be raised.
      // In this case, just resolve the name and assign testContext
      // to the object returned:
      CORBA::Object_var tmpobj;
      tmpobj = rootContext->resolve(contextName);
      testContext = CosNaming::NamingContext::_narrow(tmpobj);
      if (CORBA::is_nil(testContext)) {
        cerr << "Failed to narrow naming context." << endl;
        return 0;
      }
    } 

    // Bind the object (obj) to testContext, naming it anyExample:
    CosNaming::Name objectName;
    objectName.length(1);
    objectName[0].id   = (const char*) "anyExample";   // string copied
    objectName[0].kind = (const char*) "Object"; // string copied


    // Bind obj with name anyExample to the testContext:
    try {
      testContext->bind(objectName,obj);
    }
    catch(CosNaming::NamingContext::AlreadyBound& ex) {
      testContext->rebind(objectName,obj);
    }
    // Note: Using rebind() will overwrite any Object previously bound 
    //       to /test/anyExample with obj.
    //       Alternatively, bind() can be used, which will raise a
    //       CosNaming::NamingContext::AlreadyBound exception if the name
    //       supplied is already bound to an object.
  }
  catch (CORBA::COMM_FAILURE& ex) {
    cerr << "Caught system exception COMM_FAILURE, unable to contact the "
         << "naming service." << endl;
    return 0;
  }
  catch (omniORB::fatalException& ex) {
    throw;
  }
  catch (...) {
    cerr << "Caught a system exception while using the naming service."<< endl;
    return 0;
  }
  return 1;
}

\end{verbatim}

\newpage

\subsection{anyExample\_clt.cc}
\begin{verbatim}
// anyExample_clt.cc -  This is the source code of the example used in 
//                      Chapter 9 "Type Any and TypeCode" of the omniORB2 
//                      users guide.
//
//              This is the client. It uses the COSS naming service
//              to obtain the object reference.
//
// Usage: anyExample_clt
//
//
//        On startup, the client lookup the object reference from the
//        COS naming service.
//
//        The name which the object is bound to is as follows:
//              root  [context]
//               |
//              text  [context] kind [my_context]
//               |
//              anyExample  [object]  kind [Object]
//

#include <iostream.h>
#include "anyExample.hh"

static CORBA::Object_ptr getObjectReference(CORBA::ORB_ptr orb);
static void invokeOp(anyExample_ptr& tobj, const CORBA::Any& a);

int
main (int argc, char **argv) 
{
  CORBA::ORB_ptr orb = CORBA::ORB_init(argc,argv,"omniORB2");
  CORBA::BOA_ptr boa = orb->BOA_init(argc,argv,"omniORB2_BOA");
  CORBA::Object_var obj;
  
  try {
    obj = getObjectReference(orb);
  }
  catch(CORBA::COMM_FAILURE& ex) {
    cerr << "Caught system exception COMM_FAILURE, unable to contact the "
         << "object." << endl;
    return -1;
  }
  catch(omniORB::fatalException& ex) {
    cerr << "Caught omniORB2 fatalException. This indicates a bug is caught "
         << "within omniORB2.\nPlease send a bug report.\n"
         << "The exception was thrown in file: " << ex.file() << "\n"
         << "                            line: " << ex.line() << "\n"
         << "The error message is: " << ex.errmsg() << endl;
    return -1;
  }
  catch(...) {
    cerr << "Caught a system exception." << endl;
    return -1;
  }


  anyExample_ptr tobj = anyExample::_narrow(obj);
  
  if (CORBA::is_nil(tobj)) {
    cerr << "Can't narrow object reference to type anyExample." << endl;
    return -1;
  }


  CORBA::Any a;

  try {
    // Sending Long
    CORBA::Long l = 100;
    a <<= l;
    cout << "Sending Any containing Long: " << l << endl; 
    invokeOp(tobj,a);
    
    // Sending Double
#ifndef NO_FLOAT
    CORBA::Double d = 1.2345;
    a <<= d;
    cout << "Sending Any containing Double: " << d << endl; 
    invokeOp(tobj,a);
#endif
  
    // Sending String
    const char* str = "Hello";
    a <<= str;
    cout << "Sending Any containing String: " << str << endl;
    invokeOp(tobj,a);
    
    // Sending testStruct  [Struct defined in IDL]
    testStruct t;
    t.l = 456;
    t.s = 8;
    a <<= t;
    cout << "Sending Any containing testStruct: l: " << t.l << endl;
    cout << "                                   s: " << t.s << endl;
    invokeOp(tobj,a);
  }
  catch(CORBA::COMM_FAILURE& ex) {
    cerr << "Caught system exception COMM_FAILURE, unable to contact the "
         << "object." << endl;
    return -1;
  }
  catch(omniORB::fatalException& ex) {
    cerr << "Caught omniORB2 fatalException. This indicates a bug is caught "
         << "within omniORB2.\nPlease send a bug report.\n"
         << "The exception was thrown in file: " << ex.file() << "\n"
         << "                            line: " << ex.line() << "\n"
         << "The error message is: " << ex.errmsg() << endl;
    return -1;
  }
  catch(...) {
    cerr << "Caught a system exception." << endl;
    return -1;
  }
	
  return 0;
}

static 
CORBA::Object_ptr
getObjectReference(CORBA::ORB_ptr orb)
{
  CosNaming::NamingContext_var rootContext;
  
  try {
    // Obtain a reference to the root context of the Name service:
    CORBA::Object_var initServ;
    initServ = orb->resolve_initial_references("NameService");

    // Narrow the object returned by resolve_initial_references()
    // to a CosNaming::NamingContext object:
    rootContext = CosNaming::NamingContext::_narrow(initServ);
    if (CORBA::is_nil(rootContext)) 
      {
        cerr << "Failed to narrow naming context." << endl;
        return CORBA::Object::_nil();
      }
  }
  catch(CORBA::ORB::InvalidName& ex) {
    cerr << "Service required is invalid [does not exist]." << endl;
    return CORBA::Object::_nil();
  }


  // Create a name object, containing the name test/context:
  CosNaming::Name name;
  name.length(2);

  name[0].id   = (const char*) "test";       // string copied
  name[0].kind = (const char*) "my_context"; // string copied
  name[1].id   = (const char*) "anyExample";
  name[1].kind = (const char*) "Object";
  // Note on kind: The kind field is used to indicate the type
  // of the object. This is to avoid conventions such as that used
  // by files (name.type -- e.g. test.ps = postscript etc.)

  
  CORBA::Object_ptr obj;
  try {
    // Resolve the name to an object reference, and assign the reference 
    // returned to a CORBA::Object:
    obj = rootContext->resolve(name);
  }
  catch(CosNaming::NamingContext::NotFound& ex)
    {
      // This exception is thrown if any of the components of the
      // path [contexts or the object] aren't found:
      cerr << "Context not found." << endl;
      return CORBA::Object::_nil();
    }
  catch (CORBA::COMM_FAILURE& ex) {
    cerr << "Caught system exception COMM_FAILURE, unable to contact the "
         << "naming service." << endl;
    return CORBA::Object::_nil();
  }
  catch(omniORB::fatalException& ex) {
    throw;
  }
  catch (...) {
    cerr << "Caught a system exception while using the naming service."<< endl;
    return CORBA::Object::_nil();
  }
  return obj;
}


static void 
invokeOp(anyExample_ptr& tobj, const CORBA::Any& a)
{
  CORBA::Any_var bp;

  cout << "Invoking operation." << endl;
  bp = tobj->testOp(a);

  cout << "Operation completed. Returned Any: ";
  CORBA::ULong ul;

  if (bp >>= ul) {
    cout << "ULong: " << ul << "\n" << endl;
  }
  else {
    cout << "Unknown value." << "\n" << endl;
  }
}

\end{verbatim}
}


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\chapter{Dynamic Management of Any Values}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

In CORBA specification 2.2, a new facility- {\bf DynAny} is
introduced. Previously, it is not possible to insert or extract constructed
and other complex types from an {\bf any} without using the stub code
generated by an idl compiler for these types. This makes it impossible to
write generic servers (bridges, event channels supporting filtering etc)
because these servers can not have static knowledge of all the possible data
types that they have to handle. 

To fill this gap, the {\bf DynAny} facility is defined to enable traversal
of the data value associated with an {\bf any} at runtime and extraction of
its constituents. This facility also enables the construction of an {\bf
any} at runtime, without having static knowledge of its types.

This chapter explains how {\bf DynAny} may be used. For completeness, you
should also read the DynAny specification defined in Chapter 7 of the CORBA
specification 2.2. Where possible, the implementation in omniORB2 adheres
closely to the specification. However, there are areas in the specification
that are ambiguous or lacking in details. A number of these issues are
currently opened with the ORB revision task force. Until the issues are
resolved, it is possible that a different implementation may choose to
intepret the specification differently. This chapter provides
clarifications to the specification, explains the interpretation used and
offers some advice and warnings on potential portability problems.

\section{C++ mapping}

{\small
\begin{verbatim}

  // namespace CORBA

  class ORB {
  public:
    ...

    class InconsistentTypeCode : public UserException { ... };

    DynAny_ptr create_dyn_any(const Any& value);

    DynAny_ptr create_basic_dyn_any(TypeCode_ptr tc);

    DynStruct_ptr create_dyn_struct(TypeCode_ptr tc);

    DynSequence_ptr create_dyn_sequence(TypeCode_ptr tc);

    DynArray_ptr create_dyn_array(TypeCode_ptr tc);

    DynUnion_ptr create_dyn_union(TypeCode_ptr tc);

    DynEnum_ptr create_dyn_enum(TypeCode_ptr tc);

  };

  typedef DynAny* DynAny_ptr;
  class DynAny_var { ... };

  class DynAny {
  public:    

    class Invalid : public UserException { ... };
    class InvalidValue : public UserException { ... };
    class TypeMismatch : public UserException { ... };
    class InvalidSeq : public UserException { ... };

    typedef _CORBA_Unbounded_Sequence__Octet OctetSeq;

    TypeCode_ptr type() const;

    void assign(DynAny_ptr dyn_any) throw(Invalid,SystemException);
    void from_any(const Any& value) throw(Invalid,SystemException);
    Any* to_any() throw(Invalid,SystemException);
    void destroy();
    DynAny_ptr copy();

    DynAny_ptr current_component();
    Boolean next();
    Boolean seek(Long index);
    void rewind();

    void insert_boolean(Boolean value) throw(InvalidValue,SystemException);
    void insert_octet(Octet value) throw(InvalidValue,SystemException);
    void insert_char(Char value) throw(InvalidValue,SystemException);
    void insert_short(Short value) throw(InvalidValue,SystemException);
    void insert_ushort(UShort value) throw(InvalidValue,SystemException);
    void insert_long(Long value) throw(InvalidValue,SystemException);
    void insert_ulong(ULong value) throw(InvalidValue,SystemException);
    void insert_float(Float value) throw(InvalidValue,SystemException);
    void insert_double(Double value) throw(InvalidValue,SystemException);
    void insert_string(const char* value) throw(InvalidValue,SystemException);
    void insert_reference(Object_ptr v) throw(InvalidValue,SystemException);
    void insert_typecode(TypeCode_ptr v) throw(InvalidValue,SystemException);
    void insert_any(const Any& value) throw(InvalidValue,SystemException);

    Boolean get_boolean() throw(TypeMismatch,SystemException);
    Octet get_octet() throw(TypeMismatch,SystemException);
    Char get_char() throw(TypeMismatch,SystemException);
    Short get_short() throw(TypeMismatch,SystemException);
    UShort get_ushort() throw(TypeMismatch,SystemException);
    Long get_long() throw(TypeMismatch,SystemException);
    ULong get_ulong() throw(TypeMismatch,SystemException);
    Float get_float() throw(TypeMismatch,SystemException);
    Double get_double() throw(TypeMismatch,SystemException);
    char* get_string() throw(TypeMismatch,SystemException);
    Object_ptr get_reference() throw(TypeMismatch,SystemException);
    TypeCode_ptr get_typecode() throw(TypeMismatch,SystemException);
    Any* get_any() throw(TypeMismatch,SystemException);

    static DynAny_ptr _duplicate(DynAny_ptr);
    static DynAny_ptr _narrow(DynAny_ptr);
    static DynAny_ptr _nil();
  };

  // DynFixed is not supported.

  typedef DynEnum* DynEnum_ptr;
  class DynEnum_var { ... };

  class DynEnum :  public DynAny {
  public:

    char* value_as_string();
    void value_as_string(const char* value);
    ULong value_as_ulong();
    void value_as_ulong(ULong value);

    static DynEnum_ptr _duplicate(DynEnum_ptr);
    static DynEnum_ptr _narrow(DynAny_ptr);
    static DynEnum_ptr _nil();
  };

  typedef char* FieldName;
  typedef String_var FieldName_var;

  struct NameValuePair {
    String_member id;
    Any value;
  };

  typedef _CORBA_ConstrType_Variable_Var<NameValuePair> NameValuePair_var;
  typedef _CORBA_Unbounded_Sequence<NameValuePair > NameValuePairSeq;

  typedef DynStruct* DynStruct_ptr;
  class DynStruct_var { ... };

  class DynStruct :  public DynAny {
  public:

    char*  current_member_name();
    TCKind current_member_kind();
    NameValuePairSeq* get_members();
    void set_members(const NameValuePairSeq& NVSeqVal)
                     throw(InvalidSeq,SystemException);

    static DynStruct_ptr _duplicate(DynStruct_ptr);
    static DynStruct_ptr _narrow(DynAny_ptr);
    static DynStruct_ptr _nil();
  };

  typedef DynUnion* DynUnion_ptr;
  class DynUnion_var { ... };

  class DynUnion :  public DynAny {
  public:

    Boolean set_as_default();
    void set_as_default(Boolean value);
    DynAny_ptr discriminator();
    TCKind discriminator_kind();
    DynAny_ptr member();
    char*  member_name();
    void member_name(const char* value);
    TCKind member_kind();

    static DynUnion_ptr _duplicate(DynUnion_ptr);
    static DynUnion_ptr _narrow(DynAny_ptr);
    static DynUnion_ptr _nil();
  };

  typedef _CORBA_Unbounded_Sequence<Any > AnySeq;

  typedef DynSequence* DynSequence_ptr;
  class DynSequence_var { ... };

  class DynSequence :  public DynAny {
  public:

    ULong length();
    void length (ULong value);
    AnySeq* get_elements();
    void set_elements(const AnySeq& value) throw(InvalidValue,SystemException);

    static DynSequence_ptr _duplicate(DynSequence_ptr);
    static DynSequence_ptr _narrow(DynAny_ptr);
    static DynSequence_ptr _nil();
  };

  typedef DynArray* DynArray_ptr;
  class DynArray_var { ... };

  class DynArray : public DynAny {
  public:

    AnySeq* get_elements();
    void set_elements(const AnySeq& value) throw(InvalidValue,SystemException);

    static DynArray_ptr _duplicate(DynArray_ptr);
    static DynArray_ptr _narrow(DynAny_ptr);
    static DynArray_ptr _nil();
  };

\end{verbatim}
}

\section{The DynAny Interface}
\label{dynany}

\subsection{Example: extract data values from an Any}

If an {\bf any} contains a value of one of the basic data types, its value
can be extracted using the pre-defined operators in the Any interface. When
the value is a struct or other non-basic types, one can use the DynAny
interface to extract its constituent values. 

In this section, we use a struct as an example to illustrate how the DynAny
interface can be used.

The example struct is as follows:

{\small
\begin{verbatim}
    // IDL
    
    struct exampleStruct1 {
      string s;
      double d;
      long   l;
    };
    
\end{verbatim}
}

To {\bf create} a DynAny from an Any value, one uses the {\tt create\_dyn\_any}
method:

{\small
\begin{verbatim}
    // C++
    
    CORBA::ORB_ptr orb;  // orb initialised by CORBA::ORB_init.
    
    Any v;
    ...       // Initialise v to contain a value of type exampleStruct1.
    
    CORBA::DynAny_var dv = orb->create_dyn_any(v);
    
\end{verbatim}
}

Like CORBA object and pseudo object references, a {\tt DynAny\_ptr} can be
managed by a \_var type ({\tt DynAny\_var}) which will release the {\tt
DynAny\_ptr} automatically when the variable goes out of scope.

\subsubsection{Iterate through the components}
\label{dynanyiterate}

Once the DynAny object is created, we can use the
DynAny interface to extract the individual components in {\tt
exampleStruct1}. The DynAny interface provides a number of
functions to extract and insert component values. These functions are
defined to operate on the component identified by the {\bf current
component} pointer. 

A {\bf current component} pointer is an internal state of a DynAny object.  
When a DynAny object is created, the pointer is initialised to point to the
first component of the any value. 

The pointer can be advanced to the next component with the {\tt next()}
operation. The function returns FALSE (0) if there are no more components.
Otherwise it returns TRUE (1). When the any value in the DynAny object
contains only one component, the {\tt next()} operation always returns
FALSE(0).

Another way of adjusting the pointer is the {\tt seek()} operation. The
function returns FALSE (0) if there is no component at the specified
index. Otherwise it returns TRUE (1). The index value of the first
component is zero. Therefore, a {\tt seek(0)} call rewinds the pointer to
the first component, this is also equivalent to a call to the {\tt
rewind()} operation.

For completeness, we should also mention here the {\tt
current\_component()} operation. This operation causes the DynAny object to
return a reference to another DynAny object that can be used to access the
current component. It is possible that the current component pointer is not
pointing to a valid component, for instance, the {\tt next()} operation has
been invoked and there is no more component. Under this circumstance, the {\tt
current\_component()} operation returns a nil DynAny object
reference\footnote{Testing a nil DynAny object with CORBA::is\_nil()
returns TRUE(1). The CORBA 2.2 specification does not specify what is the
return value of this function when the current component pointer is
invalid. To ensure portability, it is best to avoid calling {\tt
current\_component()} under this condition.}. For components which are just
basic data types, calling {\tt current\_component()} is an overkill because
we can just use the basic type extraction and insertion functions directly.

\subsubsection{Extract basic type components}

In our example, the component values can be extracted as follows:

{\small
\begin{verbatim}
    CORBA::String_var s = dv->get_string();
    CORBA::Double     d = dv->get_double();
    CORBA::Long       l = dv->get_long();
\end{verbatim}
}

Each get basic type operation has the side-effect of advancing the current
component pointer. For instance:

{\small
\begin{verbatim}
    CORBA::String_var s = dv->get_string();
\end{verbatim}
}

is equivalent to:

{\small
\begin{verbatim}
    CORBA::DynAny_var temp = dv->current_component();
    CORBA::String_var s = temp->get_string();
    dv->next();
\end{verbatim}
}

The get operations ensure that the current component is of the same type as
requested. Otherwise, the object throws a TypeMismatch exception. If the
current component pointer is invalid when a get operation is called, the
object also throws a TypeMismatch exception\footnote{The CORBA 2.2
specification does not define the behavior of this error condition. To
ensure portability, it is best to avoid calling the get operations when the
current component pointer is known to be invalid.}. 

To repeatedly access the components, one can use the {\tt rewind()} or {\tt
seek()} operation to manipulate the current component pointer. For
instance, to access the {\tt d} member in {\tt exampleStruct1} directly:

{\small
\begin{verbatim}
    dv->seek(1);          // position current component to member d.
    CORBA::Double     d = dv->get_double();
\end{verbatim}
}

\subsubsection{Extract complex components}

When a component is not one of the basic data types, it is not possible to
extract its value using the get operations. Instead, a DynAny object has to
be created from which the component is accessed. 

Consider this example:

{\small
\begin{verbatim}
    // IDL
    
    struct exampleStruct2 {
      string m1;
      exampleStruct1 m2;
    };
\end{verbatim}
}

In order to extract the data members within {\tt m2} (of type 
{\tt exampleStruct1}), we use {\tt current\_component()} as follows:

{\small
\begin{verbatim}
    // C++
    
    CORBA::ORB_ptr orb;  // orb initialised by CORBA::ORB_init.
    Any v;
    ...       // Initialise v to contain a value of type exampleStruct2.
    
    CORBA::DynAny_var dv = orb->create_dyn_any(v);
    
    CORBA::String_var m1 = dv->get_string();  // extract member m1
    CORBA::DynAny_var dm = dv->current_component(); // DynAny reference to m2
    CORBA::String_var s = dm->get_string();   // m2.s
    CORBA::Double     d = dm->get_double();   // m2.d
    CORBA::Long       l = dm->get_long();     // m2.l
\end{verbatim}
}


\subsubsection{Clean-up}
Now we finish off this example with a description on destroying DynAny
objects. There are two points to remember:

\begin{enumerate}
\item A DynAny reference ({\tt DynAny\_ptr}) is like any CORBA object or
psuedo object reference and should be handled in the same way. In
particular, one has to call the {\tt CORBA::release} operation to indicate
that a DynAny reference will no longer be accessed. In the example, this is
done automatically by {\tt DynAny\_var}.
\item A DynAny object and its references are separate entities, just as a
CORBA object implementation and its object references are different
entities. While {\tt CORBA::release} will release any resource associated
with a {\tt DynAny\_ptr}, one has to separately destroy the DynAny object
to avoid any memory leak. This is done by calling the {\tt destroy()}
operation.
\end{enumerate}

In the example, the DynAny object can be destroyed as follows:

{\small
\begin{verbatim}
    // C++
    ...
    CORBA::DynAny_var dv = orb->create_dyn_any(v);
    ...
    dv->destroy();
    
    // From now on, one should not invoke any operation in dv. Otherwise the
    // behavior is undefined.
    
\end{verbatim}
}

\subsection{Example: insert data values into an Any}

Using the DynAny interface, one can create an Any value from scratch.  In
this example, we are going to create an Any containing the value of the
{\tt exampleStruct1} type.

Firstly, we have to create a DynAny to store the value using one of the
{\tt create\_dyn} functions. Because {\tt exampleStruct1} is a struct type, we
use the {\tt create\_dyn\_struct()} operation.

{\small
\begin{verbatim}
    // C++
    
    CORBA::ORB_ptr orb;  // orb initialised by CORBA::ORB_init.
    
    // create the TypeCode for exampleStruct.
    StructMemberSeq tc_members;
    tc_members.length(3);
    tc_members[0].name = (const char*)"s";
    tc_members[0].type = CORBA::TypeCode::_duplicate(CORBA::_tc_string);
    tc_members[0].type_def = CORBA::IDLType::_nil();
    tc_members[1].name = (const char*)"d";
    tc_members[1].type = CORBA::TypeCode::_duplicate(CORBA::_tc_double);
    tc_members[1].type_def = CORBA::IDLType::_nil();
    tc_members[2].name = (const char*)"l";
    tc_members[2].type = CORBA::TypeCode::_duplicate(CORBA::_tc_long);
    tc_members[2].type_def = CORBA::IDLType::_nil();
    CORBA::TypeCode_var tc = orb->create_struct_tc("IDL:exampleStruct1:1.0",
                                                   "exampleStruct1",
                                                   tc_members);
    
    // create the DynAny object to represent the any value
    CORBA::DynAny_var dv = orb->create_dyn_struct(tc);
\end{verbatim}
}

\subsubsection{Insert basic type components}

Once the DynAny object is created, we can use the DynAny interface to
insert the components. The DynAny interface provides a number of insert
operations to insert basic types into the any value. In our example, the
component values can be inserted as follows:

{\small
\begin{verbatim}
    CORBA::String_var s = (const char*)"Hello";
    CORBA::Double     d = 3.1416;
    CORBA::Long       l = 1;
    
    dv->insert_string(s);
    dv->insert_double(d);
    dv->insert_long(l);
\end{verbatim}
}

Each insert basic type operation has the side-effect of advancing the
current component pointer. For instance:

{\small
\begin{verbatim}
    dv->insert_string(s);
\end{verbatim}
}

is equivalent to:

{\small
\begin{verbatim}
    CORBA::DynAny_var temp = dv->current_component();
    temp->insert_string(s);
    dv->next();
\end{verbatim}
}

The insert operations ensure that the current component is of the same type
as the inserted value. Otherwise, the object throws a InvalidValue
exception. If the current component pointer is invalid when an insert operation
is called, the object also throws a InvalidValue exception\footnote{The
CORBA 2.2 specification does not define the behavior of this error
condition. To ensure portability, it is best to avoid calling the insert
operations when the current component pointer is known to be invalid.}.

Sometimes, one may just want to modify one component in an Any value. For
instance, one may just want to change the value of the double member in
{\tt exampleStruct1}. This can be done as follows:

{\small
\begin{verbatim}
    // C++
    
    CORBA::ORB_ptr orb;  // orb initialised by CORBA::ORB_init.
    
    Any v;
    ...       // Initialise v to contain a value of type exampleStruct1.
    
    CORBA::Double d = 6.28;
    
    CORBA::DynAny_var dv = orb->create_dyn_any(v);
    
    dv->seek(1);
    dv->insert_double(d);    // Change the value of the member d.
\end{verbatim}
}

Finally, the any value can be obtained from the DynAny object using the
{\tt to\_any()} operation:

{\small
\begin{verbatim}
    CORBA::Any_var v = dv->to_any();    // Obtain the any value.
\end{verbatim}
}

\subsubsection{Insert complex components}

When a component is not one of the basic data types, it is not possible to
insert its value using the insert operations. Instead, a DynAny object has
to be created through which the component can be inserted.

In our example, one can insert component values into {\tt exampleStruct2} as
follows:

{\small
\begin{verbatim}
    // C++
    
    CORBA::ORB_ptr orb;  // orb initialised by CORBA::ORB_init.
    
    CORBA::TypeCode_var tc;
    // create the TypeCode for exampleStruct2.
    ...
    // create the DynAny object to represent the any value
    CORBA::DynAny_var dv = orb->create_dyn_struct(tc);
    
    CORBA::String_var m1  = (const char*)"Greetings";
    CORBA::String_var m2s = (const char*)"Hello";
    CORBA::Double     m2d = 3.1416;
    CORBA::Long       m2l = 1;
    
    dv->insert_string(m1);   // insert member m1
    CORBA::DynAny_var dm = dv->current_component(); // DynAny reference to m2
    dm->insert_string(m2s);  // insert member m2.s
    dm->insert_double(m2d);  // insert member m2.d
    dm->insert_long(m2l);    // insert member m2.l
    
    CORBA::Any_var v = dv->to_any();  // obtain the any value
    
    dv->destroy();          // destroy the DynAny object.
                            // No operation should be invoked on dv
                            // from this point on except CORBA::release.
\end{verbatim}
}


In addition to the DynAny interface, a number of derived interfaces are
defined. These interfaces are specialisation of the DynAny interface to
facilitate the handling of any values containing non-basic types: struct,
sequence, array, enum and union\footnote{In the CORBA 2.2 specification, the
DynFixed interface is defined to handle the fixed data type. This is not
supported in this implementation.}. The next few sections will provide more
details on these interfaces.

\section{The DynStruct Interface}

When a DynAny object is created through the {\tt create\_dyn\_any()}
operation and the any value contains a struct type, a DynStruct object is
created. The DynAny reference returned can be narrowed to a DynStruct
reference using the {\tt CORBA::DynStruct::\_narrow()} operation.

In the previous example, the components are extracted using the get
operations. Alternatively, the DynStruct interface provides an addition
operation ({\tt get\_members()}) to return all the components in a single
call. The returned value is a sequence of name value pair. The member name
is given in the name field and its value is returned as an Any value.
For example, an alternative way to extract the components in the previous
example is as follows:

{\small
\begin{verbatim}
    // C++
    
    CORBA::ORB_ptr orb;  // orb initialised by CORBA::ORB_init.
    Any v;
    ...       // Initialise v to contain a value of type exampleStruct1.
    CORBA::DynAny_var dv = orb->create_dyn_any(v);
    
    CORBA::DynStruct_var ds = CORBA::DynStruct::_narrow(dv);
    
    CORBA::NameValuePairSeq* sq = ds->get_members();
    
    char*         s;
    CORBA::Double d;
    CORBA::Long   l;
    
    (*sq)[0].value >>= s;        // 1st element contains member s
    (*sq)[1].value >>= d;        // 2nd element contains member d
    (*sq)[2].value >>= l;        // 3rd element contains member l
\end{verbatim}
}

Similarly, the DynStruct interface provides an addition operation ({\tt
set\_members()}) to insert all the components in a single call. The
following is an alternative way to insert the components of the type
{\tt exampleStruct1} into an Any value:

{\small
\begin{verbatim}
    // C++
    
    CORBA::ORB_ptr orb;  // orb initialised by CORBA::ORB_init.
    
    CORBA::TypeCode_var tc;
    // create the TypeCode for exampleStruct1.
    ...
    // create the DynAny object to represent the any value
    CORBA::DynAny_var dv = orb->create_dyn_struct(tc);
    
    CORBA::String_var s = (const char*)"Hello";
    CORBA::Double     d = 3.1416;
    CORBA::Long       l = 1;
    
    CORBA::NameValuePairSeq sq;
    sq.length(3);
    sq[0].id = (const char*)"s";
    sq[0].value <<= CORBA::Any::from_string(s,0); 
                                    // 1st element contains member s
    sq[1].id = (const char*)"d";
    sq[1].value <<= d;             // 2nd element contains member d
    sq[2].id = (const char*)"l";
    sq[2].value <<= l;             // 3rd element contains member l
    
    dv->set_members(sq);    
\end{verbatim}
}

Notice that the name-value pairs in the argument to {\tt set\_members()}
must match the members of the struct exactly or the object would throw the
InvalidSeq exception.

In addition to the {\tt current\_component()} operation, the DynStruct
interface provides two operations: {\tt current\_member\_name()} and {\tt
current\_member\_kind()}, to return information about the current
component.

\section{The DynSequence Interface}

Like struct values, sequence values can be traversed using the operations
introduced in section~\ref{dynany}. The first sequence element can be
accessed as the first DynAny component, the second sequence element as the
second DynAny component and so on. 

To extract component values from an Any containing a sequence, the length
of the sequence can be obtained using the get length operation in the
DynSequence interface. Here is an example to extract the components of a
sequence of long:

{\small
\begin{verbatim}
    // C++
    
    CORBA::ORB_ptr orb;  // orb initialised by CORBA::ORB_init.
    Any v;
    ...       // Initialise v to contain a value of a sequence of long
    CORBA::DynAny_var dv = orb->create_dyn_any(v);
    
    CORBA::DynSequence_var ds = CORBA::DynSequence::_narrow(dv);
    CORBA::ULong len = ds->length();     // extract the length of the sequence
    CORBA::ULong index;
    for (index = 0; index < len; index++) {
      CORBA::Long v = ds->get_long();
      cerr << "[" << index << "] = " << v << endl;
    }
\end{verbatim}
}

Conversely, the set length operation is provided to set the length of the
sequence. Here is an example to insert the components of a sequence of
long:

{\small
\begin{verbatim}
    // C++
    
    CORBA::ORB_ptr orb;  // orb initialised by CORBA::ORB_init.
    
    CORBA::TypeCode_var tc;
    // create the TypeCode for a sequence of long.
    ...
    // create the DynAny object to represent the any value
    CORBA::DynSequence_var ds = orb->create_dyn_sequence(tc);
    
    CORBA::ULong len = 3;
    
    ds->length(len);             // set the length of the sequence
    
    CORBA::ULong index;
    for (index = 0; index < len; index++) {
      ds->insert_long(index);    // insert a sequence element
    }
\end{verbatim}
}

Similar to the DynStruct interface, the {\tt get\_elements()} operation is
provided to return all the sequence elements and the {\tt set\_elements()}
operation is provided to insert all the sequence elements.

\section{The DynArray Interface}

Array values are handled by the DynArray interface. The DynArray interface
is the same as the DynSequence interface except that the former does not
provide the set length and get length operations. 

\section{The DynEnum Interface}

Enum values are handled by the DynEnum interface. A DynEnum object contains
a single component which is the enum value. This value cannot be
extracted or inserted using the get and insert operations of the DynAny
interface. Instead, two pairs of operations are provided to handle this
value.

The {\tt value\_as\_string} operations allow the enum value to be
extracted or inserted as a string. The {\tt value\_as\_ulong} operations
allow the enum value to be extracted or inserted as an unsigned long.


\section{The DynUnion Interface}

Union values are handled by the DynUnion interface. Unfortunately, the
CORBA 2.2 specification does not define the DynUnion interface in sufficent
details to nail down its intended usage\footnote{This interface is
currently an open issue with the ORB revision task force.}. In this
section, we try to fill in the gaps and describe a sensible way to use the
DynUnion interface. Where necessary, the semantics of the operations is
clarified. It is possible that the behavior of this interface in another
ORB is different from this implmentation. Where appropriate, we give
warnings on usage that might cause problems with portability.

In relation to the current component pointer (\ref{dynanyiterate}), a
DynUnion object contains two components. The first component (with the
index value equals 0) is the discriminator value, the second one is the
member value.  Therefore, one can use the {\tt seek()} and {\tt
current\_component()} operations to obtain a reference to the DynAny
objects that handle the two components. However, it is better to use the
operations defined in the DynUnion interface to manipulate these components
as the semantics of the operations is easier to understand.

\subsection{Three Categories of Union}
\label{dynunioncat}

Before we continue, it is important to understand that unions can be
classified into the following categories:

\begin{enumerate}
\item One that has a default branch defined in the IDL. This will be called
{\bf explicit default union} in the rest of this section.
\item One that has no default branch and not all the possible values of the
discriminator type are covered by the branch labels in the IDL. This will
be called {\bf implicit default union}.
\item One that has no default branch but all the possible values of the
discriminator type are covered. This will be called {\bf no default union}.
\end{enumerate}

Of the three categories, the implicit default union is interesting because
by definition if the discriminator value is not equal to any of the branch
labels, the union has {\bf no} member. That is, the union value consists
solely of the discriminator value.

\subsection{Example: extract data values from a union}

\subsubsection{Explicit default union}

Consider a union of the following type:

{\small
\begin{verbatim}
    // IDL
    
    union exampleUnion1 switch(boolean) {
    case TRUE: long l;
    default:   double d; 
    };
\end{verbatim}
}

The most straightforward way to extract the member value is as follows:

{\small
\begin{verbatim}
    // C++
    
    CORBA::ORB_ptr orb;  // orb initialised by CORBA::ORB_init.
    
    Any v;
    ...       // Initialise v to contain a value of type exampleUnion1.
    
    CORBA::DynAny_var dv = orb->create_dyn_any(v);
    CORBA::DynUnion_var du = CORBA::DynUnion::_narrow(dv);
    
    CORBA::String_var di = du->member_name();
    CORBA::DynAny_var dm = du->member();
    
    if (strcmp((const char*)di,"l") == 0) {
      // branch label is TRUE
      CORBA::Long v = dm->get_long();
      cerr << "l = " << v << endl;
    }
    
    if (strcmp((const char*)di,"d") == 0) {
      // Is default branch
      CORBA::Double v = dm->get_double();
      cerr << "d = " << v << endl;
    }
\end{verbatim}
}

In the example, the operation {\tt member\_name()} is used to determine
which branch the union has been instantiated. The operation {\tt member()}
is used to obtain a reference to the DynAny object that handles the member.

Alternatively, the branch can be determined by reading the discriminator
value:

{\small
\begin{verbatim}
    // C++
    
    CORBA::DynAny_var di = du->discriminator();
    CORBA::DynAny_var dm = du->member();
    
    CORBA::Boolean di_v = di->get_boolean();
    
    switch (di_v) {
    case 1:
      CORBA::Long v = dm->get_long();
      cerr << "l = " << v << endl;
      break;
    default:
      CORBA::Double v = dm->get_double();
      cerr << "d = " << v << endl;
    }
\end{verbatim}
}

The operation {\tt discriminator()} is used to obtain the value of the
discriminator.

Finally, the third way to determine the branch is to test if the default is
selected:

{\small
\begin{verbatim}
    // C++
    
    switch (dv->set_as_default()) {
    case 1:
      CORBA::Double v = dm->get_double();
      cerr << "d = " << v << endl;
      break;
    default:
      CORBA::Long v = dm->get_long();
      cerr << "l = " << v << endl;
    }

\end{verbatim}
}

The operation {\tt set\_as\_default()} returns TRUE (1) if the
discriminator has been assigned a valid default value.


\subsubsection{Implicit default union}

Consider a union of the following type:

{\small
\begin{verbatim}
    // IDL
    
    union exampleUnion2 switch(long) {
    case 1: long l;
    case 2: double d; 
    };
\end{verbatim}
}

This example is similar to the previous one but there is no default branch.
The description above also applies to this example. However, the
discriminator may be set to neither 1 nor 2. Under this condition, the
implicit default is selected and the union value contains the discriminator
only!

When the discriminator contains an implicit default value, one might ask
what is the value returned by the {\tt member\_name()} and {\tt member()}
operation. Since there is no member in the union value, omniORB2 returns a
null string and a nil DynAny reference respectively. This behavior is not
specified in the CORBA 2.2 specification. To ensure that your application
is portable, it is best to avoid calling these operations when the DynUnion
object might contain an implicit default value.

\subsubsection{No default union}

This is the last union category. For instance:

{\small
\begin{verbatim}
    // IDL
    
    union exampleUnion3 switch(boolean) {
    case TRUE: long l;
    case FALSE: double d; 
    };
\end{verbatim}
}

In this example, all the possible values of the discriminator are used as
union labels. There is no default branch. The only difference between this
category and the explicit default union is that the {\tt
set\_as\_default()} operation always returns FALSE (0).


\subsection{Example: insert data values into a union}

Writing into a union involves selecting the union branch with the
appropriate discriminator value and then writing the member value.
There are three ways to set the discriminator value:

\begin{enumerate}
\item Use the {\tt member\_name()} write operation to specify the union
branch by specifying the union member directly. This operation has the side
effect of setting the discriminator to the label value of the
branch.
\item Write the label value of a union branch into the DynAny
object that handles the discriminator.
\item If the union has a default branch, either explicitly or implicitly,
use the {\tt set\_as\_default()} write operation to set the discriminator
to a valid default value.
\end{enumerate}

The following example shows the three ways of writing into a union:

{\small
\begin{verbatim}
    // C++
    
    CORBA::ORB_ptr orb;  // orb initialised by CORBA::ORB_init.
    
    CORBA::TypeCode_var tc;
    // create the TypeCode for exampleUnion1.
    ...
    // create the DynAny object to represent the any value
    CORBA::DynUnion_var dv = orb->create_dyn_union(tc);
    
    CORBA::Any_var v;
    DynAny_ptr dm;
    
    // Use member_name to select the union branch
    dv->member_name("l");
    dm = dv->member();
    dm->insert_long(10);
    v = dv->to_any();          // transfer to an Any
    CORBA::release(dm);
    
    // Setting the discriminator value to select the union branch
    CORBA::DynAny_var di = dv->discriminator();
    di->insert_boolean(1);     // set discriminator to label TRUE
    dm = dv->member();
    dm->insert_long(20);
    v = dv->to_any();          // transfer to an Any
    CORBA::release(dm);
    
    // Use set_as_default to select the default union branch
    dv->set_as_default(1);
    dm = dv->member();
    dm->insert_double(3.14);
    v = dv->to_any();          // transfer to an Any
    CORBA::release(dm);
    
    dv->destroy();

\end{verbatim}
}

\subsubsection{Ambiguous usage}

\begin{enumerate}

\item When the discriminator is set to a different value, a different
member branch is selected. Suppose the application has previously obtained
a DynAny reference to a union member when it changes the discriminator
value. As a result of the value change, the union is now instantiated to
another union branch, i.e. a call to the {\tt member()} operation will now
return a reference to a different DynAny object. If the application
continues to access the DynAny object of the old union member, the behavior
of the ORB under this condition is not defined by the CORBA 2.2
specification. With omniORB2, the DynAny object of the old union member is
detached from the union when a new union branch is selected. Therefore
reading or writing this object will not have any relation to the current
value of the union. To avoid this ambiguity, the reference to the old union
member should be released before a different union branch is selected.

\item The write operation {\tt set\_as\_default()} takes a boolean
argument. It is ambiguous to call this function with the argument set to
FALSE (0). With omniORB2, such a call will be silently ignored.

\item It is also ambiguous to pass the value TRUE (1) to the {\tt
set\_as\_default()} operation when the union is a no default union
(\ref{dynunioncat}). With omniORB2, such a call will be silently ignored.

\item When the discriminator value is not set, calling the {\tt member()}
operation is ambiguous. With omniORB2, such a call will return a nil DynAny
reference. Similarly, a call to the {\tt member\_kind()} operation under
this condition will return {\tt tk\_null}.

\end{enumerate}

To ensure portability, it is best to avoid using the DynUnion interface
and not to rely on the ORB to behave as omniORB2 does under these ambiguous
conditions.

\section{Duplicate DynAny References}

Like any CORBA object and psuedo object references, a DynAny reference can
be duplicated using the {\tt \_duplicate()} operations. When an application
has obtained multiple DynAny references to the same DynAny object, it
should be noted that a change made to the object by invoking on one
reference is also visible through the other references. In particular, if
a call through one reference has caused the current component pointer to be
changed, subsequent calls through other references will operate on the new
current component pointer.


\section{Other Operations}

The following is a short summary of the other operations in the DynAny
interface which have not been covered in previous sections:

\begin{description}
\item[{\tt assign()}] initialises a DynAny object with another DynAny
object. The two objects must have the same typecode.

\item[{\tt from\_any()}] initialises a DynAny object from the value in an
any. The typecode in the two objects must be the same.

\item[{\tt copy()}] creates a new DynAny object whose value is a deep copy
of the current object.

\item[{\tt type()}] returns the typecode associated with the DynAny object.

\end{description}


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\chapter{The Dynamic Invocation Interface}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

The Dynamic Invocation Interface (or DII) allows applications to
invoke operations on CORBA objects about which they have no static
information. That is to say the application has not been linked with
stub code which performs the remote operation invocation. Thus using
the DII applications may invoke operations on \emph{any} CORBA object,
possibly determining the object's interface dynamically by using an
Interface Repository.
% ?? Ref IR section?

This chapter presents an overview of the Dynamic Invocation Interface.
An toy example use of the DII can be found in the omniORB2 distribution in
the {\tt <top>/src/examples/dii} directory.
The DII makes extensive use of the type Any, so ensure that you have read
chapter~\ref{ch_any}. For more information refer to the Dynamic Invocation
Interface and C++ Mapping sections of the CORBA 2
specification~\cite{corba2-spec}.


\section{Overview}

To invoke an operation on a CORBA object an application needs an object
reference, the name of the operation and a list of the parameters. In
addition the application must know whether the operation is one-way,
what user-defined exceptions it may throw, any user-context
strings which must be supplied, a 'context' to take these values from and the
type of the returned value. This
information is given by the IDL interface declaration, and so is normally
made available to the application via the stub code. In the DII this
information is encapsulated in the {\tt CORBA::Request} pseudo-object.

To perform an operation invocation the application must obtain an instance of
a {\tt Request} object, supply the information listed above and call one of
the methods to actually make the invocation. If the invocation causes an
exception to be thrown then this may be retrieved and inspected, or the
return value on success.


\section{Pseudo Objects}

The DII defines a number of psuedo-object types, all defined in the CORBA
namespace. These objects behave in many ways like CORBA objects. They
should only be accessed by reference (through {\tt foo\_ptr} or
{\tt foo\_var}), may not be
instantiated directly and should be released by calling
{\tt CORBA::release()}\footnote{if not managed by a {\tt \_var} type.}.
A nil reference should only be represented by {\tt foo::\_nil()}.

These pseudo objects, although defined in pseudo-IDL in the specification do
not follow the normal mapping for CORBA objects. In particular the memory
management rules are different - see the CORBA 2
specification~\cite{corba2-spec} for more details. New instances of these
objects may only be created by the ORB. A number of methods are defined
in {\tt CORBA::ORB} to do this.


\subsection{Request}

A {\tt Request} encapsulates a single operation invocation. It may \emph{not}
be re-used - even for another call with the same arguments.

{\small \begin{verbatim}
class Request {
public:
  virtual Object_ptr        target() const;
  virtual const char*       operation() const;
  virtual NVList_ptr        arguments();
  virtual NamedValue_ptr    result();
  virtual Environment_ptr   env();
  virtual ExceptionList_ptr exceptions();
  virtual ContextList_ptr   contexts();
  virtual Context_ptr       ctxt() const;
  virtual void              ctx(Context_ptr);

  virtual Any& add_in_arg();
  virtual Any& add_in_arg(const char* name);
  virtual Any& add_inout_arg();
  virtual Any& add_inout_arg(const char* name);
  virtual Any& add_out_arg();
  virtual Any& add_out_arg(const char* name);

  virtual void set_return_type(TypeCode_ptr tc);
  virtual Any& return_value();

  virtual Status  invoke();
  virtual Status  send_oneway();
  virtual Status  send_deferred();
  virtual Status  get_response();
  virtual Boolean poll_response();

  static Request_ptr _duplicate(Request_ptr);
  static Request_ptr _nil();
};
\end{verbatim}}


\subsection{NamedValue}

A pair consisting of a string and a value - encapsulated in an Any. The
name is optional. This type is used to encapsulate parameters and returned
values.

{\small \begin{verbatim}
class NamedValue {
public:
  virtual const char* name() const;
  // Retains ownership of return value.

  virtual Any* value() const;
  // Retains ownership of return value.

  virtual Flags flags() const;

  static NamedValue_ptr _duplicate(NamedValue_ptr);
  static NamedValue_ptr _nil();
};
\end{verbatim}}


\subsection{NVList}

A list of {\tt NamedValue} objects.

{\small \begin{verbatim}
class NVList {
public:
  virtual ULong count() const;
  virtual NamedValue_ptr add(Flags);
  virtual NamedValue_ptr add_item(const char*, Flags);
  virtual NamedValue_ptr add_value(const char*, const Any&, Flags);
  virtual NamedValue_ptr add_item_consume(char*,Flags);
  virtual NamedValue_ptr add_value_consume(char*, Any*, Flags);
  virtual NamedValue_ptr item(ULong index);
  virtual Status remove (ULong);

  static NVList_ptr _duplicate(NVList_ptr);
  static NVList_ptr _nil();
};
\end{verbatim}}


\subsection{Context}

Represents a set of context strings. User contexts are not supported by
the omniidl2 IDL compiler - and so cannot be used with statically defined
operations. However they are supported in the DII.

{\small \begin{verbatim}
class Context {
public:
  virtual const char* context_name() const;
  virtual CORBA::Context_ptr parent() const;
  virtual CORBA::Status create_child(const char*, Context_out);
  virtual CORBA::Status set_one_value(const char*, const CORBA::Any&);
  virtual CORBA::Status set_values(CORBA::NVList_ptr);
  virtual CORBA::Status delete_values(const char*);
  virtual CORBA::Status get_values(const char* start_scope,
                                   CORBA::Flags op_flags,
                                   const char* pattern,
                                   CORBA::NVList_out values);
  // Throws BAD_CONTEXT if <start_scope> is not found.
  // Returns a nil NVList in <values> if no matches are found.

  static Context_ptr _duplicate(Context_ptr);
  static Context_ptr _nil();
};
\end{verbatim}}


\subsection{ContextList}

A {\tt ContextList} is a list of strings, and is used to specify which
strings from the 'context' should be sent with an operation.

{\small \begin{verbatim}
class ContextList {
public:
  virtual ULong count() const;
  virtual void add(const char* ctxt);
  virtual void add_consume(char* ctxt);
  // consumes ctxt

  virtual const char* item(ULong index);
  // retains ownership of return value

  virtual Status remove(ULong index);

  static ContextList_ptr _duplicate(ContextList_ptr);
  static ContextList_ptr _nil();
};
\end{verbatim}}


\subsection{ExceptionList}

{\tt ExceptionList}s contain a list of TypeCodes - and are used to specify
which user-defined exceptions an operation may throw.

{\small \begin{verbatim}
class ExceptionList {
public:
  virtual ULong count() const;
  virtual void add(TypeCode_ptr tc);
  virtual void add_consume(TypeCode_ptr tc);
  // Consumes <tc>.

  virtual TypeCode_ptr item(ULong index);
  // Retains ownership of return value.

  virtual Status remove(ULong index);

  static ExceptionList_ptr _duplicate(ExceptionList_ptr);
  static ExceptionList_ptr _nil();
};
\end{verbatim}}


\subsection{UnknownUserException}

When a user-defined exception is thrown by an operation it is unmarshalled
into a value of type Any. This is encapsulated in an
{\tt UnknownUserException}. This type follows all the usual rules for
user-defined exceptions - it is not a pseudo object, and its resources may
be released by using {\tt delete}.

{\small \begin{verbatim}
class UnknownUserException : public UserException {
public:
  UnknownUserException(Any* ex);
  // Consumes <ex> which MUST be a UserException.

  virtual ~UnknownUserException();

  Any& exception();

  virtual void _raise();
  static UnknownUserException* _narrow(Exception*);
};
\end{verbatim}}


\subsection{Environment}

An {\tt Environment} is used to hold an instance of a system exception or
an {\tt UnknownUserException}.

{\small \begin{verbatim}
class Environment {
  virtual void exception(Exception*);
  virtual Exception* exception() const;
  virtual void clear();

  static Environment_ptr _duplicate(Environment_ptr);
  static Environment_ptr _nil();
};
\end{verbatim}}


\section{Creating Requests}

{\tt CORBA::Object} defines three methods which may be used to create a
{\tt Request} object which may be used to perform a single operation
invocation on that object:

{\small \begin{verbatim}
class Object {
  ...
  Status _create_request(Context_ptr ctx,
                         const char* operation,
                         NVList_ptr arg_list,
                         NamedValue_ptr result,
                         Request_out request,
                         Flags req_flags);

  Status _create_request(Context_ptr ctx,
                         const char* operation,
                         NVList_ptr arg_list,
                         NamedValue_ptr result,
                         ExceptionList_ptr exceptions,
                         ContextList_ptr ctxlist,
                         Request_out request,
                         Flags req_flags);

  Request_ptr _request(const char* operation);
  ...
};
\end{verbatim}}

{\tt operation} is the name of the operation - which is the same as the name
given in IDL. To access attributes the name should be prefixed by
{\tt \_get\_} or {\tt \_set\_}.

In the first two cases above the list of parameters may be supplied. If the
parameters are not supplied in these cases, or {\tt \_request()} is used
then the parameters (if any) may be specified using the {\tt add\_*\_arg()}
methods on the {\tt Request}. You must use one method or the other - not
a mixture of the two. For \emph{in}/\emph{inout} arguments the value must be
initialised, for \emph{out} arguments only the type need be given.
Similarly the type of the result may be specified by
passing a {\tt NamedValue} which contains an Any which has been initialised
to contain a value of that type, or it may be specified using the
{\tt set\_return\_type()} method of {\tt Request}.

When using {\tt \_create\_request()}, the management of any pseudo-object
references passed in remains the responsibility of the application. That is,
the values are not consumed - and must be released using
{\tt CORBA::release()}. The CORBA specification is unclear about when these
values may be released, so to be sure of portability do not release them
until after the request has been released.
Values which are not needed need not be supplied - so if no parameters are
specified then it defaults to an empty parameter list. If no result type is
specified then it defaults to void. A {\tt Context} need only be given if
a non-empty {\tt ContextList} is specified. The {\tt req\_flags} argument
is not used in the C++ mapping.


\subsection{Examples}

An operation might be specified in IDL as:

{\small \begin{verbatim}
short anOpn(in string a);
\end{verbatim}}

\noindent{}An operation invocation may be created as follows:

{\small \begin{verbatim}
CORBA::NVList_var args;
CORBA::ORB::create_list(1, args);
*(args->add(CORBA::ARG_IN)->value()) <<= (const char*) "Hello World!";

CORBA::NamedValue_var result;
CORBA::ORB::create_named_value(result);
result->value()->replace(CORBA::_tc_short, 0);

CORBA::Request_var req = obj->_create_request(CORBA::Context::_nil(),
                                        "anOpn", args, result, 0);
\end{verbatim}}

\noindent{}or alternatively and much more concisely:

{\small \begin{verbatim}
CORBA::Request_var req = obj->_request("anOpn");
req->add_in_arg() <<= (const char*) "Hello World!";
req->set_return_type(CORBA::_tc_short);
\end{verbatim}}


\section{Invoking Operations}
\label{dii_invoke}

Once the {\tt Request} object has been properly constructed the operation
may be invoked by calling one of the following methods on the request
object:

\paragraph{invoke()} blocks until the request has completed. The application
should then test to see if an exception was raised. Since the CORBA spec is
not clear about whether or not system exceptions should be thrown from this
method, a runtime configuration variable is supplied so that you can specify
the behavior:
{\small \begin{verbatim}
namespace omniORB {
  ...
  CORBA::Boolean diiThrowsSysExceptions;
  ...
};
\end{verbatim}}
By default this is FALSE, and the application should call the {\tt env()}
method of the request to retrieve an exception (it returns 0 (nil) if no
exception was generated). If it is TRUE then system exceptions will be thrown
out of {\tt invoke()}. User-defined exceptions are always passed via
{\tt env()}, which will return a pointer to a
{\tt CORBA::UnknownUserException}.
The application can determine which type of exception was returned by
{\tt env()}
by calling the {\tt \_narrow()} method defined for each exception type.

After determining that no exception was thrown the application may retrieve
any returned values by calling {\tt return\_value()} and {\tt arguments()}.

\paragraph{send\_oneway()} has the same semantics as a \emph{oneway}
IDL operation. It is important to note that oneway operations have
at-most-once semantics, and it is not guaranteed that they will not
block. Any operation may be invoked 'oneway' using the DII,
even if it was not declared as 'oneway' in IDL. A system exception may be
generated, in which case it will either be thrown or may be retrieved
using {\tt env()} depending on {\tt diiThrowsSysExceptions} as above.

\paragraph{send\_deferred()} initiates the invocation, and then returns
without waiting for the result. At some point in the future the application
must retrieve the result of the operation - but other than testing for
completion of the operation the application must not call any of the
request's methods in the meantime.
\begin{itemize}
\item {\tt get\_response()} blocks until the reply is received.
\item {\tt poll\_response()} returns TRUE if the reply has been received,
      and FALSE if not. It does not block.
\end{itemize}
Once {\tt poll\_response()} has returned TRUE, or {\tt get\_response()}
has been called and returned, the application may test for an exception
and retrieve returned values as above. If {\tt diiThrowsSysExceptions} is
true, then a system exception may be thrown from {\tt get\_response()}.
It is guaranteed that {\tt poll\_response()} will not raise an
exception, so if polling, the application must also call another method
to give the request an opportunity to raise the exception. This can be
one of the methods to retrieve values from the request, or
{\tt get\_response()}.


\section{Multiple Requests}

The following methods are provided by the ORB to enable multiple requests to
be invoked asynchronously.

{\small \begin{verbatim}
namespace CORBA {
  ...
  class ORB {
  public:
    ...
    Status send_multiple_requests_oneway(const RequestSeq&);
    Status send_multiple_requests_deferred(const RequestSeq&);
    Boolean poll_next_response();
    Status get_next_response(Request_out);
    ...
  };
  ...
};
\end{verbatim}}

\paragraph{send\_multiple\_requests\_oneway()} is used to invoke a number
of oneway requests. An attempt will be
made to invoke each of the requests, even if one or more of the early
requests fails.
The application may check for failure of any of the requests by testing
the request's {\tt env()} method. System exceptions are never raised by
this method.

\paragraph{send\_multiple\_requests\_deferred()} will initiate an invocation
of each of the given requests, and return without waiting for the reply.
At some point in the future the application must retrieve the reply by
calling {\tt get\_next\_response()}, which returns a completed request.
If no requests have yet completed it will block.
This method never throws exceptions - the request's {\tt env()}
method must be used to determine if an exception was generated. If not
then any returned values may then be queried.

{\tt poll\_next\_response()} returns TRUE if there are any completed requests,
and FALSE otherwise, without blocking. If this returns true then the next call
to {\tt get\_next\_response()} will not block. However, if another
thread may also be calling {\tt get\_next\_response()} then it could retrieve
the completed message first - in which case this thread might block.

There are no guarantee as to the order in which replies will be received.
If multiple threads are using this interface then it is not even guaranteed
that a thread will receive replies to the requests it sent. Any thread may
receive replies to requests sent by any other thread. It is legal to call
{\tt get\_next\_response()} even if no requests have yet been invoked - in
which case the calling thread blocks until another thread invokes a request
and the reply is received.


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\chapter{The Dynamic Skeleton Interface}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

The Dynamic Skeleton Interface (or DSI) allows applications to provide
implementations of the operations on CORBA objects without static
knowledge of the object's interface. It is the server-side equivalent of the
Dynamic Invocation Interface.

This chapter presents the Dynamic Skeleton Interface and explains how to
use it.
An toy example use of the DSI can be found in the omniORB2 distribution in
the {\tt <top>/src/examples/dsi} directory.
For further information refer to the Dynamic Skeleton Interface
and C++ Mapping sections of the CORBA 2 specification~\cite{corba2-spec}.


\section{Overview}

When an ORB receives an invocation request, the information includes
the object reference and the name of the operation. Typically this information
is used by the
ORB to select an instance of an object and call into the implementation of
the operation (which knows how to unmarshal the parameters etc.).
The Dynamic Skeleton Interface however makes this
information directly available to the application - so that it can
implement the operation (or pass it on to another server) without static
knowledge of the interface. In fact it is not even necessary for the server
to always implement the same interface on any particular object!

To provide an implementation for one or more objects an application must
sub-class {\tt DynamicImplementation} and override the method {\tt invoke()}.
An instance of this class is registered with the BOA and is assigned an
object reference (see below). When the ORB receives a request for that
object the {\tt invoke()} method is called and will be passed a
{\tt ServerRequest} object which provides:
\begin{itemize}
\item the operation name
\item context strings
\item access to the parameters
\item a way to set the returned values
\item a way to throw user-defined exceptions.
\end{itemize}


\section{DSI Types}

\subsection{DynamicImplementation}

This class must be sub-classed by the application to provide an implementation
for DSI objects. The method {\tt invoke()} will be called for each operation
invocation.

{\small \begin{verbatim}
namespace CORBA {
  ...
  class BOA {
    ...
    class DynamicImplementation {
    public:
      DynamicImplementation();
      virtual ~DynamicImplementation();

      virtual void invoke(ServerRequest_ptr request,
                          Environment& env) throw() = 0;

    protected:
      Object_ptr _this();
      // Must only be called from within invoke(). Caller must release
      // the reference returned.

      BOA_ptr _boa();
      // Must only be called from within invoke(). Caller must NOT
      // release the reference returned.
    };
    ...
  };
  ...
};
\end{verbatim}}


\subsection{ServerRequest}

A {\tt ServerRequest} object provides the interface between a dynamic
implementation and the ORB.

{\small \begin{verbatim}
namespace CORBA {
  ...
  class ServerRequest {
  public:
    virtual const char*      op_name();
    virtual OperationDef_ptr op_def();
    virtual Context_ptr      ctx();
    virtual void             params(NVList_ptr parameters);
    virtual void             result(Any* value);
    virtual void             exception(Any* value);

    static ServerRequest_ptr _duplicate(ServerRequest_ptr);
    static ServerRequest_ptr _nil();
  };
  ...
};
\end{verbatim}}


\section{Creating Dynamic Implementations}

The application must override the {\tt invoke()} method of
{\tt DynamicImplementation} to provide an implementation for DSI objects.
This method must behave as follows:

\begin{itemize}
\item It may be called concurrently by multiple threads of execution, and
so must be thread-safe.
\item It may not throw any exceptions. User-defined exceptions are passed
in a value of type Any and given to
{\tt ServerRequest::exception()}, and system exceptions may be
passed via the {\tt env} parameter. Since the methods provided by
{\tt ServerRequest} may throw system exceptions, the application must catch
any such exception, duplicate it and place the value in {\tt env}.
\item The operations on the {\tt ServerRequest} object must be carried out
in the correct order, as described below.
\end{itemize}


\subsection{Operations on the ServerRequest}

{\tt op\_name()} will return the name of the operation, and may be called at
any time. For attribute access the operation name is the IDL name of the
attribute, prefixed by {\tt \_get\_} or {\tt \_set\_}. If the operation name
is not recognised a {\tt CORBA::BAD\_OPERATION} exception should be passed
back through {\tt env}. This will allow the ORB to then see if it is one of
the standard object operations.

Firstly {\tt params()} must be called passing a
{\tt CORBA::NVList}\footnote{obtained by calling {\tt
CORBA::ORB::create\_list()}}
which must be initialised to contain the type and mode of the parameters.
The ORB consumes this
value and will release it when the operation is complete. At this point any
\emph{in}/\emph{inout} arguments will be unmarshalled, and when this operation
returns their values will be in the {\tt NVList}. The application may set
the value of \emph{inout}/\emph{out} arguments by modifying this
parameter list.

If the operation has user-context information, then {\tt ctx()} must be
called after {\tt params()} to retrieve it.

{\tt result()} must then be called exactly once if the operation has a non-void
return value (unless an exception is thrown). The value passed should be
an Any allocated with {\tt new}, and will be freed by the ORB.

At any point in the above sequence {\tt exception()} may be called to set
a user-defined exception, or a system exception may be inserted into
the {\tt env} parameter of the {\tt invoke()} method. If this happens then no
further operations should be invoked on the {\tt ServerRequest} object, and
the {\tt invoke()} method should return.

Within the {\tt invoke()} method {\tt \_this()} and {\tt \_boa()} may be
called to obtain the object reference and BOA reference respectively. These
methods may not be used at any other time.


\section{Registering Dynamic Objects}

To use a {\tt DynamicImplementation} a CORBA object must be created and
associated with the implementation. The way in which this is done is not
defined by the CORBA 2.0 specification, so the following method is omniORB2
specific:

{\small \begin{verbatim}
namespace CORBA {
  ...
  class BOA {
    ...
    Object_ptr create_dynamic_object(DynamicImplementation_ptr dir,
                                     const char* intfRepoId);
    ...
  };
  ...
};
\end{verbatim}}

Ownership of the {\tt DynamicImplementation} object is taken over by the ORB,
and it will be deleted when associated the object is destroyed.
The returned object may then be entered into the object table with a call to
{\tt BOA::obj\_is\_ready()} as usual, and will then start accepting operation
invocations.

For some applications it will not be possible to register all DSI objects
in advance of invocations arriving. In this case DSI objects can be
created on demand in the same way as normal objects - see
section~\ref{load_on_demand}.


\section{Example}

This implementation of {\tt DynamicImplementation::invoke()} is taken from
an example which can be found in the omniORB2 distribution. The operation
``echoString'' is declared in IDL as:

{\small \begin{verbatim}
string echoString(in string mesg);
\end{verbatim}}

\noindent{}Here is the Dynamic Implementation Routine:

{\small \begin{verbatim}
void
MyDynImpl::invoke(CORBA::ServerRequest_ptr request, CORBA::Environment& env)
  throw()
{
  try {
    if( strcmp(request->op_name(), "echoString") )
      throw CORBA::BAD_OPERATION(0, CORBA::COMPLETED_NO);

    CORBA::NVList_ptr args;
    orb->create_list(0, args);
    CORBA::Any a;
    a.replace(CORBA::_tc_string, 0);
    args->add_value("", a, CORBA::ARG_IN);

    request->params(args);

    CORBA::Any& input_any = *(args->item(0)->value());
    CORBA::String_var input;
    input_any >>= input.out();

    CORBA::Any* result = new CORBA::Any();
    *result <<= CORBA::Any::from_string(input._retn(), 0);
    request->result(result);
  }
  catch(CORBA::SystemException& ex){
    env.exception(CORBA::Exception::_duplicate(&ex));
  }
  catch(...){
    cout << "echo_dsiimpl: MyDynImpl::invoke - caught an"
        " unknown exception." << endl;
    env.exception(new CORBA::UNKNOWN(0, CORBA::COMPLETED_NO));
  }
}
\end{verbatim}}



\appendix
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\chapter{hosts\_access(5)}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\subsection*{DESCRIPTION}

This manual page describes a simple access control language that is
based on client (host name/address, user name), and server (process
name, host name/address) patterns.  Examples are given at the end. The
impatient reader is encouraged to skip to the EXAMPLES section for a
quick introduction.

An extended version of the access control language is described in the
hosts\_options(5) document. The extensions are turned on at
program build time by building with -DPROCESS\_OPTIONS.

In the following text, {\em daemon} is the the process name of a
network daemon process, and {\em client} is the name and/or address of
a host requesting service. Network daemon process names are specified
in the inetd configuration file.

\subsection*{ACCESS CONTROL FILES}

The access control software consults two files. The search stops
at the first match:

\begin{itemize}
\item Access will be granted when a (daemon,client) pair matches an entry in
the {\tt /etc/hosts.allow} file.

\item Otherwise, access will be denied when a (daemon,client) pair matches an
entry in the {\tt /etc/hosts.deny} file.

\item Otherwise, access will be granted.

\end{itemize}

A non-existing access control file is treated as if it were an empty
file. Thus, access control can be turned off by providing no access
control files.

\subsection*{ACCESS CONTROL RULES}

Each access control file consists of zero or more lines of text.  These
lines are processed in order of appearance. The search terminates when a
match is found.

\begin{itemize}

\item A newline character is ignored when it is preceded by a backslash
character. This permits you to break up long lines so that they are
easier to edit.

\item Blank lines or lines that begin with a {\tt \#} character are ignored.
This permits you to insert comments and whitespace so that the tables
are easier to read.

\item All other lines should satisfy the following format, things between []
being optional: {\tt daemon\_list : client\_list [ : shell\_command ] }

\end{itemize}

{\tt daemon\_list} is a list of one or more daemon process names
(argv[0] values) or wildcards (see below).  

{\tt client\_list} is a list
of one or more host names, host addresses, patterns or wildcards (see
below) that will be matched against the client host name or address.

The more complex forms {\tt daemon@host} and {\tt user@host} are
explained in the sections on server endpoint patterns and on client
username lookups, respectively.

List elements should be separated by blanks and/or commas.  

With the exception of NIS (YP) netgroup lookups, all access control
checks are case insensitive.

\subsection*{PATTERNS}

The access control language implements the following patterns:

\begin{itemize}

\item A string that begins with a {\tt .} character. A host name is matched if
the last components of its name match the specified pattern.  For
example, the pattern {\tt .tue.nl} matches the host name
{\tt wzv.win.tue.nl}.

\item A string that ends with a {\tt .} character. A host address is matched if
its first numeric fields match the given string.  For example, the
pattern {\tt 131.155.} matches the address of (almost) every host on the
Eindhoven University network ({\tt 131.155.x.x}).

\item A string that begins with an {\tt \@} character is treated as an NIS
(formerly YP) netgroup name. A host name is matched if it is a host
member of the specified netgroup. Netgroup matches are not supported
for daemon process names or for client user names.

\item An expression of the form {\tt n.n.n.n/m.m.m.m} is interpreted as a
``net/mask'' pair. A host address is matched if ``net'' is equal to the
bitwise AND of the address and the ``mask''. For example, the net/mask
pattern {\tt 131.155.72.0/255.255.254.0} matches every address in the
range {\tt 131.155.72.0} through {\tt 131.155.73.255}.

\end{itemize}

\subsection*{WILDCARDS}

The access control language supports explicit wildcards:

\begin{description}
\item[\tt ALL] The universal wildcard, always matches.
\item[\tt LOCAL] Matches any host whose name does not contain a dot character.
\item[\tt UNKNOWN] 
Matches any user whose name is unknown, and matches any host whose name
or address are unknown.  This pattern should be used with care:
host names may be unavailable due to temporary name server problems. A
network address will be unavailable when the software cannot figure out
what type of network it is talking to.
\item[\tt KNOWN]
Matches any user whose name is known, and matches any host whose name
and address are known. This pattern should be used with care:
host names may be unavailable due to temporary name server problems.  A
network address will be unavailable when the software cannot figure out
what type of network it is talking to.
\item[\tt PARANOID]
Matches any host whose name does not match its address.  When tcpd is
built with -DPARANOID (default mode), it drops requests from such
clients even before looking at the access control tables.  Build
without -DPARANOID when you want more control over such requests.

\end{description}

\subsection*{OPERATORS}

\begin{description}

\item[\tt EXCEPT]
Intended use is of the form: {\tt list\_1 EXCEPT list\_2}; this construct
matches anything that matches {\tt list\_1} unless it matches
{\tt list\_2}.  The {\tt EXCEPT} operator can be used in {\tt daemon\_lists} and in
{\tt client\_lists}. The {\tt EXCEPT} operator can be nested: if the control
language would permit the use of parentheses, {\tt a EXCEPT b EXCEPT c}
would parse as {\tt (a EXCEPT (b EXCEPT c))}.

\end{description}

\subsection*{SHELL COMMANDS}

If the first-matched access control rule contains a shell command, that
command is subjected to {\tt \%<letter>} substitutions (see next section).
The result is executed by a /bin/sh child process with standard
input, output and error connected to /dev/null.  Specify an {\tt \&}
at the end of the command if you do not want to wait until it has
completed.

Shell commands should not rely on the PATH setting of the inetd.
Instead, they should use absolute path names, or they should begin with
an explicit PATH=whatever statement.

The hosts\_options(5) document describes an alternative language
that uses the shell command field in a different and incompatible way.

\subsection*{\% EXPANSIONS}

The following expansions are available within shell commands:

\begin{itemize}

\item[\tt \%a (\%A)] The client (server) host address.
\item[\tt \%c] Client information: user@host, user@address, a host name, or just an
address, depending on how much information is available.
\item[\tt \%d] The daemon process name (argv[0] value).
\item[\tt \%h (\%H)]
The client (server) host name or address, if the host name is
unavailable.
\item[\tt \%n (\%N)] The client (server) host name (or "unknown" or "paranoid").
\item[\tt \%p] The daemon process id.
\item[\tt \%s]  Server information: daemon@host, daemon@address, or just a daemon name,
depending on how much information is available.
\item [\tt \%u] The client user name (or "unknown").
\item [\tt \%\%] Expands to a single {\tt \%} character.

\end{itemize}

Characters in \% expansions that may confuse the shell are replaced by
underscores.

\subsection*{SERVER ENDPOINT PATTERNS}

In order to distinguish clients by the network address that they
connect to, use patterns of the form:

{\tt process\_name@host\_pattern : client\_list ... }

Patterns like these can be used when the machine has different internet
addresses with different internet hostnames.  Service providers can use
this facility to offer FTP, GOPHER or WWW archives with internet names
that may even belong to different organisations. See also the ``twist''
option in the hosts\_options(5) document. Some systems (Solaris,
FreeBSD) can have more than one internet address on one physical
interface; with other systems you may have to resort to SLIP or PPP
pseudo interfaces that live in a dedicated network address space.
.sp
The {\tt host\_pattern} obeys the same syntax rules as host names and
addresses in {\tt client\_list} context. Usually, server endpoint information
is available only with connection-oriented services.


\subsection*{CLIENT USERNAME LOOKUP}

When the client host supports the RFC 931 protocol or one of its
descendants (TAP, IDENT, RFC 1413) the wrapper programs can retrieve
additional information about the owner of a connection. Client username
information, when available, is logged together with the client host
name, and can be used to match patterns like:

{\tt daemon\_list : ... user\_pattern@host\_pattern ...}

The daemon wrappers can be configured at compile time to perform
rule-driven username lookups (default) or to always interrogate the
client host.  In the case of rule-driven username lookups, the above
rule would cause username lookup only when both the {\tt daemon\_list}
and the {\tt host\_pattern} match. 

A user pattern has the same syntax as a daemon process pattern, so the
same wildcards apply (netgroup membership is not supported).  One
should not get carried away with username lookups, though.

\begin{itemize}

\item The client username information cannot be trusted when it is needed
most, i.e. when the client system has been compromised.  In general,
ALL and (UN)KNOWN are the only user name patterns that make sense.

\item Username lookups are possible only with TCP-based services, and only
when the client host runs a suitable daemon; in all other cases the
result is ``unknown''.

\item A well-known UNIX kernel bug may cause loss of service when username
lookups are blocked by a firewall. The wrapper README document
describes a procedure to find out if your kernel has this bug.

\item Username lookups may cause noticeable delays for non-UNIX users.  The
default timeout for username lookups is 10 seconds: too short to cope
with slow networks, but long enough to irritate PC users.

\end{itemize}

Selective username lookups can alleviate the last problem. For example,
a rule like:

{\tt daemon\_list : @pcnetgroup ALL@ALL }

would match members of the pc netgroup without doing username lookups,
but would perform username lookups with all other systems.

\subsection*{DETECTING ADDRESS SPOOFING ATTACKS}

A flaw in the sequence number generator of many TCP/IP implementations
allows intruders to easily impersonate trusted hosts and to break in
via, for example, the remote shell service.  The IDENT (RFC931 etc.)
service can be used to detect such and other host address spoofing
attacks.

Before accepting a client request, the wrappers can use the IDENT
service to find out that the client did not send the request at all.
When the client host provides IDENT service, a negative IDENT lookup
result (the client matches {\tt UNKNOWN@host}) is strong evidence of a host
spoofing attack.

A positive IDENT lookup result (the client matches {\tt KNOWN@host}) is
less trustworthy. It is possible for an intruder to spoof both the
client connection and the IDENT lookup, although doing so is much
harder than spoofing just a client connection. It may also be that
the client's IDENT server is lying.

Note: IDENT lookups don't work with UDP services. 

\subsection*{EXAMPLES}

The language is flexible enough that different types of access control
policy can be expressed with a minimum of fuss. Although the language
uses two access control tables, the most common policies can be
implemented with one of the tables being trivial or even empty.

When reading the examples below it is important to realise that the
allow table is scanned before the deny table, that the search
terminates when a match is found, and that access is granted when no
match is found at all.

The examples use host and domain names. They can be improved by
including address and/or network/netmask information, to reduce the
impact of temporary name server lookup failures.

\subsection*{MOSTLY CLOSED}

In this case, access is denied by default. Only explicitly authorised
hosts are permitted access. 

The default policy (no access) is implemented with a trivial deny
file:

{\small
\begin{verbatim}
/etc/hosts.deny:
    ALL: ALL
\end{verbatim}
}

This denies all service to  all  hosts,  unless  they  are
permitted access by entries in the allow file.

The  explicitly  authorised  hosts are listed in the allow file.
For example:

{\small
\begin{verbatim}
/etc/hosts.allow:
   ALL: LOCAL @some_netgroup
   ALL: .foobar.edu EXCEPT terminalserver.foobar.edu
\end{verbatim}
}

The first rule permits access from hosts in the local domain (no .
in the host name) and from members of the {\tt some\_netgroup}
netgroup.  The second rule permits access from all hosts in the
{\tt foobar.edu} domain (notice the leading dot), with the exception of
{\tt terminalserver.foobar.edu}.

\subsection*{MOSTLY OPEN}

Here, access is granted by default; only explicitly specified hosts are
refused service. 

The default policy (access granted) makes the allow file redundant so
that it can be omitted.  The explicitly non-authorised hosts are listed
in the deny file. For example:

{\small
\begin{verbatim}
/etc/hosts.deny:
   ALL: some.host.name, .some.domain
   ALL EXCEPT in.fingerd: other.host.name, .other.domain
\end{verbatim}
}

The first rule denies some hosts and domains all services; the second
rule still permits finger requests from other hosts and domains.


\subsection*{BOOBY TRAPS}

The next example permits tftp requests from hosts in the local domain
(notice the leading dot).  Requests from any other hosts are denied.
Instead of the requested file, a finger probe is sent to the offending
host. The result is mailed to the superuser.

{\small
\begin{verbatim}

/etc/hosts.allow:
   in.tftpd: LOCAL, .my.domain

/etc/hosts.deny:
   in.tftpd: ALL: (/some/where/safe\_finger -l @%h | \
       /usr/ucb/mail -s %d-%h root) &
\end{verbatim}
}

The {\tt safe\_finger} command comes with the tcpd wrapper and should be
installed in a suitable place. It limits possible damage from data sent
by the remote finger server.  It gives better protection than the
standard finger command.

The expansion of the \%h (client host) and \%d (service name) sequences
is described in the section on shell commands.

Warning: do not booby-trap your finger daemon, unless you are prepared
for infinite finger loops.

On network firewall systems this trick can be carried even further.
The typical network firewall only provides a limited set of services to
the outer world. All other services can be "bugged" just like the above
tftp example. The result is an excellent early-warning system.

\subsection*{DIAGNOSTICS}

An error is reported when a syntax error is found in a host access
control rule; when the length of an access control rule exceeds the
capacity of an internal buffer; when an access control rule is not
terminated by a newline character; when the result of %<letter>
expansion would overflow an internal buffer; when a system call fails
that shouldn\'t.  All problems are reported via the syslog daemon.


\subsection*{FILES}

\noindent {\tt /etc/hosts.allow}, (daemon,client) pairs that are granted access.

\noindent {\tt /etc/hosts.deny}, (daemon,client) pairs that are denied access.

\subsection*{SEE ALSO}

\noindent tcpd(8) tcp/ip daemon wrapper program.

\noindent tcpdchk(8), tcpdmatch(8), test programs.

\subsection*{BUGS}

If a name server lookup times out, the host name will not be available
to the access control software, even though the host is registered.

Domain name server lookups are case insensitive; NIS (formerly YP)
netgroup lookups are case sensitive.

\subsection*{AUTHOR}

Wietse Venema (wietse@wzv.win.tue.nl)\\
Department of Mathematics and Computing Science\\
Eindhoven University of Technology\\
Den Dolech 2, P.O. Box 513,\\
5600 MB Eindhoven, The Netherlands\\

\backmatter

\begin{thebibliography}{tjr96}

\bibitem[OMG96a]{corba2-spec} 
{\em The Common Object Request Broker: Architecture and
  Specification}, 
Revision 2.0, 
OMG,
Updated July 1996.

\bibitem[OMG96b]{corbaservices} 
{\em CORBAservices: Common Object Services Specification},
OMG,
Updated July 1996.

\bibitem[Richardson96a]{tjr96a}
{\em The OMNI Thread Abstraction},
Tristan Richardson, ORL, 22 October 1996.

\bibitem[Richardson96b]{tjr96b}
{\em The OMNI Development Environment Version 4.0},
Tristan Richardson, ORL, 5 November 1996.

\end{thebibliography}

\end{document}
