## Asynchronous Remote Calls

### Asynchronous remote call invocation

Asynchronous remote calls allow you to initate remote calls on one thread, and have them complete asynchronously on another thread.

Asynchronous remote calls are implemeted in RCF using the `RCF::Future<>` template. Given an RCF interface:

    RCF_BEGIN(I_HelloWorld, "I_HelloWorld")

        // Returns number of characters printed.
        RCF_METHOD_R1(int, Print, const std::string &)

    RCF_END(I_HelloWorld)

, an asynchronous call is made by specifying one or more `RCF::Future<>` arguments. For example:

    RcfClient<I_HelloWorld> client(( RCF::TcpEndpoint(port) ));
    RCF::Future<int> fRet = client.Print("Hello World");

The thread that executes this code will return immediately. It can subsequently poll for completion:

    // Poll until remote call completes.
    while (!fRet.ready())
    {
        RCF::sleepMs(500);
    }

, or it can wait for completion:

    // Wait for remote call to complete.
    fRet.wait();

Once the call is complete, the return values can be recovered from the relevant `Future<>` instances:

    int charsPrinted = *fRet;

If the call resulted in an error, the error will be thrown when the `Future<>` instance is dereferenced, as above. Alternatively, the error can be retrieved by calling `Future<>::getAsyncException()`:

    std::auto_ptr<RCF::Exception> ePtr = fRet.getAsyncException();

Instead of polling or waiting, the thread that initiates an asynchronous remote call can provide a completion callback that will be called by the RCF runtime, on a background thread, when the call completes:

    typedef boost::shared_ptr< RcfClient<I_HelloWorld> > HelloWorldPtr;
    void onCallCompleted(HelloWorldPtr client, RCF::Future<int> fRet)
    {
        std::auto_ptr<RCF::Exception> ePtr = fRet.getAsyncException();
        if (ePtr.get())
        {
            // Deal with any exception.
            // ...
        }
        else
        {
            int charsPrinted = *fRet;
            // ...
        }
    }

    RCF::Future<int> fRet;
    HelloWorldPtr client( new RcfClient<I_HelloWorld>(RCF::TcpEndpoint(port)) );
    fRet = client->Print(
        RCF::AsyncTwoway( boost::bind(&onCallCompleted, client, fRet)),
        "Hello World");

Notice that the `Future<>` arguments are passed as arguments to the completion callback function. `Future<>` objects are internally reference counted, and can be copied freely, while still referring to the same underlying value.

An asynchronous call in progress can be canceled by disconnecting the client:

    client.getClientStub().disconnect();

If a `RcfClient` is destroyed while an asynchronous call is in progress, the call is automatically disconnected and any asynchronous operations are canceled.

### Asynchronous remote call dispatching

On the server-side, RCF will normally dispatch a remote call on the same server thread that receives the remote call request from the transport. Asynchronous dispatching allows you to instead transfer the remote call over to other threads, freeing up the RCF thread to process other remote calls.

The `RCF::RemoteCallContext<>` class is used to capture the server-side context of a remote call. `RemoteCallContext<>` objects can be copied into queues and stored for later execution on arbitrary application threads.

`RemoteCallContext<>` objects are created from within the corresponding servant implemenation method. Here is a non-asynchronously dispatched `Print()` method:

    RCF_BEGIN(I_HelloWorld, "I_HelloWorld")

        // Returns number of characters printed.
        RCF_METHOD_R1(int, Print, const std::string &)

    RCF_END(I_HelloWorld)

    class HelloWorldImpl
    {
    public:
        int Print(const std::string & s)
        {
            std::cout << "I_HelloWorld service: " << s << std::endl;
            return s.length();
        }
    };

To instead dispatch the call asynchronously, a `RemoteCallContext<>` object is created in `Print()`, with template parameters corresponding to the method signature:

    class HelloWorldImpl
    {
    public:

        typedef RCF::RemoteCallContext<int, const std::string&> PrintContext;

        int Print(const std::string & s)
        {
            // Capture current remote call context.
            PrintContext printContext(RCF::getCurrentRcfSession());

            // Create a new thread to dispatch the remote call.
            RCF::ThreadPtr threadPtr( new RCF::Thread( boost::bind(
                &HelloWorldImpl::threadFunc,
                this,
                printContext) ) );

            return 0;
        }

        void threadFunc(PrintContext printContext)
        {
            const std::string & s = printContext.parameters().a1.get();
            std::cout << "I_HelloWorld service: " << s << std::endl;
            printContext.parameters().r.set( s.length() );
            printContext.commit();
        }
    };

Once created, the `RemoteCallContext<>` can be stored and copied like any other C++ object. When the `Print()` function returns, RCF will not send a response to the client. The response will only be sent when `RemoteCallContext<>::commit()` is called.

`RemoteCallContext::parameters()` provides access to all the parameters of the remote call, including the return value. We can access in parameters:

    const std::string & s = printContext.parameters().a1.get();

, and set out parameters (in this case the return value):

    printContext.parameters().r.set( s.length() );