404 Not Found


nginx/1.18.0 (Ubuntu)

General Architecture of the Messaging System

404 Not Found

404 Not Found


nginx/1.18.0 (Ubuntu)
The Messaging system provides for a simple, extensible, and easily-implemented interface for "asynchronous" communication, using the built-in facilities of the Java language. Being asynchronous, it is designed in a multithreaded environment, which is able to send and receive Java objects without any "protocol," that is, there is no specified order in which data must be sent by either party of communication. In other words, unlike traditional network communication systems which require constant communication between the parties, the messaging system uses a separate listening thread, which, upon receiving data, notifies registered objects in the fashion of the Java listener/event model.

Because of the asynchronous nature of the system, two problems arise. The first, naturally, is the set of difficulties that normally accompany any multithreaded program: the need for synchronization, the possibility of non-deterministic behavior, and so on. The messaging system attempts to avoid these common threading problems as much as possible. The second problem is inherent in the nature of the program itself: because of its asynchronousness, it is difficult to establish a "protocol," or a set order of communication. For example, in a game of chess there is the protocol in which one player makes a move, and then the other player makes the next, and so on. A simple networked game of two player chess would have one player send a move, and the second player "reads" the move from the stream and then sends a move, and so on. However, with the messaging system, there is no way to prevent one player from sending ten moves in a row before the other player has sent anything. To solve such a problem, the implementor must develop a "state machine" on both ends of the communication which determines when to send what data. In the example of the chess game, a flag indicating whose move is to be made next would solve the problem. An example of a state machine establishing a protocol within the messaging system is the FileTransferManager.

However, these problems of creating protocol are greatly overshadowed by the benefits found in being able to send and receive information independent of each other. After all, this is how telephones, people, and most modern operating systems work.

Outline

DataReceiver

The DataReceiver class forms the core of the Messaging architecture. It provides for the "asynchronous" receipt of objects through some provided stream, and contains a mechanism for acting upon the immediate receipt of those objects.

DataListener and DataEvent

The DataReceiver invokes notification of received data through DataListener objects which have registered themselves with the DataReceiver. When an object is received, the DataReceiver creates a DataEvent object containing the received object, and fires it to all DataListeners through the dataReceived method.

Additionally, when the stream through which the DataReceiver is receiving objects is closed, it fires the streamClosed method on all of its DataListeners. The object which is fired with this method should be ignored.

Object Serialization

The DataReceiver's constructor requires an InputStream. This InputStream should be unused and unwrapped (it may be buffered). The DataReceiver will use it to construct an ObjectInputStream. This means that the output end of the stream must be an ObjectOutputStream; otherwise the constructor will block until the stream header is flushed.

For more information, see the Javadoc for ObjectInputStream on Sun's web site.

Multithreading

In order to provide the immediate-response data receiving system of the DataReceiver, an external thread is used. This thread continuously reads objects from the stream and fires events, until there is an error in the stream (indicating generally that the stream has closed).

This means that the DataListener's actions must take into consideration that they will not be invoked on the main thread, so that any resources which they access should be protected through synchronization. Specifically, if those actions manipulate a GUI, then the SwingUtilities.invokeLater method must be used to perform such manipulations.

Packets

Although DataReceiver is capable of handling any type of Serializable object, the messaging system requires a more strict hierarchy of possible objects to be read. This hierarchy starts from the class:
edu.harvard.cduan.messaging.RoutingPacket
This object has three fields, two Users (a sender and a receiver) and a serializable object being sent. This information is immutable. Objects should always be sent wrapped in some type of packet. For even greater type security (and the possibility of including additional fields) the class may be extended. Newly introduced fields should also be immutable.

Users

Rather than using simply strings to represent user names, all user names are contained in immutable objects of type:
edu.harvard.cduan.messaging.User
In addition to providing type safety, this allows for users to be compared without case sensitivity. Future implementations may be able to ignore whitespace as well.

Messenger

The Messenger class provides the interface for the messaging system; all users should perform their message sending/receiving through this class. In its constructor, the Messenger requires an input and an output stream; the streams will be wrapped appropriately in object streams. The Messenger class also provides support for reconnection.

The Messenger class contains a user name. The object itself never actually uses that name; it is provided primarily for the implementor's convenience, since each Messenger is associated usually with only one user.

The class processes received packets through its method processObject, which is abstract. Any object received by the messenger will cause this method to be invoked. In alternate versions, a listener mechanism like that of DataReceiver may be chosen over the overridden-method model, particularly since many implementations of processObject would be better-suited to a listener-type environment.

Objects are sent through the sendObject method. Despite its name, only RoutingPackets may be passed to this method. It does not check the name of the sender of the packet.

Since the Messenger operates on the basis of a multithreaded environment, it provides start and stop methods, to start and stop the listening mechanism. It is often useful--and sometimes necessary--to override these methods. However, there is the danger that stop may be invoked multiple times. As an alternative, the Messenger may take ChangeListeners, which are notified when either of the two methods are invoked.

Next: Server Architecture

404 Not Found

404 Not Found


nginx/1.18.0 (Ubuntu)