CIS 211 - Computer Science II
Winter, 2003 - A. Hornof

Project 4

This Project is due on Monday, February 17, at 5 PM.

Purpose

This project will give you practice the following programming techniques:

  • Coordinating the interaction between file i/o and objects in your program.
  • Designing and maintaining a modular system.
  • Adapting and extending existing code to provide new functionality.
  • Converting functional code into class methods.
  • Throwing and catching your own Exceptions.

Overview

In this project, you will write a program that reads the input file as in Project 2 and creates a MaritimeModel as in Project 3. In this project, you will reuse and extend both of those sets of code (or the Project 2 and 3 solutions provided on the course web page). You will write a program that reads in the input file and puts the specified Ships and Islands into the MaritimeModel. Your program will read the model from a slightly-enhanced version of the data file used in Project 2. It will create a MaritimeModel of the dimensions specified in the input data file. It will create a Ship or Island object for each Ship or Island described in the data file. As in Project 3, the constructors will announce each object's creation. Once all objects are created, the program will list the contents of the MaritimeModel and then save the objects back to the data file.

An Evolving Program and Specification

Project 4 builds on Projects 2 and 3. You may build on your previous code or you may build on the solutions provided for previous projects. You may not, however, start with any code written by other students in the class.

The Project 4 Addendum posted on the course web site is officially part of these project specifications. You should check it at least at the beginning of each work session. Be sure to start the project early enough to have an opportunity to ask for clarification in case it is necessary.

Step 1 - Create general purpose file-reading method and file-writing methods.

The first step in Project 4 is for you to create a general purpose file-reading method and file-writing method and to put these methods into a class called FileUtils.java in a package called "util". These utilities will be useful in this project as well as in any future projects in which you want to read/write files to/from ArrayLists while providing a minimum set of user interaction if problems are encountered.

This will be a class that contains only two public methods: fileToStringList() and stringListToFile(). The first opens and reads an input file into an ArrayList of Strings, and the second puts an ArrayList of Strings into a file. It should recreate the same user interaction specified in the first part of Project 2. The fileToStringList() method should not verify the contents of the file. For example, it shouldn't check that the first line is "Maritime Simulation World State". You can re-use any of the methods that you wrote for Project 2, or any of the methods provided in the Project 2 Solution on the web page. (But keeping with the academic honest policy of the course--see the Syllabus--you may not reuse code written by other students. See me if you have any questions or concerns on this matter.)

All methods besides the two specified here should be private. All variables should be private. All methods should be class methods. No instance of FileUtils should ever be created, and you should in fact insure that no code written outside of the FileUtils class could possibly create a FileUtils object.

The parameters passed in and out of the methods should be as follows:
String fileToStringList (String, ArrayList ) // String is the filename. It is returned in case it is modified.
void stringListToFile (ArrayList, String )

To make the methods slightly more generic and useful, remove the word "simulation" from all of the error messages. When you are done, you will have a generic and useful FileUtils.java class that you can use any time you want to load a file into an ArrayList or save the ArrayList into a file.

There is one additional mechanism for you to add: a QuittingException class which is derived from the Exception class. Follow the Java convention of one class per ".java" file. Put the QuittingException class in the "util" package. As in Project 2, if the user types a 'Q' or 'q' at the specified places, the program quits. This will be accomplished by fileToStringList() and stringListToFile() throwing a QuittingException that is caught by main(). The following functionality provided in Project 2 must be also preserved: If a user types a 'Q' during the file-reading phase, the program quits with no message, but if the user types the 'q' during the file-writing phase, the program should display the message "The data file was not saved." No other junk such as "util.QuittingException" should be displayed. No blank lines should be printed either.

Write a program P4_1.java that uses the FileUtils methods from the "util" package to read in a file, save it to an ArrayList, and writes the ArrayList to the same file. The functionality is identical to simModel_2_1.java except that the word "simulation" is removed from all user messages. As before, use the first command line argument as the input filename or "world.txt" if no argument is provided. Ignore any other command line arguments.

P4_1.java should be a very small file primarily containing just the following code. You will need to add a little additional code before and after, but the "try" block should be cut and pasted from here.

	...
	try
	{
		// Read the file into the stringList.
		fileName = FileUtils.fileToStringList (fileName, stringList);			

		// Save the stringList into the file.
		FileUtils.stringListToFile(stringList, fileName);
	}
	...

The Products of Step 1 include P4_1.java, FileUtils.java, and QuittingException.java. Submit them via e-turnin.

 

Step 2 - Extend the methods that check the maritime simulation file format.

In Project 2, the checkFileFormat() method was used to confirm that the contents of the stringList ArrayList conformed to a maritime simulation file format specification. Since the specification relates closely to the design of the maritime classes, the format-checking functionality is being moved into the MaritimeModel class as a public "class method" called stringListToModel(). It will take one argument, an ArrayList that is the contents of a maritime simulation data file. The contents of the ArrayList will not have been verified to conform to maritime data file format specifications. The method stringListToModel() will both (1) verify that the ArrayList conforms to specifications and (2) load the ArrayList into the MaritimeModel.

There are two subtasks in this step of the project: (1) Upgrade the file-checking to accommodate the new file specification and (2) get the checked file into MaritimeModel by calling the appropriate constructors in the maritime package. It is probably best to start by extending the code to accommodate the new file format specification without creating any maritime objects. However, as you make these modifications, bear in mind that you will need to call constructors with the data in each ArrayList entry, so at least jot down some notes or comments as you go as to what kinds of modifications will be needed, and where they will be needed. But it is probably best to save the implementation until later. Solve one problem at a time.

Modifications to the Project 2 maritime data file format

These are the modifications you will make to checkFileFormat(), regardless of whether you start with your own solution or the solution provided on the course web page.

1. The world size must be at least 1 1. If not, output the error message shown below and quit.

2. When reading the input data file, verify that the Ships and Island X and Y coordinates are less than or equal to the corresponding coordinates provided for the size of the world. If they are not, output the error message shown below and quit. Consider implementing this one after you have added the code that fills the MaritimeModel, so that you can you retrieve the world size from the MaritimeModel.

3. Expand the data file's description of Islands to include two additional integers. The first is the amount of fuel oil currently available at the island. The second is the production rate of oil on that island. Verify that both can be parsed as Integers. If not, output the error message shown below and quit.

4. Since we will not be simulating wind patterns in our simulation, there will be no means for a Sailboat to move. Hence, a Sailboat is no longer an acceptable Ship type, and should generate an error message if specified in the data file.

5. This is the new error message for any improperly formatted line in the data file.

Error: Line <line number> in maritime simulation data 
file <data filename> is improperly formatted: "<The line appears here>"

Quit after the first error

As in Project 2, when the first file format error is encountered, the error message should be displayed and then the program should quit. In this Project, this will be accomplished in part by having stringListToModel() throw a QuittingException that is caught in main().

Fill the MaritimeModel

After the file format-checking is complete, further modify stringListToModel() so that it creates a Ship and an Island object for every Ship and Island specified in the data file and adds all the Ships and Islands to the appropriate ArrayLists in MaritimeModel. Each should be added in the order that it is encountered in the data file.

The stringListToModel() method should also set the size of the MaritimeWorld as specified in the input file. To do this, MaritimeModel class will need a couple new methods. Add the following two "instance methods" to the MaritimeModel class:
void setWorldSize(Location); // Sets the size of the world to the X and Y coordinates in the Location that is input.
Location getWorldSize(); // Returns the size of the world as the X and Y coordinates in a Location.

Confirm everything is working by studying the constructor output statements for a variety of input files that you create.

 

Step 3 - Write the MaritimeModel to the ArrayList

Finally, write the code that will output the objects to an ArrayList. This will be done in the public method modelToStringList() in the MaritimeModel class. The method will take an ArrayList as a parameter, clear the the ArrayList, and fill it with Strings that correspond to the correctly-formatted lines in a maritime simulation data file. Don't forget to include the first two Strings in the file. Traverse the MaritimeModel list of SimObjects in order from start to end.

To make this method easier to implement, create a public getFileLine() method in every class in which you created a toString() method in Project 3. The method getFileLine() will be identical in every way to the toString() methods except that getFileLine() will return a String that is formatted appropriately for the maritime simulation data file. The Location getFileLine() will return simply "<X> <Y>" (an String consisting of an integer, a space, and an integer) which you should find useful inside of all of the other getFileLine() methods.

The getFileLine() for the Island class, for example, would return the following (assuming these data values):

Island Hawaii 87 2

The P4.java that you turn in should include the following try block, exactly as it appears here. This code block should also help you to understand how the four methods work together.

		try
		{

			// Read the file into the stringList.
			fileName = FileUtils.fileToStringList (fileName, stringList);			

			// Load the stringList into the model.
			(MaritimeModel.getInstance()).stringListToModel(stringList);
			
			stringList.clear();  // Just to make sure it is cleared.

			// Save the model to the stringList.
			(MaritimeModel.getInstance()).modelToStringList(stringList);

			// Save the stringList into the file.
			FileUtils.stringListToFile(stringList, fileName);
		}

As before, P4 should use the first command line argument as the input filename or "world.txt" if no argument is provided.

The Products of Steps 2 and 3 include P4.java and a new MaritimeModel.java. Submit them via e-turnin.

 

Additional Notes

  • All keyboard input should be done using L&L's Keyboard class, which should be accessed via the "cs1" package by putting the "Keyboard.class" file in the appropriate directory in the CLASSPATH, and by setting up your CLASSPATH appropriately. Neither Keyboard.java nor Keyboard.class should be in your working directory. Import the package only where necessary.
  • Wherever visibility modifiers are not specified throughout this project specification, you should close the visibility of all classes and methods as much as possible. Classes should become package-only whenever possible, and methods should be, in order of preference: private, package-only, protected, and public.
  • You may create whatever private methods and variables you like, but you may not create any classes or any public methods other than those specified here.
  • There should not be any calls to System.exit() in any of the code that you submit for this assignment.
  • The program must compile and run correctly using Java 1.4.1.

 

Some advice on how to do it

If you didn't get full credit on Project 2, consider using the solution provided on the web. We may "regression test" to make sure that all of the Project 2 file-reading and file-checking is still there.

Start early. If you do not have a good solution to Project 2 and decide to use the solution provided on the course web page, you will need to spend some time understanding how it works and how to modify it so that it throws the correct QuittingException. Regardless of which Project 2 you use, there will be a lot of code surgery and fine-tuning to be done.

Compile regularly. Bring your code to working stopping points regularly. Back up these intermediary working versions, such as in a folder called "Backup" and in a further subfolder with the current date and time, as in "2-2-03-1130PM". In case you accidentally ruin working code later on or your disk crashes, you can easily revert back to a previous working version and continue.

Test your code and your package specifications by deleting all class files in your current directory and in the CLASSPATH directories, by removing all .java files except P4.java from your current working directory, and by then compiling and running P4.java from the command line.

Grading Criteria

You will receive credit for programs that compile using the correct package declarations and that solve the problems as specified. You will not receive any credit for code that does not compile from the command line using Java 1.4.1. Any problems with your Project 2 and Project 3 solutions must be fixed for this project. For example, if your program still has a bug of always requiring a command line argument, then your project could fail all of the tests in Project 4.