getHobbies(Person person) throws ActivitiesServiceException;
+
+ /**
+ * Assign a hobby to a person.
+ *
+ * @param hobby The hobby to assign
+ * @param person The person to assign the hobby too.
+ * @throws ActivitiesServiceException if a service can not read or write the requested data
+ * or otherwise perform the requested operation.
+ */
+ public void addHobbyToPerson(Hobby hobby, Person person) throws ActivitiesServiceException;
+
+}
diff --git a/WK6/ORM_Example/src/main/java/com/origamisoftware/teach/advanced/service/ActivitiesServiceException.java b/WK6/ORM_Example/src/main/java/com/origamisoftware/teach/advanced/service/ActivitiesServiceException.java
new file mode 100644
index 0000000..216ec83
--- /dev/null
+++ b/WK6/ORM_Example/src/main/java/com/origamisoftware/teach/advanced/service/ActivitiesServiceException.java
@@ -0,0 +1,25 @@
+package com.origamisoftware.teach.advanced.service;
+
+/**
+ * Used to signal an issue with ActivitiesService
+ */
+public class ActivitiesServiceException extends Exception {
+
+ /**
+ * Constructs a new exception with the specified detail message and
+ * cause. Note that the detail message associated with
+ * {@code cause} is not automatically incorporated in
+ * this exception's detail message.
+ *
+ * @param message the detail message (which is saved for later retrieval
+ * by the {@link #getMessage()} method).
+ * @param cause the cause (which is saved for later retrieval by the
+ * {@link #getCause()} method). (A null value is
+ * permitted, and indicates that the cause is nonexistent or
+ * unknown.)
+ * @since 1.4
+ */
+ public ActivitiesServiceException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/WK6/ORM_Example/src/main/java/com/origamisoftware/teach/advanced/service/ActivitiesServiceFactory.java b/WK6/ORM_Example/src/main/java/com/origamisoftware/teach/advanced/service/ActivitiesServiceFactory.java
new file mode 100644
index 0000000..d9ac28e
--- /dev/null
+++ b/WK6/ORM_Example/src/main/java/com/origamisoftware/teach/advanced/service/ActivitiesServiceFactory.java
@@ -0,0 +1,21 @@
+package com.origamisoftware.teach.advanced.service;
+
+/**
+ * A factory that returns a ActivitiesService instance.
+ */
+public class ActivitiesServiceFactory {
+
+ /**
+ * Prevent instantiations
+ */
+ private ActivitiesServiceFactory() {}
+
+ /**
+ *
+ * @return get a StockService instance
+ */
+ public static ActivitiesService getInstance() {
+ return new DatabaseActivitiesService();
+ }
+
+}
diff --git a/WK6/ORM_Example/src/main/java/com/origamisoftware/teach/advanced/service/DatabaseActivitiesService.java b/WK6/ORM_Example/src/main/java/com/origamisoftware/teach/advanced/service/DatabaseActivitiesService.java
new file mode 100644
index 0000000..7ef016f
--- /dev/null
+++ b/WK6/ORM_Example/src/main/java/com/origamisoftware/teach/advanced/service/DatabaseActivitiesService.java
@@ -0,0 +1,152 @@
+package com.origamisoftware.teach.advanced.service;
+
+import com.origamisoftware.teach.advanced.model.Hobby;
+import com.origamisoftware.teach.advanced.model.Person;
+import com.origamisoftware.teach.advanced.model.PersonHobby;
+import com.origamisoftware.teach.advanced.util.DatabaseUtils;
+import org.hibernate.Criteria;
+import org.hibernate.HibernateException;
+import org.hibernate.Session;
+import org.hibernate.Transaction;
+import org.hibernate.criterion.Restrictions;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ *
+ */
+public class DatabaseActivitiesService implements ActivitiesService {
+
+
+
+
+
+ /**
+ * Get a list of all people
+ *
+ * @return a list of Person instances
+ */
+ @Override
+ @SuppressWarnings("unchecked")
+ public List getPerson() throws ActivitiesServiceException{
+ Session session = DatabaseUtils.getSessionFactory().openSession();
+ List returnValue = null;
+ Transaction transaction = null;
+ try {
+ transaction = session.beginTransaction();
+ Criteria criteria = session.createCriteria(Person.class);
+
+ /**
+ * NOTE criteria.list(); generates unchecked warning so SuppressWarnings
+ * is used - HOWEVER, this about the only @SuppressWarnings I think it is OK
+ * to suppress them - in almost all other cases they should be fixed not suppressed
+ */
+ returnValue = criteria.list();
+
+ } catch (HibernateException e) {
+ if (transaction != null && transaction.isActive()) {
+ transaction.rollback(); // close transaction
+ }
+ throw new ActivitiesServiceException("Could not get Person data. " + e.getMessage(), e);
+ } finally {
+ if (transaction != null && transaction.isActive()) {
+ transaction.commit();
+ }
+ }
+
+ return returnValue;
+
+ }
+
+ /**
+ * Add a new person or update an existing Person's data
+ *
+ * @param person a person object to either update or create
+ */
+ @Override
+ public void addOrUpdatePerson(Person person) {
+ Session session = DatabaseUtils.getSessionFactory().openSession();
+ Transaction transaction = null;
+ try {
+ transaction = session.beginTransaction();
+ session.saveOrUpdate(person);
+ transaction.commit();
+ } catch (HibernateException e) {
+ if (transaction != null && transaction.isActive()) {
+ transaction.rollback(); // close transaction
+ }
+ } finally {
+ if (transaction != null && transaction.isActive()) {
+ transaction.commit();
+ }
+ }
+ }
+
+ /**
+ * Get a list of all a person's hobbies.
+ *
+ * @param person the person
+ * @return a list of hobby instances
+ */
+ @Override
+ @SuppressWarnings("unchecked")
+ public List getHobbies(Person person) {
+ Session session = DatabaseUtils.getSessionFactory().openSession();
+ Transaction transaction = null;
+ List hobbies = new ArrayList<>();
+ try {
+ transaction = session.beginTransaction();
+ Criteria criteria = session.createCriteria(PersonHobby.class);
+ criteria.add(Restrictions.eq("person", person));
+ /**
+ * NOTE criteria.list(); generates unchecked warning so SuppressWarnings
+ * is used - HOWEVER, this about the only @SuppressWarnings I think it is OK
+ * to suppress them - in almost all other cases they should be fixed not suppressed
+ */
+ List list = criteria.list();
+ for (PersonHobby personHobby : list) {
+ hobbies.add(personHobby.getHobby());
+ }
+ transaction.commit();
+ } catch (HibernateException e) {
+ if (transaction != null && transaction.isActive()) {
+ transaction.rollback(); // close transaction
+ }
+ } finally {
+ if (transaction != null && transaction.isActive()) {
+ transaction.commit();
+ }
+ }
+ return hobbies;
+
+ }
+
+ /**
+ * Assign a hobby to a person.
+ *
+ * @param hobby The hobby to assign
+ * @param person The person to assign the hobby too.
+ */
+ @Override
+ public void addHobbyToPerson(Hobby hobby, Person person) {
+ Session session = DatabaseUtils.getSessionFactory().openSession();
+ Transaction transaction = null;
+ try {
+ transaction = session.beginTransaction();
+ PersonHobby personHobby = new PersonHobby();
+ personHobby.setHobby(hobby);
+ personHobby.setPerson(person);
+ session.saveOrUpdate(personHobby);
+ transaction.commit();
+ } catch (HibernateException e) {
+ if (transaction != null && transaction.isActive()) {
+ transaction.rollback(); // close transaction
+ }
+ } finally {
+ if (transaction != null && transaction.isActive()) {
+ transaction.commit();
+ }
+ }
+ }
+}
diff --git a/WK6/ORM_Example/src/main/java/com/origamisoftware/teach/advanced/util/DatabaseConnectionException.java b/WK6/ORM_Example/src/main/java/com/origamisoftware/teach/advanced/util/DatabaseConnectionException.java
new file mode 100644
index 0000000..ea8d91e
--- /dev/null
+++ b/WK6/ORM_Example/src/main/java/com/origamisoftware/teach/advanced/util/DatabaseConnectionException.java
@@ -0,0 +1,25 @@
+package com.origamisoftware.teach.advanced.util;
+
+/**
+ * This class is used to signal a problem connecting to a database.
+ */
+public class DatabaseConnectionException extends Exception {
+
+ /**
+ * Constructs a new exception with the specified detail message and
+ * cause. Note that the detail message associated with
+ * {@code cause} is not automatically incorporated in
+ * this exception's detail message.
+ *
+ * @param message the detail message (which is saved for later retrieval
+ * by the {@link #getMessage()} method).
+ * @param cause the cause (which is saved for later retrieval by the
+ * {@link #getCause()} method). (A null value is
+ * permitted, and indicates that the cause is nonexistent or
+ * unknown.)
+ * @since 1.4
+ */
+ public DatabaseConnectionException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/WK6/ORM_Example/src/main/java/com/origamisoftware/teach/advanced/util/DatabaseInitializationException.java b/WK6/ORM_Example/src/main/java/com/origamisoftware/teach/advanced/util/DatabaseInitializationException.java
new file mode 100644
index 0000000..bc09f7d
--- /dev/null
+++ b/WK6/ORM_Example/src/main/java/com/origamisoftware/teach/advanced/util/DatabaseInitializationException.java
@@ -0,0 +1,25 @@
+package com.origamisoftware.teach.advanced.util;
+
+/**
+ * This class is used to signal a problem initializing to a database.
+ */
+public class DatabaseInitializationException extends Exception {
+
+ /**
+ * Constructs a new exception with the specified detail message and
+ * cause.
Note that the detail message associated with
+ * {@code cause} is not automatically incorporated in
+ * this exception's detail message.
+ *
+ * @param message the detail message (which is saved for later retrieval
+ * by the {@link #getMessage()} method).
+ * @param cause the cause (which is saved for later retrieval by the
+ * {@link #getCause()} method). (A null value is
+ * permitted, and indicates that the cause is nonexistent or
+ * unknown.)
+ * @since 1.4
+ */
+ public DatabaseInitializationException(String message, Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/WK6/ORM_Example/src/main/java/com/origamisoftware/teach/advanced/util/DatabaseUtils.java b/WK6/ORM_Example/src/main/java/com/origamisoftware/teach/advanced/util/DatabaseUtils.java
new file mode 100644
index 0000000..03f34b9
--- /dev/null
+++ b/WK6/ORM_Example/src/main/java/com/origamisoftware/teach/advanced/util/DatabaseUtils.java
@@ -0,0 +1,112 @@
+package com.origamisoftware.teach.advanced.util;
+
+import com.ibatis.common.jdbc.ScriptRunner;
+import com.origamisoftware.teach.advanced.service.DatabaseActivitiesService;
+import org.hibernate.SessionFactory;
+import org.hibernate.cfg.Configuration;
+import org.hibernate.service.ServiceRegistry;
+import org.hibernate.service.ServiceRegistryBuilder;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+
+/**
+ * A class that contains database related utility methods.
+ */
+public class DatabaseUtils {
+
+ public static final String initializationFile = "./src/main/sql/db_initialization.sql";
+
+ private static SessionFactory sessionFactory;
+ private static Configuration configuration;
+
+ /*
+ * @return SessionFactory for use with database transactions
+ */
+ public static SessionFactory getSessionFactory() {
+
+ // singleton pattern
+ synchronized (DatabaseActivitiesService.class) {
+ if (sessionFactory == null) {
+
+ Configuration configuration = getConfiguration();
+
+ ServiceRegistry serviceRegistry = new ServiceRegistryBuilder()
+ .applySettings(configuration.getProperties())
+ .buildServiceRegistry();
+
+ sessionFactory = configuration.buildSessionFactory(serviceRegistry);
+
+ }
+ }
+ return sessionFactory;
+ }
+
+ /**
+ * Create a new or return an existing database configuration object.
+ *
+ * @return a Hibernate Configuration instance.
+ */
+ private static Configuration getConfiguration() {
+
+ synchronized (DatabaseUtils.class) {
+ if (configuration == null) {
+ configuration = new Configuration();
+ configuration.configure("hibernate.cfg.xml");
+ }
+ }
+ return configuration;
+ }
+
+ public static Connection getConnection() throws DatabaseConnectionException {
+ Connection connection = null;
+ Configuration configuration = getConfiguration();
+ try {
+
+ Class.forName("com.mysql.jdbc.Driver");
+ String databaseUrl = configuration.getProperty("connection.url");
+ String username = configuration.getProperty("hibernate.connection.username");
+ String password = configuration.getProperty("hibernate.connection.password");
+ connection = DriverManager.getConnection(databaseUrl, username, password);
+
+ // an example of throwing an exception appropriate to the abstraction.
+ } catch (ClassNotFoundException | SQLException e) {
+ throw new DatabaseConnectionException("Could not connect to the database." + e.getMessage(), e);
+ }
+ return connection;
+ }
+
+ /**
+ * A utility method that runs a db initialize script.
+ *
+ * @param initializationScript full path to the script to run to create the schema
+ * @throws DatabaseInitializationException
+ */
+ public static void initializeDatabase(String initializationScript) throws DatabaseInitializationException {
+
+ Connection connection = null;
+ try {
+ connection = getConnection();
+ connection.setAutoCommit(false);
+ ScriptRunner runner = new ScriptRunner(connection, false, false);
+ InputStream inputStream = new FileInputStream(initializationScript);
+
+ InputStreamReader reader = new InputStreamReader(inputStream);
+
+ runner.runScript(reader);
+ reader.close();
+ connection.commit();
+ connection.close();
+
+ } catch (DatabaseConnectionException | SQLException | IOException e) {
+ throw new DatabaseInitializationException("Could not initialize db because of:"
+ + e.getMessage(), e);
+ }
+
+ }
+}
diff --git a/WK6/ORM_Example/src/main/resources/hibernate.cfg.xml b/WK6/ORM_Example/src/main/resources/hibernate.cfg.xml
new file mode 100644
index 0000000..c327342
--- /dev/null
+++ b/WK6/ORM_Example/src/main/resources/hibernate.cfg.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+
+
+
+
+ jdbc:mysql://localhost:3306/activities
+ com.mysql.jdbc.Driver
+ org.hibernate.dialect.MySQLDialect
+
+ monty
+ some_pass
+
+
+
+
+
+
+
+
diff --git a/WK6/ORM_Example/src/main/sql/db_initialization.sql b/WK6/ORM_Example/src/main/sql/db_initialization.sql
new file mode 100644
index 0000000..80aac40
--- /dev/null
+++ b/WK6/ORM_Example/src/main/sql/db_initialization.sql
@@ -0,0 +1,59 @@
+
+/* delete tables if they exist already - ensuring a clean db*/
+DROP TABLE IF EXISTS activities.person_hobby CASCADE;
+DROP TABLE IF EXISTS activities.hobbies CASCADE;
+DROP TABLE IF EXISTS activities.person CASCADE;
+
+
+/* creates a table to store a list of hobbies and their recommended ages */
+CREATE TABLE activities.hobbies
+(
+ ID INT PRIMARY KEY NOT NULL AUTO_INCREMENT,
+ name VARCHAR(256) NOT NULL,
+ description VARCHAR(2056) NOT NULL,
+ minimum_age INT NOT NULL
+);
+
+/** creates a table to store a list of people */
+CREATE TABLE activities.person
+(
+ ID INT PRIMARY KEY NOT NULL AUTO_INCREMENT,
+ first_name VARCHAR(256) NOT NULL,
+ last_name VARCHAR(256) NOT NULL,
+ birth_date DATETIME NOT NULL
+);
+
+/** A list of people and their hobbies */
+CREATE TABLE activities.person_hobby
+(
+ ID INT PRIMARY KEY NOT NULL AUTO_INCREMENT,
+ person_id INT NOT NULL,
+ hobbie_id INT NOT NULL,
+ FOREIGN KEY (person_id) REFERENCES person (ID),
+ FOREIGN KEY (hobbie_id) REFERENCES hobbies (ID)
+);
+
+/** now add some sample data */
+
+INSERT INTO activities.hobbies (name,description,minimum_age) VALUES ('board games', 'assorted board games like monopoly', 8);
+INSERT INTO activities.hobbies (name,description,minimum_age) VALUES ('chess', 'ancient strategy game', 5);
+INSERT INTO activities.hobbies (name,description,minimum_age) VALUES ('go', 'ancient strategy game', 5);
+INSERT INTO activities.hobbies (name,description,minimum_age) VALUES ('archery', 'shot arrows with a bow', 12);
+INSERT INTO activities.hobbies (name,description,minimum_age) VALUES ('alpine skiing', 'recreation of sliding down snow-covered hills on skis with fixed-heel bindings', 2);
+INSERT INTO activities.hobbies (name,description,minimum_age) VALUES ('snow shoeing', 'traverse snow wearing large funny shoes', 6);
+INSERT INTO activities.hobbies (name,description,minimum_age) VALUES ('stamp collecting', 'collect rare and unusual postage stamps', 6);
+
+INSERT INTO activities.person (first_name,last_name,birth_date) VALUES ('Drew', 'Hope', '1999/10/10');
+INSERT INTO activities.person (first_name,last_name,birth_date) VALUES ('Lang', 'Heckman', '1959/11/11');
+INSERT INTO activities.person (first_name,last_name,birth_date) VALUES ('Lucy', 'Jones', '2010/1/1');
+INSERT INTO activities.person (first_name,last_name,birth_date) VALUES ('Stew', 'Hammer', '1990/3/28');
+INSERT INTO activities.person (first_name,last_name,birth_date) VALUES ('Dan', 'Lane', '1986/4/18');
+
+INSERT INTO activities.person_hobby (ID, person_id, hobbie_id) VALUES (1, 1, 2);
+INSERT INTO activities.person_hobby (ID, person_id, hobbie_id) VALUES (2, 1, 1);
+INSERT INTO activities.person_hobby (ID, person_id, hobbie_id) VALUES (3, 2, 1);
+INSERT INTO activities.person_hobby (ID, person_id, hobbie_id) VALUES (4, 3, 1);
+INSERT INTO activities.person_hobby (ID, person_id, hobbie_id) VALUES (5, 3, 3);
+INSERT INTO activities.person_hobby (ID, person_id, hobbie_id) VALUES (6, 3, 4);
+INSERT INTO activities.person_hobby (ID, person_id, hobbie_id) VALUES (7, 4, 7);
+
diff --git a/WK6/ORM_Example/src/test/java/com/origamisoftware/teach/advanced/model/HobbyTest.java b/WK6/ORM_Example/src/test/java/com/origamisoftware/teach/advanced/model/HobbyTest.java
new file mode 100644
index 0000000..0b6b406
--- /dev/null
+++ b/WK6/ORM_Example/src/test/java/com/origamisoftware/teach/advanced/model/HobbyTest.java
@@ -0,0 +1,41 @@
+package com.origamisoftware.teach.advanced.model;
+
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Unit test for Hobby class
+ */
+public class HobbyTest {
+
+ final static String description = "ride on a skateboard";
+ final static int minimumAge = 10;
+ final static String hobbyName = "SkateBoarding";
+
+ /**
+ * Testing helper method for generating Hobby test data
+ *
+ * @return a Hobby object that uses static constants for data.
+ */
+ public static Hobby createHobby() {
+ Hobby hobby = new Hobby();
+ hobby.setDescription(description);
+ hobby.setMinimumAge(minimumAge);
+ hobby.setName(hobbyName);
+ return hobby;
+ }
+
+ @Test
+ public void testHobbySettersAndGetters() {
+ Hobby hobby = createHobby();
+ int id = 10;
+ hobby.setId(id);
+ assertEquals("Minimum age", minimumAge, hobby.getMinimumAge());
+ assertEquals("Description", description, hobby.getDescription());
+ assertEquals("Name", hobbyName, hobby.getName());
+ assertEquals("id", id, hobby.getId());
+
+ }
+
+}
diff --git a/WK6/ORM_Example/src/test/java/com/origamisoftware/teach/advanced/model/PersonHobbyTest.java b/WK6/ORM_Example/src/test/java/com/origamisoftware/teach/advanced/model/PersonHobbyTest.java
new file mode 100644
index 0000000..b8e7223
--- /dev/null
+++ b/WK6/ORM_Example/src/test/java/com/origamisoftware/teach/advanced/model/PersonHobbyTest.java
@@ -0,0 +1,72 @@
+package com.origamisoftware.teach.advanced.model;
+
+import org.junit.Test;
+
+import java.sql.Timestamp;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Unit test for PersonHobby class
+ */
+public class PersonHobbyTest {
+
+ /**
+ * Testing helper method for generating PersonHobby test data
+ *
+ * @return a PersonHobby object that uses Person and Hobby
+ * return from their respective create method.
+ */
+ public static PersonHobby createPersonHobby() {
+ Person person = PersonTest.createPerson();
+ Hobby hobby = HobbyTest.createHobby();
+ return new PersonHobby(person, hobby);
+ }
+
+ @Test
+ public void testPersonHobbiesGetterAndSetters() {
+ Hobby hobby = HobbyTest.createHobby();
+ Person person = PersonTest.createPerson();
+ PersonHobby personHobby = new PersonHobby();
+ int id = 10;
+ personHobby.setId(id);
+ personHobby.setPerson(person);
+ personHobby.setHobby(hobby);
+ assertEquals("person matches", person, personHobby.getPerson());
+ assertEquals("hobby matches", hobby, personHobby.getHobby());
+ assertEquals("id matches", id, personHobby.getId());
+ }
+
+ @Test
+ public void testEqualsNegativeDifferentPerson() {
+ PersonHobby personHobby = createPersonHobby();
+ personHobby.setId(10);
+ Hobby hobby = HobbyTest.createHobby();
+ Person person = new Person();
+ Timestamp birthDate = new Timestamp(PersonTest.birthDayCalendar.getTimeInMillis() + 10000);
+ person.setBirthDate(birthDate);
+ person.setFirstName(PersonTest.firstName);
+ person.setLastName(PersonTest.lastName);
+ PersonHobby personHobby2 = new PersonHobby(person, hobby);
+ assertFalse("Different person", personHobby.equals(personHobby2));
+ }
+
+ @Test
+ public void testEquals() {
+ PersonHobby personHobby = createPersonHobby();
+ assertTrue("Same objects are equal", personHobby.equals(createPersonHobby()));
+ }
+
+ @Test
+ public void testToString() {
+ PersonHobby personHobby = createPersonHobby();
+ assertTrue("toString has lastName", personHobby.toString().contains(PersonTest.lastName));
+ assertTrue("toString has person", personHobby.toString().contains(PersonTest.firstName));
+ assertTrue("toString has hobby description", personHobby.toString().contains(HobbyTest.description));
+ assertTrue("toString has hobby name", personHobby.toString().contains(HobbyTest.hobbyName));
+ assertTrue("toString has hobby min age", personHobby.toString().contains(Integer.toString(HobbyTest.minimumAge)));
+ }
+
+}
diff --git a/WK6/ORM_Example/src/test/java/com/origamisoftware/teach/advanced/model/PersonTest.java b/WK6/ORM_Example/src/test/java/com/origamisoftware/teach/advanced/model/PersonTest.java
new file mode 100644
index 0000000..6ec0aaa
--- /dev/null
+++ b/WK6/ORM_Example/src/test/java/com/origamisoftware/teach/advanced/model/PersonTest.java
@@ -0,0 +1,50 @@
+package com.origamisoftware.teach.advanced.model;
+
+import org.junit.Test;
+
+import java.sql.Timestamp;
+import java.util.Calendar;
+
+import static org.junit.Assert.assertEquals;
+
+/**
+ * Unit test for the Person class
+ */
+public class PersonTest {
+
+ public static final Calendar birthDayCalendar = Calendar.getInstance();
+
+ static {
+ birthDayCalendar.set(1990, Calendar.JANUARY, 12);
+ }
+
+ public static final String firstName = "Spencer";
+ public static final String lastName = "Marks";
+ public static final Timestamp birthDate = new Timestamp(birthDayCalendar.getTimeInMillis());
+
+ /**
+ * Testing helper method for generating Person test data
+ *
+ * @return a Person object that uses static constants for data.
+ */
+ public static Person createPerson() {
+ Person person = new Person();
+ person.setBirthDate(birthDate);
+ person.setFirstName(firstName);
+ person.setLastName(lastName);
+ return person;
+ }
+
+ @Test
+ public void testPersonGettersAndSetters() {
+ Person person = createPerson();
+ int id = 10;
+ person.setId(id);
+ assertEquals("first name matches", firstName, person.getFirstName());
+ assertEquals("last name matches", lastName, person.getLastName());
+ assertEquals("birthday matches", birthDate, person.getBirthDate());
+ assertEquals("id matches", id, person.getId());
+
+ }
+
+}
diff --git a/WK6/ORM_Example/src/test/java/com/origamisoftware/teach/advanced/services/ActivitiesServiceFactoryTest.java b/WK6/ORM_Example/src/test/java/com/origamisoftware/teach/advanced/services/ActivitiesServiceFactoryTest.java
new file mode 100644
index 0000000..5807920
--- /dev/null
+++ b/WK6/ORM_Example/src/test/java/com/origamisoftware/teach/advanced/services/ActivitiesServiceFactoryTest.java
@@ -0,0 +1,19 @@
+package com.origamisoftware.teach.advanced.services;
+
+import com.origamisoftware.teach.advanced.service.ActivitiesService;
+import com.origamisoftware.teach.advanced.service.ActivitiesServiceFactory;
+import org.junit.Test;
+
+import static org.junit.Assert.assertNotNull;
+
+/**
+ * JUnit test for activitiesService
+ */
+public class ActivitiesServiceFactoryTest {
+
+ @Test
+ public void testFactory() {
+ ActivitiesService instance = ActivitiesServiceFactory.getInstance();
+ assertNotNull("Make sure factory works", instance);
+ }
+}
diff --git a/WK6/ORM_Example/src/test/java/com/origamisoftware/teach/advanced/services/DatabaseActivitiesServiceTest.java b/WK6/ORM_Example/src/test/java/com/origamisoftware/teach/advanced/services/DatabaseActivitiesServiceTest.java
new file mode 100644
index 0000000..1e50efb
--- /dev/null
+++ b/WK6/ORM_Example/src/test/java/com/origamisoftware/teach/advanced/services/DatabaseActivitiesServiceTest.java
@@ -0,0 +1,103 @@
+package com.origamisoftware.teach.advanced.services;
+
+import com.origamisoftware.teach.advanced.model.Hobby;
+import com.origamisoftware.teach.advanced.model.Person;
+import com.origamisoftware.teach.advanced.model.PersonTest;
+import com.origamisoftware.teach.advanced.service.ActivitiesService;
+import com.origamisoftware.teach.advanced.service.ActivitiesServiceException;
+import com.origamisoftware.teach.advanced.service.ActivitiesServiceFactory;
+import com.origamisoftware.teach.advanced.util.DatabaseUtils;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.sql.Timestamp;
+import java.util.Calendar;
+import java.util.List;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Unit tests for the DatabaseActivitiesService
+ */
+public class DatabaseActivitiesServiceTest {
+
+ private ActivitiesService activitiesService;
+
+ private void initDb() throws Exception {
+ DatabaseUtils.initializeDatabase(DatabaseUtils.initializationFile);
+ }
+
+ // do not assume db is correct
+ @Before
+ public void setUp() throws Exception {
+ // we could also copy db state here for later restore before initializing
+ initDb();
+ activitiesService = ActivitiesServiceFactory.getInstance();
+ }
+
+ // clean up after ourselves. (this could also restore db from initial state
+ @After
+ public void tearDown() throws Exception {
+ initDb();
+ }
+
+ @Test
+ public void testGetInstance() {
+ assertNotNull("Make sure activitiesService is available", activitiesService);
+ }
+
+ @Test
+ public void testGetPerson() throws ActivitiesServiceException {
+ List personList = activitiesService.getPerson();
+ assertFalse("Make sure we get some Person objects from service", personList.isEmpty());
+ }
+
+ @Test
+ public void testAddOrUpdatePerson()throws ActivitiesServiceException {
+ Person newPerson = PersonTest.createPerson();
+ activitiesService.addOrUpdatePerson(newPerson);
+ List personList = activitiesService.getPerson();
+ boolean found = false;
+ for (Person person : personList) {
+ Timestamp returnedBirthDate = person.getBirthDate();
+ Calendar returnCalendar = Calendar.getInstance();
+ returnCalendar.setTimeInMillis(returnedBirthDate.getTime());
+ if (returnCalendar.get(Calendar.MONTH) == PersonTest.birthDayCalendar.get(Calendar.MONTH)
+ &&
+ returnCalendar.get(Calendar.YEAR) == PersonTest.birthDayCalendar.get(Calendar.YEAR)
+ &&
+ returnCalendar.get(Calendar.DAY_OF_MONTH) == PersonTest.birthDayCalendar.get(Calendar.DAY_OF_MONTH)
+ &&
+ person.getLastName().equals(PersonTest.lastName)
+ &&
+ person.getFirstName().equals(PersonTest.firstName)) {
+ found = true;
+ break;
+ }
+ }
+ assertTrue("Found the person we added", found);
+ }
+
+ @Test
+ public void testGetHobbiesByPerson() throws ActivitiesServiceException {
+ Person person = PersonTest.createPerson();
+ List hobbies = activitiesService.getHobbies(person);
+ // make the person have all the hobbies
+ for (Hobby hobby : hobbies) {
+ activitiesService.addHobbyToPerson(hobby, person);
+ }
+ List hobbyList = activitiesService.getHobbies(person);
+ for (Hobby hobby : hobbies) {
+ boolean removed = hobbyList.remove(hobby);
+ assertTrue("Verify that the hobby was found on the list", removed);
+ }
+ // if hobbyList is empty then we know the lists matched.
+ assertTrue("Verify the list of returned hobbies match what was expected ", hobbyList.isEmpty());
+
+ }
+
+
+}
diff --git a/WK6/ORM_Example/src/test/java/com/origamisoftware/teach/advanced/util/DatabaseUtilsTest.java b/WK6/ORM_Example/src/test/java/com/origamisoftware/teach/advanced/util/DatabaseUtilsTest.java
new file mode 100644
index 0000000..06e08d2
--- /dev/null
+++ b/WK6/ORM_Example/src/test/java/com/origamisoftware/teach/advanced/util/DatabaseUtilsTest.java
@@ -0,0 +1,39 @@
+package com.origamisoftware.teach.advanced.util;
+
+import org.junit.Test;
+
+import java.sql.Connection;
+import java.sql.Statement;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Tests for the DatabaseUtils class
+ */
+public class DatabaseUtilsTest {
+
+ @Test
+ public void testGoodInitFile() throws Exception {
+ DatabaseUtils.initializeDatabase(DatabaseUtils.initializationFile);
+ }
+
+ @Test(expected = DatabaseInitializationException.class)
+ public void testBadInitFile() throws Exception {
+ DatabaseUtils.initializeDatabase("bogus");
+ }
+
+ @Test
+ public void testGetConnection() throws Exception{
+ Connection connection = DatabaseUtils.getConnection();
+ assertNotNull("verify that we can get a connection ok",connection);
+ }
+
+ @Test
+ public void testGetConnectionWorks() throws Exception{
+ Connection connection = DatabaseUtils.getConnection();
+ Statement statement = connection.createStatement();
+ boolean execute = statement.execute("select * from person");
+ assertTrue("verify that we can execute a statement",execute);
+ }
+}
diff --git a/WK6/stockquote-week5-solved/lib/antlr-2.7.7.jar b/WK6/stockquote-week5-solved/lib/antlr-2.7.7.jar
new file mode 100644
index 0000000000000000000000000000000000000000..5e5f14b35584eac2a9f0f888769f0ab93ca6d849
GIT binary patch
literal 445288
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