YAMI - Yet Another Messaging Infrastructure


YAMI Home

Concept

Specification

Implementation

What next?

Questions
& Answers


Comments<

Concept

In short, YAMI is a project which objective is to provide programmers with a simple infrastructure for inter-object communication.
Of course, there are ready to deploy, free and commercial solutions, some of them are backed by big organizations and are really well designed - YAMI is not designed nor supposed to substitute them.
What could make YAMI competitive with other solutions is its simplicity and ease of use in cases, where big, full-blown infrastructures are just not necessary.
Here is a short description of three of the mainstream distributed infrastructures that I knew at the time YAMI was born:

COM

In general, COM has nothing to do with Windows - it's a way of writing programs. However, thanks to some commercial reasons, COM and Windows are strongly connected, so whenever I say COM, I mean that COM (the one from Windows).
COM works on MS Windows platform and is completely incorporated into the operating system.
There is no need to have any library around, everything can be done using the system API. It has some advantages (can use very low-level features of the system to speed up communication, parameter marshalling and so on), as well as disadvantages (allows interoperability between objects when both parties involved are on the Windows systems). There are bridges which allows to cross the platform and even technological (I know that COM-CORBA communication is possible) boundaries, but they add up to the complexity of the whole infrastructure.
Anyway, creating a small COM component that could communicate with another component on the same machine or even on a different one is quite easy (especially, using VB wizards...).

CORBA

I'm very impressed by the amount of work that OMG has put into it. And probably it's the best choice for bigger systems or where objects have to interoperate across different platforms (it's completely platform-independent). There are free and commercial implementations that can provide all the infrastructure for inter-object communication and the whole idea with its specification seems very promising.
There is only one problem: it's so big, that apart from very simple cases, it can appear to be overwhelming. Also, the ORB (the run-time part of this infrastructure, which has to exist together with the process hosting the communicating objects) tends to be quite fat. Even in small, simple programs that need some communication infrastructure, the ORB can add a few MBs to their size. I estimate, that in majority of cases, it's too big.
But, as stated before, it's probably the best choice for industrial-strength, big systems.

Java RMI

Well, it works only when all parties involved in communication speak Java...
It's platform-independent, but not language-independent.

To be more exact: some of the readers keep correcting me that it is possible to use JavaRMI from other languages, especially those that can run on VM. Whereas technically true, the general experience with this is not really wide. If we concentrate only on mainstream uses, it is safe to associate RMI with Java only.

This is exactly the reason, why I believe the simple, light, platform- and language-independent, freely-available messaging infrastructure would be the solution for quite a big part of object systems built nowadays.

And this is just what the YAMI project is supposed to provide.
Also, the objective of this project is not only to give the ready-to-deploy solution, but also to invite other programmers and people interested in object systems to participate in it, which can mean everything from using, discussion to designing and development.


Description of the YAMI communication model

In all object systems, there is always a notion of the object.
YAMI is no different about that - let's define the object as any piece of software that is able to send and/or reply to a message. And that's all. There is no notion of a class or component. The object is anything that can communicate, but to make things more neat, let's define some schema or strategy to which all YAMI systems should stick.

There is one thing that makes YAMI different from other messaging infrastructures.
COM, CORBA and JavaRMI go very far to hide as much as possible behind the notion of object reference. In those systems, the client is never aware of the location of the object. And this is the most difficult thing to achieve and probably what makes them so hard to implement. I believe that in many cases it's not necessary.
In YAMI, every object has an explicit location, and it's defined by the domain.
Domain is a group of objects:

Domain

What makes one object distinguishable from others, is the pair (domain_name, object_name). It also means, that two objects are considered different, if they have at least one value in this pair different. It's possible to have objects with the same name if they exist in different domains.

Object can send a message to any other object.
To do that, object has to provide a name of the destination domain and a name of the object to which the message is sent.
What makes the message is its name and its parameters.
The message name can be just any string. Messages are not defined (although it is possible to create an optional layer of static interfaces on top of this dynamic model) and their names are always managed dynamically. It means, that there is no constraint on the message name at run-time.
The parameters that go with a message is a set of values that can have one of the predefined (primitive) types. The type of the parameter in a set is also not constrained at run-time. Parameter sets are created for every message sent.
Both of the above mean that there is nothing like type-safety of the messages. It's possible to send a message twice with the same name and with different parameter sets.
Object to which the message is sent can reply with a different parameter set (which corresponds to the notion of the out parameters) or can reject the message. Anyway, this information (return parameters or a rejection message) is sent back and can be processed by the object which has begun the communication.
Every message is asynchronous from the point of view of the YAMI model.
It means, that object is not blocked after sending a message - it can go on uninterrupted and later retrieve the result parameters of the call or the flags (like after rejection). Of course, this allows to build a client that will block waiting for the response, but in its core, YAMI does not require that. Conceptually, the act of sending a message does not have to map to the invocation of the method on the receiving object. Such a model is possible, but not required.

In every domain there is one agent.
Agent is a very close equivalent of the CORBA's ORB. It's a piece of software that is supposed to hide the low-level details of communication from objects.
Objects request the agent to send a message or to retrieve the return information from the previous message sent. Objects have to register themselves with the agent, so that it knows if a message received from another agent (ie. from another domain) can be delivered to a valid object.
Agent in fact defines the scope of the domain. If an object is able to connect to the agent and request him to send a message, it can be said that this object is in the domain managed by this particular agent.
This is a little more exact model:

Agents

There are three possible types of agents with regard to their scope of work:

InProc agent

This agent exists in one process together with the objects.
It means, that it is visible to the objects as any other object or through some function calls (depending on the implementation). The scope of its domain is the process in which it's created. It means, that only objects created in the same process can register with it and send it a request.
It's possible to create more than one agent in the same process (thus, more than one domain).
Probably this is the simplest agent to implement and use.

OnSite agent

This agent exists on the same computer where the objects of its domain are located.
The communication between the objects and the agent is a little more complicated and can be achieved by means of IPC - Inter Process Communication - (shared memory, pipes, whatever).
Again, it's possible to create more than one agent (and thus more than one domain) on the same computer.

OffSite agent

The scope of this agent is in theory not limited. If there is a way for the object to connect to the agent (it may be even separate network connection), then this object is included in that domain.

Each agent type has its advantages and drawbacks:

InProc agent is limited in its scope and where there are objects distributed across many processes (even one per process) it's necessary to create many agents (and many domains).
From the other hand, the InProc agent can take advantage of the fact that it resides in the same process as its objects and can considerably speed up message delivery if it discovers that two communicating objects are in the same domain (so - in the same process) - there is no need for any network connection nor IPC to deliver the message.

OnSite agent can manage all the objects on one computer and also can take advantage of IPC if two objects are on the same machine, but this improvement will not be so big as with the InProc agent.

OffSite agent has the broadest scope, but the communication between him and objects in its domain is the slowest.

Anyway, it's imperative to state that agents of different types can coexist in one process or one machine and thus can make a good compromise if the whole system is well-designed.

Considering the above, the usual steps taken by the object during its lifetime are:

  1. create new agent or connect to the existing one (it's not necessary with the InProc agent)
  2. register with it (ie. declare the object's name)
  3. one of (maybe repeatedly):
    • request the agent to send a message
    • request the agent for the return values from previous messages
    • request the agent for any incoming messages (from other objects)
    • reply to the message received.
  4. unregister with the agent
  5. destroy the agent (only if there are no more objects using this agent)

To make the communication possible, every agent, during its initialization, has assigned IP address and the port number.
It makes the communication process more explicit (the location of the domain must be known at the run-time), but at the same time allows to write very simple implementations. It also means, that agents will communicate using TCP/IP protocol. It's probably not the fastest solution (UDP would be at least so fast, but would require sophisticated protocol so that messages will be delivered reliably and every implementation would have to comply to this protocol), but surely one of the simplest to use.

Every agent has to keep the map that will translate domain names to IP addresses and port numbers. This information can be filled in during system startup and initialization, but can be changed at run-time.
There is no need for such a strong naming system as in CORBA or COM (where uniqueness of object names - namely, interface identifiers - is most important), because name clash could not occur if only domains are properly registered. So, there is also no problem if in one system domain and object names will be the same as in other system:

Names

It's possible to write agents so that they will queue requests or just transform them into usual method invocations on the registered objects. In the first case, there is a possibility that the object will not request for incoming messages fast enough (or even not at all). To make the queue impossible to overflow, agent is allowed to set (but this should be possible to change from the object's perspective) a limit for the queue's length or time-out.
This is implementation detail, but YAMI allows messages to be discarded in case of the time-out and this is one possible situation when this could happen.


The above model allows to implement very simple (in comparison with other infrastructures) messaging system. It's important to say, that this system can be implemented in any language which libraries support TCP/IP (ie. in any useful language) and on any platform, which supports this protocol (again, on any useful platform). This is what can make this idea language- and platform-independent.
Namely, it should be quite easy to implement appropriate agents in languages such as C, C++, Java, Tcl or Python for Unix, GNU/Linux and Windows platforms.