Skip to main content

FMP Tutorial: Standard APIs to invoke active objects

Posted by rexyoung on August 17, 2013 at 9:42 AM PDT

Fast Messenger Programming (FMP) introduces two types of objects. Active objects are designed to represent business logics while messenger objects are designed to support active objects on underlying programming languages. As Figure 1 illustrates, messenger objects are native objects written using the underlying programming language. Active objects, on the other hand, are virtual objects. FMP decides not to implement active objects using any underlying programming language. Instead FMP is taking a virtual machine approach. Active objects are hosted inside of messenger objects that provide standardized APIs to administrate and invoke active objects as Figure 2 shows. However Figure 2 does not show how active objects are implemented. That will be covered by other tutorials. In short, an active object is backed by a native object, called active implementation object, written using the underlying programming language. The active object’s hosting messenger object provides necessary support so that an active object and its impl object could be organized in various structures e.g. as suggested by design patterns of adapter, proxy, façade, etc.

Figure 1: Active objects are virtual objects

Figure 2: Messenger provides APIs and supports to invoke active object

Figure 2 shows how a messenger object provides APIs for all of its active objects. An active object has a private inbox that is used to accept invocation requests from outside. It is the only way active objects understand, but it is not sufficient for user programs that may be employing various programming styles. So that FMP designs an independent API layer sits on top of active objects. This API layer provides user programs a standard set of methods to invoke active objects. These methods may differ a little bit according to the underlying programming language. But their principles remain the same.

All messenger APIs can be used to access and invoke active objects by codes either inside or outside of active objects. An active object can access or invoke itself by using these APIs.

Figure 2 also shows three active objects named "Bob", "Dave", and "Mike". I need them in this tutorial to explain standard APIs. Active objects are asynchronous so that they can be perfectly modeled as independent server-like services. You can name them by their roles or even personalized names as I do here.

#1: Messenger.sendMessage ()

Figure 3: messenger.sendMessage ()

The sendMessage () is the fundamental way to access an active object, because this is how active object works. All other methods are derived from this method.

1: messenger.sendMessage ("Bob:doThis", msgArgs);
2: messenger.sendMessage ("Dave:doThat", msgArgs);

These two lines of codes denote what happens in Figure 3. The first line is used in a user program that is not an active object. It sends a message to Bob, then immediately continue without blocking, and does not care if Bob would have a return value or not. The second line is used by Mike to send a message to Dave.

Note that in FMP sending a message to an active object is interchangeable with invoking a method, function, or service on the active object.
Note that a message in FMP is represented as an ordered list of objects, while a return value is represented as a single object.

#2: Messenger.sendInquiry ()

Figure 4: messenger.sendInquiry ()

FMP uses inquiry to name a type of message and indicate that the sender expects a response message from the target active object. However the response message does not necessary go back to the sender. It can go to any active object of course including the sender self.

1: messenger.sendInquiry ({"Dave:doThat", 0, respArgs}, "Bob:doThis", msgArgs);
2: messenger.sendInquiry ({"Mike:handleReponse", 2, respArgs}, "Bob:doThis", msgArgs);

These two lines of codes denote what happens in Figure 4. Note that any code can send an inquiry to an active object, but not any code is able to receive a response message. You have to be an active object to receive a response message.

The sendInquiry () is achieved by two uses of sendMessage (). The original sender has to prepare two messages as codes above show. However the response message and recipient is captured by the API layer that does not forward it to Bob at all. I mentioned earlier that active object only accept invocation requests from its inbox and won’t do extra logics like sending response to someone else. (Of course, user may code any kind of user level logics in any active object.) So that the API layer put response message aside until Bob executed the original message and generated a return value (the return value is optional.) Then the API layer uses messenger.sendMessage () to send the response message to the designated response recipient.

There are numbers 0 and 2 in the code above. A number instructs the API layout to compose the final response message with the return value from the first message recipient. The number indicates the index of respArgs on which the return value will be injected.

#3: Messenger.callService ()

Figure 5: messenger.callService ()

The callService () is specially designed for non-active object to receive response message e.g. the return value of a message. The method will immediately return a token object to the caller. The API layer will update the token with return value when the associated message is executed by the recipient active object which is not aware of this of course.

1: Token token = messenger.callService ("Bob:doThis", msgArgs);
2: while ( not token.isReturnReady () ) {
3:     // do something else or sleep for a while
4: }
5: MyResult result = token.get ();

According to FMP, a token object must provide a non-blocking isReturnReady () method for callers to determine if a return is ready. Other features would be nice to have based on what the underlying programming language is. For example, a token in Java may provide a blocking get () method. A token may also accept a callback used when a return value is ready; or associate with a data or context object so that the token could be passed to someone else who would have enough information to process the return value.

#4: Messenger.publishMessage ()

Figure 6: messenger.publishMessage ()

Figure 6 shows a set of routing rules that can be provided at any time to the messenger by invoking its administrative methods:

messenger.registerRoute ("Alice:forThis", "Mike:doThis");
messenger.registerRoute ("Bob:forThat", "Dave.doThat");

Publishing messages is a complete addressing service provided by the API layer. In this mode, a sender sends a message to a messenger without indicating a recipient active object. Instead, the sender indicates its own ID along with the message. The API layer receives such a message and will loop up all routes it currently have and get a set of recipient active objects if any. The API layer then uses sendMessage () to send the message to any of them.

1: messenger.publishMessage ("Alice:forThis", msgArgs);
2: messenger.publishMessage ("Bob:forThat", msgArgs);

The publishMessage () completely decouples senders and recipients, and may be very helpful in certain programming styles and distributed environments.

A messenger object may decide how it wants to enforce real name policy. In Figure 6 above, the user program on the left is not an active object at all but still claims it is Alice. In this case, Alice is more like a third place that is well known to many different senders for the purpose to group messages from them and heading to the same recipients.

However, a messenger implementation may choose to enforce real name policy. In that case, only an active object may publish messages in its own name.


Related Topics >>