This is a simple example of a peer-to-peer application that uses
nested function calls.

"Peer_impl" implements the "decrement" operation of the interface
"Peer" as follows: First, "inout long value" is printed, then
decremented. If the decremented value is larger than zero, the
"decrement" operation will be called on the object reference "in Peer
peer".

The process "peer1" must be started first. It creates a new
"Peer_impl", saves the IOR of this object in the file "Peer.ref" and
than enters the dispatch loop with "impl_is_ready".

The "peer2" process, which must be started next, creates a new "Peer_impl"
(p2) and loads the IOR of the "peer1" process (p1).

The user can now enter a number. With this number and the "p2" object
reference as argument, the "decrement" operation of the "p1" object
reference is called (which resides in process "peer1"). This operation
will print the passed value and then call the "decrement" operation of
"p2" in the "peer2" process. This will continue until the value is
decremented to zero. For example, if the user enters the number 3,
the calling tree looks like this:

Process Peer2             Process Peer1             Process Peer2
main()                    Reference p1              Reference p2

    |                          |                          |
    | p1 -> decrement(3, p2)   |                          |
    | -----------------------> |                          |
    |                          |                          |
    |                       prints 3                      |
    |                          |                          |
    |                          | p2 -> decrement(2, p1)   |
    |                          | -----------------------> |
    |                          |                          |
    |                          |                       prints 2
    |                          |                          |
    |                          |   p1 -> decrement(1, p2) |
    |                          | <----------------------- |
    |                          |                          |
    |                       prints 1                      |
    |                          |                          |
    |                          | return                   |
    |                          | -----------------------> |
    |                          |                          |
    |                          |                          |
    |                          |                          |
    |                          |                   return |
    |                          | <----------------------- |
    |                          |                          |
    |                          |                          |
    |                          |                          |
    |                   return |                          |
    | <----------------------- |                          |

As you can see, with ORBacus it is possible to make nested function
calls even if the functions are implemented in two different
processes. To use this feature, the following concurrency model
combinations can be used:

	For the ORB:	For the BOA:
(1)	reactive	reactive
(2)	threaded        thread per request

To use concurrency model (1), the options -ORBreactive and -OAreactive can
be used, or the operations

CORBA_ORB::thread_model(CORBA_ORB::ConcModelReactive)
CORBA_BOA::thread_model(CORBA_BOA::ConcModelReactive)

must be called. To use concurrency model (2), either the options
-ORBthreaded and -OAthread_per_request must be used or the operations

CORBA_ORB::thread_model(CORBA_ORB::ConcModelThreaded)
CORBA_BOA::thread_model(CORBA_BOA::ConcModelThreadPerRequest)

must be called. 

Especially (1) is very useful. (1) disables multi threading completely,
but nevertheless allows nested methods calls, though there is only a
single thread of execution.

Note that there are limits for the maximum nesting level. If (1) is
used, the maximum nesting level depends on the available per-process
stack size. If (2) is selected, the maximum nesting level depends on
the maximum number of threads per process. (1) usually offers a
considerably higher maximum nesting level than (2). Typical values
are > 10000 for (1) and < 500 for (2). (1) has also the advantage of
usually being much faster than (2), due to the overhead involved for
starting and terminating threads.

