!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
- Come up with a design for a class hierarchy that implements the
above protocol messages. As a starting point:
- There should be one class for each of the three messages
types, and these should inherit from a common base class
called
Message
- 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.
- You should have the following functions in the base class:
const string &sender() const;
This function returns the name of the message sender.
time_t timestamp() const;
This function returns the timestamp of the message, in seconds
elapsed since 00:00:00 UTC, January 1, 1970.
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).
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.
- 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.
- 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:
- 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.
- 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.
- 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.
- 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.
- 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:
- Deviations from your approved design.
- Not compiling. If your code does not compile, then you will get
no points for this lab.
- Warnings or errors in the compile. Your code should not generate
any warning messages when compiled with the
-Wall
flag.
- Failing on any of the submitted test files, or on any of our test
files.
- Deviations from the coding guidelines.
- 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
- 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.
- 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).
- Since they're all related, all of the message classes can probably
live in the same header and implementation files.
- You'll be working with strings a lot in this lab. We recommend
that you use the
string class.
- 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.
- 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.
- 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.
- 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.
- 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.
- 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.
- 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.