CS 302, Program 4

Program 4, Spring 2013: Restaurant Review

  P4 TEAMS DUE before 10:00 PM on Friday, May 3rd, 2013
  P4 CODE DUE before 10:00 PM on Friday, May 10, 2013
  NO LATE PROGRAMS WILL BE ACCEPTED!

[ P4 Announcements | Overview | Getting Started | Program Specifications | Milestones | Testing | Sample Runs | Extra Credit | Submission ]

P4 Announcements

Corrections, clarifications, and other announcements regarding this programming assignment will be found below.

Overview:

Assignment Goals:

You will be implementing a program that allows the user to search for reviews of a specific restaurant, add and remove reviews, and retrieve recommendations based on reviews currently in the database.

Getting Started:

There are no skeleton files for this project. The program design is up to you, although we do require that the main() method that starts your application be inside a file called RestaurantReview.java. So be sure to: create a new Java Project and add a class named RestaurantReview.java that has a main method. This is the class that will be run as a Java Application.

For this project, you will implement a database of restaurants, which the user can interact with using the menus and submenus described below. Before writing any code, we suggest that you design your program on paper, describing and naming the classes your program will use. Next, begin identifying data fields and methods for each class. Only once you have a good idea of what classes you will create and what their responsibilities will be, should you start writing code.

Program Specifications:

Command Line Arguments

Your program must require two command line arguments. The first should be the number of recent reviews to display when option 2 is selected from the main menu. The second determines the number of top reviews to display when option 5 is selected.

You can set up Eclipse to use command line arguments as follows. While in your project, click Run -> Run Configurations. Then click on the arguments tab. In the program arguments box, simply type each command line argument, separated by a space. Your run config should look like this: run_configuration.png

When you are in your main method, you can refer to these command line arguments by typing args[0] and args[1]. Each argument must be a positive integer. If the user inputs anything else, you should immediately exit the program without printing any error messages. Tip: use exception handling here to catch any errors that may occur when you try to use the command-line arguments and convert them to integer values.

See Section 7.3 in your textbook for further details on command line arguments.

Main Menu Options

Throughout this section, bold text in sample runs will refer to user-entered input.

When your program begins, print the following welcome message and menu:

	Welcome to the CS302 Restaurant Reviewer!
	Check out reviews for local restaurants, and add your own.

	What would you like to do?
	1. Review a restaurant
	2. View recently reviewed
	3. Search for a restaurant
	4. Get a recommendation
	5. Get the top reviews for one restaurant
	6. Import reviews from a file
	7. Export reviews to a file
	8. Remove reviews
	9. Exit
    
You should only display the welcome message once, when you first run your program, but display the menu (beginning with 'What would you...') again after each menu item is executed. See the Sample Runs.

1. Review a restaurant

This option allows the user to review a single restaurant. Prompt the user for the following information:

  1. Restaurant name: The name of the restaurant.
  2. Reviewer name: The name of the reviewer.
  3. Rating [0-10]: The restaurant rating. This is a value from 0 to 10, inclusive. Input validation for this field should be handled in the same manner the Error Checking section describes below.
  4. Comment: A free text comment. This comment must be one line long (in other words, it cannot contain newline symbols. You may assume the user will not enter any.)
  5. Recommended [y/n]: Whether or not the reviewer recommends the restaurant. If the user enters any text that contains a 'y' or a 'Y' as the first character, treat it as recommended. Otherwise, treat it as not recommended.
Restaurant names and reviewer names are case sensitive - thus, 'rob' is a different reviewer than 'Rob'. If the restaurant name, reviewer name, or free text comments contain any commas, print the following error message and return to the main menu:

Cannot contain commas.

See the following example of a restaurant review:
	Restaurant name:
	Ginger Root
	Reviewer name:
	Happy Harry
	Rating [0-10]:
	10
	Comment:
	Sesame chicken is the best!
	Recommended [y/n]:
	y
	

2. View recently reviewed

Display N recent reviews, where N is the number of recent reviews specified by the first command line argument. The most recent review should appear first, second most recent second, and so forth. Print one blank line between each review. If there are fewer than N reviews, print as many as you can. If there are no reviews in the system, nothing is printed.

The format for printing each review is the same as the search option (see below):

	Unique ID: 0
	Restaurant: Ginger Root
	Reviewer: Negative Nancy
	Rating: 0
	Comment: Line is too long!
	Recommended: No
	

HINT: Depending on how you structure your program, and the relationships between various classes, it might make sense to use a separate ArrayList or array of objects to keep track of the most recent reviews. I.e., the length of this list will always be specified by the first command line argument.

3. Search for a restaurant

Allow the user to search for a particular review.

If there are no reviews in the system, print the following error message and return to the main menu:

No reviews.

Otherwise, begin by printing a menu of restaurants currently in the database in a numbered name format. For example, if Ginger Root and Harvest Grains are the two restaurants in the database, the following menu is printed:

	Select a restaurant:
	1. Ginger Root
	2. Harvest Grains
    

The user then selects one of the restaurants by typing the appropriate number. This brings up a list of reviews for that particular restaurant. The user must choose one of these reviews to read. The reviews are numbered and listed with the format

Reviewer Name, Unique Review ID.
	Select a review:
	1. Negative Nancy, 0
	2. Happy Harry, 1
	

The user selects a review based on the left (menu) number (not based on the review ID). The selected review is then printed. This includes the unique ID, restaurant name, reviewer name, rating, reviewer comment, and whether the restaurant is recommended or not:

	Unique ID: 0
	Restaurant: Ginger Root
	Reviewer: Negative Nancy
	Rating: 0
	Comment: Line is too long!
	Recommended: No
	

After printing the selected review, return to the main menu.

Restaurant names and reviewer/review ID pairs should appear in the order that they were entered into the database. Only restaurants that currently have reviews should appear in the restaurants menu (so, if you enter a review for Ginger Root, delete it, and there are no other reviews for it, it should not be an option). Reviews with larger unique IDs should never appear before reviews with earlier unique IDs. Hint: there's a data structure we've seen that handles this behavior nicely, with minimal additional work on your part.

4. Get a recommendation

Recommend a particular restaurant for the user.

If there are no reviews in the system, print the following error message and return to the main menu:

No reviews.

First, display a numbered list of all reviewers in the system. The user then selects the number corresponding to their desired reviewer, and the program then randomly displays a recommended restaurant from that reviewer and returns to the main menu. Keep in mind that a recommended restaurant is one that a reviewer explicitly specified as recommended as described above in the Review a restaurant section - it is not based upon the restaurants rating.)

	Get a recommendation from:
	1. Happy Harry
	2. Negative Nancy
	1
	Ginger Root
	

If the selected user has not recommended any restaurants, do not display any restaurant names - simply return to the main menu. If the reviewer has recommended one restaurant twice and another restaurant once, get recommendation should select the first restaurant about two thirds of the time.

5. Get the top reviews for one restaurant

Get the N top reviews for one particular restaurant, where N is the value of the second argument supplied to the program.

If there are no reviews in the system, print the following error message and return to the main menu:

No reviews.

Begin by displaying a numbered list of restaurants in the database. The user selects a number corresponding to a restaurant and up to N top reviews for that restaurant are listed. We define the top N reviews to be the highest rated reviews for the restaurant, with preference given to newer reviews. Specifically:

  1. A better review (higher rating) always appears before a worse review (lower rating).
  2. A newer review (higher ID number) always appears before an older review (lower ID number) if the ratings for each review are the same.

If there are fewer reviews for a restaurant than the command line argument specifies, then display as many as there are in sorted order

There are many ways to implement this functionality. One approach that we suggest is to take advantage of either the .sort() method in the Java Arrays class (if you store your reviews in an array) or the .sort() method in the Java Collections class (if you store your reviews in an ArrayList). Whichever way you store your reviews, in order for them to sort as described, you must implement the Comparable interface in an appropriate class in your program with the appropriate logic for comparing two reviews. Then, you can simply select the first N reviews in the resulting array or ArrayList.

For example, if the number of top reviews to display is 3, we could see the following output:

	Get top reviews for:
	1. Ginger Root
	2. Harvest Grains
	1
	Unique ID: 3
	Restaurant: Ginger Root
	Reviewer: Happy Helen
	Rating: 10
	Comment: Lots of time to play on my phone while waiting in line!
	Recommended: Yes

	Unique ID: 1
	Restaurant: Ginger Root
	Reviewer: Happy Harry
	Rating: 10
	Comment: Sesame chicken is the best!
	Recommended: Yes

	Unique ID: 2
	Restaurant: Ginger Root
	Reviewer: Satisfied Sam
	Rating: 9
	Comment: Chicken eggrolls better than veggie eggrolls
	Recommended: Yes
	

6. Import reviews from a file

The import option allows the user to import review data from a file. If the user selects the import option, the prompt:

Enter file name:
my_review_data.txt

should appear and the user should enter the name of a file to be imported. If the import is successful, add the reviews from the file to the database in the order they appear and return to the main menu. If the file is not found, print the message:

Unable to find file.

and return to the main menu. For the base project (no extra credit) you can assume that EVERY line in the file will be valid.

The following is one example of a valid input file:

Happy Harry,Ginger Root,10,Sesame chicken is the best!,y
Negative Nancy,Ginger Root,0,Line is too long!,Nonononononono 

Each line of the input file contains one review and should have the following format:

Reviewer name, Restaurant name, Ranking [0-10], Comment, Recommended [y/n]

Each field is separated by a comma. The reviewer name, restaurant name, comment, and recommended fields are Strings, while the ranking is an integer between 0 and 10 inclusive. If the first character in the recommendation string is a 'y' or a 'Y', treat it as recommended; otherwise, consider it not recommended.

Note: Importing a file does not overwrite or remove any existing reviews. The new reviewers are simply added to the database even if this creates duplicates.

7. Export review to a file

The export option allows the user to save the current state of the database. If the user selects the export option, the prompt

Enter file name:
my_review_data.txt

should appear. If the output file does not exist, it is created; if it does exist,it is overwritten. This will fail if the user provides an illegal file name. In this case, the error message

Error writing to file.

should appear and the program should return to the main menu.

The format of the output file is the same as that of the input file described above (i.e. each field of the review separated by commas). The reviewer name, restaurant name, rating, and comment should be copied from the review as is. For the recommendation field, save 'y' if the review recommends the restaurant and 'n' if it does not.

8. Remove reviews

The remove reviews option allows the user to remove a specific review or clear the entire database. If the user selects this option, print the following submenu:

	What would you like to do?
	1. Delete review
	2. Clear database
	3. Cancel
	

If the user selects 1 to delete a review, then immediately search for a review (as you did in the "select a review" portion of searching for a restaurant). If no review is selected, return to the main menu. If a review is selected, delete that review, and return to the main menu. Deleting a review should not alter the unique ID assigned to any other review, or the unique ID assigned to the next new review.

If the deleted review was in the list of recent reviews, you may either leave that review in the list of recent reviews, or remove it from the list of recent reviews. We will leave this decision up to you, and both approaches will be considered correct.

If the user selects 2 to clear the database, all reviews are removed. Clearing the database does NOT reset the unique ID.

And finally, the user can select 3 to cancel the remove operation and return to the main menu.

9. Exit

If the user elects to exit the program, do not print or save any information; simply exit immediately.

Unique Review IDs

Each review contains various pieces of information - a restaurant, a reviewer, a rating, a comment, and a recommendation. In addition, each review should be associated with a particular unique Identification number that sets it apart from every other review in the system. The first review that you create should have ID 0, the second review should have ID 1, and so forth. The user should not need to specify these numbers. Instead, they should be automatically assigned as part of your programs operation.

Each time you create a new review, it should be assigned the next new ID. There are a few special cases you'll have to think about.

Note that IDs are not saved when we export to a file - instead, they are dynamically assigned whenever we load a file.

Error Checking

Your program must handle invalid input for each menu selection. You need to account for the following errors:

If you encounter any error that results in one of the above messages, you should print the appropriate message, and then wait for the user to enter another selection.

Restaurant and reviewer display order

When prompting the user to select a restaurant (for instance, when searching for a review) or to select a reviewer (for instance, when getting a recommendation), options should appear in the order that they were first entered into the system. So, if restaurant B was reviewed before restaurant A, then B should be the first option in the restaurant select list. If a restaurant is reviewed once, that review is deleted, and the restaurant is later reviewed again, treat it as though the newer review was the first for the restaurant.

Development Milestones:

We suggest that you incrementally develop this program by following the milestones in the order listed below. This order will make it easy for you to check that each milestone is working properly before you move on to the next one. Don't move on to a new milestone until you can convince yourself that the current milestone is working correctly. The further along you get, the harder it will be to detect errors in code you developed early on. The percentages listed in ( )'s indicate what you'll earn in the "correctness of execution" portion of your grade (total of 75%) by correctly completing each milestone.

Milestone #1: Get Started

Create a Java Project for Program 4 and add a new Java class file named RestaurantReview. This class will be your main class and thus have a main method that gets the program started. Add code to display the welcome message and main menu to the user. Add code to implement reading in user input and implement the exit feature of the program. Add code to handle invalid user input for the main menu prompt.

Milestone #2: List the methods (functions) and data fields you will use

Think of all the things that your program will have to do, and come up with a corresponding list of methods that you will implement. Be as specific (but brief) as you can with the idea that each task will be performed by one method (that may or may not call other methods).

Identify data (fields) and data structures (arrays and or ArrayLists) that will be useful for the methods that you've identified. Should that data be a field or can it be passed as a parameter? (Hint: Fields are good for data that must be accessed by many methods and reasonable represents the state of the object.)

Milestone #3: Organize your methods and data into classes

Organize the methods and fields into groups to identify useful classes. Diagram (outline) each class and include the type and name of each field and the method headers for each method of that class. If time permits, ask a CS302 Instructor or TA to review your program design. We will be happy to make suggestions if we see something unexpected in any of your class outlines.

Give each class a descriptive name and write a description of the role of that class is in the context of your overall solution. For example:

	main class name: RestaurantReview
	comment: The main application class, will also handle user I/O and file I/O
	         (or whatever you intend your main class to do)
	fields: 
	        data structure(s) to store restaurants, reviewers, reviews, etc.
	methods: 
	        static void main(String [] args) - the main method starts the program
	        ??? - method to get valid integer input from the user
	        ??? - method to handle a valid user input choice
	        ??? - (hint: there are lots of other things your final program needs to do)
	

Here's a sample form to get you started outlining an instantiable class. Or, you can develop your class outlines in Eclipse. Just be sure to create stub methods and write good comments, so your project always compiles and you remember why you wanted that method, field, or class.

	instantiable class name: __________________
	comment: briefly describe the class

	class or shared (static) fields: type name - description
	        static _____ __________ - __________________
	        static _____ __________ - __________________

	instance fields: type name - description
	        _____ __________ - __________________
	        _____ __________ - __________________
	        _____ __________ - __________________
	        _____ __________ - __________________

	constructor: ClassName name (parameter list) - description
	        __________ (___________________) - initialize data fields 

	class or shared (static) methods: type name (parameter list) - description
	        static _____ __________ (___________________) - _______________________

	instance methods: type name (parameter list) - description
	        _____ __________ (___________________) - _______________________
	        _____ __________ (___________________) - _______________________
	        _____ __________ (___________________) - _______________________
	

Some of the tasks your program will need will be easier to implement than others. Work on getting the easy parts working first as those parts will help you learn and make the other parts easier to implement later. For example: don't worry about reading and writing files until you have a program that works without that feature. It will be easier to read and write data once you have and understand what data you are using in your program.

Milestone #4: Implement individual functionality or classes.

Pick one of the basic functions or classes you have outlined and start implementing that function or class independent of the rest of the program. You can start by adding comments and stub methods so that your project will always compile. Then, implement one or more of those methods and add some code to your main class to test the newly written method. Continue revising the method until it works as you intend. Continue until all methods for the selected function or class have been implemented and work the way that you need them to. It is okay to revise your program outline as you learn what works.

Milestone #5: Complete implementation except File I/O.

Continue implementing each new program function or class you have outlined until you have implemented all functions and classes so that restaurants and review can be added and displayed by the user. Don't worry about File I/O until the rest of your program is working. You can now start comparing your out put to that of our sample runs.

Milestone #6: Implement File I/O

Now, try writing data from your program to a file. Then, try reading our data into your program from a file. Finally, try reading data that your file has written to a file back into your program.

Milestone #7: Final Testing

You're almost there. Test all of the menu items, add more error handling if needed. Try to recreate the sample runs to see if all is working as we require.

Testing

You should test your program by running it frequently as you develop. It is a worthy goal to always have a compiling program so that you can run it and see what it does. If you follow the milestones outlined above, you should be able to verify whether you have completed each milestone by running your program and interacting with it.

Sample Runs

Use the following sample runs to gauge your progress starting at Milestone 5.

Input files and output files for testing Milestone 6 (these correspond to our sample run for Milestone 6):

Input files and output files for testing Extra Credit (these correspond to the sample runs for Extra Credit):

Extra Credit (1%):

There are two functionalities you can implement for extra credit. When completing the extra credit, you must create an entirely new project, with all the same files that you used in your base project. However, you must name all files in your extra credit project by putting EC at the end of the file name. So your main class should be called RestaurantReviewEC.java. Note that this means that any other objects you create will be renamed throughout your program as well. So if you have a Square class (not relevant to this project), you would have to replace all reference to Square objects with references to SquareEC objects. Eclipse provides an easy way to do this. In your new EC project, copy your existing classes into the source folder. Then, in the Package Explorer window, right click on the file you want to rename, click on "refactor", and then click on "rename". Specify what you want the new class to be named (SquareEC) and then click "finish". After doing this, all references to the old name will be replaced with the new name.

  1. You can implement error checking on the import file. If the file contains a line that cannot be parsed as described in the Import Reviews section (menu item 6), either because there are too few or too many commas or because the ranking cannot be converted to an integer in the range 0 to 10, the program should load each review up to the invalid line, then print the error message :

    File invalid.

    The program should then immediately return to the main menu - do not load any reviews after the incorrect line. However, all valid lines in the file up to the invalid line should be loaded.

  2. You can implement the feature to search for a restaurant by type, in addition to a restaurant's name. This feature will be accessible through main menu item 3, Search for a restaurant. When this option is selected, the following menu should be displayed:

    1. Search by restaurant name
    2. Search by restaurant type

    The first option works the same as in the original Search for a restaurant option. The second option brings up a prompt asking the user to enter a restaurant type:

    Select a type:

    A list of restaurants of that type is then listed, and the user can select one using the same implementation as before. If multiple restaurants have the same type, that type should only be listed once. Types are case sensitive.

    To implement this, you will also need to adjust the option to review a restaurant, which adds a restaurant to the database. In addition to the other fields, you should add a field requesting the restaurant type. The following prompt should appear after the user has entered the restaurant name:

    Restaurant type:

    This field cannot contain commas. The same error message as described in the base project applies here if the user enters a type with commas in it.

    You should also be able to accept import files that have the extra restuarant type field. The default type for a restaurant should be "Other". Restaurants imported without a type field should be given this type. When printing out information about a restaurant, you do not need to print out the type.

    An example of a valid line of an input file which includes a type field is the following:

    Happy Harry, Ginger Root, Asian, 10, Sesame chicken is the best!, Y

Submission:

Before handing in your program, check that you've done the following:

Use the CS302 Forms Page to electronically submit and backup your work:

Submit these files: