Commit 83f00d45 authored by Hallvard Trætteberg's avatar Hallvard Trætteberg
Browse files

Merge branch 'issue-16-db-support'

parents 25704dea f026130a
Pipeline #9320 failed with stages
in 5 minutes and 47 seconds
......@@ -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>
......
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;
}
}
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);
}
}
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);
}
}
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);
}