Messenger Library Addresses
Addresses in Messenger Library
At its simplest, an "address" in Messenger_Library is just something to which one can send a message. But it is also Messenger Library's primary feature, as there are many types of addresses that allow important functionality and high flexibility. They are implemented as a set of LVOOP classes, but detailed knowledge of LVOOP is not needed to use them.
Here is a listing of the different types of addresses.
Send is the most generic class ("parent" class); any other address can be carried on a "Send"-class wire. "Send" defines the key method (subVI) of an address: "Send.vi", to send a message. There are a large number of extensions of this core method, designed to support the use of various messaging patterns. For example, to send a message and wait for a reply.
A secondary method of the "Send" class (and thus of all addresses) is "Valid.vi", which indicates if a message sent to an address will actually go somewhere. An address of the "Send" class itself serves as a "null" address, and thus messages sent to it do not go anywhere and so it is not "Valid". Note that being not "valid" is not the same as there being an error on trying to send to an address. Though most subtypes of addresses will thow an error if they are not valid (since that indicates a failure of the underlying communication), sending to the "null" address is not an error condition (see also: "Observers").
Messengers are addresses that actually specify an underlying communication means. A QueueMessenger carries messages on a LabVIEW Queue, an Event Messenger uses a User Event, and a NotifierMessgenger wraps a Notifier. All these types implement ("override") "Send.vi" of the parent "Send" class.
Messengers have the additional methods of "Create" and "Destroy", which create and release the underlying communication reference.
Note that from the point-of-view of the sender, all Messengers are interchangable, as they all implement "Send" and "Valid". Only on the receiving end is their use different. QueueMessengers call "Receive.vi" to dequeue messages; EventMessengers are registered to an Event Structure, etc. This was the key initial motivation of Messenger Library: to make the sender of a message be able to use any communication method, as specified by the receiver.
TCP Messengers: Basic Messengers only communicate locally inside a LabVIEW application or instance; TCP Messengers extend communiction between instances and/or computers, via TCP/IP. The implementation pattern is Client-Server. There are TCP extensions of both Queue- and EventMessengers. In both cases, creating the Messenger starts up a TCP Server process, which accepts remote connections and forwards all received messages into the Queue or User Event. The receiving process uses the same API as it would with a local Queue- or EventMessenger. Note that this means conversion of a local-only component to a network-capable one is very easy and quick.
The client side is provided by "RemoteTCPMessenger", which creates a client connection to a remote server (identified by a "service name" and ip address). Messages sent to this Messenger are sent to the remote process.
The TCP Messengers are designed to work with the messaging patterns of Messenger Library. They automatically route replies and notification messages back through the same TCP connection as the initial request and registration messages. Note that this means that one must keep a RemoteTCPMessenger open in order to receive replies or notifications.
Future Tokens are a special type of temporary single-use address. They are somewhat similar to "futures" of other languages, and generally serve to refer to the yet-to-be-received replies to a messages in the "Scatter-Gather" messaging pattern. A Future Token is an address that can only ever accept one message (sending to a Token twice results in an error), and receiving that message, via a "Redeem Token" method, destroys the Token.
Observers: Observers are the "force multipliers" of addresses. They do not represent the actual means of sending messages themselves; instead, they "wrap" other addresses with extended functionality. Each Observer can contain multiple other addresses (copies of messages sent to the Observer are sent to each contained address) and, crucially, a "Translator", an object that alters messages. Via translators, an Observer can do things like relabel a message, or substitute a different message, or place the message inside an "Outer Envelope" (a message that contains another message).
Observers have the key methods of "Create Observer", which allows the combination of multiple addreses into one Observer, and "Translate", a polymorphic VI that allows the specification of what mesage translation to do.
The motivation behind "Observers" is to support "observation" of one process by another. This is to be contrasted with the more ususal "command" of one process of another. The difference is illustrated by thinking of process S sending a message to process R. If this message represents a "command" from S to R, then S must "know" R. R defines what commands it can handle, and S must know the command to send. Also, a failure to execute the command is a failure of S, since it has failed to get its command done. If, instead, the message represents the observation of S by R, then the "active" party is R. S is providing information that R chooses what to do with. It is S's job to provide the information, but it is not "commanding" R to do anything, and shouldn't need to know what "command" R should execute on receiving the message. R should define the command, and thus should control the command-element of the message (S supplies the data). "Observer" addresses support this kind of idea, as they allow the receiving process to pre-configure an address that defines aspects of the messages that it will receive.
The most basic (and common) use of an Observer address is to configure the relabeling of a message. For example, a sender might send messages labelled "Temperature", but the observing process may provide an Observer address configured to relabel the message "Record Main Furnace Temperature", representing a command to itself of what to do with the data.
Error-handling note: Observer address never produce an error when calling Send on them. As the sender is not instigating the observation, it should not be a failure to it if the observation has failed. An Observer Address will (silently) drop any contained address that produces an error on a Send call. This simplifies programming in situations where temporary processes observe a longer-running process, as "dead" addresses are automatically dropped. Note that this means that an Observer can change on calling "Send". Observer addresses are by-value collections containing by-reference Messengers, and should be treated as by-value objects.
An Observer will read as "Valid" if any contained address is valid.
Actor Address: The Actor Model describes a way of programming that uses independant processes that interact via passing messages. Actors can also be created ("launched") by other actors. LabVIEW comes with an existing implementation of this idea, the "Actor Framework", but this is an alternate design based on Messeger-Library. Please note that there are very significamt differences between the two.
An "actor" address class in Messenger Library identifies a VI (called "Actor.vi") that will be asynchronously run when the actor is "launched" (Launch method called on the actor address). After launch, the actor address contains a Messenger that will communicate with the new actor. Sending to the actor address sends the message to the message-handling loop withing the actor VI.
Creating a new type of "actor" involves copying a template class. Several templates can be accessed via the Tools menu (from an open Project, select Tools>>Messenger Library>>Create Actor from Template..). The recomended templet is called "DEV". Note, however, that any message-handling loop design can be substituted, based on either a Queue- or EventMessenger.
An "Actor Manager" debug tool is also installed under the Tools menu. This allows one to see what actor/VI launch what, and gives the ability to open all front panels or block diagrams.