CS 302 Programming Assignment 4: RSVP

Due dates:

Announcements | Overview | Topics engaged | Description | Hints | Handin

Last modified: Monday, April 16


Announcements

Includes:  Additions, Revisions, and FAQs (Frequently Asked Questions).
Please check here frequently.

04/16/2007 Check back often for new announcements!


Overview

For this assignment, you will develop social software -- specifically, you will be developing the code for RSVP, a website that allows people to organize social events, invite their friends to these events, and respond to invitations. You will use test-driven development to ensure that your code meets certain requirements as you are developing it. Finally, you will organize your code in a certain way -- a way that programmers call the model-view-controller pattern -- that enables code reuse and modular development. You will exploit the modular design by developing an alternate interface for the RSVP application.

Note: you are not allowed to use the ArrayList class or any other java.util collection class on this assignment. You must use Java arrays that are accessed with the [] operator. (If you don't know what a “collection class” is, don't worry about it, just make sure that you use standard arrays!) If you’re weary of writing out array operations, feel free to develop your own class that encapsulates a Java language array and get, put, insert, remove, and resize operations -- just don't use a class from the Java library or from somewhere else that does this.


Topics engaged


Description

What you’ll be doing

There are two phases to this project, with different due dates: developing tester classes, and developing instantiable classes. We shall talk about the instantiable classes first, even though you will be developing the tester classes first.

You will be developing classes for RSVP, a social networking application that allows friends to organize social events, invite one another to these events, and respond to invitations. We have provided a design for you that uses the model-view-controller pattern; you will be implementing

  1. model classes, which represent application-domain objects,
  2. view classes, which provide user interface elements, and
  3. controller classes, which implement “application logic” and mediate interactions between the user interface classes and the model classes.
By “application-domain classes”, we simply mean instantiable classes that model objects that occur in the problem domain. In this case, these objects include events, responses, email addresses, and strings.

We will provide one set of view classes that implement a web-based interface to the RSVP application (much like the one you’d use on a web site like eVite or Renkoo.com); you will be implementing view classes that implement a text-based, menu-driven interface for RSVP.

We also provide a class to make it easy to load and save event databases to a file. If you would like, you can extend your project to enable loading and saving of event data. This way, you can stop running the program and restart it with the same events as before. This is optional. You will not have to implement file I/O for this project; you may if you wish.

Before you start implementing this code, though, you will have to write test harnesses that exercise every method in the public interfaces of every model class. Writing test cases before you write the instantiable code that you’ll be testing will help you as you develop the code. Recall that we encourage incremental development, or developing and testing one feature at a time. Since you will have the tests before you will develop any of the actual application-domain classes, you'll be able to test individual features as you implement them.

Introduction to patterns and MVC

Introduction to patterns

Design patterns are general solutions to common design problems. Patterns will typically describe relationships between classes or objects in an abstract way, so that the solution described by the pattern is really a template that is applicable to a wide range of software design situations.

As an example, you’ve already seen one of the simplest example patterns in CS 302: the Immutable Object pattern. If a design features the Immutable Object pattern, then that design contains classes that have no mutator methods. Such classes are useful in many cases: it can greatly simplify the task of understanding code if you can be sure that an instance of a particular class is unmodifiable. (In the Java library, classes such as String, Integer, and Double exemplify the Immutable Object pattern.)

Of course, you probably could have come up with the idea for an object with no mutator methods on your own, but design patterns provide not only a template solution but also the vocabulary to discuss such a solution. Many design patterns illustrate excellent object-oriented solutions; however, design patterns are even more useful because they enhance your capacity to communicate with other programmers. Since a big part of a working programmer’s job involves communication (both in documentation and in meetings), solid knowledge of design patterns is one of the hallmarks of an excellent object-oriented programmer.

It’s much easier, once you’re familiar with the pattern vocabulary, to say:

I used the Command pattern to eliminate an unwieldy switch statement.

than it is to say:

I had a big switch statement in my code, and every case called a different method depending on a parameter p passed in to that method. I wanted to get rid of the switch statement by writing a method that took another method as a parameter, but Java won’t let me do that. I wound up writing an interface that had an “execute()” method, implementing it for every case: then I could just pass in an object that instantiated that interface that was appropriate for the value of p when I called the method, and eliminate the unwieldy switch statement.

Think of learning patterns as building your design vocabulary. (You can learn more about design patterns by visiting Wikipedia or Google.)

The Model-View-Controller pattern

The Model-View-Controller, or “MVC,” pattern provides a template for structuring an entire application by dividing classes into three groups or “layers:”

  1. Model classes represent potentially-persistent, domain-specific entities. The entities are persistent because they may continue to exist after the program has stopped running (whether in a file or in a database); they are domain-specific because they are particular to a certain kind of program. Therefore, a social event or a person might be a model class, but a pull-down menu is not.
  2. View classes represent user interface objects. Typically, view classes are general-purpose (as opposed to domain-specific model classes). View classes might implement pull-down menus, radio buttons, or dialog boxes. Of course, view classes don’t have to implement graphical user interfaces. View classes could also implement an auditory interface, a console-based text interface, a special hardware interface (like a keypad), or a web interface.
  3. Controller classes provide the application-specific logic. Controller classes decide how model objects are manipulated and provide the “glue” that connects model objects to view objects.

It’s important to note that these groups of classes only interact in well-defined ways. The classes in the controller layer will typically interact with two different sets of interfaces: one to communicate with view classes and one to communicate with model classes. Note that view and model classes do not directly interact with one another.

The illustration above demonstrates the interactions between layers. The “puzzle pieces” that fit together are calls to public interfaces. End-users of the application will interact with view classes, while model classes will represent application-domain objects.

Why use MVC?

There are three major benefits to the model-view-controller pattern:

  1. Better design. Following the MVC pattern can help ensure that unrelated classes aren’t tightly coupled by enforcing separation between layers.
  2. Reusable code. If your view classes aren’t closely coupled to your model classes, then you can re-use view classes in all of your applications. (When you think about it, there’s no reason for a pull-down menu to know about a party!) Perhaps more importantly, model classes are reusable as well: once you’ve written one set of model classes to deal with events or people, you can reuse those classes for social software that accomplishes different tasks.
  3. Interchangeable components. What if you want to change to a different kind of view? Let’s say you want a web interface for your program, or a text-only interface, or a carrier-pigeon interface. These are all possible with the model-view-controller paradigm. Likewise, since the model layer isolates the rest of your program from persistent storage, your program can change from using one file format to using another file format (or even to using a database) simply by changing the model classes that deal with storage.

Design of the RSVP application

The RSVP application consists of several classes that comprise model, view, and controller functionality. To make it easier to deal with these classes, we have divided them into several packages:

rsvp.controller
Classes implementing the controller layer (i.e. classes that mediate interaction between view and model components)
rsvp.exceptions
Some specific exception classes that RSVP components can use to signal errors to each other
rsvp.model
Model classes, modeling application-domain objects (e.g. events, responses, email addresses, and dates)
rsvp.util
A class that enables you to save an event database to a file
rsvp.view
Classes relating to user interfaces and interaction

As with any class using the model-view-controller pattern, the model classes will represent the application-domain entities involved in our problem domain. The view classes will provide a means for the user to interact with the application, and the controller classes will mediate interactions between the view components and the model components.

We'll start by taking a look at how the model components interact:

Now, we'll look at the view and controller components. (To avoid having to draw arrows between pictures, we've represented model classes in this picture as boxes with dashed lines around them.)

You may download a PDF file of the whole design here.


What RSVP does

In this section, we'll examine the functionality of the RSVP application by considering how users may interact with it. Recall that RSVP is designed to enable users to create, browse, and update social event invitations. Users may also reply to invitations to particular events, indicating their intention to attend or not. We shall consider each of those tasks.

Creating social events

A host begins by creating a new event. To do so, she will specify her email address, an event name, a location, and a date. In case she wants to change the event in the future, she will also specify a passcode to identify herself to RSVP later. Once she has supplied this information to RSVP, it returns an event ID. She can then give this event ID to friends in an invitation; they can use RSVP to reply to the invitation.

(See AppController)

Browsing social events

The RSVP system can also list the names, event organizers, dates, and event IDs of every event stored in the system. This is useful if, for example, a user can recall that a friend sent her an invitation with an event ID and she would like to reply, but she has lost the invitation. She can then view detailed information about that event, including who is planning to attend.

(See AppController and EventController)

Updating social events

Everyone makes mistakes (except CS 302 instructors), so RSVP provides a facility for making changes to the date, location, host, or name of an established event. The event organizer must use the passcode she chose when creating the event in order to make a change, though, to prevent vandalism or other unauthorized changes by other parties.

(See EventController)

Replying to invitations

A guest can use her event ID to view information about the event. She may also reply to the host's invitation. A reply consists of the guest's email address, a reply of YES, NO, or MAYBE, and a comment -- perhaps an expression of enthusiasm, a dietary preference, or a schedule constraint. Each event has a collection of responses, which RSVP will show when it displays the detail information for an event. (To protect RSVP users from spammers, RSVP only displays an abbreviated version of respondent and host email addresses.)

A guest may wish to change her response at a later date. This does not require a passcode in the same way that changing an event's details does. Instead, the RSVP application simply requires that the guest enter her full email address to identify herself before making a change to her reply.

(See ResponseController and EventController)


Provided classes and interfaces

Note: This section provides only a brief overview of the classes and interfaces you'll need to know about. Please see the Javadoc for more detailed information.

We have provided some instantiable and utility classes for you to use in your projects. We have also provided several interfaces that your classes should implement. We have done this both to afford you some flexibility (in the case of the view classes) and to help you ensure that you have implemented all of the required instance methods with the correct signatures. If your classes implement the provided interfaces, then the Java compiler will check that you have declared every instance method with the right names and parameter lists. However, since interfaces cannot describe static methods or constructors, you will need to take care to ensure that you have properly implemented these methods exactly as they are documented.

Instantiable and utility classes

rsvp.model.SimpleDate
This class models a date; it also validates whether or not a date corresponds to an actual calendar date.
rsvp.util.DBPersistence
This class provides static methods for saving an event database to a file and loading it from a file. If you would like to extend your program to support loading and saving of event data, you may wish to use this class to make your work easier. Note that supporting loading and saving of event data is optional. However, you may wish to do so to have a more realistic application (as well as to ease testing).
rsvp.util.DBPersistenceException
This class is used to signal some sort of error when loading or saving event data. You will need to handle it in your AppController methods that implement loading and saving if you decide to implement loading and saving.

The RSVPView interface

rsvp.view.RSVPView
This interface defines all of the functionality necessary for a view -- whether a web view, like the one we provide you, or a text-based view, like the one you will develop. A view must be associated with a controller object and then the application can turn over control to the view.

Other useful interfaces

rsvp.controller.AppControllerInterface
This defines all of the instance methods that your AppController class must support.
rsvp.controller.EventControllerInterface
This defines all of the instance methods that your EventController class must support.
rsvp.controller.ResponseControllerInterface
This defines all of the instance methods that your ResponseController class must support.
rsvp.model.EmailAddressInterface
This defines all of the instance methods that your EmailAddress class must support.
rsvp.model.EventDBInterface
This defines all of the instance methods that your EventDB class must support.
rsvp.model.EventInterface
This defines all of the instance methods that your Event class must support.
rsvp.model.ResponseInterface
This defines all of the instance methods that your Response class must support.

Classes you will have to implement

Note: This section provides only a brief overview of the classes and interfaces you'll need to know about. Please see the Javadoc for more detailed information.

Tester and stub classes

You will develop tester and stub classes for every model class as part of Phase I of this assignment. (You will also develop a tester class for SimpleDate, even though we have provided that class for you.) We discuss what is involved in producing these classes in greater detail here.

RSVP application classes

You will be implementing these classes for Phase II of the assignment. Every RSVP application class must implement the corresponding interface (e.g. AppController must implement AppControllerInterface). If you want to use the DBPersistence class, then your model classes must also implement the standard Java interface java.io.Serializable. (You will not have to implement any other methods to implement this interface -- see here for an example.) Your solution may rely on additional classes that you have implemented because you deem them necessary or helpful. (For example, you may wish to make classes that encapsulate Java language arrays.)

rsvp.controller.AppController
The AppController is the main controller for the RSVP application. It provides a layer of functionality related to making new events, retrieving event information, and dealing with event database metadata. The view classes will interact with the AppController after the main application has created an EventDB.
rsvp.controller.EventController
An EventController mediates interactions between the view layer and a particular Event.
rsvp.controller.ResponseController
An ResponseController mediates interactions between the view layer and a particular Response.
rsvp.model.EmailAddress
An EmailAddress models an email address (which may or may not be valid).
rsvp.model.EventDB
An EventDB is a collection of Events.
rsvp.model.Event
An Event models a social gathering. An event has a name, an organizer (i.e. host or hostess), a date, a location, and a collection of Responses. An event also has a passcode, which the organizer will use to identify herself if she wishes to change the event at some point in the future.
rsvp.model.Response
A Response models a response to an event invitation.
rsvp.view.text.TextView
A TextView provides a console-based, menu-driven interface to the functionality provided in AppController. It must implement rsvp.view.RSVPView.
rsvp.exceptions.BogusParameterException
This class, which extends RuntimeException, indicates that a method has been called with an invalid parameter.
rsvp.exceptions.PermissionException
This class, which extends RuntimeException, indicates that a user has tried to modify an event or response without the proper credentials.
rsvp.Main
rsvp.Main is your application class. It will contain only a main method. This main method will get user input to determine whether to run the text-based interface or the web-based interface, create an empty EventDB, create an AppController, create an instance of an appropriate class implementing RSVPView and invoke its run method. The main method will not need to do anything else.

Testing

We have always recommended that you develop your classes incrementally and test each one. For this assignment, we will be using test-driven development to facilitate this process. This means that you will be developing tester classes for each of the model classes before you implement those model classes. Your tester classes will deal with references to classes implementing the interfaces we have provided for you (e.g. EventInterface, etc.) rather than with references to the classes you will develop (e.g. Event). However, you will have to develop stub classes so that you can test constructors and static methods. (We'll talk more about stub classes momentarily.)

Our typical goal when developing tests is to try a variety of test parameters so as to provide sufficient code coverage (i.e., try enough different parameters to exercise every statement in every method at least once). Since you don't know how you will implement the methods, this is an example of what your textbook calls black-box testing. You won't be able to consider different paths through each method and guarantee complete code coverage, since the methods won't exist yet! Instead, you will have to be clever about how you design your test cases. Be sure to choose a good variety of positive, negative, and borderline test cases; it may also be helpful to think about how you might implement the methods as you are choosing your test cases.

Stub classes

One downside to using test-driven development with interfaces is that interfaces can't fully describe the objects you’ll be interacting with. Specifically, interfaces don’t describe constructors or static methods. For example, if you were developing a tester class for classes that implement the EmailAddressInterface, you'd want to test the following methods:

public interface EmailAddressInterface {
    public String toString();
    public void setEmail(String email);
    public String getDisplayEmail();
    public String getEmail();
}

However, you'd also need to test the static method isValid() and the constructor for your EmailAddress class. Unfortunately, you haven't written EmailAddress yet, so tester classes that use constructors or static methods won't compile! To work around this situation, we will develop a stub class for EmailAddress. A stub class contains all of the method declarations that the real class will have, but with the simplest possible method bodies. That is: void methods will return nothing; methods with a return type will return the default value for that type. The stub class will fail almost all of your tests, of course, but you'll be able to fill in the method bodies one by one when the time comes to write your real class.

As an example, let's consider a stub class for EmailAddress:

/**
 * Stub class for EmailAddress.  Each method does nothing except 
 * return the default value for its return type.
 * @author willb
 */
public class EmailAddress implements EmailAddressInterface, java.io.Serializable {
    public EmailAddress(String email) { /* No body */ }

    public static boolean isValid(String address) {
        return false;
    }
    
    public String toString() {
        return null;
    }
    
    public void setEmail(String email) { /* No body */ }
    
    public String getDisplayEmail() {
        return null;
    }
    
    public String getEmail() {
        return null;
    }
}

Obviously, a stub class doesn't do much, but if you write stub classes for all of the model classes, you'll be able to compile and run all of your tests even before you've written the actual model classes. Then, as you develop and refine your model classes, you'll be able to see more and more tests passing. We can guarantee that it will feel great to see the FAILs become PASSes.


Questions (for Phase II)

Note: There are no questions for Phase I.

You should create a text file named questions.txt with answers to the following questions. Note that these may require more involved answers than questions for previous assignments.

Be sure to include the descriptive information listed below as well as the answers to each question:

Assignment Number:
Assignment Name:
Date Completed:

Partner 1 Name:
Partner 1 Login:
Partner 1 Lecturer's Name:
Partner 1 Lab Section:

Partner 2 Name:
Partner 2 Login:
Partner 2 Lecturer's Name:
Partner 2 Lab Section:
  1. The RSVP application has a rather lax approach to security. Anyone can claim to be the person with a given email address, and the Event class has no concept of who is invited to an event -- anyone can issue a Response to an Event if they know what the event ID is. If we were developing an application to deploy on the public internet, we would want it to be more secure. How would you make RSVP more secure? What parts of the design would need to change? What parts of the implementation would need to change? Describe any additional classes you'd need.
  2. We use a fairly simple method to check whether or not email addresses are valid. One of your enthusiastic colleagues has suggested that it might be better to check over the internet to see if the domain name in the email address is valid, or even to try and send a message to the address and see if it bounces. Do you think this is a good idea, or not? Justify your answer.
  3. Describe two changes you'd like to make the the RSVP application that are possible because of the model-view-controller design pattern, and two changes that might be difficult even given the model-view-controller design pattern.
  4. Discuss the advantages and disadvantages of test-driven development. Also, discuss some bugs you found due to test-driven development, and how you went about fixing them.
  5. Identify the coupling and dependency in the RSVP design. Discuss whether or not the coupling is warranted. How would you reduce the coupling and dependency in the design we provided? Is it necessary to do so? Justify your answer.
  6. Discuss the cohesion of the classes in the RSVP design. How would you increase the cohesion of the provided design? Is it necessary to do so? Justify your answer.

Assignment requirements

This section outlines the major requirements of the assignment. Your solution to the assignment must meet each of these requirements. Be sure to read the announcements frequently and ask questions if you need clarification.

  1. Include name, login, lecture, and lab section information at the top of all assignment files.
  2. Follow the style and commenting standards for CS 302. This includes:
    • including file header comments,
    • including JavaDoc comments for every portion of the public interface of every class,
    • using symbolic names wherever they are appropriate, and
    • using visibility modifiers appropriately; data members should be private and publicly accessible methods should be public.
  3. Follow the assignment specifications exactly, e.g., each method you implement must have the correct spelling, the correct return type, and the correct parameter type(s) and must behave according to the specifications.
  4. Submit your answers to the questions in a text-only file (no Word documents) named questions.txt.
  5. Use the Handin program to hand in all work electronically.

Hints


Handin

Use the Handin program to hand in your work (see the instructions on how to use the Handin program). Students working in pairs will only submit one copy of all program files, except the README file described below.

Only hand in the files listed below; do not hand in any other files. These files may be handed in any time prior to the due date. Note: you may hand in your files before the deadline as many times as you wish. We suggest you use your handin directory to keep your most recent working copy as you develop your solution.

Required files for Phase I of this assignment:

Required files for Phase II of this assignment:

For both phases of this assignment:

Pair Programming students must also submit a README.txt file: All students working in pairs must read the Pair Programming Guidelines and submit a README.txt file. Each student working in a pair must hand-in this file to his/her own hand-in directory. Copy, complete, and hand-in the file that is linked here:


Feedback, questions, or accessibility issues: contact Rebecca Hasti (hasti@cs.wisc.edu)
©2007 Will Benton and Rebecca Hasti, all rights reserved