Project 2: Instant Messaging

6.005 Elements of Software Construction
Fall 2007
Due: Tuesday, October 16, 5:00 PM

Problem

Instant messaging (IM) is a staple of the web and has been around almost since its inception, starting with simple text-based programs like talk and IRC and progressing to today's GUI-based IM clients from Yahoo, Microsoft, AOL, etc. In this project you will design and implement a text-based IM system (both the client and the server). The following characteristics constrain the design space of an IM system:

Your task will be to design a text-based IM system with the above properties, as well as additional properties that you will incorporate into your design.

Purpose

The purpose of this project is twofold. First,you will learn several Java technologies, including networking (to support connectivity over a network), sockets and I/O (to support real-time, text-based communication), and threads (to support two or more people communicating concurrently). As in project 1, you will have the opportunity to use state machines to specify certain aspects of the system's behavior.

More importantly, you will start learning how to take a set of high-level, informal requirements and iterate through the design, specification, implementation and testing of an end-to-end system.

Specification

Implement an IM system in Java with the following properties.

Tasks

  1. Prepare. Complete the lab.
  2. Define a conversation. Define a precise notion of conversation in your IM system. See the hints on how to do this step.
  3. Define the commands. Define a set of commands for the IM client that allow the client to perform the actions stipulated by the specification.
  4. Specify the client/server protocol. Create a specification of the text-based client/server protocol as a state machine. The state machine must include the possible transitions, the state of the server, and of the client if it stores any state.
  5. Design. Come up with a simple and clean class design that minimizes the risk of concurrency bugs (like race conditions and deadlocks), and that also supports easy unit testing of your state machine. Write a brief argument explaining how the design achieves this. The hints below may be helpful.
  6. Implement the protocol. You can use what you learned in lab as a guide to using Java's networking facilities.
  7. Test. There are no staff-provided JUnit tests for this project, because the design of the protocol is in your hands. However, you should create a small number of unit tests for your server. Use your state machine specification to devise a coherent testing strategy, so that the test cases you choose achieve some reasonable coverage. See the hints on how to design your server so that it's easy for your unit tests to drive.
  8. Iterate. You will probably need to iterate, making adjustments to the design and the code until you have a working program that satisfies the specification.
  9. Extend. Think of two features of an IM client that you would like to implement in your IM client. You don't have to model these features with state machines (but you can if you want). Possible ideas: a client having the ability to change status among "online," "offline," "busy," etc. Or giving the client the ability to request the transcript of a specific conversation. In short, anything that you would like to implement that may or may not be part of existing IM systems.
  10. Demonstrate. At your grading meeting, present your IM client to your TA. The presentation must include: (1) an overview and justification of the design choices, (2) a walk-through of the protocol, and (3) a demo of the IM client in action, showing how it implements the protocol.

Infrastructure

The lab code includes several classes that you became familiar with during the lab, and which you can use as a starting point. Designing your chat server and deciding how to divide it into modules is in your hands.

Deliverables and Grading

Your deliverables for the project are: the command specification; state machine model; the code; any automated tests you may have written for the code; and any commentary you wrote to explain the decisions you made, especially your argument that your design is free of concurrency bugs.

All commentary and diagrams should be in plain text or PDF and saved at the top level of your project directory. Each PDF or text file must contain an appropriate title describing it, along with the Athena usernames of you and your partner. Make sure your files have the appropriate extension (.pdf or .txt).

90% of your grade will be allotted to the design and implementation, and 10% to the design extensions. Of the 90%, 30% will be allotted to the command grammar and state machine model, 40% to the code (half for structure and half for correctness), and 20% to test cases.

Hints

Defining a conversation. Part of your job is to determine what a conversation means. For example, does a conversation have a name, and can other users join the conversation by specifying the name? Is it like a chat room, that people can enter and exit? In that case, can a conversation be empty (a chatroom can), waiting for users?

Or is a conversation more like a phone call, where a person "dials" another person? In that case, can the receiving party deny the conversation?

However you define a conversation, remember to keep it simple for your first iteration. You can always extend your program with interesting ideas if you have time left.

Handling multiple clients. Since instant messaging is useless without at least two people, your server must be able to handle multiple clients connected at the same time. The Friendly server you'll develop in the lab gives you some starting code, but note that Friendly doesn't need its clients to interact or share any state. Your server will certainly need to do that. One reasonable design approach follows the Friendly model (using one thread for reading input from each client) but adds a central state machine representing the state of the server (using one more thread, to which each of the client threads pass messages through a shared queue).

Designing for safe concurrency. In general, making an argument that an implementation is free of concurrency bugs (like race conditions and deadlocks) is very difficult and error-prone. The best strategy therefore is to design your program to allow a very simple argument, by limiting your use of concurrency and especially avoiding shared state wherever possible. For example, one approach is to use concurrency only for reading sockets, and to make the rest of the design single-threaded.

Designing for testability. To make it possible to write unit tests without having to open socket connections and parse streams of responses, you should design your state machine(s) in such a way that they can be driven directly by a unit test -- either by calling methods, or by putting messages into a queue read by the state machine's thread.