ZCD
===

ZCD stands for Zero Configuration Dispatchers.
It is a framework for Remote Procedure Call.
Its name refers to the fact that it is specifically designed to allow communication
between two nodes that are directly connected to a common switch, and for which one
cannot presume that any previous network configuration has been done.

The framework is composed of 3 separated levels.

What is the separation of the three levels and how you can use it.
==================================================================

The first level is a generic one, in that it does not imply a
specific model.
We can deploy it in the form of a library, without having to know the classes, methods and data that you want
to be able to remotely call.
This implies that we provide a class to be used as a client (e.g. NeighbourClient) and you have to
derive it when you apply a model (in the next level) before you can use it in a form like
"var x = myneighbourclient.myproperty.mymethod(a,b,c)".

The second level provides a model by specifying:
 * the definition of the serializable classes that are used as arguments to the
   remotable methods;
 * the interfaces that have to be implemented by the remote objects, with the names of properties
   and the signatures of the methods.
In this level you derive [one of] the classes that we provide
as rpc-client.
By separating this level from the upper one, you can define a stable version of the
communication interfaces, although you are free to modify their implementation. For
instance, you can make a program to monitor a node by calling some of its remotable
methods and you make this program depend on the interfaces defined at this level at
version 1.0; suppose that the node that you are monitoring runs version 1.3 of the
server (upper level) that has been implemented at a later time than the monitoring
tool; you can be assured that the monitoring tool will correctly behave if the
version 1.3 of the server is still based on version 1.0 of
the interface.

Finally, at the third level you implement the remote methods in a server and the
respective calls in a client app by means of the classes provided
by the lower levels.

What is provided in the generic library.
========================================

This library provides the infrastructure to easily implement an RPC mechanism.
The RPC mechanism allows for 3 different styles to request the execution of
a remote method:
 1. TCP. Request to a specific IP in the whole network, with or without waiting
    for a reply.
 2. UDP. Unicast. Request to one of our direct neighbours, with or without waiting
    for a reply.
 3. UDP. Broadcast. Message to all (or a subset of) our direct neighbours, without waiting
    for a reply.

Optionally, if you are interested, you can read in file README_architecture for an insight
on the design goals that lead to the definition of these 3 styles. We advise, anyway, to read
it after having fully read and understood this one.

We aim to provide a complete reference for how to produce a correct definition (in one or more
.vala files) of the data model. At the moment you can have a look at the sample interface where
you can find an errordomain, a remote class definition with a property containing a second remote
class, another class with a remotable method, a number of serializable classes used as arguments
and return value, ...
Also, below you will find an overview of the content of the data model. You should be able to
identify those contents on the sample interface that is provided.

*Server side*

We provide an abstract class RPCDispatcher.
We provide the tool "rpcdesign" that you can use to automatically generate a source file for a skeleton class
based on the data model interfaces that you provided (see above).
In this skeleton file you will find a concrete class that derives RPCDispatcher (e.g. AddressManagerDispatcher)
in order to:
 * receive [at creation time] the instance where the method has to be called (e.g. IAddressManagerRootDispatcher);
 * override its method "remoteexception_dispatch" to implement the serialization of errors
   defined in the model;
 * override its method "_dispatch" to implement a method call. The method and the serialized arguments
   are passed in the RemoteCall instance.

In this example IAddressManagerRootDispatcher is an interface that you define manually.
AddressManagerDispatcher is a class that is automatically generated afterwards by the tool.
All of them are part of the second level
of the framework.

We also provide a class TCPServer and a UDPServer. An instance of them is created in order to have
a server listen the network for requests. By means of 3 delegates (one for each of the calling styles
mentioned above) these objects demand to the uppermost (third) level
the task to create/identify the instance of the skeleton class to call
the method on.

*Client side*

We provide an abstract class FakeRmt.
We provide the class TPCClient, the class NeighbourClient and the class BroadcastClient. They implement
the sending of a request/message in the 3 calling styles mentioned above. But they are not intended to be
used directly by you.

Again by using the tool "rpcdesign", you will generate a source file for a stub class based on the
data model interfaces that you provided (see above).
In this stub file you will find a model-specific class (e.g. AddressManagerFakeRmt) derived from FakeRmt
that will still be astract; and also 3 concrete classes, derived from it, that use the 3 client classes
mentioned above to actually do the network communications and send the request/message.

In this example IAddressManagerRootDispatcher is an interface that you define manually.
AddressManagerFakeRmt and the derived AddressManagerTCPClient are classes that are automatically generated
afterwards by the tool. All of them are part of the second level
of the framework.

Defining the data model. Overview. (This is a Work in progess)
==============================================================

The remote methods can receive a number of arguments and return a value. The types that you can use as
arguments and return value are various basic types and any complex class that implements the interface
ISerializable. Here an explanation is provided to help you define a serializable class that suits your
needs.
Basically, the class that you want to be serializeable has to be able to put in a Variant its internal
data, in such a way that a new instance of that class could retrieve its state from the Variant and it
would be equivalent to the original instance.
Make a class that inherits from ISerializable. Implement its abstract methods serialize_to_variant and
deserialize_from_variant. In the first one produce a Variant from the values of the members of the
class instance. In the second one set the values of the members from a Variant.
Here's how you can implement serialize_to_variant. Cycle through the class' members. If you have one
of the basic types (int, char, string, arrays) use one of the functions in Serializer to produce a
Variant. If you have one instance of another serializable class use its own serialize_to_variant to
produce a Variant. In the end you will have produced a ordered list of Variant, and you can use one of
the functions in Serializer to produce a single Variant from the list of Variant.
In the method deserialize_from_variant you have to make the inverse steps, in order to retrieve the
single values of the class' members.

In addition to the classes that are part of the signatures of the remote methods, you need to define
two special serializable classes that you will use as a identification for a node or for a set of
nodes. The first one, we call it a unicast_id, is a mean to identify a node. You can use it to send
a message to a certain node of your neighbours. You need this if you send the message inside a packet
UDP to broadcast address.
The second one, a broadcast_id, is used to identify a set of nodes. You use it when you send a message
via UDP to all, or a subset of, your neighbours.
Another piece that is part of the signature of a method is the error that the method can throw. You
can define in the data model all the error domains that you need for your remote methods. If the server
during the execution of a remote method throws that error, the client will be able to catch it.

In your data model you define one class (*) that is the root of your RPC model. In the interface file
you don't need to define the whole class, just an interface. The client will have a stub class that
inherits that interface and implements its methods and members.
In this root interface, you can place remotable methods and/or instance members that are effectively
additional RPC classes, which in turn have remotable methods and members.

(*) It is also possible (at least in theory) to have more than one available roots. You just need to
define a mechanism in the serializable class that you use as unicast_id (or broadcast_id, or tcp_id)
that enables the client to specify each time (and the server to identify) the root object that you
want to use.

