diff --git a/tdt4140-gr1800/app.core/pom.xml b/tdt4140-gr1800/app.core/pom.xml index dba0131a6c8e5266fc30c198a251e94d1f823e13..2cf80a0a5c51a17cae683694c8afe1ea722d4f00 100644 --- a/tdt4140-gr1800/app.core/pom.xml +++ b/tdt4140-gr1800/app.core/pom.xml @@ -9,33 +9,49 @@ <version>0.0.1-SNAPSHOT</version> </parent> + <properties> + <jackson-version>2.9.3</jackson-version> + </properties> + <dependencies> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> - <version>2.9.3</version> + <version>${jackson-version}</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> - <version>2.9.3</version> + <version>${jackson-version}</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-annotations</artifactId> - <version>2.9.3</version> + <version>${jackson-version}</version> </dependency> <dependency> - <groupId>com.fasterxml.jackson.dataformat</groupId> - <artifactId>jackson-dataformat-xml</artifactId> - <version>2.9.3</version> + <groupId>com.fasterxml.jackson.dataformat</groupId> + <artifactId>jackson-dataformat-xml</artifactId> + <version>${jackson-version}</version> </dependency> - + <!-- https://mvnrepository.com/artifact/io.jenetics/jpx --> <dependency> - <groupId>io.jenetics</groupId> - <artifactId>jpx</artifactId> - <version>1.2.3</version> + <groupId>io.jenetics</groupId> + <artifactId>jpx</artifactId> + <version>1.2.3</version> + </dependency> + + <dependency> + <groupId>de.grundid.opendatalab</groupId> + <artifactId>geojson-jackson</artifactId> + <version>1.8</version> + </dependency> + + <dependency> + <groupId>org.hsqldb</groupId> + <artifactId>hsqldb</artifactId> + <version>2.4.0</version> </dependency> <dependency> diff --git a/tdt4140-gr1800/app.core/src/main/java/tdt4140/gr1800/app/core/Person.java b/tdt4140-gr1800/app.core/src/main/java/tdt4140/gr1800/app/core/Person.java new file mode 100644 index 0000000000000000000000000000000000000000..2499a3849839beb453f0c8fd0acac5001954f707 --- /dev/null +++ b/tdt4140-gr1800/app.core/src/main/java/tdt4140/gr1800/app/core/Person.java @@ -0,0 +1,23 @@ +package tdt4140.gr1800.app.core; + +public class Person extends GeoLocationsOwner { + + private String name; + private String email; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getEmail() { + return email; + } + + public void setEmail(String email) { + this.email = email; + } +} diff --git a/tdt4140-gr1800/app.core/src/main/java/tdt4140/gr1800/app/db/AbstractDbAccessImpl.java b/tdt4140-gr1800/app.core/src/main/java/tdt4140/gr1800/app/db/AbstractDbAccessImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..c4e335f698d4a694cf82976e313f4aec6dfaeda9 --- /dev/null +++ b/tdt4140-gr1800/app.core/src/main/java/tdt4140/gr1800/app/db/AbstractDbAccessImpl.java @@ -0,0 +1,120 @@ +package tdt4140.gr1800.app.db; + +import java.time.LocalTime; +import java.util.ArrayList; +import java.util.Collection; + +import tdt4140.gr1800.app.core.GeoLocated; +import tdt4140.gr1800.app.core.GeoLocation; +import tdt4140.gr1800.app.core.GeoLocations; +import tdt4140.gr1800.app.core.Person; + +public abstract class AbstractDbAccessImpl implements IDbAccess { + + protected IdMap<Person> personIds = new IdMap<Person>(); + protected IdMap<GeoLocations> geoLocationsIds = new IdMap<GeoLocations>(); + protected IdMap<GeoLocation> geoLocationIds = new IdMap<GeoLocation>(); + + public int getId(Person person) { + return personIds.getId(person); + } + + public int getId(GeoLocations geoLocations) { + return geoLocationsIds.getId(geoLocations); + } + + public int getId(GeoLocation geoLocation) { + return geoLocationIds.getId(geoLocation); + } + + @Override + public Person createPerson(String name, String email) { + Person person = new Person(); + person.setName(name); + person.setEmail(email); + return person; + } + + @Override + public GeoLocations createGeoLocations(Person owner) { + GeoLocations geoLocations = new GeoLocations(owner); + owner.addGeolocations(geoLocations); + return geoLocations; + } + + @Override + public GeoLocation addGeoLocation(GeoLocations geoLocations, GeoLocated geoLoc, int elevation, LocalTime time) { + // TODO Auto-generated method stub + return null; + } + + @Override + public Collection<Person> getAllPersons(boolean refresh) { + return new ArrayList<Person>(personIds.get()); + } + + @Override + public Person getPerson(int id, boolean refresh) { + Person person = personIds.get(id); + return person; + } + + @Override + public Person getPersonByName(String name, boolean refresh) { + for (Person person : personIds.get()) { + if (name == person.getName() || (name != null && name.equals(person.getName()))) { + return person; + } + } + return null; + } + + @Override + public Person getPersonByEmail(String email, boolean refresh) { + for (Person person : personIds.get()) { + if (email == person.getEmail() || (email != null && email.equals(person.getEmail()))) { + return person; + } + } + return null; + } + + @Override + public Collection<GeoLocations> getGeoLocations(Person owner, boolean refresh) { + Collection<GeoLocations> result = new ArrayList<>(); + for (GeoLocations geoLocations : geoLocationsIds.get()) { + if (geoLocations.getOwner() == owner) { + result.add(geoLocations); + } + } + return result; + } + + @Override + public void updateGeoLocationsData(GeoLocations geoLocations) { + // TODO Auto-generated method stub + + } + + @Override + public void updateGeoLocationData(GeoLocations geoLocations, GeoLocations geoLocation) { + // TODO Auto-generated method stub + + } + + @Override + public void deletePerson(Person person) { + personIds.remove(person); + } + + @Override + public void deleteGeoLocations(GeoLocations geoLocations) { + geoLocations.getOwner().removeGeolocations(geoLocations); + geoLocationsIds.remove(geoLocations); + } + + @Override + public void deleteGeoLocation(GeoLocations geoLocations, GeoLocation geoLocation) { + geoLocationIds.remove(geoLocation); + } +} diff --git a/tdt4140-gr1800/app.core/src/main/java/tdt4140/gr1800/app/db/DbAccessHelper.java b/tdt4140-gr1800/app.core/src/main/java/tdt4140/gr1800/app/db/DbAccessHelper.java new file mode 100644 index 0000000000000000000000000000000000000000..0b6c0542d2852815d7b188651673646c2a2fac60 --- /dev/null +++ b/tdt4140-gr1800/app.core/src/main/java/tdt4140/gr1800/app/db/DbAccessHelper.java @@ -0,0 +1,131 @@ +package tdt4140.gr1800.app.db; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.SQLType; +import java.sql.Statement; +import java.sql.Types; + +public class DbAccessHelper { + + private Connection dbConnection; + private Statement dbStatement; + + public DbAccessHelper(Connection dbConnection) { + this.dbConnection = dbConnection; + } + + public DbAccessHelper(String connectionUri, String user, String pass) throws SQLException { + this(DriverManager.getConnection(connectionUri, user, pass)); + } + + public DbAccessHelper(String connectionUri) throws SQLException { + this(connectionUri, "SA", ""); + } + + public Connection getDbConnection() { + return dbConnection; + } + + private Statement getDbStatement() throws SQLException { + if (dbStatement == null) { + dbStatement = getDbConnection().createStatement(); + } + return dbStatement; + } + + protected void throwException(SQLException e) throws RuntimeException { + throw new RuntimeException(e); + } + + protected void executeStatement(String statement) { + try { + getDbStatement().execute(statement); + } catch (SQLException e) { + throwException(e); + } + } + + protected ResultSet executeQuery(String statement) { + ResultSet result = null; + try { + result = getDbStatement().executeQuery(statement); + } catch (SQLException e) { + throwException(e); + } + return result; + } + + protected PreparedStatement prepareStatement(String statement, Object... args) { + PreparedStatement preparedStatement = null; + try { + preparedStatement = dbConnection.prepareStatement(statement); + for (int argNum = 1; argNum <= args.length; argNum++) { + Object arg = args[argNum - 1]; + if (arg == null) { + preparedStatement.setNull(argNum, Types.VARCHAR); + } else if (arg instanceof String) { + preparedStatement.setString(argNum, (String) arg); + } else if (arg instanceof Double) { + preparedStatement.setDouble(argNum, (Double) arg); + } else if (arg instanceof Integer) { + preparedStatement.setInt(argNum, (Integer) arg); + } else if (arg instanceof Boolean) { + preparedStatement.setBoolean(argNum, (Boolean) arg); + } + } + } catch (SQLException e) { + throwException(e); + } + return preparedStatement; + } + + protected void executeDbStatement(String statement, Object... args) { + PreparedStatement preparedStatement = prepareStatement(statement, args); + executeStatement(preparedStatement); + } + + protected int executeDbInsertGettingIdentity(String statement, Object... args) { + executeDbStatement(statement, args); + // TODO + // https://stackoverflow.com/questions/1915166/how-to-get-the-insert-id-in-jdbc/1915197#1915197 + ResultSet result = executeQuery(String.format("CALL IDENTITY()")); + try { + if (result.next()) { + int id = result.getInt(1); + return id; + } else { + throw new RuntimeException("Couldn't get id after " + statement); + } + } catch (SQLException e) { + throwException(e); + } + return -1; + } + + protected void executeStatement(PreparedStatement preparedStatement) { + try { + preparedStatement.executeUpdate(); + } catch (SQLException e) { + throwException(e); + } + } + + protected ResultSet executeQuery(PreparedStatement preparedStatement) { + ResultSet result = null; + try { + result = preparedStatement.executeQuery(); + } catch (SQLException e) { + throwException(e); + } + return result; + } + + protected ResultSet executeQuery(String statement, Object... args) { + PreparedStatement preparedStatement = prepareStatement(statement, args); + return executeQuery(preparedStatement); + } +} diff --git a/tdt4140-gr1800/app.core/src/main/java/tdt4140/gr1800/app/db/DbAccessImpl.java b/tdt4140-gr1800/app.core/src/main/java/tdt4140/gr1800/app/db/DbAccessImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..88f3b905a2a2dfe33d658b50c7a60049be42f452 --- /dev/null +++ b/tdt4140-gr1800/app.core/src/main/java/tdt4140/gr1800/app/db/DbAccessImpl.java @@ -0,0 +1,237 @@ +package tdt4140.gr1800.app.db; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.Collection; + +import tdt4140.gr1800.app.core.GeoLocations; +import tdt4140.gr1800.app.core.Person; + +public class DbAccessImpl extends AbstractDbAccessImpl { + + private final DbAccessHelper helper; + + private DbAccessImpl(DbAccessHelper helper) { + this.helper = helper; + } + + public DbAccessImpl(Connection dbConnection) { + this(new DbAccessHelper(dbConnection)); + } + + public DbAccessImpl(String connectionUri, String user, String pass) throws SQLException { + this(DriverManager.getConnection(connectionUri, user, pass)); + } + + public DbAccessImpl(String connectionUri) throws SQLException { + this(connectionUri, "SA", ""); + } + + // + + @Override + public synchronized Person createPerson(String name, String email) { + Person person = super.createPerson(name, email); + int id = helper.executeDbInsertGettingIdentity(String.format("INSERT INTO person (name, email) VALUES ('%s', '%s')", name, email)); + personIds.set(person, id); + return person; + } + + protected Person createPerson(int id, String name, String email) { + Person person = new Person(); + person.setName(name); + person.setEmail(email); + personIds.remove(id); + personIds.set(person, id); + return person; + } + + @Override + public Collection<Person> getAllPersons(boolean refresh) { + if (refresh) { + personIds.clear(); + ResultSet result = helper.executeQuery("SELECT id, name, email FROM person"); + try { + while (result.next()) { + int id = result.getInt(1); + String name = result.getString(2), email = result.getString(3); + createPerson(id, name, email); + } + } catch (SQLException e) { + helper.throwException(e); + } + } + return super.getAllPersons(false); + } + + @Override + public Person getPerson(int id, boolean refresh) { + Person person = null; + if (! refresh) { + person = super.getPerson(id, false); + } + if (person == null || refresh) { + ResultSet result = helper.executeQuery("SELECT id, name, email FROM person WHERE id = ?", id); + try { + if (result.next()) { + String name = result.getString(2), email = result.getString(3); + person = createPerson(id, name, email); + } + } catch (SQLException e) { + helper.throwException(e); + } + } + return person; + } + + @Override + public Person getPersonByName(String name, boolean refresh) { + Person person = null; + if (! refresh) { + person = super.getPersonByName(name, false); + } + if (person == null || refresh) { + ResultSet result = helper.executeQuery("SELECT id, name, email FROM person WHERE name = ?", name); + try { + if (result.next()) { + int id = result.getInt(1); + String dbName = result.getString(2), email = result.getString(3); + person = createPerson(id, dbName, email); + } + } catch (SQLException e) { + helper.throwException(e); + } + } + return person; + } + + @Override + public Person getPersonByEmail(String email, boolean refresh) { + Person person = null; + if (! refresh) { + person = super.getPersonByEmail(email, false); + } + if (person == null || refresh) { + ResultSet result = helper.executeQuery("SELECT id, name, email FROM person WHERE email = ?", email); + try { + if (result.next()) { + int id = result.getInt(1); + String name = result.getString(2), dbEmail = result.getString(3); + person = createPerson(id, name, dbEmail); + } + } catch (SQLException e) { + helper.throwException(e); + } + } + return person; + } + + @Override + public synchronized void updatePersonData(Person person) { + helper.executeDbStatement("UPDATE person SET name = ?, email = ? WHERE id = ?", person.getName(), person.getEmail(), getId(person)); + } + + @Override + public synchronized void deletePerson(Person person) { + int id = getId(person); + super.deletePerson(person); + helper.executeDbStatement("DELETE FROM person WHERE id = ?", id); + // not needed with ON DELETE CASCADE set on foreign keys +// helper.executeDbStatement("DELETE FROM geoLocations WHERE ownerId = ?", person.getId()); +// helper.executeDbStatement("DELETE FROM geoLocation WHERE ownerId = ?", person.getId()); + } + + // + + @Override + public GeoLocations createGeoLocations(Person owner) { + GeoLocations geoLocations = super.createGeoLocations(owner); + int id = helper.executeDbInsertGettingIdentity(String.format("INSERT INTO geoLocations (ownerId) VALUES ('%s')", getId(owner))); + geoLocationsIds.set(geoLocations, id); + return geoLocations; + } + + private static enum TagOwnerType { + GLS, // GeoLocations, + GL1, // GeoLocation, + } + + @Override + public Collection<GeoLocations> getGeoLocations(Person owner, boolean refresh) { + Collection<GeoLocations> existingGeoLocations = super.getGeoLocations(owner, false); + if (refresh || existingGeoLocations.isEmpty()) { + owner.removeGeolocations((String[]) null); + geoLocationsIds.removeAll(existingGeoLocations); + existingGeoLocations.clear(); + int ownerId = getId(owner); + ResultSet result = helper.executeQuery("SELECT id, path, name, description, date, time FROM geoLocations WHERE ownerId = ?", ownerId); + try { + while (result.next()) { + int id = result.getInt(1); + boolean path = result.getBoolean(2); + String name = result.getString(3), description = result.getString(3); + GeoLocations geoLocations = new GeoLocations(owner); + owner.addGeolocations(geoLocations); + geoLocations.setPath(path); + geoLocations.setName(name); + geoLocations.setDescription(description); + // TODO: date and time + existingGeoLocations.add(geoLocations); + geoLocationsIds.set(geoLocations, id); + ResultSet tagResults = helper.executeQuery(String.format("SELECT tag FROM tag WHERE ownerId = ? AND ownerType = '%s'", TagOwnerType.GLS), id); + while (tagResults.next()) { + geoLocations.addTags(tagResults.getString(1)); + } + } + } catch (SQLException e) { + helper.throwException(e); + } + ResultSet tagResult = helper.executeQuery(String.format("SELECT geoLocations.id, tag.tag FROM geoLocations, tag WHERE geoLocations.ownerId = ? AND tag.ownerId = geoLocations.id AND ownerType = '%s'", TagOwnerType.GLS), ownerId); + try { + while (tagResult.next()) { + int geoLocationsId = tagResult.getInt(1); + String tag = tagResult.getString(2); + GeoLocations geoLocations = geoLocationsIds.get(geoLocationsId); + if (geoLocations != null) { + geoLocations.addTags(tag); + } + } + } catch (SQLException e) { + helper.throwException(e); + } + } + return existingGeoLocations; + } + + @Override + public void updateGeoLocationsData(GeoLocations geoLocations) { + boolean path = geoLocations.isPath(); + String name = geoLocations.getName(), desc = geoLocations.getDescription(); + int ownerId = getId(geoLocations); + helper.executeDbStatement("UPDATE geoLocations SET path = ?, name = ?, description = ? WHERE id = ?", path, name, desc, ownerId); + deleteTags(ownerId, TagOwnerType.GLS); + String insertStatement = "INSERT INTO tag (ownerId, ownerType, tag) VALUES "; + String[] tags = geoLocations.getTags(); + for (int i = 0; i < tags.length; i++) { + if (i > 0) { + insertStatement += ", "; + } + insertStatement += String.format("(%s, '%s', '%s')", ownerId, TagOwnerType.GLS, tags[i]); + } + helper.executeDbStatement(insertStatement); + } + + protected void deleteTags(int ownerId, TagOwnerType ownerType) { + helper.executeDbStatement(String.format("DELETE FROM tag WHERE ownerId = ? AND ownerType = '%s'", ownerType), ownerId); + } + + @Override + public void deleteGeoLocations(GeoLocations geoLocations) { + int ownerId = getId(geoLocations); + super.deleteGeoLocations(geoLocations); + helper.executeDbStatement("DELETE FROM geoLocations WHERE id = ?", ownerId); + deleteTags(ownerId, TagOwnerType.GLS); + } +} diff --git a/tdt4140-gr1800/app.core/src/main/java/tdt4140/gr1800/app/db/IDbAccess.java b/tdt4140-gr1800/app.core/src/main/java/tdt4140/gr1800/app/db/IDbAccess.java new file mode 100644 index 0000000000000000000000000000000000000000..1a0be1aba4cac9226b2677f26ba6d33c9290cb1f --- /dev/null +++ b/tdt4140-gr1800/app.core/src/main/java/tdt4140/gr1800/app/db/IDbAccess.java @@ -0,0 +1,63 @@ +package tdt4140.gr1800.app.db; + +import java.time.LocalTime; +import java.util.Collection; + +import tdt4140.gr1800.app.core.GeoLocated; +import tdt4140.gr1800.app.core.GeoLocation; +import tdt4140.gr1800.app.core.GeoLocations; +import tdt4140.gr1800.app.core.GeoLocationsOwner; +import tdt4140.gr1800.app.core.Person; + +/* + * CRUD interface for our domain: + * + * @startuml + * class GeoLocationsOwner { + * String id + * } + * class Person { + * String name + * String email + * } + * GeoLocationsOwner <|-- Person + * class GeoLocations { + * String name + * String description + * } + * GeoLocationsOwner *-- GeoLocations: owner + * class GeoLocation { + * int elevation + * LocalTime time + * String name + * String description + * } + * GeoLocations *-- GeoLocation + * GeoLocation *-- LatLong + * @enduml + */ +public interface IDbAccess { + + // Create + public Person createPerson(String name, String email); + public GeoLocations createGeoLocations(Person owner); + public GeoLocation addGeoLocation(GeoLocations geoLocations, GeoLocated geoLoc, int elevation, LocalTime time); + + // Read + public Collection<Person> getAllPersons(boolean refresh); + public Person getPerson(int id, boolean refresh); + public Person getPersonByName(String name, boolean refresh); + public Person getPersonByEmail(String email, boolean refresh); + + public Collection<GeoLocations> getGeoLocations(Person owner, boolean refresh); + + // Update + public void updatePersonData(Person person); + public void updateGeoLocationsData(GeoLocations geoLocations); + public void updateGeoLocationData(GeoLocations geoLocations, GeoLocations geoLocation); + + // Delete + public void deletePerson(Person person); + public void deleteGeoLocations(GeoLocations geoLocations); + public void deleteGeoLocation(GeoLocations geoLocations, GeoLocation geoLocation); +} diff --git a/tdt4140-gr1800/app.core/src/main/java/tdt4140/gr1800/app/db/IdMap.java b/tdt4140-gr1800/app.core/src/main/java/tdt4140/gr1800/app/db/IdMap.java new file mode 100644 index 0000000000000000000000000000000000000000..e83e889afdbb13c7aca0142ed333826fd35f53ab --- /dev/null +++ b/tdt4140-gr1800/app.core/src/main/java/tdt4140/gr1800/app/db/IdMap.java @@ -0,0 +1,69 @@ +package tdt4140.gr1800.app.db; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +public class IdMap<T> { + + protected Map<Integer, T> id2o = new HashMap<Integer, T>(); + protected Map<T, Integer> o2id = new HashMap<T, Integer>(); + + public T get(int id) { + return id2o.get(id); + } + + public int getId(T o) { + Integer id = o2id.get(o); + return (id != null ? id : -1); + } + + public Collection<T> get() { + return o2id.keySet(); + } + + public Collection<Integer> getIds() { + return id2o.keySet(); + } + + // + + void set(T o, int id) { + if (o2id.containsKey(o)) { + throw new IllegalStateException(o + " already has the id " + o2id.get(o)); + } + if (id2o.containsKey(id)) { + throw new IllegalStateException(id + " already used by " + id2o.get(id)); + } + id2o.put(id, o); + o2id.put(o, id); + } + + void clear() { + o2id.clear(); + id2o.clear(); + } + + private void remove(T o, int id) { + o2id.remove(o); + id2o.remove(id); + } + + void remove(T o) { + if (o2id.containsKey(o)) { + remove(o, o2id.get(o)); + } + } + + void removeAll(Iterable<T> os) { + for (T o : os) { + remove(o); + } + } + + void remove(int id) { + if (id2o.containsKey(id)) { + remove(id2o.get(id), id); + } + } +} diff --git a/tdt4140-gr1800/app.core/src/main/resources/tdt4140/gr1800/app/db/schema.sql b/tdt4140-gr1800/app.core/src/main/resources/tdt4140/gr1800/app/db/schema.sql new file mode 100644 index 0000000000000000000000000000000000000000..321c749e8b043366e55297301b6bc7ce820ac08d --- /dev/null +++ b/tdt4140-gr1800/app.core/src/main/resources/tdt4140/gr1800/app/db/schema.sql @@ -0,0 +1,46 @@ +DROP TABLE person; +DROP TABLE geoLocations; +DROP TABLE geoLocation; +DROP TABLE tag; + +CREATE TABLE person ( + id INTEGER GENERATED BY DEFAULT AS IDENTITY (START WITH 1000) PRIMARY KEY, + + name varchar(80) NULL, + email varchar(80) NULL +); + +CREATE TABLE geoLocations ( + id INTEGER GENERATED BY DEFAULT AS IDENTITY (START WITH 1000) PRIMARY KEY, + ownerId int NOT NULL FOREIGN KEY REFERENCES person(id) ON DELETE CASCADE, + + path boolean NULL, + + name varchar(80) NULL, + description varchar(200) NULL, + + date date NULL, + time time NULL, +); + +CREATE TABLE geoLocation ( + id INTEGER GENERATED BY DEFAULT AS IDENTITY (START WITH 1000) PRIMARY KEY, + ownerId int NOT NULL FOREIGN KEY REFERENCES geoLocations(id) ON DELETE CASCADE, + + name varchar(80) NULL, + description varchar(200) NULL, + + latitude decimal NOT NULL, + longitude decimal NOT NULL, + elevation int NULL, + + date date NULL, + time time NULL, +); + +CREATE TABLE tag ( + ownerId int NOT NULL, + ownerType char(3), + + tag varchar(15) NULL, +); diff --git a/tdt4140-gr1800/app.core/src/test/java/tdt4140/gr1800/app/db/HsqldbAccessTest.java b/tdt4140-gr1800/app.core/src/test/java/tdt4140/gr1800/app/db/HsqldbAccessTest.java new file mode 100644 index 0000000000000000000000000000000000000000..20c0f0b0f0acc5f0b324071d38f1b02bfca5808e --- /dev/null +++ b/tdt4140-gr1800/app.core/src/test/java/tdt4140/gr1800/app/db/HsqldbAccessTest.java @@ -0,0 +1,173 @@ +package tdt4140.gr1800.app.db; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.Collection; +import java.util.Scanner; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import tdt4140.gr1800.app.core.GeoLocations; +import tdt4140.gr1800.app.core.Person; + +public class HsqldbAccessTest { + + private Connection dbCon; + private AbstractDbAccessImpl dbAccess; + private static int testNum = 0; + + @Before + public void setUp() throws Exception { + Class.forName("org.hsqldb.jdbc.JDBCDriver"); + dbCon = DriverManager.getConnection("jdbc:hsqldb:mem:" + HsqldbAccessTest.class.getName() + testNum, "SA", ""); + executeStatements("schema.sql"); + dbAccess = new DbAccessImpl(dbCon); + testNum++; + } + + @After + public void tearDown() { + if (dbCon != null) { + try { + dbCon.close(); + } catch (SQLException e) { + } + } + } + + protected void executeStatements(String path) throws SQLException { + Statement dbStatement = dbCon.createStatement(); + StringBuilder buffer = new StringBuilder(); + try (Scanner scanner = new Scanner(HsqldbAccessTest.class.getResourceAsStream(path))) { + while (scanner.hasNextLine()) { + String line = scanner.nextLine(); + int pos = line.indexOf(";"); + if (pos >= 0) { + buffer.append(line.substring(0, pos + 1)); + String sql = buffer.toString(); + buffer.setLength(0); + if (pos < line.length()) { + buffer.append(line.substring(pos + 1)); + } + if (! sql.startsWith("DROP")) { + dbStatement.execute(sql); + } + } else { + buffer.append(line); + buffer.append("\n"); + } + } + } + } + + protected void checkPersonData(Person hal, Person dbHal) { + Assert.assertNotNull(dbHal); + Assert.assertEquals(hal.getName(), dbHal.getName()); + Assert.assertEquals(hal.getEmail(), dbHal.getEmail()); + } + + @Test + public void testCreatePersonGetAllPersons() { + Person hal = dbAccess.createPerson("hal", "hal@ntnu.no"); + Collection<Person> persons = dbAccess.getAllPersons(false); + Assert.assertEquals(1, persons.size()); + checkPersonData(hal, persons.iterator().next()); + dbAccess.personIds.clear(); + Collection<Person> dbPersons = dbAccess.getAllPersons(true); + Assert.assertEquals(1, dbPersons.size()); + checkPersonData(hal, dbPersons.iterator().next()); + } + + @Test + public void testCreatePersonGetPerson() { + Person hal = dbAccess.createPerson("hal", "hal@ntnu.no"); + int id = dbAccess.getId(hal); + Person dbHal = dbAccess.getPerson(id, true); + checkPersonData(hal, dbHal); + Assert.assertSame(dbHal, dbAccess.getPerson(id, false)); + } + + @Test + public void testCreatePersonGetPersonByName() { + Person hal = dbAccess.createPerson("hal", "hal@ntnu.no"); + Person dbHal = dbAccess.getPersonByName(hal.getName(), true); + checkPersonData(hal, dbHal); + } + + @Test + public void testCreatePersonGetPersonByEmail() { + Person hal = dbAccess.createPerson("hal", "hal@ntnu.no"); + Person dbHal = dbAccess.getPersonByEmail(hal.getEmail(), true); + checkPersonData(hal, dbHal); + } + + @Test + public void testCreatePersonUpdatePerson() { + Person hal = dbAccess.createPerson("hal", "hal@ntnu.no"); + int id = dbAccess.getId(hal); + hal.setName("Hallvard"); + hal.setEmail("hallvard.traetteberg@gmail.com"); + dbAccess.updatePersonData(hal); + Person dbHal = dbAccess.getPerson(id, true); + checkPersonData(hal, dbHal); + } + + @Test + public void testCreatePersonDeletePerson() { + Person hal = dbAccess.createPerson("hal", "hal@ntnu.no"); + dbAccess.deletePerson(hal); + Collection<Person> persons = dbAccess.getAllPersons(true); + Assert.assertEquals(0, persons.size()); + } + + @Test + public void testCreatePersonCreateGeoLocationsGetGeoLocations() { + Person hal = dbAccess.createPerson("hal", "hal@ntnu.no"); + // no GeoLocations so far + Assert.assertEquals(0, dbAccess.getGeoLocations(hal, false).size()); + GeoLocations geoLocations1 = dbAccess.createGeoLocations(hal); + // check we have one locally + Assert.assertEquals(1, hal.getGeoLocations((String[]) null).size()); + Collection<GeoLocations> geoLocations = dbAccess.getGeoLocations(hal, false); + Assert.assertEquals(1, hal.getGeoLocations((String[]) null).size()); + Assert.assertEquals(1, geoLocations.size()); + Assert.assertSame(geoLocations1, geoLocations.iterator().next()); + dbAccess.geoLocationsIds.clear(); + // check we have one in the db + Collection<GeoLocations> dbGeoLocations = dbAccess.getGeoLocations(hal, true); + Assert.assertEquals(1, hal.getGeoLocations((String[]) null).size()); + Assert.assertEquals(1, dbGeoLocations.size()); + } + + @Test + public void testCreatePersonCreateUpdateGeoLocationsGetGeoLocations() { + Person hal = dbAccess.createPerson("hal", "hal@ntnu.no"); + GeoLocations geoLocations1 = dbAccess.createGeoLocations(hal); + geoLocations1.setName("geoLocs1"); + String[] tags = {"tag1", "tag2"}; + geoLocations1.addTags(tags); + dbAccess.updateGeoLocationsData(geoLocations1); + dbAccess.geoLocationsIds.clear(); + // check the db + Collection<GeoLocations> dbGeoLocations = dbAccess.getGeoLocations(hal, true); + Assert.assertEquals(1, hal.getGeoLocations((String[]) null).size()); + Assert.assertEquals(1, dbGeoLocations.size()); + GeoLocations dbGeoLocations1 = dbGeoLocations.iterator().next(); + Assert.assertEquals(2, dbGeoLocations1.getTags().length); + Assert.assertTrue(dbGeoLocations1.hasTags(tags)); + } + + @Test + public void testCreatePersonCreateGeoLocationsDeleteGeoLocations() { + Person hal = dbAccess.createPerson("hal", "hal@ntnu.no"); + GeoLocations geoLocations = dbAccess.createGeoLocations(hal); + Collection<GeoLocations> dbGeoLocations = dbAccess.getGeoLocations(hal, true); + Assert.assertEquals(1, dbGeoLocations.size()); + dbAccess.deleteGeoLocations(geoLocations); + } +}