Java:Assignment - Address book - Tasks

From Juneday education
Jump to: navigation, search

Contents

Getting started with this assignment

Video

Download the code

First download (download instructions) the zip file with all the code Create a directory for your work and move the zip file there and unzip it.

Task 1. Finish the Contact class

Compile the Contact class and verify that it compiles.

$ javac -d bin src/org/addressbook/storage/Contact.java

Hint: you must be in the directory containing the directories bin, src, and doc. The flag -d bin tells javac to put the class file for Contact in the bin directory structure.

Overview of where in the project you are working

.
`-- src
    `-- org
        `-- addressbook
            |-- main
            |   |-- SimpleApplication.java
            |   `-- SimpleMain.java
            |-- storage
            |   |-- Contact.java    <--------You are working on this class now!
            |   |-- SimpleAddressBook.java
            |   `-- SimpleMutableList.java
            |-- tests
            |   |-- TestContact.java<--------You are using this class to test your code!
            |   `-- TestSimpleAddressBook.java
            |-- textutils
            |   |-- TextUtilsExample.java
            |   `-- TextUtils.java
            `-- ui
                `-- cli
                    `-- menu
                        |-- MenuAction.java
                        |-- MenuExample.java
                        `-- Menu.java

Scripts

Video

Task 1.1 Finish the constructor

Skills needed

In order to complete this task, you need the skills acquired in the following exercises:

The actual task

Your first task is to finish the constructor (in the class Contact). The body of the constructor is empty as it is now. Your first task is to make sure that the constructor saves the parameters in appropriate instance variables.

Hint: remember the keyword “this” to distinguish between parameters and instance variables that share the same name!

Before you start coding, compile and run the tests for the Contact class. Compiling the test program requires that you add the flag -cp bin. Running the test program requires that you add the flag -ea to the java command, as well as the flag -cp bin. The full compilation and command lines then becomes

$ javac -cp bin -d bin src/org/addressbook/tests/TestContact.java
$ java -ea -cp bin org.addressbook.tests.TestContact

The tests should fail with the following message:

$ java -ea -cp bin org.addressbook.tests.TestContact
=====Testing constructor=====
Testing new Contact("Name Nameson", "email@email.com", "123")
Exception in thread "main" java.lang.AssertionError: * Name wasn't saved!
	at org.addressbook.tests.TestContact.testConstructor(TestContact.java:14)
	at org.addressbook.tests.TestContact.main(TestContact.java:65)

The test should fail! You haven’t fixed the constructor to save the parameters yet! Write the code that saves the parameters to the instance variables, and run the test again. This time, the test should be successful if you have written the code correctly. Verify that the first test passes by looking at the output from the test and verify that it says:

=====Testing constructor=====
Testing new Contact("Charlie Ceeson", "charlie@email.com", "12345")
* Constructor test for contact: Charlie Ceeson charlie@email.com 12345 passed.

Don’t worry if the next test fails! If the constructor test doesn’t pass, try to fix your code, compile and run the test until the test passes with the message above. Don't forget to save your source code between each fix, and don't forget to re-compile it before running the test again. The command line to compile the Contact class was:

$ javac -d bin src/org/addressbook/storage/Contact.java

The test verifies that the constructor has saved the arguments to the instance variables, by calling the accessor methods name(), email() and phone() on a newly created Contact object.

Task 1.2 Make the constructor smarter

Skills needed

In order to complete this task, you need the skills required from doing the exercises here:

The actual task

Next, you should make your constructor in Contact a little smarter and safer. We want Contact objects which have at least a name! Email and phone may be empty, but not the name.

We don’t want to accept a null value for the name parameter. Write an if-statement such that if name is null, a NullPointerException should be thrown with a message explaining that name cannot be null.

Also, we do not want to accept an empty String for the name parameter. Add an if-statement which checks if name equals the empty String. Hint: use the equals() method! The empty String is two double quotes with nothing inside them. If the name parameter is the empty String, throw an IllegalArgumentException with a message explaining that the name parameter cannot be the empty String. Finally, we do accept null parameters for the email and phone parameters, but they should be saved as the empty String in the instance variables, if they are null.

Add an if-statement which checks if email is null. If so, save the empty String in the email instance variable, otherwise save the parameter email in the instance variable. Do the same for the phone parameter and instance variable.

Hint: To distinguish between a parameter and an instance variable with the same name, use the keyword this. If the parameter is called email, then you can use this.email to specify the instance variable with the same name.

To check if you have succeeded, run the test again and verify that you get this result:

=====Testing constructor=====
Testing new Contact("Charlie Ceeson", "charlie@email.com", "12345")
* Constructor test for contact: Charlie Ceeson charlie@email.com 12345 passed.
=====Testing constructor with null checks=====
* Constructor null tests passed.

If the tests in the org.addressbook.tests.TestContact test program passed, you have succeded in this part of the assignment! The Contact class’ constructor works as required.

Task 1.3 Finish the compareTo() method

Skills needed

Skills from the following exercises (and all of the above):

The actual task

In order for a list of contacts to be sortable, we have decided that Contact should implement the Comparable<Contact> interface. This is a small interface which only declares one method, public int compareTo(Contact other) . The only part of a contact that should be considered when comparing two Contacts is the name (which is a simple String reference). Now, the good news is that Strings are Comparable, so we only have to do two things in the method body for compareTo:

  1. Check if the parameter other is null, in which case we throw a NullPointerException
  2. return the result of using compareTo between this object’s name and other’s name

Run the tests for Contact again and verify that you have passed the tests for compareTo().

Task 1.4 Finish the equals() method

Skills needed

Skills from the following exercises (and all of the above) are needed:

The actual task

We have decided that it is useful to be able to check if two contacts are to be considered equal using the equals() method inherited from Object. In order for this to work, we need to override the inherited version of this method. Don’t worry about this step, because as with compareTo, the only part of a Contact to consider when deciding whether two objects are equal is, again, the name (for simplicity). And, again, we can take advantage of the String class’ implementation, since it has a functional equals() method we can use.

There is, however a contract for the equals() method, which is that two objects who are equal (according to the equals() method) must also return the same hashCode(). We have implemented the hashCode() method for you. You can read more about equals(), hashCode() and the contract mentioned before here.

There are a few steps to follow for you to implement the equals() method as listed below:

  1. Check if parameter other is null, in which case you should return false
  2. Check that parameter other is an instanceof Contact - if it isn’t return false
    Hint: the two checks above could be done in one if statement using ||
  3. Create a local reference variable of type reference to Contact and assign it the other parameter cast to a reference to Contact
  4. Return the result of the local variable’s name equals this object’s name

Run the tests again and verify that the equals test also passes.

A complete successful test run for Contact should yield the following output:

=====Testing constructor=====
Testing new Contact("Name Nameson", "email@email.com", "123")
* Constructor test for contact: Name Nameson email@email.com 123 passed.
=====Testing constructor=====
Testing new Contact("Bob Bobson", "bob@email.com", "1234")
* Constructor test for contact: Bob Bobson bob@email.com 1234 passed.
=====Testing constructor=====
Testing new Contact("Charlie Ceeson", "charlie@email.com", "12345")
* Constructor test for contact: Charlie Ceeson charlie@email.com 12345 passed.
=====Testing constructor with null checks=====
* Constructor null tests passed.
=====Testing compareTo=====
* Test of compareTo() in Contact passed!
===Testing equals===
* equals() test for Contact passed.

Task 2. Finishing the SimpleAddressBook class

Overview of where in the project you are working

.
`-- src
    `-- org
        `-- addressbook
            |-- main
            |   |-- SimpleApplication.java
            |   `-- SimpleMain.java
            |-- storage
            |   |-- Contact.java    
            |   |-- SimpleAddressBook.java<------You are working on this class now!
            |   `-- SimpleMutableList.java
            |-- tests
            |   |-- TestContact.java
            |   `-- TestSimpleAddressBook.java<--You are using this class to test your code!
            |-- textutils
            |   |-- TextUtilsExample.java
            |   `-- TextUtils.java
            `-- ui
                `-- cli
                    `-- menu
                        |-- MenuAction.java
                        |-- MenuExample.java
                        `-- Menu.java

Skills needed

In order to finish this task, you need the skills acquired from the following exercises:

  • Exercises on Interfaces (most of them)
  • Exercises on instance methods

Task description

The idea here is that the Main class, the actual starting point of your program, can create and start the objects it needs. That would be a Menu, where the different menu options work on a SimpleAddressBook object!

Before we try to tie everyting together, we’d better make sure that the actual SimpleAddressBook object (which keeps a list of Contacts) is also working.

What signifies a SimpleAddressBook? In our case, the requirements are that the SimpleAddressBook should be able to respond to the following simple requests for actions:

  1. adding a Contact
  2. retrieving the number of contacts currently in the address book
  3. listing all Contact:s to the stdout
  4. saving the current address book to some place
  5. loading a previous address book from some place
  6. indicating whether a specified contact is already in the address book (not used in this lab, but in the next)

Actually, these actions correspond to the methods declared in the SimpleMutableList interface we have provided:

public interface SimpleMutableList<E> {

  public int numberOfEntries();
  
  public void listEntries();
  
  public void addEntry(E entry);

  public void save();
  
  public void load();

  public boolean contains(E entry);

}

Since SimpleAddressBook implements the SimpleMutableList interface, we know that SimpleAddressBook has implemented all methods above. One of the methods, however, is not fully functional yet. It is your task to finish it.

Task 2.1 - compile SimpleAddressBook

Skills needed

  • Revisit exercises on packages, compiling classes in packages, compiling with -d to separate source code and class files

Task description

TODO: why change dir - before we compiled from TOP level? - because we need class path otherwise maybe. We can provide alternatives and let the student choose.

Start by confirming that you can compile the SimpleAddressBook class:

$ cd src/
$ javac -d ../bin/ org/addressbook/storage/SimpleAddressBook.java
$ cd ..

Note that you go down to the src/ directory because it simplifies how to compile for you. Then when you have confirmed that the file SimpleAddressBook.java actually does compile without errors, you go back up to the directory above src where all the scripts are.

Task 2.2 finish the add() method

Required skills

  • Exercises on writing methods, calling methods

Task description

Compile and run the tests for SimpleAddressBook. Don’t worry that the tests fail, it is expected:

$ ./run_test_simple_address_book.sh
Test: adding Arnold Llloyd a@test.com 12345
You must implement addEntry(Contact c)
In class org.addressbook.storage.SimpleAddressBook
* Adding null null null
Exception in thread "main" java.lang.AssertionError: number of entries should increase by one after add!
	at org.addressbook.tests.TestSimpleAddressBook.testAdd(TestSimpleAddressBook.java:22)
	at org.addressbook.tests.TestSimpleAddressBook.main(TestSimpleAddressBook.java:30)

If you would like to build and run manually (instead of using the script above), do the following:

$ ./build.sh
$ java -cp bin -ea org.addressbook.tests.TestSimpleAddressBook 
Test: adding Arnold Llloyd a@test.com 12345
You must implement addEntry(Contact c)
In class org.addressbook.storage.SimpleAddressBook
* Adding null null null
Exception in thread "main" java.lang.AssertionError: number of entries should increase by one after add!
	at org.addressbook.tests.TestSimpleAddressBook.testAdd(TestSimpleAddressBook.java:22)
	at org.addressbook.tests.TestSimpleAddressBook.main(TestSimpleAddressBook.java:30)

The tests fail with a complaint about you having to implement add()! So let’s do that. Here’s the single simple step to implement the add method:

  • Add a statement which adds the parameter c to the internal list called entries

Explanation: The SimpleAddressBook class maintains an internal List<Contact> in an instance variable called entries. This means that the add(Contact c) method simply stores the parameter c in this internal list, using the method add(E) from the java.util.List interface. Check the online API docs to verify that the java.util.List interface has an add() method if you don’t believe us! In fact, check the online API docs, anyway, since it is good practice.

Run the tests again and verify that the first test now passes:

$ java -cp bin -ea org.addressbook.tests.TestSimpleAddressBook 
Test: adding Arnold Llloyd a@test.com 12345
* Adding Arnold Llloyd a@test.com 12345
* Number of entries was increased by one
* list.contains(c) returns true
* Test with Arnold Llloyd a@test.com 12345 passed.
Test: adding Bernard Blake b@test.com 234354
* Adding Bernard Blake b@test.com 234354
* Number of entries was increased by one
* list.contains(c) returns true
* Test with Bernard Blake b@test.com 234354 passed.
Test: adding Cecil B. Demented c@test.com 234234
* Adding Cecil B. Demented c@test.com 234234
* Number of entries was increased by one
* list.contains(c) returns true
* Test with Cecil B. Demented c@test.com 234234 passed.

That’s actually all you had to do in order to complete the SimpleAddressBook class.

You can now move on to the next task, unless you want to do the optional challenge below.

Skills needed for this optional challenge

  • Exercises on exceptions, writing your own exceptions, wrapping an exception inside another and re-throwing

Optional challenge - you don't have to do this unless you want

Optional (NOT mandatory): Change the save() method so that instead of printing the stacktrace in the catch clause, it logs the exception and re-throws a new RuntimeException with an error message saying that it couldn't save the address book.

This will later make the global exception handler in main() to catch this message, and point the user to the log file where the exception was logged.

END OPTIONAL challenge

Task 3 - Create the SimpleApplication class

Overview of where in the project you are working

.
`-- src
    `-- org
        `-- addressbook
            |-- main
            |   |-- SimpleApplication.java<------You are working on this class now!
            |   `-- SimpleMain.java
            |-- storage
            |   |-- Contact.java<------------+
            |   |-- SimpleAddressBook.java<--'<-These classes are used in your class
            |   `-- SimpleMutableList.java
            |-- tests
            |   |-- TestContact.java
            |   `-- TestSimpleAddressBook.java
            |-- textutils
            |   |-- TextUtilsExample.java
            |   `-- TextUtils.java<--------------This class is used in your class
            `-- ui
                `-- cli
                    `-- menu
                        |-- MenuAction.java<---+
                        |-- MenuExample.java<--|<-These classes are used in your class
                        `-- Menu.java<---------+

Our suggested design for the complete application is that you create a class, SimpleApplication, which is responsible for creating a menu with options for the functionality of the application and a way to start the application.

The main class (which you haven't written yet) will create an object of type SimpleApplication and call the start() method on the SimpleApplication object. The SimpleApplication object then starts the menu object which displays the menu options to the user and handles the user’s choice.

The SimpleApplication class should create a menu with three menu options:

0. List
1. Add
2. Quit

It is your task to populate the menu object in SimpleApplication with these menu items. See the MenuExample.java file for an example on how to create a menu item with menu options as text and a MenuAction connected to each option.

So, to summarize, you will write a main class with a main method. The only thing the main method does, is to create an instance of SimpleApplication and run the start() method on the instance. The start() method will create the menu system and display it to the user, who will interact with the menu system. The menu system will print out the choices for what to do, e.g. add (a new contact), list (all contacts) or quit (the whole application).

  • SimpleMain has the main method and creates a SimpleApplication and calls start() on it.
    • SimpleApplication has the start() method which starts the menu system, which is responsible for the interaction with the user (present options and do what the user wants)
    • SimpleApplication therefore has a Menu with a set of MenuActions for list(), add() and quit().
    • SimpleApplication also has a SimpleAddressBook in a variable called list
    • SimpleApplication will use the list variable in its menu's menu actions
      • in the add() menu action, the action will read in data for a new contact, create a new Contact with said data and add the Contact to the list
      • in the list() menu action, the action will loop through the list and print each Contact
      • the quit() menu action exists in the menu already and you don't have to write it
  • The main method will have exception handling around the SimpleApplication code, so that the main method can handle any unhandled exceptions that might occur in the menu or SimpleAddress book, and at least write a user-friendly error message.

In this task, you will start with the SimpleApplication class and only after that, will you write the small main method in SimpleMain.

Do you have to write this class from scratch? You can choose to if you want, or use a simple path as explained below.

Task 3 - simple version

Skills needed

  • The most important skill here, is to read all the instructions carefully.
  • Skills from the exercises on
    • Classes; methods, instance variables, import statements, package declaration
    • Interfaces, in particular how to write an anonymous inner class (see the example in TextUtilsExample also)
  • Read the example code in org.addressbook.textutils.TextUtilsExample
  • The most important skill here, is to read all the instructions carefully. We say this again.

The actual task

Use the file src/org/addressbook/main/SimpleApplication.java and complete only the createMenu() method.

The createMenu() method should add two menu items to the menu (the "Quit" menu item is added automatically by the menu object!).

The first item should have the text "List" and a MenuAction which in its onItemSelected() method calls listEntries() on the address book (the SimpleApplication class maintains a SimpleAddressBook in a variable called list!).

The second item should have the text "Add" and a MenuAction which in its onItemSelected() method reads a name, an email and a phone number from the user, then creates a new Contact using this information and calls addEntry(), with this Contact as the only argument, on the address book. Note:As the last statement in the onItemSelected() method, save() should be called on the address book (so that the new entry is saved in the address book file as well).

The "Add" MenuAction is the harder-to-write of the two. Let's explain how it should work again! It should present the user with a prompt for the name of the new contact and save it in a variable, then prompt the user for the email and save that in a variable and finally prompt the user for the phone number and save that in a variable. After getting the name, email and phone from the user, it should create a new Contact object, and call addEntry() on the list variable with the new Contact reference variable as the argument.

How can you ask the user for a name and save the result in a variable? You may write your own implementation in order to do this, but you can also use a utility method we have provided for you. See org.addressbook.textutils.TextUtilsExample to see how to ask the user a question and get a String reference back.

How do you know that your code works? Well, you need to complete Task 4 and create and run the SimpleApplication from the main method. You'll create the class with the main method in the next task, but first we'll give you the harder version of this subtask which is optional.

Task 3 - challenge version (optional and harder)

If you want something more challenging, you are free to create the SimpleApplication class from scratch. Start by removing (or moving) the SimpleApplication.java file we have provided for you, and start writing your own version.

Create the class org.addressbook.main.SimpleApplication (it should be declared in a file: src/org/addressbook/main/SimpleApplication.java and have a package declaration declaring it to be part of the package org.addressbook.main).

The class should have the following components:

  • A private instance variable of type reference to SimpleMutableList<Contact>
    Hint: you need to import the following classes:
org.addressbook.storage.Contact
org.addressbook.storage.SimpleMutableList
org.addressbook.storage.SimpleAddressBook
org.addressbook.ui.cli.menu.Menu
org.addressbook.ui.cli.menu.MenuAction
  • A private instance variable of type reference to Menu which should be initialized to a new Menu object with a suitable title for the menu, e.g. “Address Book”
  • A public constructor which takes no arguments, but performs the following tasks:
    • initializes the SimpleMutableList variable to a new SimpleAddressBook()
    • calls the load() method of the address book
    • prints a diagnostic message indicating how many Contacts was loaded
  • A private method createMenu() which adds two menu items to the menu (the “Quit” menu item is added automatically by the menu)
    • The first item should have the text “List” and a MenuAction which in its onItemSelected() method calls listEntries() on the address book
    • The second item should have the text “Add” and a MenuAction which in its onItemSelected() method reads a name, an email and a phone number from the user, creates a new Contact using this information and calls addEntry with this Contact as the only argument on the address book. As the last statement in the onItemSelected() method, save() should be called on the address book.
  • A public method start() which calls, in turn, createMenu() in this object and start() on the menu variable.

This is a rough outline of the class SimpleApplication:

package declaration...
import statements...
public class SimpleApplication{
  declare the SimpleMutableList<Contact> variable (call it e.g. list)
  declare the Menu variable (call it e.g. menu) and
        assign it a new Menu object with the argument "Address book"
  declare the public constructor with no arguments{
     list is assigned a new AddressBook object
     call load() on the list
     print how many contacts were loaded (use the numberOfEntries() 
           method for the list variable) 
  }
  declare a private void method createMenu(){
     use the menu variable and call addMenuItem with a text of
         "List" as the first argument and an anonymous inner class
         of MenuAction overriding public void onItemSelected()
         which calls listEntries() on the list variable
     use the menu variable and call addMenuItem with a text of
         "Add" as the first argument and an anonymous inner class
         of MenuAction overriding public void onItemSelected()
         which reads name, email and phone from the user (and saves
         the result in three variables), and creates a new Contact 
         using the three variables.
         Call addEntry() on the list variable with the new contact 
         reference as the argument.
         Call save() on the list variable.
  }
  declare a public void method start(){
    call createMenu()
    call start() on the menu variable
  }
}

How can you ask the user for a name and save the result in a variable? You may write your own implementation in order to do this, but you can also use a utility method we have provided for you. See org.addressbook.textutils.TextUtilsExample to see how to ask the user a question and get a String reference back.

How do you know that your code works? Well, you need to complete Task 4 and create and run the SimpleApplication from the main method.

Task 4 - write the main class which starts the application

Overview of where in the project you are working

.
`-- src
    `-- org
        `-- addressbook
            |-- main
            |   |-- SimpleApplication.java<-----This class is used in your class
            |   `-- SimpleMain.java<------------You are working on this class now!
            |-- storage
            |   |-- Contact.java
            |   |-- SimpleAddressBook.java
            |   `-- SimpleMutableList.java
            |-- tests
            |   |-- TestContact.java
            |   `-- TestSimpleAddressBook.java
            |-- textutils
            |   |-- TextUtilsExample.java
            |   `-- TextUtils.java
            `-- ui
                `-- cli
                    `-- menu
                        |-- MenuAction.java
                        |-- MenuExample.java
                        `-- Menu.java

Task 4.1 write a simple main method which starts the application

Your final task is to write the class with the main method which kicks off (starts) the application. Write the class org.addressbook.main.SimpleMain (in the file src/org/addressbook/main/SimpleMain.java). This class needs a package declaration, declaring that it is part of the org.addressbook.main package, and a standard main method.

The main method should declare a local variable of type reference to SimpleApplication and assign it a new SimpleApplication. Run start() on this variable and verify that the application starts (by showing the user the menu alternatives).

Task 4.2 - add a global exception handler to the main method

Put a try-catch block around the code in main. Catch any Exception and print an error message to System.err directing the user to read the log file for more information.

TODO: discuss what we expeect from a real application if something goes wrong Why do we want to do this? If there is an uncaught exception in the code, it will bubble up all the way to the main method. We’d like to spare the user from any Java-specific error messages like NullPointerException or stack traces, so we present an error message instead and refer the user to the log file for such technical information.

How does this work? If there is a failure (an exception is thrown) for instance in the file handling code for loading the address book from the file system, the load() method catches this exception and logs the stack trace to the log file, before re-throwing an unchecked runtime exception which will bubble up all the way to main. Why do we want this to propagate all the way to main? Because if there is a problem reading the saved address book from the file system, there is really nothing we can do about it but to gracefully shut down the application and log the error. There is no way we can recover from this error.

The outline of this final version of the main method now becomes:

public static void main(String[] args){
  try{
    create simple application object and call start()
  }catch(Exception e){
    write error message to standard error referring the user to the log file
  }
}

Hint #01: Look at the class org/addressbook/storage/SimpleAddresBook for information about the log file's location. - You might want to change the static variable LOG_FILE in SimpleAddressBook to public

Hint #02: For Windows users the home directory path follows the Windows home variable, typically C:\Users\UserName where UserName is your user name (e g Ada Lovelace). It is not the cygwin home directory.

Testing the main application (and indirectly the SimpleApplication class)

You have to run the main class in order to test if your SimpleApplication’s menu items work. We suggest the following procedure to test your application:

Start by running the application and select the "List" menu item. It should list nothing, since it doesn’t yet contain any Contacts:

$ java -cp bin/ org.addressbook.main.SimpleMain
INFO: There is no address book file.
0 items loaded from file.

====Address book====

0 List
1 Add
2 quit
Please enter a number from the menu: 0        <---- user enters "0"

You selected List


====Address book====

0 List
1 Add
2 quit
Please enter a number from the menu: 2        <---- user enters "2"

Bye!
$

Note that the applications notifies you that there are no entries loaded, and when you select the number for listing the contacts, nothing is printed (since there are no contacts).

Next, run the program again and add a few contacts:

$ java -cp bin/ org.addressbook.main.SimpleMain
INFO: There is no address book file.
0 items loaded from file.

====Address book====

0 List
1 Add
2 quit
Please enter a number from the menu: 1        <---- user enters "1"

You selected Add

Name: Ben Afflec
Email: ben@hollywood.com
Phone: 123456
Saving in /home/USERNAME/.address_book...

====Address book====

0 List
1 Add
2 quit
Please enter a number from the menu: 1        <---- user enters "1"

You selected Add

Name: Adam Axelson
Email: adam@name.com
Phone: 654321
Saving in /home/USERNAME/.address_book...

====Address book====

0 List
1 Add
2 quit
Please enter a number from the menu: 2        <---- user enters "2"

Bye!

Next, run the application again, to verify that it finds the address book file (in your home directory, it should have been created for you) and try to list the contacts:

$ java -cp bin/ org.addressbook.main.SimpleMain
2 items loaded from file.

====Address book====

0 List
1 Add
2 quit
Please enter a number from the menu: 0

You selected List

Adam Axelson adam@name.com 654321
Ben Afflec ben@hollywood.com 123456

====Address book====

0 List
1 Add
2 quit
Please enter a number from the menu: 2

Bye!

Verify that the application indicates that the correct number of contacts was loaded on startup, and that the "List" menu option lists the contacts you added in the last run of the application.

If you need to start over, you can remove the address book file from your home directory. On GNU/Linux the file should be in /home/USERNAME/.address_book on Mac OS it should be in /Users/USERNAME/.address_book and on Windows C:\Users\USERNAME\.address_book

If there are any errors/exceptions, they should be logged to .address_book.log also in your home directory. Note that USERNAME should be replaced with your actual USERNAME on your computer!

When you have verified that the application and menu is working, you are done with the assignment!

Trouble shooting

Compiling

You must cd down to the directory where src/ and bin/ are located in order to compile. In order to compile you need to do two things:

  1. give javac the flag -cp src
  2. give javac the flag -d bin

The first flag, is to give the compiler the class path needed to find the package structure. Inside src the top level package org is located. In order to compile the classes while you are in the directory above src, you must tell the compiler that it should start looking for packages (directories) inside the src directory. The src directory is not part of the package structure, but it is convenient to have all the Java source code files under this directory.

The second flag, is to give the compiler a directive for where to create the resulting class files. Telling it to put all the class files under the bin directory lets you separate the source code directory tree from the binary class file directory tree.

The full command for compiling, e.g. the source code for org.addressbook.storage.Contact from the directory above src now becomes:

$ javac -cp src -d bin src/org/addressbook/storage/Contact.java

Note that the argument to javac is the relative path to the source code file (of course). But if the source code file imports some classes from a package located under the src directory structure, the compiler would not be able to resolve this without the classpath src. Giving the classpath src will let javac find all packages and classes referred to by the source code file given as argument.

Running files

Since all the class files should be created under the bin directory, we need to give java the class path bin in order to find the class files in packages.

If we, for instance want to run the SimpleMain class in the package org.addressbook.main from the directory above bin, we need to to this:

$ java -cp bin org.addressbook.main.SimpleMain

This allows us to run the main class from the directory above bin. Using classpath (the -cp flag) allows us to do all work from the directory containing both src and bin. There is therefore no need to ever leave the directory where you find both bin and src.

Running the test files

The test programs we have provide you with are using a mechanism called assertions. An assertions checks a condition and if the condition is not met (evaluated to false) the test should fail with an error message. But in order for Java to care about assertions, you need to provide the flag -ea (enable assertions). To run the test program for the Contact class, you should use this command line (note that running the test from the directory above bin requires both the classpath flag and the -ea flag!):

$ java -cp bin -ea org.addressbook.tests.TestContact 
=====Testing constructor=====
Testing new Contact("Name Nameson", "email@email.com", "123")
* Constructor test for contact: Name Nameson email@email.com 123 passed.
=====Testing constructor=====
Testing new Contact("Bob Bobson", "bob@email.com", "1234")
* Constructor test for contact: Bob Bobson bob@email.com 1234 passed.
=====Testing constructor=====
Testing new Contact("Charlie Ceeson", "charlie@email.com", "12345")
* Constructor test for contact: Charlie Ceeson charlie@email.com 12345 passed.
=====Testing constructor with null checks=====
* Constructor null tests passed.
=====Testing compareTo=====
* Test of compareTo() in Contact passed!
=====Testing equals=====
* equals() test for Contact passed.

Knowing how to get started on the assignment

Read the section above called Getting started. There you’ll find four main tasks, which should be completed in the same order as listed. The first task is to finsh the Contact class. The second task is to finish the SimpleAddressBook class. The third task is to finish (or optionally create) the SimpleApplication class. The fourth and last task is to write the SimpleMain class with the main method for the whole application.

Do the tasks in order, and use the test programs to verify that you have completed the tasks. Test programs are available for task 1 and task 2. In order to verify task 3 and four you need to finish both and run the SimpleMain program.

Tips and tricks

These commands lines are here if you want to automate your tests a bit. We assume that the menu (in your address book app) looks are numbered like below:

====Address book====

0 List
1 Add
2 quit
Pleas enter a number from the menu:

Since our program is interactive it expects input while it is executed (as opposed to given as arguments on the command line) we can communicate with your programs by preparing a user input and use "pipes". Let's say we want to list the contacts ("0" in the menu) and then exit ("2" in the menu) we would enter the following interactively: 1<Enter>2<Enter>. By pressing <Enter> we write a newline character so the input is really 0\n2\n. This is what we would like to send to the program interactively. Using pipes we can do this the following way:

$ printf "0\n2\n" | java -cp bin/ org.addressbook.main.SimpleMain

What what? Ok, let's do it in two steps. Let's skip the pipe and the java command and focus on the printf statement and see what happends if we execute that:

$ printf "0\n2\n"
0
2

The part after the pipe sign is obviously how we start the Address Book app. The pipe in between makes the output (like printf, System.out.println and echo) become input to the program. For a more deep explanation, check out our pages Bash Standard streams and Bash redirection.

Test if exit works

$ printf "2\n" | java -cp bin/ org.addressbook.main.SimpleMain

List all contacts

$ printf "0\n2\n" | java -cp bin/ org.addressbook.main.SimpleMain

Add a contact

If we would like to add a contact called Francesco with email francesco@emailicum.org and phone number 12354 we would interactively have typed:

1
Francesco
francesco@emailicum.org
12354
2

If we put this on one line and pipe it to our Address Book app we get the following:

$ printf "1\nFrancesco\nfrancesco@emailicum.org\n12354\n2\n" | java -cp bin/ org.addressbook.main.SimpleMain

Let's make sure it was added by listing the contacts and grep for the name:

$ printf "0\n2\n" | java -cp bin/ org.addressbook.main.SimpleMain | grep Francesco
Francesco francesco@emailicum.org 12354

If the adding above failed we would not have seen the line

Francesco francesco@emailicum.org 12354

Links

Where to go next

The next page explains the code given to you in the address book assignment: Java:Assignment_-_Address_book_-_About_the_code

« PreviousBook TOCNext »