The Java Whiteboard System:

An Experiment in Internet Collaborative Communication

 

Jeff LoughridgeChris Jenkins
Duke UniversityDuke University
jbl2@duke.edu chris.jenkins@duke.edu
  1. Introduction
  2.  

    Email and other forms of communication have become an integral part of contemporary society. Older Internet text-based programs such as gopher and WAIS have given way to the visual nature of the World Wide Web. The move towards visual, electronic communication is a trend that will continue in all areas including collaborative applications. The Java Whiteboard System (JAWS) is a step in that direction. It blends the best elements of text and visual-based communication into a single collaborative tool for use on the Internet.

     

  3. Overview
  4. The JAWS team began the yearlong project with three goals in mind:

    1. Write a commercial-quality collaboration tool that would be useful
    2. Fully implement all features
    3. Make the source code free for distribution on the Internet

    The motivation for these goals was simple a product as described above does not yet exist, and the JAWS programmers have often desired using such a collaborative tool. The similar tools that do exist do not entirely meet all three goals because they either are not free, do not freely distribute the source code, or have very low functionality.

     

    The first step in designing the tool was to establish the desired behavior of finished product. The collaboration tool should model actual collaboration by

    1. Allowing individual participation at all times
    2. Providing an outlet for group work
    3. Allowing graphical and textual communication

    Each of the above three is vital to effective collaborative communication. For efficiency, communication must always be available to all users. Any turn-taking algorithm where users must wait for permission to communicate would be too stifling. Communication must be two-way during the entire session. Also because users should be able to produce some work independently, individual whiteboards were deemed necessary. Group work was made possible by including one larger community whiteboard editable by each user. The final element necessary was a chat area where the users could talk about the designs and sketches on the whiteboards.

     

    The large whiteboard is the editable area of the whiteboards. This is where each user can add to or alter the community or individual whiteboards. The color of the objects drawn identifies which user made the additions. JAWS is superior to other whiteboards available on the Internet because it offers simultaneous editing while maintaining overall data consistency. The action-based and object-based methodology used makes this possible. The sending of objects across the network is triggered by the completion of an action. For example, objects such as ovals are not drawn on other collaborators whiteboards until the originator has completely drawn the ovals. All visual elements in the viewing areas and on the workspace represent discrete objects. The objects may be moved individually or grouped to function as a single until. Data consistency is restored after all object completions and alterations.

     

    The four or fewer individual whiteboards and community whiteboard on the right of the application are the graphical views. These are for display only and are not editable. The larger community display is always visible since this location is where most of the group work will take place. The lower panel of four individual whiteboards can be dynamically changed into a single larger view for closer inspection of another individuals work (and of course the larger view can be changed back into the original four user view).

     

    One especially important feature worth mentioning is the ability to save and restore state. While the session is in progress, the current state of the application is always internally stored in each separate application. It is possible to save this state to a file in order to revisit the collaboration at a later time. On starting the application there is an option for starting a session from an old session (discussed in detail later and in the user manual).

     

  5. Design and Implementation of the Networking


  6. Considerable time and effort was put into the design of JAWS. A crucial decision that drastically influenced the design was the before-mentioned action and object-based distribution system. JAWS implements the distribution through a server/client model with the majority of complexity built into the client. The server simply multiplexes all incoming messages to all collaborators, including the originator of the message. The servers serial processing of the messages ensures overall data consistency.

     

    A collaborative structure is required to dictate how users interact. The first step in setting up the collaboration is connecting the users. The first user to start the application is designated as the leader and is charged with starting up the server and distributing a color mapping to users as they connect. Once all the users have joined, they can begin to draw on their individual and community whiteboards. A user can only draw in his/her own color on the individual and community whiteboard. This ensures that the originator of each alteration can be properly identified. The control and separation of whiteboards is achieved by maintaining separate lists of graphic objects for each whiteboard.

     

    Concurrency issues were a major consideration in the design. Nearly all of these issues could be resolved by updating at regular intervals or requiring users to manually send objects, but since collaboration on an actual whiteboard does not occur in this manner, this restraint was unacceptable. Simultaneous editing was the only option considered worthy of implementing. This choice improved the model of collaboration but made design much more difficult.

     

    JAWS implements a scheme in which drawing is done simultaneously with discrete updates. When a given user is drawing, other objects should not appear because this would not only muddle the users view but also would introduce concurrency problems. JAWS resolves this conflict through the use of a lock class that guarantees mutual exclusion between mouse drags and updates. The down click of the mouse stops incoming objects from being received and added to the list by grabbing the lock, thereby preventing alterations to the screen. Objects are buffered for the duration of the draw in the systems TCP buffer. This buffer is finite but does not introduce a problem because TCP will advertise a receive window of zero, effectively halting new data from being sent until data is consumed on the receiving end. This highly unlikely event will only occur it the user spent an inordinate amount of time holding down the mouse. On the release of the mouse button, the lock is removed, the new object is sent to the server, and then incoming objects are processed. It is important to note that when the new object is echoed back to the originator that it may appear in a different context. Several updates could occur while drawing a single object, altering the background on which the returned object will be drawn.

     

  7. From JAWS version 1 to JAWS version 2
  8. JAWS version 1 (Jv1) had a number of shortcomings that limited its potential. Foremost, users could draw objects but there was no corresponding delete option. Once the screen filled with objects, the session was virtually useless. Secondly, the number of collaborators was fixed at four. If the leader wanted to initiate a session, he had to have three others join him for the session to begin. The last serious deficiency was that the collaborators could not save a session, quit, and restore it at a later time.

     

    The authors set out to continue the JAWS program this semester addressing the faults in Jv1 listed above. By semester-end, the JAWS version 2 (Jv2) users would have the ability to:

    These items comprised a substantial undertaking and the team knew that considerable amount of time to reach would need to be invested to achieve these goals. However, early in the semester, it became apparent that the above goals could not be easily met using the existing design. The initial design stages did not account for the features described above and adding them in de facto would not have been easy. Also, there were numerous hacks that pervaded Jv1s code and were becoming more of a problem as new features were added.

     

    After careful consideration, the team decided a complete redesign was necessary. A new design was established that would accommodate the semester goals and eliminate hacks. This decision was quite ambitious because it required huge amounts of re-writing code. Some classes could be kept with minor alterations but others were eliminated entirely. The crucial aspects of the new design are object serialization and the Observer design pattern. The following sections will discuss the motivation for including these elements in Jv2, their implementation and how they achieved the semester goals.

     

    The communication between client in version 1 of the program used the traditional network programming model. Bytes of data were parsed into discrete messages by preceding the message with a header. The header included the length of message plus some other control information that indicated the type of message. The message body was further broken up for differing types of messages. There was also complexity in the process in which graphic objects had an encoding layer for converting the graphic object to a network-transferable form. There was a corresponding decoding layer that would convert the message back into a graphic object. Problems arose with this design when these encoding/decoding layers increased in size and complexity.

     

    Dr. Jeff Chase, the JAWS teams advisor, pointed out to the JAWS team a superior means of inter-client communication object serialization, a feature built into Java 1.1. To quote from Suns web page: "Object Serialization supports the encoding of objects and the objects reachable from them into a stream of bytes and it supports the complementary reconstruction of the object graph from the stream". The power in this technique is its simplicity. The programmer simply has to have the class implement the java.io.Externalizable or java.io.Serializable for it to be serialized. The below code example shows the writing of an object to the network.

    Socket sk = new Socket("remotehost.org", 5554);

    DataOutputStream dos = new DataOutputStream(sk.getOutputStream());

    ObjectOutputStream s = new ObjectOutputStream(dos);

    s.writeObject(new Foo());

    s.flush();

    The most important element of the process is the ObjectOutputStream class. Its writeObject method is called to serialize the object and then recursively serialize references to other objects contained in the class. The class also has write methods for Java primitives writeInt, writeFloat, writeUTF, etc. Another important feature of the ObjectOutputStream class is that its constructor can take any OutputStream as an argument. Thus, writing to a file is trivial as this code illustrates.

    FileOutputStream fos = new FileOutputStream("object.out");

    ObjectOutputStream s = new ObjectOutputStream(fos);

    s.writeInt(12345);

    s.writeObject(new Foo());

    s.flush();

    After this code is executed, the file object.out will contain the information necessary to reconstruct the class.

     

    Once an object is written to an OutputStream it must be deserialized to be useful. The receiving side must know about the class since only the classs data is serialized not the methods. Data within a class can be marked with the Java keyword transient, meaning that it should not be packaged for serialization. The below code snippet shows a class being read from an ObjectInputStream.

    // in is an instance of an InputStream

    ObjectInputStream s = new ObjectInputStream(in);

    Foo f = (Foo)s.readObject();

    The inter-client communication of Jv2 was designed to fully utilize serialization. Clients write classes to the network exclusively. The hack-filled message passing of Jv1 was eliminated. JAWSclient, the class that handles reads and writes to the network, was halved in size due to the ease of communicating via serialization. JAWSclient is a thread and thus has a run method that is executed at its creation. The run method has the following loop to read objects from the network.

    Object o;

    while(true) { // this loop runs for the duration of the program

    o=readObject(); // read object

    [snip] // send it off depending on type

    }

    The server has almost an identical loop that reads objects from the network. Once it receives an object it multiplexes it out to the OutputStreams connected to the collaborators.

     

    Using object serialization, the six message types of Jv1 have been simplified into the serialization of three classes Ping, JAWSchat_text and GraphicObject. Of these, JAWSchat_text is the least complex. It is a simple class that has two strings. One represents the originator of the message and the other the message text. JAWSclient will send JAWSchat_text messages directly to JAWSchat. The other classes are slighty more complex.

     

    The Ping class consists of data that is necessary in setting up the connection. Much like its ICMP ping cousin, a Ping is either a request or reply. The variables are divided between those two states. The only variable in a Ping request is a string name. A client sends out a Ping request with its name set. The leader receives the request and prepares a Ping response. Note that other clients who might already be attached will also receive the request but will ignore it. The leader is responsible for setting four variables in the response the hash that maps user to color, the number of collaborators connected already and the number of collaborators expected. (There is actually a fifth variable that will be discussed later in the paper). The leader sends the Ping response and all the clients update their knowledge about the session. If the number of members expected equals the number connected, than the session officially starts, and GraphicObjects can begin to be distributed.

     

    The GraphicObject class is base class of all objects able to be drawn on the whiteboards. This class includes the basic information necessary for drawing the object on a rectangular area. This basic information includes two sets of Coordinates describing the boundary of the rectangle in which the object can be drawn, the color of the object, the current state of the object, and the name of the object. The state of the object describes if the object is selected for moving or resizing. The name of the object is a string that describes the origin of the object.

     

    GraphicLine and GraphicPolygon are the only two objects that directly inherit from GraphicObject. The representation of a line in GraphicLine simply uses a pair of Coordinates for representing the endpoints. This along with mechanisms for moving, selecting, and painting the line are the only additions needed when extending GraphicObject to represent the line. Because of the similarity of being able to represent a rectangle with two Coordinates, GraphicRectangle was chosen to extend GraphicLine. Again adding mechanisms for painting, moving, and selecting was necessary. GraphicOval is perhaps the simplest of the GraphicObjects. It simply extends GraphicRectangle and changes the paint method to draw an oval instead of a rectangle. GraphicPolygon was one of the most challenging objects because of its variable number of vertexes. This unknown variable strains the action-based model because a polygon is not complete until its last vertex has been drawn. Also selecting the object for resizing involves finding the proper vertex.

     

    Each GraphicObject resides in at least one GraphicList. These GraphicLists represent the work of each individual and the community whiteboard. GraphicLists have a name and a color associated with them. The color for the individual whiteboard is the color assigned to that individual. The color for the community whiteboard is the color assigned to the current application. The name of the GraphicList is just the name of the individual for the individual whiteboards or "Community" for the community whiteboard. GraphicLists also contains a lock for guaranteeing mutual exclusion when concurrency becomes an issue. Effectively, obtaining the lock outside of the GraphicList guarantees that objects will not be added

     

    A critical element of the design of Jv2 is the JAWSstate class. Each client maintains a JAWSstate instance that contains information about all whiteboards in the session. It does this using five GraphicLists four individual and one community. When JAWSclient receives a GraphicObject, it sends it to JAWSstate which in turn places it in the appropriate list based on the owner field in the GraphicObject. The beauty in this JAWSstate class becomes apparent when it is used as part of the Observer design pattern.

     

    The JAWS design makes use of the Observer design pattern to separate the model from the view. All data for the graphics is kept in separate observable GraphicLists, one for each individual and one for the community whiteboard. The only assumption the GraphicList makes about the view is that it will be two-dimensional and rectangular. All information stored is in ratio form using the Coordinates class, that is the coordinates are stored as fractions of the width and height of the view. The ratios along with the any actual width and height can be used to construct the actual screen coordinates needed for the display.

     

    The GraphicLists within JAWSstate are the Observables. JAWSdisplay, the Observer, is the display for the GraphicLists. JAWSdisplays are the Observers that represent the GraphicLists while they are not being edited. JAWSdisplay is essentially a Panel with a paint method that queries the GraphicList when the GraphicList has been altered. How does JAWSdisplay know when a GraphicList has been altered? The Observers register themselves to the Observable and the Observable calls the notifyObservers method when something has changed. Thus changes in the state of the GraphicLists can be asychronously propagated instead of having JAWSdisplay continuously poll the GraphicList.

     

    The Observer design pattern is not suitable when the GraphicObjects are being altered because the GraphicList changes almost continuously during resizing. The result of continuous notification (which would happen because the list is changing continuously) would be continuous repaints of the entire screen, which would in turn cause the application for crawl. Because of this problem and that editing requires the changes to be sent over the network, a second display, JAWSsketch was required. This display is different from the others in that it directly alters the lists. Consistency is not an issue when directly altering the individual whiteboards because only the owner of the individual whiteboard may send out GraphicObjects directed at their own individual whiteboard. The order of the sends of GraphicObjects must be the order in which they are received because there is only one source of the sends. This is not the case for the Community whiteboard. Because of the delay in network transmissions, when two different users alter the whiteboard at nearly the same time, the order in which the server will receive the messages cannot be determined. Because of this, users cannot permanently change the Community whiteboard as they did the individual ones. The resolution is to temporarily alter the whiteboard (so that the user can see the changes he/she is making), and reestablish consistency when objects are received from the server.

     

    Now that the three main object types have been introduced (Ping, JAWSchat_text, and GraphicObject), the loop in the client can be expounded.

     

    Object o;

    // this loop runs for the duration of the program

    while(true) {

    o=readObject(); // read object

    // send it off depending on type

    if(o instanceof JAWSchat_text) {

    _app.addText((JAWSchat_text)o);

    }

    else if(o instanceof GraphicObject) {

    _state.addObject((GraphicObject)o);

    }

    else if(o instanceof Ping) {

    processPing((Ping)o);

    }

    else {

    System.err.println("not prepared to handle object");

    System.exit(1);

    }

    }

    The Java instanceof operator makes the processing of objects simple. It returns true if the left side is an instance of the class on the right side and false otherwise.

     

    Jv2s clean design made accomplishing the first goal of this semester simple. Saving state only involves serializing the JAWSstate class to a file. Both the leader and other collaborators can save the state. At start-up time, the leader has the option of restoring a session from a file. If he/she chooses to do so, the normal start up procedure is modified. The JAWSstate class is deserialized from a file and put in a Ping reply (the fifth variable in a Ping class). The clients know a session is being restored if the JAWSstate object exists in the Ping reply. The client sets its JAWSstate to the one in the Ping reply.

     

    The ability to delete and resize existed objects was successfully incorporated into Jv2. Deletes are done by marking a GraphicObject for deletion and then sending it out on the network. The other clients receive the GraphicObject and remove it from one of the GraphicLists in the JAWSstates. Resizes are implemented using delete. GraphicObjects are marked for deletion as above, but then a new GraphicObject with different coordinates is immediately sent.

     

    The drawback of forcing a four collaborator session was removed. Now between 2 and 4 people can collaborate. The simplicity of the Ping class was the major factor in this change. Still the limit is four due to a design decision that the medium could no t effectively support more users. Currently, monitor displays are not large enough to allow more than four users work to be adequately viewed in the graphical interface of JAWS.

  9. Conclusion
  10. The JAWS team has met the three goals outlined in the opening of the paper. The final product is a robust implementation of a whiteboard accompanied by readable source code. Since the code has been released on the Internet, it could be used as an example of a moderately complex distributive system. Programmers interested in object serialization, the Observer design pattern and concurrency issues will benefit from reading the source. If this does occur, the goals of the team will be surpassed and the hundreds of hours invested will have been worthwhile.