Fundamentals of Computer Science II (CSC-152 99F)


Notes on Assignment 1: A MailMessage Class

As I've mentioned in the past, an assignment that met the basic requirements of the assignment earned a B. Something that lacked some of those requirements What were the basic requirements (both explicit and implicit)? I expected that you would turn in working could, that you would follow my standards for commenting and formatting code, and that your class would have:

I also expected that you would test at least the toString and makeReply methods

Deficiencies

Few of you followed my standards for commenting code. I realize that it's hard to see the reasons for those standards right now, but they are important. We'll come back to those in a little bit. I was relatively lenient in how much I took off for failure to follow standards.

Many of you neglected to include methods to set and get fields. Surprisingly, some of you included all the set methods, but none of the get methods (or vice versa). I realize that some sample classes (e.g., SimpleDate) don't include methods for setting the fields, but it's equally clear that we will want to update mail messages before we send them. The default for most classes should be to include setters and getters for each of the important fields. If you don't think it's reasonable to provide such methods, you should document why.

Almost none of you bothered to describe the appropriate format (or limitations on values) for your fields. For example, what should the string for a sender look like? Is it the name? The email address? Some combination thereof? You might document such restrictions in the introductory comment, in the field descriptions, in the constructor comment, in the comments for the setXXX methods, or some combination thereof. (I'd recommend the introductory comment.)

A few of you ignored the return type of makeReply. The makeReply method is supposed to return a new MailMessage. Why does it return a MailMessage? Because it's making a reply to an existing message. A reply is a MailMessage. It's also a different message. That means that your method should have something like the following structure.

  public MailMessage makeReply() {
    // Create the reply.
    MailMessage reply = new MailMessage(...);
    // Fill in the details.
    ...
    // Return the newly-created reply.
    return reply;
  } // makeReply()

A few of you made the recipient of the message the sender of the reply. While that seems reasonable for now, please realize that someone who has been CC'd a message might also reply to the message. (One option would have been to note that you realized that what you were doing was inaccurate.)

A few of you were not very careful about your variable, parameter, or field names. For example, here's a similar constructor header to one I saw in a few of your programs.

  /** Create a new message, filling in all the details. */
  public MailMessage(String s, String nm1, 
                     String nm2, String str, 
                     String d) {
    ...
  } // MailMessage(String,String,String,String,String)

Your goals is to choose sufficiently clear parameter names that someone using your method can figure out what each parameter should be. That's not possible in this case.

Some of you compounded the problem by having too many parameters to the constructor. When a constructor has more than five parameters, it's likely that the programmer who has to use the constructor will have trouble getting them in the right order, and won't realize the mistake until the program has problems. A better strategy would be to provide a zero-parameter constructor and have the programmer use lots of setXXX methods. It's a little bit more time-consuming, but it's a lot clearer.

Parts of Better Solutions

Most of the better solutions covered the basics described above and below, but did them particularly well or carefully. Some of you provided me with nice solutions that go beyond the basics described above. What are things that caught my eye?

A few of you decided to separate senders (and recipients) into two fields: one for the email address and one for the name. Of course, an even better solution would be to create a helper class, such as NetEntity, which contains both fields. For example,

  /** The sender.  See the NetEntity class for restrictions. */
  protected NetEntity sender;
  // ...
  sender = new NetEntity(senderEmail, senderName);
  // ...
  public String toString() {
    return "From: " + sender.toString() 
    // + ...
  } // toString()

A few of you carefully thought about how you might use helper classes for things like the header. Careful separation into subclasses can ease development and make your program much clearer.

A few of you noted that the sender of a reply may not be the direct recipient (it may be someone cc'd or bcc'd) and found some clever ways to describe and handle the issue. One that I particularly liked was having some user settings that could be included.

A few of you succeeded in quoting the reply, most typically by putting something like "XXX wrote" before the body and "end of quotation" afterwards. For example, you might have written the following.

  public MailMessage makeReply(boolean quote, User replier) {
    // Generate the new message for the reply.
    MailMessage reply = new MailMessage();
    // Set the sender.  The sender is the user making the reply.  We need
    // his/her name and email address.
    reply.setSender(replier.getEmail(), replier.getName());
    // Set the recipient.  The recipient of a reply is most typically the
    // person who sent the original email message.
    reply.setRecipient(this.sender.getEmail(), this.sender.getName());
    // Set the subject of the reply.  Custom dictates that this is 
    // "Re: oldsubject".  However, some believe that if the old subject 
    //  was itself a reply ("Re: XXX"), one can just use "Re: XXX" again
    // instead of "Re: Re: XXX".  We choose the more extreme version, 
    // which sometimes generates subjects like "Re: Re: Re: Re: Hi!".
    reply.setSubject("Re: " + this.subject);
    // Prepare the body of the reply.  We expect that someone will later
    // add some real content.
    reply.setBody(this.sender.getName() + " wrote: " + \n" + body + "\n" + 
      "----- end quoted material -----\n\n" + replier.signature);
    // That's it.
    return reply;
  } // makeReply(boolean, User)

Rather than relying on preset messages, some of you allowed the tester to enter a message. One of you went so far as to try to simulate an email program. All of these made it easier to test variations (e.g., what happens if you don't include part of the message?).

Comments and Formatting

I've documented some general expectations elsewhere. Here's a quick summary.

Examples

The MailMessage Class


/**
 * A simple implementation of mail messages.  Intended to illustrate
 * a basic, but correct, solution for assignment 1 of CS152 99F.
 *
 * Right now, includes only one primary recipient and no carbon-copied
 * recipients.  Also ignores many common header fields.  All email
 * addresses should be of the form name@host.  Names should not include
 * quotation marks.  Of all the components you can set and get, only
 * dates can be null.
 *
 * May eventually be expanded to include that additional information.
 *
 * @author Samuel A. Rebelsky
 * @version 1.1 of September 1999
 */
public class SimpleMailMessage {
  // +--------+--------------------------------------------------
  // | Fields |
  // +--------+

  /** The name of the person who sent the message. */
  protected String senderName;
  /** The email address of the person who sent the message. */
  protected String senderEmail;
  /** The name of the intended recipient.  */
  protected String recipientName;
  /** The email address of that recipient. */
  protected String recipientEmail;
  /** The date the message was sent. */
  protected SimpleDate dateSent;
  /** The subject of the message. */
  protected String subject;
  /** The body of the message. */
  protected String body;

  // +--------------+--------------------------------------------
  // | Constructors |
  // +--------------+

  /**
   * Create a new message, specifying all of the components.
   * Of these components, only the date can be null.  For the
   * others, use the empty string ("") for "unspecified".
   * If the body is not empty, please use a carraige return at the
   * end of the body.
   */
  public SimpleMailMessage(
      String senderName,
      String senderEmail,
      String recipientName,
      String recipientEmail,
      SimpleDate dateSent,
      String subject,
      String body) {
    this.senderName = senderName;
    this.senderEmail = senderEmail;
    this.recipientName = recipientName;
    this.recipientEmail = recipientEmail;
    this.dateSent = dateSent;
    this.subject = subject;
    this.body = body;
  } // SimpleMailMessage(...)

  /**
   * Create a simple mail message, with no components.
   */
  public SimpleMailMessage() {
    this.senderName = "";
    this.senderEmail = "";
    this.recipientName = "";
    this.recipientEmail = "";
    this.dateSent = null;
    this.subject = "";
    this.body = "";
  } // SimpleMailMessage()

  // +-----------+-----------------------------------------------
  // | Accessors |
  // +-----------+

  /**
   * Get the body of the message.
   */
  public String getBody() {
    return this.body;
  } // getBody()

  /**
   * Get the date the message was sent. 
   */
  public SimpleDate getDate() {
    return this.dateSent;
  } // getDate()

  /**
   * Get the email address of the recipient of the message. 
   */
  public String getRecipientEmail() {
    return this.recipientEmail;
  } // getRecipientEmail()

  /**
   * Get the name of the recipient of the message. 
   */
  public String getRecipientName() {
    return this.recipientName;
  } // getRecipientName()

  /**
   * Get the email address of the sender of the message. 
   */
  public String getSenderEmail() {
    return this.senderEmail;
  } // getSenderEmail()

  /**
   * Get the name of the sender of the message. 
   */
  public String getSenderName() {
    return this.senderName;
  } // getSenderName()

  /**
   * Get the subject of the message.
   */
  public String getSubject() {
    return this.subject;
  } // getSubject()

  /**
   * Get a simple, printable, version of the message.
   */
  public String toString() {
    String message = "";
    // Add a from address, if it exists.
    if (!this.senderEmail.equals("") || !this.senderName.equals("")) {
      message = message + "From: ";
      if (!this.senderName.equals("")) {
        message = message + "\"" + this.senderName + "\" ";
      }
      if (!this.senderEmail.equals("")) {
        message = message + "<" + this.senderEmail + ">";
      }
      // Don't forget the carriage return
      message = message + "\n";
    } // if there is a from address
    // Add a to address, if it exists.
    if (!this.recipientEmail.equals("") || !this.recipientName.equals("")) {
      message = message + "To: ";
      if (!this.recipientName.equals("")) {
        message = message + "\"" + this.recipientName + "\" ";
      }
      if (!this.recipientEmail.equals("")) {
        message = message + "<" + this.recipientEmail + ">";
      }
      // Don't forget the carriage return
      message = message + "\n";
    } // if there is a to address
    // Add a subject, if it exists.
    if (!this.subject.equals("")) {
      message = message + "Subject: " + this.subject + "\n";
    }
    // Add a date, if it exsits.
    if (this.dateSent != null) {
      message = message + "Date: " + this.dateSent.toString() + "\n";
    }
    // Add a blank line if the header is nonempty.
    if (!message.equals("")) {
      message = message + "\n";
    }
    // Add the body.  The body should end with a carriage return.
    message = message + body;
    // That's it.  Return the result.
    return message;
  } // toString()

  // +-----------+-----------------------------------------------
  // | Modifiers |
  // +-----------+

  /**
   * Set the body.  Empty messages should have the empty string
   * ("") as their bodies.  Returns the old body.
   */
  public String setBody(String newBody) {
    String oldBody = this.body;
    this.body = newBody;
    return oldBody;
  } // setBody(String)
   
  /** 
   * Set the date.  Use null for unknown date.  Returns the old date.
   */
  public SimpleDate setDate(SimpleDate newDate) {
    SimpleDate oldDate = this.dateSent;
    this.dateSent = newDate;
    return oldDate;
  } // setDate(SimpleDate)

  /**
   * Set the recipient.  Requires both a name and an email address.
   * Neither should be null.
   */
  public void setRecipient(String newName, String newEmail) {
    this.recipientName = newName;
    this.recipientEmail = newEmail;
  } // setRecipeint(String,String)

  /**
   * Set the sender.  Requires both a name and an email address.
   * Neither should be null.
   */
  public void setSender(String newName, String newEmail) {
    this.senderName = newName;
    this.senderEmail = newEmail;
  } // setSender(String,String)

  /**
   * Set the subject.  An empty message should have the empty string
   * ("") as its subject.  Returns the old subject.
   */
  public String setSubject(String newSubject) {
    String oldSubject = this.subject;
    this.subject= newSubject;
    return oldSubject;
  } // setSubject(String)
   
  // +---------------+-------------------------------------------
  // | Miscellaneous |
  // +---------------+

  /**
   * Create the initial reply to this message.  The reply will
   * have inverted sender and recipient and a slightly updated
   * subject.  The body will be empty.  Note that the choice to
   * make the recipient the sender is not necessarily appropriate,
   * since the person making the reply may be someone on the
   * Cc or Bcc list.  However, it should suffice for now.
   */
  public SimpleMailMessage makeReply() {
    SimpleMailMessage reply = new SimpleMailMessage();
    reply.setSender(this.recipientName, this.recipientEmail);
    reply.setRecipient(this.senderName, this.senderEmail);
    reply.setSubject("Re: " + this.subject);
    return reply;
  } // makeReply()

} // class SimpleMailMessage


The Test Program


import SimpleDate;
import SimpleMailMessage;
import SimpleOutput;

/**
 * A simple test of the SimpleMailMessage class.
 * 
 * @author Samuel A. Rebelsky
 * @version 1.0 of September 1999
 */
public class TestSMM {
  public static void main(String[] args) {
    // Prepare for output.
    SimpleOutput out = new SimpleOutput();

    // Can we create a message by specifying all the fields?
    SimpleMailMessage messageOne = 
      new SimpleMailMessage(
        "Sam Rebelsky", "rebelsky@grinnell.edu",
        "Clif Flynt", "clif@cflynt.com",
        new SimpleDate(1999, 9, 15),
        "Thanks!",
        "Thanks for doing such a good job of preparing the\n" +
          "students in 151.  It's making my job in 152 much easier.\n" +
          "-- SamR\n");
    out.println("First message: ");
    out.println(messageOne.toString());
    out.println("-----------");
    out.println();

    // Make a reply
    SimpleMailMessage replyOne = messageOne.makeReply();
    out.println("The reply: ");
    out.println(replyOne.toString());
    out.println("-----------");
    out.println();

    // Set the body.
    replyOne.setBody("Glad to help.\n");
    out.println("The reply with updated body: ");
    out.println(replyOne.toString());
    out.println("-----------");
    out.println();

    // Can we change the recipient?
    messageOne.setRecipient("Henry Walker", "walker@math.grin.edu");
    out.println("Returning to original message ...");
    out.println("After changing recipient: ");
    out.println(messageOne.toString());
    out.println("-----------");
    out.println();

    // What happens when we drop the subject?  Note that we use ""
    // rather than null because SimpleMailMessage tells us to do so.
    messageOne.setSubject("");
    out.println("After dropping subject: ");
    out.println(messageOne.toString());
    out.println("-----------");
    out.println();
   
    // Can we change the subject?
    messageOne.setSubject("Thanks for preparing 151 students");
    out.println("After changing subject: ");
    out.println(messageOne.toString());
    out.println("-----------");
    out.println();

    // Can we drop the body?
    messageOne.setBody("");
    out.println("After dropping body: ");
    out.println(messageOne.toString());
    out.println("-----------");
    out.println();

    // What happens when we create an empty message?
    SimpleMailMessage messageTwo = new SimpleMailMessage();
    out.println("Empty message:");
    out.println(messageTwo.toString());
    out.println("-----------");
    out.println();

    // Start filling in the blanks
    messageTwo.setSender("Sam Rebelsky", "rebelsky@grinnell.edu");
    messageTwo.setRecipient("John Stone", "stone@math.grin.edu");
    messageTwo.setBody("Don't forget to send me your comments.\n");
    out.println("With some details:");
    out.println(messageTwo.toString());
    out.println("-----------");
    out.println();
     
    // Generate a reply   
    SimpleMailMessage replyTwo = messageTwo.makeReply();
    out.println("The reply:");
    out.println(replyTwo.toString());
    out.println("-----------");
    out.println();
 
    // Fill in the body
    replyTwo.setBody("Of course.\n");
    out.println("The updated reply:");
    out.println(replyTwo.toString());
    out.println("-----------");
    out.println();
 
  } // main(String[])

} // class TestSMM


Sample Output

First message: 
From: "Sam Rebelsky" <rebelsky@grinnell.edu>
To: "Clif Flynt" <clif@cflynt.com>
Subject: Thanks!
Date: 9/15/1999

Thanks for doing such a good job of preparing the
students in 151.  It's making my job in 152 much easier.
-- SamR

-----------

The reply: 
From: "Clif Flynt" <clif@cflynt.com>
To: "Sam Rebelsky" <rebelsky@grinnell.edu>
Subject: Re: Thanks!


-----------

The reply with updated body: 
From: "Clif Flynt" <clif@cflynt.com>
To: "Sam Rebelsky" <rebelsky@grinnell.edu>
Subject: Re: Thanks!

Glad to help.

-----------

Returning to original message ...
After changing recipient: 
From: "Sam Rebelsky" <rebelsky@grinnell.edu>
To: "Henry Walker" <walker@math.grin.edu>
Subject: Thanks!
Date: 9/15/1999

Thanks for doing such a good job of preparing the
students in 151.  It's making my job in 152 much easier.
-- SamR

-----------

After dropping subject: 
From: "Sam Rebelsky" <rebelsky@grinnell.edu>
To: "Henry Walker" <walker@math.grin.edu>
Date: 9/15/1999

Thanks for doing such a good job of preparing the
students in 151.  It's making my job in 152 much easier.
-- SamR

-----------

After changing subject: 
From: "Sam Rebelsky" <rebelsky@grinnell.edu>
To: "Henry Walker" <walker@math.grin.edu>
Subject: Thanks for preparing 151 students
Date: 9/15/1999

Thanks for doing such a good job of preparing the
students in 151.  It's making my job in 152 much easier.
-- SamR

-----------

After dropping body: 
From: "Sam Rebelsky" <rebelsky@grinnell.edu>
To: "Henry Walker" <walker@math.grin.edu>
Subject: Thanks for preparing 151 students
Date: 9/15/1999


-----------

Empty message:

-----------

With some details:
From: "Sam Rebelsky" <rebelsky@grinnell.edu>
To: "John Stone" <stone@math.grin.edu>

Don't forget to send me your comments.

-----------

The reply:
From: "John Stone" <stone@math.grin.edu>
To: "Sam Rebelsky" <rebelsky@grinnell.edu>
Subject: Re: 


-----------

The updated reply:
From: "John Stone" <stone@math.grin.edu>
To: "Sam Rebelsky" <rebelsky@grinnell.edu>
Subject: Re: 

Of course.

-----------

The NetEntity Helper Class


/**
 * Information on someone on the net.  Right now, includes only email
 * address and name.  The email address should take the form name@host.
 * The name should not include quotation marks.  Neither should be null:
 * use the empty string if you want an empty name.
 *
 * @author Sam Rebelsky
 * @version 1.0 of September 1999
 */
public class NetEntity {
  // +--------+--------------------------------------------------
  // | Fields |
  // +--------+
  
  /** The person's email address. */
  protected String email;
  /** The person's name (or alias). */
  protected String name;
  
  // +--------------+--------------------------------------------
  // | Constructors |
  // +--------------+
  
  /** 
   * Create a new entity, specifying email and name. See the intro 
   * for restrictions on email and name.
   */
  public NetEntity(String email, String name) {
    this.email = email;
    this.name = name;
  } // NetEntity(String,String)
  
  // +---------+-------------------------------------------------
  // | Methods |
  // +---------+
  
  /** Get the email address. */
  public String getEmail() {
    return this.email;
  } // getEmail()
  
  /** Get the name or alias. */
  public String getName() {
    return this.name;
  } // getName()
  
  /** 
   * Set the email address.  See the introduction for restrictions. 
   * Returns the old email address. 
   */
  public String setEmail(String email) {
   String old = email;
   this.email = email;
   return old;
  } // setEmail(String)
  
  /** 
   * Set the name.  *See the introduction for restrictions. 
   * Returns the old name.
   */
  public String setName(String name) {
    String old = name;
    this.name = name;
    return old;
  } // setName(String)

  /** Convert to a string for printing. */
  public String toString() {
    if (name.equals("")) {
      return "<" + this.email + ">";
    } 
    else {
      return "\"" + this.name + "\"" + "<" + this.email + ">";
    }
  } // toString()
} // class NetEntity


History

Wednesday, 15 September 1999

Sunday, 19 September 1999


Disclaimer Often, these pages were created "on the fly" with little, if any, proofreading. Any or all of the information on the pages may be incorrect. Please contact me if you notice errors.

This page may be found at http://www.math.grin.edu/~rebelsky/Courses/CS152/99F/Assignments/notes.01.html

Source text last modified Sun Sep 19 19:46:50 1999.

This page generated on Sun Sep 19 19:47:20 1999 by Siteweaver. Validate this page's HTML.

Contact our webmaster at rebelsky@grinnell.edu