CS4103 Distributed Systems: Coursework Practical – Phase 2 Richard Connor February 2022 Recommended completion: end of Week 5 Implement a message-passing system with a strict total ordering of messages The goal is to have different browser windows communicating via the server process. To achieve this, each browser window will act as a different process, each with its own id. The server will preserve a message pool of in-transit messages. Instances of a shared message class should be passed through the service interface, via calls to send and receive methods. The application should look something like this, just to give an outline idea. Obviously (!) don’t spend any serious time on making it look nice. The following text explains how this can be achieved using the GWT and Servlet architectures. Servlets, GWT etc As explained elsewhere, a single instance of the Java servlet is initialised at the first call to any of its service methods, and this stays extant until it is closed down by the server at some later time – typically when it hasn’t received any traffic for a long period. For the purposes of this project, this shouldn’t be an issue1 and you can assume that the class persists for the duration of its use. As all requests are served by a single servlet class instantiation, that object can provide shared state among different its clients. To allow message passing, all that is required is for the server class to maintain a pool of messages; a “send” from a client should add a new message to the pool, and a “receive” from a client should find a message destined for that client (if there is one), remove it from the pool, and return it to the client. If there is more than one message waiting for the client, it is up to you to decide which gets returned, but remember Lamport’s assumption that messages between the same two nodes will arrive in the order that they are sent. Be aware that the server implementation class must not have an explicit constructor. To initialise the state it’s normal to provide code for an “init” function that is called by the servlet manager when the class is initialised. All clients will require to have unique process ids; this can be achieved by the server class maintaining an integer for that purpose which is incremented and returned during an initial “registration” call from the client. As the author of a distributed system you should be aware that already this is already not necessarily safe, as two clients may make interleaved calls to this code! However it is the case that a Java integer increment-in-place operation will not be interrupted – in fact all scalar types in Java are “thread safe”. It is recommended to encode the messages as a simple Java class. Make sure this is in the “shared” package of the GWT project, implements the gwt.IsSerializable interface2, and doesn’t have an explicit constructor. If the server is maintaining a collection of such objects, it is best to make sure that this is thread safe. Although it’s possibly a reasonable assumption that it doesn’t matter – only a small number of calls are likely to be made, and each call is likely to take very little time at the server. But always remember that concurrent access to any collection type is undefined, which makes things very, very hard to debug when it happens… For collection types in Java it’s easy to ensure safety, see the example in my slides. To see what is happening at the server side, the server process can write the development mode console. It can just use the System.out object for this purpose; java.util logging is also available server-side. Or if you’re ambitious you can have a dedicated process querying the server. Interfaces The overall view of the system should be several browser windows, one representing each process, which communicate with each other via the server. The interface within each browser window can be extremely simple. For example, both send and receive events could be triggered by user buttons. It would be nice to display a text log of things like messages sent and received. 1 The programmer can supply methods which will be executed at startup and shutdown when initiated by the servlet manager, so it is possible to arrange for state to be stored and retrieved between invocations. This is not necessary for this project. 2 n.b. this is different from Java Serializable – which will almost always, but not quite always, work. As always spell serializable with a “z”… The minimal service functionality would be register (for a client to receive a unique id from the server), send, and receive. To add a little sophistication, it would be nice for receive to be a separate client-side thread (for which you need to use the gwt.Timer, not the Java Thread, class – remember all the client-side Java code is compiled into JavaScript, and JavaScript on a browser is not multi-threaded!) which regularly polls for new messages. It would also be nice for each process to learn from the server when other new clients are registered, so that messages are only sent to clients that exist (or, rather, as always in a distributed system, have existed at some point in the past!) This could be via a normal message receive sent from the server, or a separate service call. However, given the context of the exercise it’s also quite reasonable just to type a process id into the message send interface, as we’re not really expecting this application to be distributed over the Internet! Message content We will be re-using this framework for the next part of the practical exercise, so it would be good to have a relatively generic message class, which of course can be extended to allow different message types and payloads. The only requirement at this stage is for each message to have a timestamp, so that Lamport’s strict global ordering can be imposed on the set of messages passed during a session.