CPE
102
Winter
2007
Program
5
Due
Date
You must turn in a functionally
correct program to receive any credit. The grade you receive will be
based on when you turn it in minus any deductions for the quality of your
implementation and/or multiple submissions. There is no deduction for the
first submission and a 5% deduction for each additional submission, if
any. Programs will be checked for correctness once a day and you will be
notified by email if your submission is not functionally correct.
Programs will be graded after the last due date and the results will be emailed
to you within a few days of that date.
100% (minus any deductions) by 9:00pm Monday, 2/11/08
90% (minus any deductions) by 9:00pm Tuesday, 2/12/08
80% (minus any deductions) by 9:00pm Wednesday, 2/13/08
70% (minus any deductions) by 9:00pm Thursday, 2/14/08
Errata
None
Objectives
- To
learn how to write you own checked and unchecked exceptions.
- More
practice handling exceptions in code you write.
- Practice
working with file-based streams.
- To
solve the issues that come up while reading and writing comma delimited
data.
- More
practice with inheritance and interfaces.
- More
practice with the equals method – in this case equality between
collections.
- More
practice using Java Standard Library classes.
Resources
- Java Standard API
- P5TestDriver.java (will be published Monday 2/11)
- P5UnitTests.zip
- Necessary input files for the
test driver - you can examine these for examples of well-formed
comma-delimited text files:
- BadQuantityBook.txt
- BadQuantityBookOnTape.txt
- BadQuantityCD.txt
- Duplicates.txt
- GoodNegativeQuantities.txt
- MissingProduct.txt
Problem
Description
- You will be modifying and enhancing your Program 4 source
code in several ways. First, you will be detecting, reporting and, in
some cases, handling several error conditions with both checked and unchecked
exceptions that you create. You will also be working with character
streams to read and write comma-delimited text files that contain complete
product specifications. Finally, you will also be overriding the equals()
method for the Inventory class
IMPORTANT: When running the provided test driver you will need six
text file (see Resources section above for links) to be in the directory where
the .class files of your solution are found.
- JUnit tests will be provided in P5UnitTests.zip.
Replace the stubbed out versions of InventoryTest, BookOnTapeTest, and CDTest with the tests you wrote in Program 4. These versions will now need to be extended
to test additional methods that you write. Recall from Program 1,
one of the Fraction constructors threw an exception. In
FractionTest, a JUnit test was written for when we expected that exception to be thrown. In your InventoryTest
class, you will come upon a similar dilemma. The syntax for
expected an exception to be thrown in your test case is
@Test(expected=<TheNameOfYourException>.class). JUnit tests
with this annotation will ONLY run successfully if the exception IS
thrown. Refer to FractionTest in Program 1 as an example.
Suggestions
- Make
sure your Program 4 code successfully passes all of the Program 3 tests
before moving on to the Program 5 modifications
- Then,
and only then, COPY all Program 4 source files to a new project and
begin making the Program 5 modifications.
- You
can (and probably should) attemp to parse the comma-delimited input
fiiles in a seperate program (without inheritance to add to the
confusion) to learn how to use the Scanner class and String class to
get the job done. Once you understand the process in the simplier
environment it should be much easier to implement in the class
hierarchy of Program 5.
- Remember to use the tests and given documentation to understand the conditions in which your implementation should work.
- Follow
the test-driven development style by first reading the given JUnit test
for the method you want to implement, then implement that method's
functionality and watch the test pass. If the test is not given,
then write the test for how the method should work, see that it fails
(since you have not written the code yet), then write the code to pass
the test.
- Keep
track of your hours worked as you go, so you don’t have to guess when you
hand in your assignment (see handin section below for information on
time.txt).
Specification
- You must implement the classes,
interfaces, and methods exactly as described or the provided test driver
will not work!
- Add the add @throws tags to
the javadoc-style documentation in the Inventory class as
appropriate. Be sure to update any
javadoc comments in the Inventory class to reflect the changes you are
making for this program.
- Do not reinvent the
wheel. Demonstrate knowledge of the Java Standard Library classes
you are working with. When and wherever appropriate use code that
has already be written and tested for you! Your program will be
graded with this in mind!
- Create the following checked
exceptions:
- DuplicateProductIDException
– This exception should be constructed with the following message:
Product ID XXXXXX is already in the inventory
Where XXXXXX is replaced with the
actual duplicate product ID
- DuplicateProductException –
This exception should be constructed with the following message:
Product ID XXXXXX is equivalent to
existing Product ID YYYYYY
Where XXXXXX is replaced with the ID of the product that
is being added and YYYYYY is replaced with the ID of the equivalent product
already in the inventory.
- Create the following unchecked
exceptions:
- MissingProductException –
This exception should be constructed with the following message:
Can not find Product ID XXXXXX
Where XXXXXX is replaced with the product ID that cannot
be found in the inventory.
- InsufficientProductException
– This exception should be constructed with the following message:
Product only has XXX units, need
YYY
Where XXX is the quantity of product on hand and YYY is
the amount of product requested.
- Change the return type of
Inventory.addNew(Product) from boolean to void.
- The method should now throw
a DuplicateProductIDException if someone tries to add a product with an
ID that already exists in the inventory.
- The method should now throw
a DuplicateProductException if someone tries to add a logically
equivalent product using the equals() method as defined for Program
2. Recall that this means all attributes are equal except
product-ID and quantity.
- Change the return type of
Inventory.addInventory(int, int) from boolean to void.
- The method should now throw
a MissingProductException if someone tries to update the quantity of a
product that does not exist in the inventory.
- The method should now throw
an InsufficientProductException if someone tries to adjust the quantity
to a value less than zero. In such a case, the quantity should
remain unchanged.
- Override the equals(Object) method
of Object in the Inventory class. This should be a well-formed
equals() implementation that correctly compares the only instance variable
of the class (an ArrayList of inventory). This method should return
true if the two Inventory objects have the same products in the same
order based on the product’s equals() method. Think about
the efficiency of your solution. Read about the equals method of the
ArrayList class to see if it is sufficient! If it is, you should use
it, otherwise you should implement you own logic – ask me if you are not
sure!
- Write a new Java interface
called DelimitedTextIO with the following methods:
- String toText(char
delimiter) – This method returns a String containing all the data of the
implementing class as text and with each element separated by the
provided delimiter.
- void toObject(Scanner input)
– This method uses the Scanner parameter to parse delimited text
representing the data for the implementing class and initializes the
objects instance variables with the parsed values. The delimiter to use must be set
for the Scanner object being used for input before passing it to this method.
I strongly suggest you use the method that accepts a String
defining the delimiter unless you are very familiar with Regular
Expressions. Read the javadocs for the Scanner class to find the
method necessary for doing this. This method will handle
any amount of white-space before and/or after any token in the input by
removing it - you may want to use the trim method of the String class
to help you with this task.
- Implement the DelimitedTextIO
interface in the Product class and the Name class. Implement its methods in Product and
Name and override them in any necessary subclass as follows:
- The toText method should
return a comma-delimited String (a single comma - not a comma-space) in the order
specified below for each specific product. You
can include extra whitespace before and after the delimeter for
readability (as in the example below) but it is not required.
Replace the names of the variables in the example below with the
object’s actual values for those instance variables. Notice
that the Name objects must be output in the order specified (you can and
should use the toText method implemented in Name to do this) - do not include the parenthesis in your String. Take
a look at some of the provided text files to help you understand this
specification clearly and exactly before you begin coding. You
must demonstrate that you understand inheritance and overriding methods
in your implementation – this means you must not use any accessor
methods (other than toText) of Product, any of its subclasses, or Name.
Recall that you can use the getClass().getName() call to obtain
the name of any class at runtime.
“Book, product ID, quantity, description, wholesale price,
retail price, title, publisher, author (last, first, middle), type, pages,
binding”
“BookOnTape, product ID, quantity, description, wholesale
price, retail price, title, publisher, author (last, first, middle), type,
reader (last, first, middle), length, format”
“CD, product ID, quantity, description, wholesale price,
retail price, title, artist (last, first, middle)”
- The toObject method should
use the provided Scanner to reverse the process of toText above. Be sure your solution works with and without whitespace before and/or after the delimiter. You must demonstrate that you
understand inheritance and overriding methods in your implementation –
this means you must not use any accessor methods (other than toObject) of
Product, any of its subclasses, or Name.
- Implement DelimitedTextIO
interface and its methods, toText and toObject, in Name as well. The order of the instance variables
must be last, first, middle.
- Add the following new methods
to the Inventory class:
- public boolean contains(int productID)
– This method should return true if the inventory contains a product with
the specified productID, otherwise false.
- public void
writeCommaDelimitedInventory(String filename) – This method must write
every product in the inventory to a text file as comma-delimited text
with one product per line. It must make use of the toText
method written in Product, its subclasses, and Name. If, after thinking
about it sufficiently, you do not know how to do this you may ask you
instructor for clarification. You can examine the provided
comma-delimited input files for examples of what your output should look
like (see Resources section above).
The data must be written in exactly the order specified
depending on product class type.
- public ArrayList addNew(String
filename) – This method must read comma-delimited text files in the
format specified for the toText method of Product class, its subclasses,
and Name class. It must make use
of the toObject method written in Product, its subclasses, and Name. If,
after thinking about it sufficiently, you do not know how to do this you
may ask you instructor for clarification.
- After constructing and
initializing the correct kind of product for each line read from the
text file this method should attempt to add the product to the inventory
using the addNew(Product) method of the Inventory class.
- This method should handle
any exceptions that may be thrown by addNew(Product) by creating a
String object containing the 1-based line-number of the input causing
the exception and the actual comma-delimited text of the input.
These Strings should be added to an ArrayList<String> and returned
to the caller of the method. The format of the error String is as
follow:
Line XX – “Replace this with the actual comma-delimited
Product text here from its toText method”
Where “XX” with the
1-based line-number of the comma-delimited text in input file.
This means the first line in the text file is considered to be line 1, not line
0.
- public ArrayList
addInventory(String filename) – This method should read comma-delimited
text in the format specified for the toText method of Product class, its
subclasses, and Name class.
- After reading in the
product it should attempt to change the quantity of the matching
product, if any, in the inventory using the addInventory(int, int)
method.
- This method should handle
any exceptions that may be thrown by addInventory(int, int) by creating
a String object containing the 1-based line-number of the input causing
the exception and the actual comma-delimited text of the input.
These Strings should be added to an ArrayList<String> and returned
to the caller of the method. The format of the error String is as
follows:
Line XX – “Replace this with the actual comma-delimited
Product text from the input-file here
Where “XX” with the
1-based line-number of the comma-delimited text in input file.
This means the first line in the text file is considered to be line 1, not line
0.
Testing
With the Provided Tests
- Your code must be 100% correct
to recieve credit. Correctness will be determined by running the acceptance
test P5TestDriver.java to be published Monday 2/11.
- In addition to the acceptance
test, sections 7 and 9 will be graded on the quality of JUnit tests they
create for this program, section 3 will not.
- Use the JUnit tests while
developing in a test-driven approach to ensure your code's correctness
before the acceptance test is released. Run them by opening the
AllTests.java file and executing it.
- Ask
your instructor for assistance if you are not able to run these tests on
your own.
Handing
in Your Source Electronically…
- Create a plain text file called
time.txt to log the amount of time spent on the assignment. The file will contain only three lines
with the following information on each line: name, project number, hours
spent.
Example time.txt file:
Sally Student
Program 5
7.5 hours
- Move
the necessary file(s) to your vogon account using your favorite FTP
client program.
- Log
on to vogon using your favorite Shell client program.
- Change
directory (cd-command) to the directory containing the file(s) to hand
in. Be sure you code compiles and runs correctly on hornet before
turning it in!
- Use
the following handin
command being sure to:
- Replace
the x with the correct maximum
score you can earn based on the due date, i.e., replace y with 100 if you
are handing in by Monday’s deadline, 90 for Tuesday, 80 for Wednesday, or
70 for Thursday, for example Program5-100, Program5-90, et cetera.
12:01pm vogon ~$ handin graderkm
Program5-x Inventory.java Product.java
AbstractBook.java Book.java BookOnTape.java CD.java Name.java DuplicateProductIDException.java DuplicateProductException.java
MissingProductException.java InsufficientProductException.java DelimitedTextIO.java BookOnTapeTest.java InventoryTest.java CDTest.java time.txt