In this lab, you will write a Java application that lets the user enter checks into a personal finance system. Your application will store the data in a simple database and will verify that the account has sufficient balance before posting the transaction.
You will handle two types of exceptions: SQL exceptions from the database and application-defined exceptions.
Ask your instructor for the following information:
Lab Installation directory: ________________________________________
Eclipse Installation directory: ________________________________________
If your computer has the standard lab setup on a computer running a version of Windows before Windows Vista, these directories will be:
Lab Installation Directory: c:\jeeclass
Eclipse Installation Directory: c:\java\eclipse
If your computer is running Windows Vista, Windows 7 or later, the directories will be:
Lab Installation directory: c:\Users\username\jeeclass
Eclipse Installation directory: c:\Users\username\java\eclipse
Start Eclipse running:
Use Windows Explorer or My Computer to navigate to the {Eclipse Installation Directory}.
If your computer is running Windows XP and has the standard lab setup, this directory is:
c:\java\eclipse
If your computer is running Windows Vista, Windows 7 or later, the directory is:
c:\Users\username\java\eclipse
Note: Be sure to substitute your computer's actual username, e.g. librtrain for the "username" above.
Start Eclipse running by double-clicking on eclipse.exe.
When prompted for the Workspace, browse to {Lab Installation Directory}/workspace, then press OK.
If your computer is running Windows XP, and has the standard lab setup, the correct directory is:
c:\jeeclass\workspace
If your computer is running Windows Vista, Windows 7 or later and has the standard lab setup, the directory is:
c:\Users\username\jeeclass\workspace
Note: Be sure to substitute your computer's actual username, e.g. librtrain for the "username" above.
Close the Welcome window by clicking on the 'X' in its titlebar.
We also recommend running Eclipse as a maximized window.
Eclipse supports the notion of perspectives, which are sets of window panes that let you work in a particular role. For this lab, you will work in the Java perspective, which contains window panes that let you create and edit Java programs.
Open the Java perspective by choosing Window - Open Perspective - Java.
Your first job is to create a new project for your lab. Follow these steps:
Choose File - New - Java Project, Then press Next.
On the Java Project Page, enter Lab01 for the Project name, then press Finish.
You should see the new project in the Package Explorer pane. Expand it and note that it's empty except for a reference the Java Runtime Environment (JRE) and a src folder.
The basic building block of a Java program is the class. Now you will use a wizard to create a class for your program. Follow these steps:
To start the wizard, right-click on the Lab01 entry in the Package Explorer and choose New - Class.
On the first wizard page, enter part0 for the Package. A package is an organizational unit for Java classes. By convention, Java package names start with a lower-case first character.
For the Name, enter ConvertTemperature. By convention, Java class names start with an upper-case first character.
Near the bottom of the page, put a checkmark in the box labeled public static void main(String[] args). This will cause the wizard to create a main method for you which will act as the starting point of your program.
Then press Finish. Note that the new package name and class appear in the Package Explorer and that Eclipse opens the new class's source code into the Java editor.
This program's job is to accept data from the user that contain the current temperature. When the user enters this data, it will come into your program as a String; your program will convert to the appropriate Java type, double. During conversion, Java will throw an exception if the input data is not correctly formatted, for example if the user enters "abc" for the temperature rather than a numeric string such as "33". Your program will handle these exceptions.
Complete the main method as follows:
Create a Scanner that will let you retrieve keyboard input:
Scanner scanner = new Scanner(System.in);
From the Eclipse menu, choose Source - Organize Imports so that Eclipse imports the java.util.Scanner type.
Prompt the user for the temperature, and retrieve that String:
System.out.print("Enter the current temperature (F): ");
String temp = scanner.nextLine();
Use the java.lang.Double class to attempt to convert the "temperature" String into a double:
double fahrenheit = Double.parseDouble(temp);
Do a simple calculation and display the results:
double celsius = (fahrenheit - 32) * 5 / 9;
System.out.printf("The temperature in Celsius is %2.2f\n",
celsius);
scanner.close();
Highlight all of the lines in main and choose Source - Surround With - Try/catch block so that Eclipse writes simple exception handling for you.
Then modify the Eclipse-generated code in the catch block so that it looks like:
System.out.println("Bad input string");
Right-click on ConvertTemperature.java in the Package Explorer and choose Run As - Java Application.
In the Console, enter a Fahrenheit temperature and press Enter. Do you see the correct Celsius value?
Try running the program again, this time entering abc for the Fahrenheit temperature. What happens? Why?
You must configure the database for your program. We will use the free, open-source H2 database to hold the check information. Follow these steps to configure the database:
Using Windows Explorer or My Computer, navigate to {Lab Installation Directory}/lib/h2/h2-1.3.161.jar and double-click on the JAR - this starts the database running and opens a Web-based administration GUI. If your computer is running Windows XP, the JAR is at:
c:\j2eeclass\lib\h2\h2-1.3.161.jar
If your computer is running Windows Vista or later:
c:\Users\username\j2eeclass\lib\h2\h2-1.3.161.jar
In the GUI, set the JDBC URL to jdbc:h2:tcp://localhost/~/test, typing this VERY carefully.
Set both the User Name and Password to sa, then press Connect.
In the GUI, in the large command-entry area, create the database table by entering the following command all on one line:
CREATE TABLE checks (checknum INTEGER PRIMARY KEY,
accountnum INTEGER,amount DOUBLE)
Then press the Run (Ctrl+Enter) button.
To test the new table, press the CLEAR button, then enter:
SELECT * from checks
Press the Run (Ctrl+Enter) button -- you should see an empty table with the proper column names.
Next, you will import a class that contains the business logic for the program and communicates with the database. Follow these steps:
Use Windows Explorer or My Computer to navigate to {Lab Installation Directory}/starters/lab01. If your computer is running Windows XP, this folder is at:
c:\j2eeclass\starters\lab01
On Windows Vista or later:
c:\Users\username\j2eeclass\starters\lab01
Note: Do NOT navigate into the checks folder.
Highlight the checks folder, then press Ctrl+C.
Back in Eclipse, right-click on the Lab01\src folder and choose Paste - you should see the imported checks package (folder).
Edit the checks/CheckingAccount.java file and examine it and see if you can make any sense of the JDBC code that talks to the database. Especially note the connect method at the bottom that connects to the H2 database you configured earlier.
Find the writeCheck method and note what exceptions it throws.
The CheckingAccount class uses the JDBC API to communicate with the database. JDBC requires that you use a JDBC driver library -- for this program, we need to ensure that the JDBC driver is accessible to our program. Follow these steps:
In the Project Explorer, right-click on the Lab01 project and choose Properties.
In the Properties Editor, select Java Build Path, then click the Libraries tab.
Press the Add External JARs... button, then navigate to the ${Lab Installation Directory}/lib/h2 directory and select h2-1.3.161.jar. This archive contains the JDBC driver for H2. Press Open followed by OK.
In this part, you will write a program that writes a check and catch exceptions.
Create a new class named TestChecking in the test package. The new class should have a main method. Complete the main method as described below so that it retrieves a check number and amount from the user and calls the writeCheck method:
In the same fashion as the last part of lab, create a Scanner connected to System.in.
Write an infinite while loop.
while(true)
{
}
Inside the loop, ask the user if they want to continue and retrieve a keystroke. If the user enters 'Y', break out of the loop:
System.out.print("Quit? ('Y' or 'N'):");
if ( scanner.nextLine().charAt(0) == 'Y')
break;
In the loop, ABOVE the keystroke-checking code, prompt the user, then call the nextLine method in the Scanner class to retrieve two Strings -- one for the check number, one for the amount. For example, to prompt the user and retrieve a String for the check number, use code like:
System.out.print("Enter check number: ");
String checkNumberStr = scanner.nextLine();
Use Integer.parseInt to convert the check-number String to an int and Double.parseDouble to convert the amount String to a double. For example, to convert the checkNumberStr to an integer, use code like:
int checkNumber = Integer.parseInt(checkNumberStr);
Create an instance of the CheckingAccount class. Use Source - Organize Imports to import the type.
Call the writeCheck method on the CheckingAccount reference, passing the checkNumber and amount integer and double.
Save the file to compile. You should have two compilation errors about Unhandled exceptions for ClassNotFoundException and SQLException You will fix those in a moment, but if you have any other compilation errors, fix them before continuing.
Examine the writeCheck method and note which exceptions it throws -- do the compilation errors make sense?
There are two basic ways to handle exceptions -- you can write a try-catch block or pass the exceptions back to whomever called you. We'll start with the latter approach.
Modify the main method, adding the clause throws Exception. Since Exception is the superclass of all catchable exceptions, this should fix both compilation errors.
Try running the program: pass 123 for the check number and 5.5 for the amount. The program should work fine. Don't quit yet.
When prompted, enter the same check number and amount. What happens? Quit the program.
The problem is that the database is enforcing the primary-key constraint so you cannot insert two checks with the same check number.
Since your main method passed the exception back to its caller, the exception was handled by the Java Virtual Machine, which prints the lovely stack trace. While the stack trace is useful to help a developer diagnose the problem, it's probably not a good idea to display that type of information to the user -- programs that react like this to errors do not inspire user confidence.
Let's make this a bit more user friendly by handling the exception in our program. The good news is that Eclipse can help you write try-catch blocks. Follow this procedure:
Remove the throws Exception clause from main.
Highlight the line that calls writeCheck, then right-click on the highlighted area and choose Source - Surround with try/catch block.
Note that Eclipse determined which exceptions the highlighted line might throw and wrote a catch block for each. The Eclipse-generated code is not that user-friendly, so delete it in both catch blocks and replace it with:
System.out.println(e.getMessage());
This code displays the exception object's message string, which should be a human-readable description of the exception.
Try running the program again, using the same check number and amount. You should see a message indicating a "violation of unique index...". This message is a little better than the stack trace, but you will improve it in a later part of lab. Don't quit yet.
When prompted, enter "abc" for the check number and any amount. What happened and why? Quit the program.
The problem is that the conversion from String to int and double can throw the NumberFormatException. Follow this procedure to improve the program:
Highlight all of the lines from the Integer.parseInt call down through the end of the last catch block for SQLException.
Right-click on the highlighted lines and choose Source - Surround with try/catch block.
In the catch block for NumberFormatException, replace the generated code with:
System.out.println("Invalid numeric data entered.");
Note that you now have a try-catch nested within another try-catch -- that's perfectly OK. The idea here is that we only want to attempt to write the check if both input Strings contain properly formatted numbers.
Try running the program again with "abc" for the check number and any amount. Does that look better? Quit the program.
In this part, you will write exception class that encapsulate information about exceptional conditions that this program may encounter.
Create a class named DuplicateCheckNumberException in the checks package by following these steps:
Right-click on the checks package and choose New - Class.
In the New Class wizard's first page, enter DuplicateCheckNumberException for the name. For the superclass, press the Browse... button and start typing Exce into the entry field -- note how the wizard narrows down the superclass name based on your typing. Select Exception from the list and press OK.
This new class doesn't need a main method. Press Finish to create the class.
Edit the new class and write a zero-argument constructor that invokes the superclass:
public DuplicateCheckNumberException()
{
super ( "Check numbers must be unique" );
}
This defines the message string for the new exception class.
Repeat the above step to create an exception class named InsufficientFundsException. Use an appropriate message string.
Edit CheckingAccount.java and update it to use the new exception classes. Perform the following steps:
Add the DuplicateCheckNumberException and InsufficientFundsException to the list of exceptions thrown by the writeCheck method.
Find the closing brace of the if statement that checks for a non-zero balance in the writeCheck method and add an else clause:
else
{
throw new InsufficientFundsException();
}
Find the catch block in the writeCheck method that catches the SQLException and modify it so it looks like:
catch ( SQLException e )
{
if ( e.getErrorCode() == 23505 )
throw new DuplicateCheckNumberException();
throw e;
}
Save CheckingAccount.java and note that there are now errors in TestChecking.java due to the new exception types.
Edit TestChecking.java and write additional catch blocks for the new exceptions. In the catch blocks, you can display the message string in a similar fashion as before.
Save, then run the program.
To test, write a check using 123 for the check number and 5.5 for the amount -- you should see the "unique check number" message. Don't quit yet.
Try writing another check with 444 for the check number and 500 for the amount -- you should see your "insufficient funds" message. (The initial balance of the account is $100 -- see the CheckingAccount class to see how this works.)
You can quit the program when you are finished.
In this part, you will practice the techniques covered in this lab to reinforce the concepts.
Create a new class named EchoFile in the io package. The class should have a main method.
Read the JavaDoc about the java.io.FileReader class. Note that the class defines a constructor that accepts a file name. Note also that it defines a read method that returns a character from the file. Please make special note of the exceptions thrown by the constructor and the read method.
In main, write code to open the CheckingAccount.java file using a FileReader. The pathname should be src/checks/CheckingAccount.java.
Use a try-catch block to handle any exceptions.
Within the try block from the previous step, write a loop that reads characters from the file until the read method returns -1. Use System.out.print to print each character to the console.
After the loop finishes, call the close method to close the FileReader.
Use a try-catch block to handle any exceptions.
Note: The read method returns an int so you can tell end-of-file by looking for -1. However, before displaying, you will need to cast the int to char.
Save, run and test. You should see the text of the file displayed in the console.
Try changing the pathname to xxxx and running your program. Does your exception handling kick in?