!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN"> CSE 332S: Lab 3

CSE 332S: Object Oriented Software Design Laboratory

Spring 2008: Lab 3

Due 11:59pm, March 4, 2006.

Purpose

This lab will give you some experience design, implementing and testing a class hierarchy in C++, dealing with file input and output, and in dealing with other people's test files.

Background

The remainder of the labs for the class will all build towards a common final application: an Instant Message (IM) client. Your final client will perform all the functions of a standard IM client, but will use a local server and protocol (which we will explain below). This lab will be the first step, and will involve implementing the basic message data structures that you will use in the subsequent labs.

The Protocol

Our IM system will use it's own protocol. All messages will be sent as plain text strings, enclosed in XML-like tags. A message starts with the string <message> and ends with the string </message>. All messages have a type, sender, and timestamp enclosed in similar tags (such as <sender>). Some messages have additional tags, depending on the message type. Messages can include white space between the tags, so
<type>hello</type><sender>wds</sender><timestamp>1159911076</timestamp>
and
<type>hello</type>
<sender>wds</sender>   <timestamp>1159911076</timestamp>
are the same message.

Hello

A "hello" message is used to establish communication with the server, and will be sent when the client starts up. A "hello" message sent by wds looks like this:
<message>
<type>hello</type>
<sender>wds</sender>
<timestamp>1159911076</timestamp>
</message>

Goodbye

A "goodbye" message is used to close communications with the server, and will be sent when the client starts shuts down. A "goodbye" message sent by wds looks like this:
<message>
<type>goodbye</type>
<sender>wds</sender>
<timestamp>1159911076</timestamp>
</message>

Text

A "text" message carries the text of a message, and is used to send messages to other clients or the server. A "text" message sent by wds with the message "These are the actual words of the message." looks like this:
<message>
<type>text</type>
<sender>wds</sender>
<timestamp>1159911076</timestamp>
<text>These are the actual words of the message.</text>
</message>

Assignment

  1. Come up with a design for a class hierarchy that implements the above protocol messages. As a starting point:
    1. There should be one class for each of the three messages types, and these should inherit from a common base class called Message
    2. Put as much functionality as possible in the base class, and give some thought to what virtual functions and overloaded functions you want to have.
    3. You should have the following functions in the base class:
      1. const string &sender() const;
        This function returns the name of the message sender.
      2. time_t timestamp() const;
        This function returns the timestamp of the message, in seconds elapsed since 00:00:00 UTC, January 1, 1970.
      3. const char *type() const;
        This function returns the pointer to a (C-style) string containing the type of the message (the thing in the type tags).
      4. void serialize(ostream &out) const;
        This function outputs the message (in the format above) to the stream passed as the argument.
    You also need to come up with a testing plan for your design. It isn't sufficient to say "I'll do some testing". You need to write down what you're going to be testing. For example, you can test the case of a message that doesn't have a well-formed set of tags. For this lab, it is sufficient to write down the cases that you're going to test (remember to test a case where there are no problems). Also write down how you're going to determine if the test succeeded. Write all of this down below your design. Once you are happy with your design and testing plan, write it down, and show it to a TA. They will make sure that everything is OK with it, and approve it for implementation. If your design or testing plan is not approved by a TA, you will get no points for this lab.
  2. Once your design and testing plan are approved by a TA, implement it, and make sure that it works as expected. Document all of your code using the doxygen system. This involves putting special comments in your header file. We haven't covered this tool in class, but you can find out all about it at their web site. You code should include (at least) documentation that includes your name, the date, the return types and parameters of the functions, and a description of the classes. Name your configuration file Doxyfile, and set things up to only generate html documentation.
  3. Write a factory function that reads from an input stream, and generates a message from it. The function should have the following prototype:
    Message *messageFactory(istream &in);
    The function should have the following behavior:
    1. If the stream contains a valid message description, according to the protocol above, it should allocate a message of the appropriate type, and return a pointer to it.
    2. If the stream contains something that is not a valid message description, the function should consume the invalid input until it detects a valid message description. and inform the caller.
    The function should only generate (at most) one message for each call. To generate all messages from a stream, the function should be called multiple times. For example, if the stream is
    <message><type>hello</type><sender>wds</sender><timestamp>1159911076</timestamp></message><message><type>text</type><sender>wds</sender><timestamp>1159911076</timestamp><text>These are the actual words of the message.</text></message>
    your function should return a "hello" message on the first call, and a "text" message on the second.
  4. Write a program that opens a file (supplied as a command-line argument), repeated calls the factory function until all the messages have been extracted from the file, and prints out each message using the protocol described above.
  5. Create between two and five test files to make sure that your code does the right thing. These files should provide challenging cases that test the robustness and correctness of your code. Copy these files to the directory ~cse332/public. We will use these files for our own testing. Name your files using your cec login, with a lower-case letter appended. For example, abc1 would copy files named abc1a and abc1b.
  6. Implement a function that prints out English descriptions of the various messages, with their timestamp. The messages should look like this:
    [13:32:02] wds: Connection established.
    [13:32:22] wds: These are the actual words of the message.
    [13:33:12] wds: Connection terminated.
    The function should take a single argument representing the number of columns available for printing. You should format the output such that the total width (including the information at the left) takes than number of columns or fewer. For example, if the function is called foo, foo(80) would result in
    [13:32:22] wds: These are the actual words of the message.
    but foo(32) would result in
    [13:32:22] wds: These are the
               wds: actual words of
               wds: the message.

Grading

Most of the points in this lab will be for having the code work as described above. We will deduct points for the following things:
  1. Deviations from your approved design.
  2. Not compiling. If your code does not compile, then you will get no points for this lab.
  3. Warnings or errors in the compile. Your code should not generate any warning messages when compiled with the -Wall flag.
  4. Failing on any of the submitted test files, or on any of our test files.
  5. Deviations from the coding guidelines.
  6. Incorrect or poorly-written algorithms.

What to Hand In

Before you start coding, you need to show a TA your class design. This design should be written out on paper before you talk to the TA (you're not allowed to make it up on the spot on the whiteboard). It should show the class hierarchy, and list the functions (member, virtual, pure virtual, and global) and data members for each of the classes. If your design is OK, the TA will sign the piece of paper, and you are free to start coding. If there's a problem with your design, your TA will explain it to you, and ask you to revise the design.

Thoughts

  1. The most important part of this lab is the design of the class hierarchy. You need to have you design approved by a TA before you start coding. Be aware that the TA might ask for a rewrite of the design before you start, and that this rewrite will require extra time. Also, don't assume that the TAs are waiting by their computers for your design. It might take a little while for them to approve your design. If you code to an unapproved design, then you will get zero points of the lab.
  2. Times on Linux systems are measured since the start of the Epoch (00:00:00 UTC, January 1, 1970. You can find out more about the time_t type on the man page for the time system call (in section 2 of the manual).
  3. Since they're all related, all of the message classes can probably live in the same header and implementation files.
  4. You'll be working with strings a lot in this lab. We recommend that you use the string class.
  5. As part of your factory function, you will have to write some code that reads from the stream, and identifies the message tags. You're free to do this in any way you like, but you might want to consider implementing a class that does this parsing, returning the tag name and the value of the stuff inside the tag. Remember that you might have to treat the <message> tag differently.
  6. The factory function can inform the calling function in one of two ways. It can either throw an exception, or through its return value. We leave it up to you do decide which is the best option.
  7. You can open a file for reading using
    istream in("filename");
    and check that everything worked with a call to in.fail(). Input file streams require the inclusion of the fstream header file, and behave just like the standard input cin. Read the book for more details.
  8. Only copy between two and five files to the ~cse332/public directory. We will deduct points for each file less than two, or more than five you submit. We're going to use these files to test other people's code. You will get points for each test file that breaks another person's code, and lose points for each (valid) test file that breaks your code. This means that there's value in thinking about your own test files, and in testing your code against other people's files.
  9. When formatting the output of the messages, try to stick to the spirit of the assignment. Minimize the amount of white space at the end of the line, and minimize the number of lines that the output takes up. This means that you're going to have to parse the string that holds the message for the text messages. You might want to consider that happens when you have really long words in the message. Remember to document your design decisions in your README file. There are a number of ways to do this, but you might want to read about strtok for some ideas.
  10. Your factory function will be allocating things on the heap. Make sure that you get rid of these things properly, so that you do not have any memory leaks.
  11. Yes, you have to actually implement and perform the tests in your testing plan. Yes, it seems obvious for us to say this. Yes, a previous student didn't and used the "You didn't say to implement it!" defense.
Page written by Bill Smart.