Lab #8: Tut-Tut, Pardon My Queue

The purpose of this lab is to work on your Java Exception skills. You'll start with a program that works OK, but only if the input is entered perfectly. The program processes commands. The commands are:

Your job in Part 1 will be to add specialized exceptions so that when the program crashes on bad input, the stack trace is a little more informative. Your job in Part 2 will be to add real error handling, and some nice features like the ability to read input from files, which will require still more use of exceptions!

Part 1: Adding Exceptions to our good friend Queue

Download the files Lab08.java, Queue.java and ModQueue.class:

curl -O http://faculty.cs.usna.edu/IC211/docs/lab08/Lab08.java
curl -O http://faculty.cs.usna.edu/IC211/docs/lab08/Queue.java
curl -O http://faculty.cs.usna.edu/IC211/docs/lab08/ModQueue.class
The ModQueue class extends Queue in three ways:
  1. Duplicate entries are not allowed. If you try to enqueue a string that's already in the queue, the enqueue is ignored.
  2. A method void dequeue(String s) has been added, which dequeues everything up to and including entry String s in the queue. You should never call this method unless you're sure s is in the queue already.
  3. A method String dump() has been added, that returns a String that is a comma-separated list of the values in the Queue at that point.

Compile the program and run the program for yourself. Here are some example runs:

~/$ java Lab08 
> add foo
> add bar
> add goo
> dump
foo,bar,goo
> clearto bar
> dump
goo
> quit
~/$ java Lab08 
> add foo
> add bar
> dump
foo,bar
> clearto bat
Exception in thread "main" java.lang.NullPointerException
  at Queue.dequeue(Queue.java:25)
  at ModQueue.dequeue(ModQueue.java:19)
  at ModQueue.dequeue(ModQueue.java:23)
  at Lab08.main(Lab08.java:16)
~/$ java Lab08 
> dump
Exception in thread "main" java.lang.NullPointerException
  at Queue.toArray(Queue.java:41)
  at ModQueue.dump(ModQueue.java:28)
  at Lab08.main(Lab08.java:20)
Your job is to add exceptions to Queue.java so that the output for the second and third example looks instead like this:

~/$ java Lab08 
> add foo
> add bar
> dump
foo,bar
> clearto bat
Exception in thread "main" QueueException: dequeue empty queue
  at Queue.dequeue(Queue.java:24)
  at ModQueue.dequeue(ModQueue.java:19)
  at ModQueue.dequeue(ModQueue.java:23)
  at Lab08.main(Lab08.java:16)
~/$ java Lab08 
> dump
Exception in thread "main" QueueException: toArray past end of queue
  at Queue.toArray(Queue.java:41)
  at ModQueue.dump(ModQueue.java:28)
  at Lab08.main(Lab08.java:20)

You must do this in a file named QueueException.java. You cannot define QueueException as an inner class of Queue and expect to pass the tests on the submit system.

Note: These MUST be "unchecked" exceptions (i.e. the ones that Java doesn't require the caller to catch or re-throw.). Why? Because we can't modify ModQueue.java, and it isn't written to catch these!

Important: You should notice that we are able to make these changes and have everything work, even though ModQueue cannot be changed. In fact, we are doing it without access to the source code, or any way to even just recompile it. That should make crystal clear that we have distance (on the call stack) between where the errors occur (in Queue methods) and where they will ultimately be handled in Part 2 (Lab08's main). The fact that we are able to deal with this shows the strength of this approach to error handling.

Part 2: Handling Exceptions (85% lab credit)

Modify Lab08.java to add the below functionality:

  1. If -v appears as a command-line argument, the program runs in a "verbose mode", where extra information gets printed out. Exactly what gets printed is explained below.
  2. If an argument other than -v appears as a command line argument, it is treated as the name of an input file. That file should be processed as the source of commands rather than standard in. If the file cannot be opened, the following message should be printed (regardless of mode), and the source of the commands should switch over to being standard in: File 'foo.txt' could not be opened; switching input to standard in. Note 1: when the input comes from a file, no "> " prompt should be printed. Note 2: now that you know about exceptions, you should be able to understand the code we gave you before for opening files:
    Scanner sc = null;
    try {
      sc = new Scanner(new FileReader(fname));
    } catch(IOException e) {
      e.printStackTrace();
      System.exit(1);
    }
    ... and adapt it to this problem.
  3. If a user gives the dump command when the queue is empty, or the clearto with a string that isn't in the queue, the program shouldn't crash. Instead, it should silently continue, except that, in verbose mode, issuing a clearto command with a string that's not in the qeueue should result in printing to STDOUT (normal output) the error message "String 'foo' not found!" where, of course, foo should be replaced with the actual clearto string. After printing the error, however the program should continue running as if nothing bad happened. Note: in the clearto case, the queue should be emptied by a clearto command with a string that's not in the queue.
  4. If an end-of-file occurs before a "quit" command is processed, whether because the input comes from a file and the file literally ends, or because there was an end-of-file from standard in (e.g. the user pressed control-d), the program should do the following:
    • If the previous command has been completely processed, the program should exit just as if the "quit" command has been given.
    • If the previous command has not been completely processed, e.g. if the previous command was add, but no string was provided, and the end-of-file occurred when trying to read the string to be added, the program should print the message "Unexpected end of input.".
    Note: You need to think about what method would be throwing the exception if the input ended while trying to read the next string.
  5. Invalid commands (i.e. commands other than quit, add, dump and clearto) should be ignored in non-verbose mode, but in verbose mode should give the friendly error message "Unknown command 'foo'.", where "foo" should be replaced by the given command. In both cases the program should simply continue to process new commands.
One rule: You may not use the .empty() method on Queue or ModQueue objects! You must use exceptions!

Examples

Example: stdin
~/$ java Lab08 
> add cat
> add dog
> clearto rat
> dump
> ctrl-d
Example: stdin
~/$ java Lab08 -v 
> add cat
> add dog
> clearto rat
String 'rat' not found!
> dump
> ctrl-d
Example: non-existent file, switch to stdin
~/$ java Lab08 -v asdf 
File 'asdf' could not be opened; switching input to standard in.
> add cat
> add dog
> damp
Unknown command 'damp'.
> dump
cat,dog
> quit
Example: ex1.txt
~/$ java Lab08 ex1.txt 
foo,bar,bat,cat
bat,cat
Example: ex2.txt
~/$ java Lab08 -v ex2.txt 
foo,bar
String 'cat' not found!
Unexpected end of input.

Part 3: Write ModQueue (100% lab credit)

Now that you've successfully error-proofed your code, let's get some more implementation practice. We gave you a compiled ModQueue.class file. You used its interface:

void dequeue(String s);
void enqueue(String s);
String dump();

Your task is to write your own ModQueue implementation that extends Queue, and replace our ModQueue.class library with your own version. Not one line of code from your Part 1 and Part 2 solutions should be changed. Your code should still pass all the part 1/2 tests without change. Proper OOP design must be followed. This is an exercise in creating an implementation given an interface...something software engineers regularly must do.

Note that your ModQueue.java should NOT do any exception handling, i.e. no try/catch/throw statements at all.
If you have them (or think that you need to have them), then you probably have the wrong parent class for QueueException.

Submitting the lab

  1. Make sure all your .java files are commented according to the course standard for generating Javadoc.
  2. cd to the directory that contains your lab files and run ONE of the following:
    • For Part 2 submissions:
      ~/bin/submit -c=IC211 -p=Lab08 *.java ModQueue.class
    • For Part 3 submissions:
      ~/bin/submit -c=IC211 -p=Lab08 *.java