diff --git a/.classpath b/.classpath index 3300db2..42620d7 100644 --- a/.classpath +++ b/.classpath @@ -1,9 +1,10 @@ - - - - - - - - - + + + + + + + + + + diff --git a/lib/commons-dbutils-1.4.jar b/lib/commons-dbutils-1.4.jar new file mode 100644 index 0000000..7b846ea Binary files /dev/null and b/lib/commons-dbutils-1.4.jar differ diff --git a/src/com/proquest/interview/phonebook/Person.java b/src/com/proquest/interview/phonebook/Person.java index 96ccaa5..610fc30 100644 --- a/src/com/proquest/interview/phonebook/Person.java +++ b/src/com/proquest/interview/phonebook/Person.java @@ -1,7 +1,87 @@ package com.proquest.interview.phonebook; +/** + * Person represents a person with a name, address, and phone number. + * Instances of this class are immutable. + * + */ public class Person { - public String name; - public String phoneNumber; - public String address; + private final String name; + private final String phoneNumber; + private final String address; + + /** + * Creates a person. The name, address, and phone number may not be null. + * + * @param name the full name of the person + * @param phoneNumber the person's phone number + * @param address the person's address + * @throws IllegalArgumentException if any of the parameters are null + */ + public Person(String name, String phoneNumber, String address) { + if (name == null || phoneNumber == null || address == null) { + throw new IllegalArgumentException("null"); + } + this.name = name; + this.phoneNumber = phoneNumber; + this.address = address; + } + + /** Returns the person's name. */ + public String getName() { + return name; + } + + /** Returns the person's phone number. */ + public String getPhoneNumber() { + return phoneNumber; + } + + /** Returns the person's address. */ + public String getAddress() { + return address; + } + + /** Returns a string representation of the person. */ + @Override public String toString() { + return name + ", " + phoneNumber + ", " + address; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + ((address == null) ? 0 : address.hashCode()); + result = prime * result + ((name == null) ? 0 : name.hashCode()); + result = prime * result + + ((phoneNumber == null) ? 0 : phoneNumber.hashCode()); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (!(obj instanceof Person)) + return false; + Person other = (Person) obj; + if (address == null) { + if (other.address != null) + return false; + } else if (!address.equals(other.address)) + return false; + if (name == null) { + if (other.name != null) + return false; + } else if (!name.equals(other.name)) + return false; + if (phoneNumber == null) { + if (other.phoneNumber != null) + return false; + } else if (!phoneNumber.equals(other.phoneNumber)) + return false; + return true; + } } diff --git a/src/com/proquest/interview/phonebook/PhoneBook.java b/src/com/proquest/interview/phonebook/PhoneBook.java index 47627fd..d90c12c 100644 --- a/src/com/proquest/interview/phonebook/PhoneBook.java +++ b/src/com/proquest/interview/phonebook/PhoneBook.java @@ -1,6 +1,9 @@ package com.proquest.interview.phonebook; +import java.util.Collection; + public interface PhoneBook { - public Person findPerson(String firstName, String lastName); - public void addPerson(Person newPerson); + Person findPerson(String firstName, String lastName); + void addPerson(Person newPerson); + Collection allPeople(); } diff --git a/src/com/proquest/interview/phonebook/PhoneBookImpl.java b/src/com/proquest/interview/phonebook/PhoneBookImpl.java index d7eb6fe..d2b0797 100644 --- a/src/com/proquest/interview/phonebook/PhoneBookImpl.java +++ b/src/com/proquest/interview/phonebook/PhoneBookImpl.java @@ -1,31 +1,162 @@ package com.proquest.interview.phonebook; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; import java.util.List; +import org.apache.commons.dbutils.DbUtils; +import org.apache.commons.dbutils.QueryRunner; +import org.apache.commons.dbutils.ResultSetHandler; + import com.proquest.interview.util.DatabaseUtil; public class PhoneBookImpl implements PhoneBook { - public List people; - + public List people = new ArrayList(); + @Override public void addPerson(Person newPerson) { - //TODO: write this method + if (newPerson == null) throw new IllegalArgumentException("null"); + people.add(newPerson); } - + @Override - public Person findPerson() { - //TODO: write this method + public Person findPerson(String firstName, String lastName) { + if (firstName == null || lastName == null) { + throw new IllegalArgumentException("null"); + // the other option here is to return null, indicating not found + } + final String nameSought = firstName + " " + lastName; + for (Person person : people) { + if (nameSought.equals(person.getName())) return person; + } + return null; + } + + public Collection allPeople() { + return Collections.unmodifiableList(people); } + @Override public String toString() { + return people.toString(); + } + public static void main(String[] args) { - DatabaseUtil.initDB(); //You should not remove this line, it creates the in-memory database - - /* TODO: create person objects and put them in the PhoneBook and database - * John Smith, (248) 123-4567, 1234 Sand Hill Dr, Royal Oak, MI - * Cynthia Smith, (824) 128-8758, 875 Main St, Ann Arbor, MI - */ - // TODO: print the phone book out to System.out - // TODO: find Cynthia Smith and print out just her entry - // TODO: insert the new person objects into the database + DatabaseUtil.initDB(); // You should not remove this line, it creates the in-memory database + + PhoneBook phoneBook = new PhoneBookImpl(); + + // create person objects and put them in the PhoneBook and database + + phoneBook.addPerson(new Person("John Smith", "(248) 123-4567", + "1234 Sand Hill Dr, Royal Oak, MI")); + phoneBook.addPerson(new Person("Cynthia Smith", "(824) 128-8758", + "875 Main St, Ann Arbor, MI")); + + // print the phone book out to System.out + + // It isn't clear to me which of these you want: + + System.out.println(phoneBook); + + for (Person person : phoneBook.allPeople()) { + System.out.println(person); + } + + // find Cynthia Smith and print out just her entry + + System.out.println("Cynthia:"); + Person cynthiaSmith = phoneBook.findPerson("Cynthia", "Smith"); + System.out.println(cynthiaSmith); + + // It was a little unclear when you wanted me to add the objects + // to the database. At the top, you said to add people to the + // phone book and the database, but at the end, you said to add + // the new people to the database. + + // insert the new person objects into the database + + insertPeople(phoneBook.allPeople()); + } + + public static ResultSetHandler> rowsToPeople() { + return new ResultSetHandler>() { + public List handle(ResultSet rs) throws SQLException { + List people = new ArrayList(); + while (rs.next()) { + people.add(new Person(rs.getString(1), rs.getString(2), rs.getString(3))); + } + return people; + } + }; + } + + public static List byCriteria(String sql, Object... criteria) { + Connection con = null; + try { + con = getConnection(); + return new QueryRunner().query(con, sql, rowsToPeople(), criteria); + } catch (SQLException e) { + e.printStackTrace(); + // questionable; maybe we should throw some application-specific exception to indicate failure + return new ArrayList(); + } finally { + DbUtils.closeQuietly(con); + } + } + + public static List everyone() { + return byCriteria("SELECT * FROM PHONEBOOK", new Object[] {}); + } + + public static List byName(String name) { + return byCriteria("SELECT * FROM PHONEBOOK WHERE NAME = ?", name); + } + + public static List byPhoneNumber(String phoneNumber) { + return byCriteria("SELECT * FROM PHONEBOOK WHERE PHONENUMBER = ?", phoneNumber); + } + + public static List byAddress(String address) { + return byCriteria("SELECT * FROM PHONEBOOK WHERE ADDRESS = ?", address); + } + + public static void insertPeople(Collection people) { + final String sql = + "INSERT INTO PHONEBOOK (NAME, PHONENUMBER, ADDRESS) VALUES(?, ?, ?)"; + + Connection con = null; + PreparedStatement ps = null; + + try { + con = getConnection(); + con.setAutoCommit(false); + ps = con.prepareStatement(sql); + QueryRunner q = new QueryRunner(); + for (Person person : people) { + q.fillStatementWithBean(ps, person, "name", "phoneNumber", "address"); + ps.addBatch(); + } + ps.executeBatch(); + con.commit(); + } catch (SQLException e) { + e.printStackTrace(); + } finally { + DbUtils.closeQuietly(ps); + DbUtils.closeQuietly(con); + } + } + + public static Connection getConnection() throws SQLException { + try { + return DatabaseUtil.getConnection(); + } catch (ClassNotFoundException e) { + // avoid dealing with CNFE; we aren't going to do anything different in that case anyway + throw new SQLException(e); + } } } diff --git a/src/com/proquest/interview/util/DatabaseUtil.java b/src/com/proquest/interview/util/DatabaseUtil.java index a23342d..8e690de 100644 --- a/src/com/proquest/interview/util/DatabaseUtil.java +++ b/src/com/proquest/interview/util/DatabaseUtil.java @@ -5,25 +5,30 @@ import java.sql.SQLException; import java.sql.Statement; +import org.apache.commons.dbutils.DbUtils; + /** * This class is just a utility class, you should not have to change anything here * @author rconklin */ public class DatabaseUtil { public static void initDB() { + Connection cn = null; try { - Connection cn = getConnection(); + cn = getConnection(); + cn.setAutoCommit(false); Statement stmt = cn.createStatement(); stmt.execute("CREATE TABLE PHONEBOOK (NAME varchar(255), PHONENUMBER varchar(255), ADDRESS varchar(255))"); stmt.execute("INSERT INTO PHONEBOOK (NAME, PHONENUMBER, ADDRESS) VALUES('Chris Johnson','(321) 231-7876', '452 Freeman Drive, Algonac, MI')"); stmt.execute("INSERT INTO PHONEBOOK (NAME, PHONENUMBER, ADDRESS) VALUES('Dave Williams','(231) 502-1236', '285 Huron St, Port Austin, MI')"); cn.commit(); - cn.close(); } catch (Exception ex) { ex.printStackTrace(); + } finally { + DbUtils.closeQuietly(cn); } - } + public static Connection getConnection() throws SQLException, ClassNotFoundException { Class.forName("org.hsqldb.jdbcDriver"); return DriverManager.getConnection("jdbc:hsqldb:mem", "sa", ""); diff --git a/test/com/proquest/interview/phonebook/PhoneBookImplTest.java b/test/com/proquest/interview/phonebook/PhoneBookImplTest.java index 33c7c14..e39e1de 100644 --- a/test/com/proquest/interview/phonebook/PhoneBookImplTest.java +++ b/test/com/proquest/interview/phonebook/PhoneBookImplTest.java @@ -1,10 +1,62 @@ package com.proquest.interview.phonebook; +import org.junit.Before; import org.junit.Test; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; public class PhoneBookImplTest { + private PhoneBook phoneBook; + + @Before + public void setUp() { + phoneBook = new PhoneBookImpl(); + phoneBook.addPerson(new Person("David Conrad", "(313) 437-3173", + "17540 Mack Ave #4, Grosse Pointe, MI")); + } + + @Test + public void emptyPhoneBookTest() { + phoneBook = new PhoneBookImpl(); + assertEquals(phoneBook.allPeople().size(), 0); + } + + @Test + public void addPersonTest() { + int formerSize = phoneBook.allPeople().size(); + phoneBook.addPerson(new Person("Jane Doe", "(313) 555-1212", + "123 Elm Ct, Anytown, MI")); + assertEquals(phoneBook.allPeople().size(), formerSize + 1); + } + + @Test(expected=IllegalArgumentException.class) + public void addNullPersonTest() { + phoneBook.addPerson(null); + } + @Test - public void shouldAddFindPerson() { - + public void findPersonTest() { + assertNotNull(phoneBook.findPerson("David", "Conrad")); + } + + @Test + public void noSuchPersonTest() { + assertNull(phoneBook.findPerson("Joe", "Schmoe")); + } + + @Test(expected=IllegalArgumentException.class) + public void findNullPersonTest() { + phoneBook.findPerson(null, null); + } + + @Test(expected=IllegalArgumentException.class) + public void findNullFirstNameTest() { + phoneBook.findPerson(null, "Jones"); + } + + @Test(expected=IllegalArgumentException.class) + public void findNullLastNameTest() { + phoneBook.findPerson("Dev", null); } }