CS 134Homework Laboratory # 10
Spam, Spam, Spam

Objective: To gain experience with Strings and inheritance.

Before the mid-90s, Spam was a canned "meat" product. These days, the term "spam" means just one thing -- unwanted email. There is lots more information available about the history of the term "spam" online. Hormel (the makers of Spam) have an amusing web site dedicated to giving spam back its "good" reputation.

This week we will build a program that should give you insights into how you might add a spam filter capability to a mail program. Our spam filter is rather simple. The user provides a list of words. The program then searches the "from" and "subject" headers of all your mail messages and divides your mail into two lists. One list includes all the messages that contain words included in the filter list, and the other list is made up of messages that do not contain filter words.

The user interface we have in mind for the SpamFilter program is shown below:

The JTextFields on the left side of the top of the program window are used to specify the machine and account from which mail should be fetched. If the "Get mail" button is pressed after appropriate information has been entered in these fields, the program connects to the mail server and downloads the headers of all available messages.

The program then decides whether each of the messages it has fetched are good messages or spam based on what the user enters in the JTextArea labeled "Filter Terms." (See Secton 10.6.3 of the book for a description of JTextAreas, and how to add a scrollbar to them). Each line of text entered in this JTextArea is treated as an indicator of spam. If the "from" field or the "subject" field of a mail message contains a substring that is identical to one of these lines, the message is considered spam.

The JComboBox at the bottom of the screen allows the user to indicate whether the program should display the good mail or the spam in the JTextArea that occupies the center of the program window.

You can use this program to connect to your actual mailbox and filter your own mail by entering your mail server name, username and password into the user interface. We provide the code to actually communicate with a mail server. There is nothing in our code that modifies the mailbox you access in any way. As a result, you do not need to worry about errors in your program causing problems with your real mailbox.

If you don't want to use your actual mailbox, we have set up temporary mailboxes for you to use on the mail server cortland.cs.williams.edu. You would connect with the same username and password that you use to log in on our lab machines. Of course, these mailboxes are currently empty. So, you will need to send yourself a few short pieces of mail to test out your program, using the address 07abc@cortland.cs.williams.edu for example (using your login id in place of 07abc, of course).

To start click on this link to download the SpamFilter starter.

Program Interface

Within its window, your program will provide a collection of GUI components that provide the user with the ability to fetch and filter mail messages.

You don't have to lay these components out on the display exactly as we have shown in our demonstration solution. Anything reasonably organized will do (as long as the labels and text fields are kept together as explained below).

Experimenting with Inheritance

Your program's interface includes several JTextFields each of which must be placed next to a JLabel describing its function. Rather than creating each of these separately in your program's init method, we would like you to define a new class of GUI components that will combine a JLabel and a text field in such a way that you can treat them as a single GUI component. Our underlying reason for asking you to do this is that it will provide you with a chance to use inheritance.

You can create a new class of GUI components that can hold several other components together by defining a class that extends JPanel. To understand how this works, think about what you would have done if you decided to create the needed JLabels and JTextFields separately in your init method. To ensure that they were kept together in the program's interface you would create a JPanel and add them both to the JPanel (which would then in turn be added to the content pane).

Suppose now, that you instead want to define a new class named LabeledTextField designed to combine a JLabel and a JTextField. If you define the new class as an extension of JPanel this is quite easy. Since any object of the new class is a JPanel, Swing will let you add the object to the content pane. Also, since the object is a JPanel, you can include code in the constructor for the new class that creates a JLabel and a JTextArea and adds them to the object being created. Finally, if you associate the JTextArea with an instance variable then you can define a getText method for the new class which simply returns the result of invoking getText on the JTextArea associated with the instance variable.

Alas, things are made a bit more complicated by the fact that your program requires both two JTextFields and a JPasswordField, all of which need to have JLabels attached to them. You could just define two separate classes that extend JPanel as described above, but to maximize your exploration of inheritance we have something more elegent in mind.

First, you will define a class named LabeledTextComponent. This class's only purpose in life is to be extended to form the two classes we really want: LabeledTextField and LabeledPasswordField. The LabeledTextComponent class should extend JPanel. It should include an instance variable of type JTextField and a getText method that returns the String obtained by invoking getText on the instance variable. Its constructor, however, will not actually create a text field. Instead, all it will do will be to create a JLabel and add it to the JPanel. As a result, the only parameter to the constructor for this class will be the String to use when creating the JLabel. Thus, the following is a relatively complete implementation of LabeledTextComponent:

class LabeledTextComponent extends JPanel {

  protected JTextField textField;
  
  public LabeledTextComponent(String label) {
    add(new JLabel(label));
  }

  public String getText() {
    return textField.getText();
  }
}

You will define the two desired classes, LabeledTextField and LabeledPasswordField as extensions of LabeledTextComponent. Each of the constructors for these two classes will take an int that determines how wide the field should be and a String that determines what is initally displayed in the field, as well as the label necessary for the super class. The constructor for LabeledTextField will create a JTextField and add it to the object being constructed. The constructor for LabeledPasswordField will create a JPasswordField and add it to the object being constructed. Both classes will inherit getText from LabeledTextComponent.

Program Structure

Your program will consist of six classes:

SpamFilter

This will be the controller class for your program.

This class will create the components of an interface like that shown above and define event handling methods for the JButtons and JComboBox included in the interface.

Since this program will not use any features of the objectdraw library, we suggest that you describe this class as an extension of the standard JApplet class rather than using either our Controller or WindowController. This will involve only 3 changes from what you would have done if you had used our classes:

  1. You will not need to import ojbectdraw.*.
  2. You will say "extends JApplet" instead of Controller.
  3. You will put your initialization code in a method named init instead of begin.
MailConnection

This is the class that will provide the methods needed to contact a mail server through the network and download messages from the server. We will provide the code for this class.

To talk to a mail server, you must first construct a MailConnection object. The constructor for this class expects three Strings as parameters. The first must be the name of the mail server to contact. If you want to use the campus mailserver this parameter's value should be "mailhost.cs.williams.edu". To access your account on our server you would use "cortland.cs.williams.edu" instead. The other two parameters to the constructor must be your login id and your password.

When you construct a MailConnection it attempts to connect to the mail server. There are a number of reasons why it might fail. For example, the user might mistype the login id or password or the mail server might not be running for some reason. If any of these failures occur, a dialog box will pop up to inform the user. Your program must also be aware that the connection failed because it will not be possible to look at the mail if there is no connection. For that reason, we provide the isConnected method.

Once you have constructed a MailConnection you can use the following methods to access your mail.

public boolean isConnected()
Returns true if the program currently has a connection to the mail server.

public void disconnect()
Closes the connection to the mail server. This does nothing if there is no active connection.

public int getNumMsgs()
Returns the number of messages in the mailbox you are connected to. This returns 0 if there is no active connection.

public String header (int msg)
Returns the headers of a mail message identified by the number passed in. Unlike Java, mailboxes number messages beginning with 1 and going up to the number of messages contained in the mailbox.

The mail headers are returned in one long string, such as:

Return-Path: <lrobinson@cs.williams.edu>
Received: from [137.165.8.62] (tcl303.cs.williams.edu [137.165.8.62])
	by bull.cs.williams.edu (8.12.3p3/8.12.3) with ESMTP id hADDU9NG013481
	for <colloquium@cs.williams.edu>; Thu, 13 Nov 2003 08:30:09 -0500 (EST)
	(envelope-from lrobinson@bull.cs.williams.edu)
Mime-Version: 1.0
Message-Id: <a05200f02bbd9370948a5@[137.165.8.62]>
Date: Thu, 13 Nov 2003 08:30:01 -0500
To: colloquium@cs.williams.edu
From: Lorraine Robinson <lrobinson@cs.williams.edu>
Subject: November 14 colloquium
Content-Type: multipart/alternative; boundary="=======_-1143392286==_ma======="
Status: RO

Your spam filter will look at only the "From" and "Subject" headers. Part of your job, described below, is to extract just those headers from the long header list that header returns.

header returns an empty string if it is called when there is no connection.

Message

An object of the Message class will be constructed for each mail message you download from the server. The class will be very simple. It's constructor will expect a String containing the message (or at least its header) as a parameter. It will provide three accessor methods:

public String getFrom()
Returns the "From:" line found in the header of this message.

public String getSubject()
Returns the "Subject:" line found in the header of this message.

public String toString()
Returns the "From" and "Subject" headers as a single string with a newline between them and a newline at the end.
MessageList

A MessageList will hold a list of mail Messages. Internally, you should use an array to keep track of the members of the collection. To make it possible to create an array of an appropriate size, the constructor for the class should take the maximum size of the collection as a parameter.

Your MessageList class will need a method to add a message to the collection. You should also provide a toString method. This method will invoke the toString method of the Message class to obtain Strings describing each of the messages in the list. It will concatenate all of these descriptions together (separated from one another by extra newlines) and return this large String as its result.

Finally, the MessageList class should include a method to filter its contents. This method should take an array of Strings containing one String for each line entered in the filter JTextArea. It should also take a boolean indicating whether it should return the good messages or the spam. Its result will be another MessageList containing just the desired messages.

LabledTextComponent

As described above, this class will be used as a base class to define the classes used to create the pairs of JLabels and text fields included in the program's interface. It implements the getText method.
LabeledTextField

A class that constructs a JPanel containing both a JLabel and a JTextField. It extends LabeledTextComponent.
LabeledPasswordField

A class that constructs a JPanel containing both a JLabel and a JPasswordField. It extends LabeledTextComponent.

Suggestions

Design

This week we will again require that you prepare a written "design" for your program before lab. At the beginning of the lab, the instructor will briefly examine each of your designs to make sure you are on the right track. At the same time, the instructor will assign a grade to your design.

Implementation Strategy

We suggest that you approach this problem in the following order:

Submitting Your Work

When your work is complete you should deposit in the appropriate dropoff folder a copy of the entire SpamFilterStarter folder. Before you do this, make sure the folder name includes the phrase "Lab 11" and your name. Also make sure to double check your work for correctness, organization and style. This assignment is due Wednesday at 11 PM for those in the Monday lab and Thursday at 11 PM for those in the Tuesday lab.

Grading Point Allocations

Value
Feature
Design preparation (3 pts total)
1 pt. instance vbles & constants
2 pts. methods
Syntax Style (5 pts total)
2 pts. Descriptive comments
1 pt. Good names
1 pt. Good use of constants
1 pt. Appropriate formatting
Semantic style (7 pts total)
1 pt. General correctness/design/efficiency issues
1 pt. conditionals and loops
1 pt. Parameters, variables, and scoping
1 pt. Good correct use of arrays
1 pt. Good use of private methods
2 pts. Good use of strings
Correctness (5 pts total)
1 pt. Connecting to mail server and disconnecting
1 pt. Downloading mail and saving it
1 pt. Extracting from and subject headers
1 pt. Adding and removing filters
1 pt. Applying filters to downloaded mail


Computer Science 134
Department of Computer Science
Williams College