All Packages  Class Hierarchy  This Package  Previous  Next  Index

Interface uhr.core.msg.MessageRouter

public interface MessageRouter
extends MessageReceiver, MessageSender, Replicatable
This routes Messages from senders to receivers, handles connections and provides related services such as for tools needing to know things about circuits. Messages are multicast events used for part Anonymous Collaboration.

A message chain may run from PartA to Router1 to PartB and PartC, PartA to Router1 to Router2 to PartB, etc. Each container (aka cell) has a MessageRouter, allowing parts to send Messages anywhere in the system along these message chains. These chains are created by connections of part signals (from MessageSenders) to MessageRouters and interests (from MessageReceivers) from MessageRouters.

Think of a part as having a "pin" like a computer chip for each message name. A connection connects that pin to the MessageRouter. Thereafter the part can send or receive messages along that connection, because the router knows about the connection.

Connection types resolve the "same Message name endless loop" problem and allow crystal clear definition of a system's message circuits. Ultimately they allow a precise message chain between any two parts in a system. Here's a diagram explaining this.

If this looks suspiciously like an electronic circuit diagram, it is. That's because UHR uses the Circuit Based Pattern, where electrons (Messages) travel along circuits (message chains) to devices (parts) on a circuit board (the core infrastructure).

One thing to understand is once a message is sent outside a cell, only its nameis used for routing. Thus if PartA and PartB in a cell send a message with the same name, there's no way to route one message from PartA to PartC outside the cell and the other message from PartB to PartD outside the cell. This may seem odd at first, but it greatly simplifies system circuitry. It also allows a cell part to publish what it sends and accepts without reference to its internal parts. This allows a group of assembled parts to appear as one part, the cell, which can be reused like any other part.


To help you quickly understand the methods, here they are in an organized condensed format. Fur fuller understanding we include the constants from the Connection interface. Happy reading! :-)

// Connection types for messages from parts in the router's cell
int SIGNAL_OUT
int SIGNAL_IN
int SERVICE_NEED
//
// Connection types for messages to parts in the router's cell
int INTEREST_OUT
int INTEREST_IN
int SERVICE_SUPPLIER
//
// For direct part to part connections
int DIRECT
//
// Connection creation and removal
void connect(Connection connection);
void disconnect(Connection connection);
//
// Called by parts within the cell with this router
int sendMessage   (Message message, MessageSender sender);
//
// Called by routers in cells below this router
int serviceMessage(Message message, MessageSender sender);
//
// Miscellaneous properties
void setParentRouter(MessageRouter parentRouter);
MessageRouter getParentRouter();
//
// We also have many getters for tools, or may use a separate Info
// object. This is under design. Examples from generation one are:
Enumeration getMessageNames();
Enumeration getMessageReceivers(String messageName);
Enumeration getMessageNamesWithReceiver(MessageReceiver receiver);
 


Message Services - A part may be used to play a "Message Service" role, by sitting near the top of the System Tree and servicing messages from subcells below. This allow high reuse of the part. To avoid huge amounts of message chain definitions we use an "automatic upward search" to locate the message service part for a particular message name. This is described in how sendMessage(...) works.

A Message Service is a single Message name handled by a MessageReceiver part for many MessageSender parts in many subcells. This provides the Service Architecture Pattern. A part can receive both normal and service Messages. A part never knows whether it's being used as a service or not.

The exact Message Service policy is:

1. A MessageReceiver should not know if it's being used as a service or not. This allows greater reuse.

2. There can be only a single Message Service for a message name in a cell.

3. The "automatic upward search" stops when at least one receiver registered for that Message name is found. Note we don't try to use a return value from receive(Message) to determine whether the message has been handled, but the fact that the part was registered to handle it. This prevents confusing system designs. Service messages need clear destinations.

4. If a Message Service part needs to not service the Message, it should act as a filter and send the Message on. This lifts that responsibility from the router, who only has registry and explicit static routing responsibilities.

The implementation has documentation for some responsibilities that are not covered in the interface, such as Messages sent and received.

TODO - Later this interface will extend MessageReceiverDefiner and MessageSenderDefiner. We have not yet figured out how to best publish message service signals and interests. We expect this interface to evolve. :-)


Method Index

 o connect(Connection)
This creates a connection.
 o disconnect(Connection)
This disconnects a connection previously made with connect(Connection).
 o getMessageNames()
Returns all the message names currently connected.
 o getMessageNamesWithReceiver(MessageReceiver)
Returns all message names the receiver is connected to.
 o getMessageReceivers(String)
Returns all receivers for the messageName.
 o getParentRouter()
Returns the parent router or null if this is the root router.
 o sendMessage(Message, MessageSender, String)
Sends the message from the sender on to its destinations.
 o serviceMessage(Message, MessageSender)
Allows a router to handle a "service message".
 o setParentRouter(MessageRouter)
Sets the MessageRouter in the parent cell of this router.

Methods

 o connect
 public abstract void connect(Connection connection)
This creates a connection.

Parameters:
connection - the connection to connect.
Throws: IllegalStateException
if the connection has already been made.
 o disconnect
 public abstract Connection disconnect(Connection connection)
This disconnects a connection previously made with connect(Connection).

Parameters:
connection - the connection to disconnect.
Returns:
the connection removed or null if none.
 o sendMessage
 public abstract void sendMessage(Message message,
                                  MessageSender sender,
                                  String partName)
Sends the message from the sender on to its destinations. The MessageSender argument is strictly for tool (such as animation) and router use. It may have eventual other uses. It does NOT have the same use as in java.awt.EventObject, which we feel tightly couples the event source to the listener.

This method is called by the MessageDispatcher. Each part in a cell that's a MessageSender has a MessageDisplatcher. Thus this method contains messages only from parts inside the cell. These are hooked up with SIGNAL_OUT, SIGNAL_IN, SERVICE_OUT or DIRECT.

Here's the unfortunately complex and subtle algorithm for this method:

1. Internally determine the connections existing for the message name and sender. Put the results in isSignalOut, isSignalIn, isServiceNeed and isDirect.

2. If isSignalOut is true, call my receiver, as set in my setMessageReceiver(MessageReceiver) method.

3. If isSignalIn is true, call all receivers connected with INTEREST_IN for the message name.

4. If isDirect is true, call the receivers connected with DIRECT for the message name from that sender.

5. If isServiceNeed is true:

- If this router has a SERVICE_SUPPLIER for the message name, call that receiver.

- Otherwise if the parent router is not null, call parentRouter.serviceMessage(message, sender);

- Otherwise there is no one to handle the service needed, so a RuntimeException is thrown since this is a probable configuration error. Parts are welcome to catch this exception if they consider message fulfillment optional.

6. If monitoring is turned on, just before and after each message is sent, messages named "MonitorBeforeReceive" and "MonitorAfterReceive" are sent to this very method. Endless loops are avoided by not sending monitor messages for these two message names. Monitoring is an unusual message case. :-)

Parameters:
message - the message to send.
sender - the original sender of the message.
partName - the name of the sender part.
 o serviceMessage
 public abstract void serviceMessage(Message message,
                                     MessageSender sender)
Allows a router to handle a "service message". See the algorithm in sendMessage(...)

Parameters:
message - the message to send.
sender - the original sender of the message.
 o setParentRouter
 public abstract void setParentRouter(MessageRouter parentRouter)
Sets the MessageRouter in the parent cell of this router.

Parameters:
parentRouter - the parent router.
 o getParentRouter
 public abstract MessageRouter getParentRouter()
Returns the parent router or null if this is the root router.

Returns:
the parent router.
 o getMessageNames
 public abstract Enumeration getMessageNames()
Returns all the message names currently connected.

Returns:
an enumeration message names.
 o getMessageReceivers
 public abstract Enumeration getMessageReceivers(String messageName)
Returns all receivers for the messageName.

Returns:
an enumeration of MessageReceivers.
 o getMessageNamesWithReceiver
 public abstract Enumeration getMessageNamesWithReceiver(MessageReceiver receiver)
Returns all message names the receiver is connected to.

Returns:
an enumeration of message names.

All Packages  Class Hierarchy  This Package  Previous  Next  Index