Bond Messaging Component


Well present the components of the communication system, by applying them in a small application. The starting code for this is as follows:


/---------cut here ----------------

import bond.core.*;
import bond.core.util.*;

public class myStarter extends bondExecutable{

	public myStarter(){
		System.out.println("myStarter:myStarter():\n"+toString(this));  
  	}

	public static void main(String argv[]){
		bondConfiguration.initSysProperties();
		dir= new bondDirectory();
		loader = new bondLoader();
		com = new bondCommunicator();
		conf = new bondConfiguration();
		new myStarter();
	}       
}

/ ---------- end cut here -----------

The communicator - what it does

There are two important components that make the communication possible: the Communicator and the Message objects
The bondCommunicator object has a unique instance within the bondResident. It is the module that makes the communication between any components of the system possible. The scenario for this is the following (see also the basic messaging sample provided here) : The sender object creates the message (object) it wants to send, and also it creates a shadow of the destination object. On the shadow it calls a communication method (ask(), say(), etc.). These will call the communicator's send method having the message and the shadow as parameters . The communicator can either subscribe/unsubscribe the shadow into the event slots (which enables the dispatching of incomming message to the recipients interested in receiving it) or will ask the communication engine (UDP, musticast, etc) to deliver the message to the destination.
At the destination, the CommunicationEngine will distribute the message to the destination by calling the distribute(message,destObject) which will attempt to broadcast the message if the destination is unknown, to notify the methods that were waiting in the reply slots or event slots, or in the end assign a thread from the communication engine's thread pool to deliver the message to the destination object. This last step is done by calling the say() method of the destination object.
In the end, the destination object will receive the message (in the form of having called its method say() with the message and sender objetcs as parameters). Upon this, the receiver will try to detect what kind of subprotocol is appropritate to decode/handle the message (by looking at the subprotocol field in the message) and subsequently it will try to load that subprotocol. Failing to load the appropriate subprotocol, it will load the PropertyAccess subprotocol. Note that for each of this subprotocols, the receiving object will try to load the cooresponding probe that implements the specific subprotocol
For addressing purposes, the communicator has an ID (usually the name of the machine hosting the resident and the port on which the resident is running). The communicator handles the task of transferring the message objects from source to destination. Keep in mind that the source and destination, in our case are bond objects.
Partially this process is illustrated in the sample here, being restricted by the limited posibility of printing aout all the visited methods (unless we want to edit the source ode of bond environment).Also note that the initialization is done by hand, to ilustrate what components are required for the communication between two objects to take place. In the subsequent examples, we will let the initbond() to do all the necessary steps.
Regarding the messages, there is a more detailed presentation below.

Communicator startup:

Before it starts, the communicator needs the bondConfiguration to have loaded the information form the property file $BONDHOME/bond/properties. As seen in the above sample code, it also needs the loader component, that will facilitate the loading of the communication protocols. To see that these are needed, go ahead and comment out the two lines containing bondConfiguration.initSysProperties(), conf = new bondConfiguration(); and loader = new bondLoader(). You'll see that the application will fail to start (because of the communication component). Looking at the internals of the communicator, this does the following things at its own inilialization:
  1. if specified in the properties file, it will load a multicast communication engine
  2. depending on the setting from the properties file for bond.communicationengine (default UDP), it will load the appropriate communication module from the directory $BONDHOME/core/communicationengine/. This way, the environment can load different communication engines, depending on the user's choice. Here you can see a very good example of why we needed the bondLoader and how one can use its facilities.(for instance you can replace the communication engines at will).
  3. after it loaded successfully, it will initialize the communicator's messaging threads and start the listening on the specified port (default 2000)
For successful communication, you'll need to add the initMessage() method, to enable the decoding of KQML formatted messages, used by default by bond.(see below)

Messages NEEDS REVIEWING !!!

Bond uses messages to achieve communication between all the components of the system. These are objects that have attached as dynamic properties name-value pairs. This message object is passed between local objects, and they interpret the messsages by reading the dynamic properties of the message object.
Since the objects do not have the same meaning when are sent form one resident to another, it arose the need for an external messaging format. For this purpose Bond has chosen to implement KQML and XML. There is a one-to-one mapping of the bondMessage objects to the external message format
While we ar at it, you should know that messages can have any number of name-value pairs (as pieces of inforrmation that we are transmitting) but there are certain reserved names for variables: .

The code at the top needs now more additions, so in order to ilustrate the communication between two objects, we have created a new example to start playing with here It contains two bondObjects one with the role of a client, the other one with the role of a server. The client will send a message to the server, and this one will only notice that it has received the message. We'll continue building on this.

Before we can communicate with somebody else, we need to create some messages to send. The messages are bondMessage objects and have the following structure:


Communicator: internals and functionality

Internally, the communicator has a hash structure, reply_slots, which is used to store the messages that have been sent and that wait a reply. On the receiving of the remote reply, the sent message is removed from the reply_slot, and the object that has sent the initial message is notified. This process implements an asynchronous messaging system
The messages contain the ask performative with a reply-with field. If the incoming message contains a waiting slot, the message is delivered directly to the object that has sent the request. Otherwise, the say() method is used to send the reply.
The communicator contains a thread pool which has the job to deliver messages to the objects that are destined for.
The communicator also provide the framework for synchronous communication. It is implemented by the ask and on_reply() methods from the bondObject.
An example of this mechanism can be seen in the example here

The third way for bondObjects to interact is to use the subscribe-notify model of event handling. It is an extension of the java listener abstraction. The object that has subscribed to a certain event on one or several properties of an object is called monitor. Before a bondObject becomes monitor, it needs to register itself with the monitored object, in a special hashtable, event_slots (available at the Communicator), and whenever a property of the monitored object changes, it will send a message with the tell performative to all the elements registered for that specific message. The registering part is being done on the listeners field of the monitored object, by calling subscribeAsListener() and unsubscribeListener()
TODO: show the stackTrace of this process.


CommunicationEngines

Are in charge of transporting the messages from one resident to another. Bond has several agents, based on different communication protocols: bondTCPCommunicationEngine, bondUDPCommunicationEngine, bondInfospheresCommunicationEngine and bondMPCommunicationEngine (IP multicast).All communication engines implement the common bondCommunicationEngine interface, which provides the common set of methods:
Each of these have two methods for sending (either messages, or objects) and one for receiving messages. They are all based on some thread pool, that assigns each message to be send a thread, this way achieveing better performance. The thread pool is initialized when the specific communication engine is started.


Subprotocols

The bond messages are divided into small sets, called subprtocols. Examples of subprotocols are: PropertyAccess, Security,Monitoring,Agent Control, Scheduling, Persistent Storage, DataStaging, Registration. By default, all bond Objects implement PropertyAccess subprotocol, which allows to interogate and set the properties of some other object. The subprotocols are inherited by the object's class hierarchy, and failing to understand a subprotocol, the message is passed to ancestors. In case nobody understands the message, a sorry is returned.
Subprotocols can be learned dynamically by the objects, by attaching them so-called probes objects. Commonly used probes are the bondMonitoringProbe (see subscribe-notify model) and bondSecurityProbe.
To make the communication more versatile, you can define your own subprotocol (the sequence and the format of messages), and implement your own probe that will handle the messages belonging to this new subprotocol.To see how, look at this application that uses this custom-made probe.
To use a custom-made probe, I have built on the usual client-server skeleton. The things to notice are the addition of the new probe object as a dynamic property to the server object, and the genaration of a message that is writen in this new subprotocol. In our case the new subprotocol is called testSubprotocol and the message that is sent conforms to this subprotocol.:
msg=new bondMessage("(tell :content ok)","testSubprotocol");
On the server side, as noted above, all you need to do is add the probe object to the server:
set("randomly chosen name",new myProbe(this));

Miscellaneous

Also part of the communication infrastructure, the Virtual network of Objects is a means of addressing groups of related bondObjects. This group objects will receive messages using the multicast engine.

Object mobility Is a means of moving the objects across the network, from one resident to anoter. It uses the method realize() called on a shadow object. One problem that might arise because of this is the inconsistencies of the existing copies, when they are subject to changes.

Distributed Awareness Is a mechanism used by the residents to find about each other's existence. It is based on collecting information about other residents from received messages, and distributing this knowledge by means of piggybacking it to messages sent to objects at remote residents.