<!-- ** xmlrpc client and server

     $Id: sect_xmlrpc_client_server.docbook 801 2005-07-17 12:56:42Z ewald-arnold $
-->

<sect1 id="xmlrpc-client-server">
<title>Communicating via &xmlrpc;</title>

<sect2 id="xmlrpc-server">
<title>The Server</title>

<para>A minimal implementation comprises a mechanism that waits for a call, dispatches it
to the desired function and finally returns the method result.</para>

<para>The following examples omit error checking for ease of understanding.
A connection is established and the call is processed.

<programlisting>

  TcpIpConnection conn (0x7f000001, 32000); <co id="xmlrpc-server-co" linkends="xmlrpc-server-link" />
  HttpProtocol prot(&amp;conn);
  Dispatcher server(&amp;prot);

  server.addMethod(&amp;testcall,
                   "struct",
                   "testcall",
                   "int",
                   "Returns input, difference and result");

  server.addMethod(&amp;testcall_with_many_params,
                   "struct",
                   "testcall_with_many_params",
                   Signature() &lt;&lt; Integer() <co id="xmlrpc-server-sig-co" linkends="xmlrpc-server-sig-link" />
                               &lt;&lt; String()
                               &lt;&lt; Double(),
                   "Performs action xyz");

  MethodCall call = server.waitForCall();
  MethodResponse resp = server.dispatchCall(call);
  server.sendResponse(resp);

</programlisting>

<calloutlist>

 <callout arearefs="xmlrpc-server-co" id="xmlrpc-server-link">
  <para>Expect calls to 127.0.0.1 (known as <emphasis>localhost</emphasis>).</para>
 </callout>

 <callout arearefs="xmlrpc-server-sig-co" id="xmlrpc-server-sig-link">
  <para>If you have methods that take more than one or two parameters it is an error prone taks to create
  the needed signature string manually. For that purpose there is a class
  <classname>Signature</classname> that handles the parameters and generates the signature strings.
  It is also possible to "stream-in" the parameters.</para>
 </callout>

</calloutlist>

</para>

<para>And now the method that does to real work. In the following example it just takes a
number as input, adds a constant value of 1111 and returns a <classname>Struct</classname> that
contains the original value, the difference and the result.

<programlisting>

  MethodResponse testcall (const MethodCall &amp;calldata)
  {
    Integer i = calldata.getParam(0);

    Struct st;

    st.addMember("before", i);
    st.addMember("difference", Integer(1111));
    st.addMember("after", Integer(i.getInteger()+1111));

    return MethodResponse(st);
  }

</programlisting>

</para>

<para>The &xmlrpc; method may also also be implemented as a normal class method. To
access it you need some wrapper function. By using <function>make_method</function>
this is done automatically. For convenience and clearity there is also a
<function>make_method</function> for static class methods or simple functions.

<programlisting>

  class TestWorker
  {
    public:

      TestWorker ()
      {}

      MethodResponse testmethod (const MethodCall &amp;calldata) <co id="xmlrpc-server-method-co" linkends="xmlrpc-server-method-link" />
      {
        ...
      }
  };

  MethodResponse testfunction (const MethodCall &amp;calldata)  <co id="xmlrpc-server-function-co" linkends="xmlrpc-server-function-link" />
  {
      ....
  }

  server.addMethod(make_method(&amp;testfunction),  <co id="xmlrpc-server-add-function-co" linkends="xmlrpc-server-add-function-link" />
                    Signature(Integer()),
                    "testcall_function",
                    Signature(Integer())
                          .addParam(Integer()),
                    "Testcase with a c-function");


  TestWorker worker;
  server.addMethod(make_method(worker, &amp;TestWorker::testmethod),  <co id="xmlrpc-server-add-method-co" linkends="xmlrpc-server-add-method-link" />
                    Signature(Struct()),
                    "testcall_in_class_dynamic",
                    Signature(Integer()),
                    "Testcase with a dynamic method in a class");

</programlisting>

<calloutlist>

 <callout arearefs="xmlrpc-server-method-co" id="xmlrpc-server-method-link">
  <para>Implement the &xmlrpc; method as a non-static method of a class.</para>
 </callout>

 <callout arearefs="xmlrpc-server-function-co" id="xmlrpc-server-function-link">
  <para>Implement the &xmlrpc; method with a C-style function.</para>
 </callout>

 <callout arearefs="xmlrpc-server-add-method-co" id="xmlrpc-server-add-method-link">
  <para>Add the method together with the according object to the server.</para>
 </callout>

 <callout arearefs="xmlrpc-server-add-function-co" id="xmlrpc-server-add-function-link">
  <para>Add the function to the server. This approach also applies to static methods of
  a class.</para>
 </callout>

</calloutlist>


</para>

</sect2>

<sect2 id="xmlrpc-client">
<title>The Client</title>

<para>Connecting with a client needs some simple steps:

<programlisting>

  TcpIpConnection conn ("localhost", 32000); <co id="xmlrpc-client-connection-co" linkends="xmlrpc-client-connection-link" />
  HttpProtocol prot(&amp;conn);
  Requester client(&amp;prot);

  MethodCall testcall ("testcall");  <co id="xmlrpc-client-setup-co" linkends="xmlrpc-client-setup-link" />
  testcall.addParam(Integer(123));

  MethodResponse resp = client.call(testcall); <co id="xmlrpc-client-call-co" linkends="xmlrpc-client-call-link" />
  cout &lt;&lt; "call result: \n" <co id="xmlrpc-client-process-co" linkends="xmlrpc-client-process-link" />
       &lt;&lt; resp.getXml(0);

</programlisting>

<calloutlist>

 <callout arearefs="xmlrpc-client-connection-co" id="xmlrpc-client-connection-link">
  <para>As always: set up the connection.</para>
 </callout>

 <callout arearefs="xmlrpc-client-setup-co" id="xmlrpc-client-setup-link">
  <para>Select the desired method by its name. In the example the method takes one
  parameter which is an <classname>Integer</classname>.</para>
 </callout>

 <callout arearefs="xmlrpc-client-call-co" id="xmlrpc-client-call-link">
  <para>Send the call and wait for the response.</para>
 </callout>

 <callout arearefs="xmlrpc-client-process-co" id="xmlrpc-client-process-link">
  <para>The example does no further processing but just shows the result as &xml;
  output.</para>
 </callout>

</calloutlist>

</para>
</sect2>

<sect2 id="xmlrpc-async">
<title>Asynchronous Communication</title>

<para>Usually a client sends a request to the server and waits for the response.
But in rare cases you may want to send a call without the need to check
for a response, maybe because the result is of type <type>void</type> anyway.
Then you invoke <methodname>transmit()</methodname> instead of
<methodname>call()</methodname>. In this case the server will omit the response.
Network problems, on the other hand, will be reported as usual.

<caution>
<title>This is an &ulxmlrpcpp; extension</title>
<para>Servers from other implementations will always send a response. So you
might receive garbage from the next call or maybe generate a lot of error
messages on the remote server.</para>
</caution>
</para>

<para>This extension offers another and probably more interesting working mode:
asynchronous communication. The basic idea is to additionally install a server
on the client side and use some sort of callback mechanism.
This server should work in parallel with the client. See sections
<xref linkend="mt-xmlrpc-client-server"/> or <xref linkend="mt-http-client-server"/>
how this can be achieved in several ways.</para>

<para>The client then sends all asynchronous requests with
<methodname>transmit()</methodname> to the server.
The server on the other side processes the request and sends the response back
to the client machine using an &xmlrpc; request with <methodname>transmit()</methodname>
which calls the receiver function of the
callback using the helper server.</para>

<para>Of course this enhanced technique works seaminglessly with the regular
client/server approach.</para>

<para>&ulxmlrpcpp; also supports a
<link linkend="mt-rpc-client">multi-threaded working method</link> for the client. This looks
a bit similar to the above. The difference is, that each request creates a new thread to process
the result. This is convenient but consumes rather much system resources.</para>

</sect2>

</sect1>

