Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision
  • issue-10-fxmapcontrol
  • issue-13-gpx
  • issue-9-file-menu
  • master
4 results

Target

Select target project
  • bragearn/examples
  • johngu/examples
  • krisschn/examples
  • erikbd/examples
  • helenesm/examples
  • balazor/examples
  • htechter/examples
  • aslakho/examples
  • jonri/examples
  • andreski/examples
  • sigriksc/examples
  • norasbr/examples
  • jannash/examples
  • smledsaa/examples
  • mtorre/examples
  • tdt4140-staff/examples
16 results
Select Git revision
  • issue-10-fxmapcontrol
  • issue-9-file-menu
  • master
  • patch-1
  • patch-2
5 results
Show changes
Showing
with 1305 additions and 1 deletion
package tdt4140.gr1800.app.core;
public class LatLong {
public class LatLong implements GeoLocated {
public final double latitude, longitude;
......@@ -57,6 +57,13 @@ public class LatLong {
return new LatLong(lat, lon);
}
// GeoLocated
@Override
public LatLong getLatLong() {
return this;
}
/*::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::*/
/*:: :*/
/*:: This routine calculates the distance between two points (given the :*/
......
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.core;
public interface Tagged {
public boolean hasTags(String... tags);
public String[] getTags();
public String getTags(String prefix, String separator, String suffix);
public void setTags(String... tags);
public void addTags(String... tags);
public void removeTags(String... tags);
}
package tdt4140.gr1800.app.core;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
public class Tags implements Tagged, Iterable<String> {
private Collection<String> tags = null;
@Override
public Iterator<String> iterator() {
return (tags != null ? tags.iterator() : Collections.<String>emptyList().iterator());
}
public Tags(final String... tags) {
setTags(tags);
}
public Tags(final Tagged tags) {
setTags(tags.getTags());
}
public static Tags valueOf(final String tags) {
return valueOf(tags, ",");
}
public static Tags valueOf(final String tags, final String separator) {
return new Tags(tags.split(separator));
}
public int getTagCount() {
return (tags == null ? 0 : tags.size());
}
@Override
public boolean hasTags(final String... tags) {
return (tags.length == 0 || (this.tags != null && this.tags.containsAll(Arrays.asList(tags))));
}
final static String[] EMPTY_STRINGS = {};
@Override
public String[] getTags() {
return (tags != null ? tags.toArray(new String[tags.size()]) : EMPTY_STRINGS);
}
@Override
public String getTags(final String prefix, final String separator, final String suffix) {
final StringBuilder buffer = new StringBuilder();
append(buffer, prefix);
int tagNum = 0;
for (final String tag : tags) {
if (tagNum > 0 && separator != null) {
buffer.append(separator);
}
buffer.append(tag);
tagNum++;
}
append(buffer, suffix);
return buffer.toString();
}
static StringBuilder append(final StringBuilder buffer, final String s) {
if (s != null) {
buffer.append(s);
}
return buffer;
}
@Override
public void setTags(final String... tags) {
this.tags = new ArrayList<>();
addTags(tags);
}
@Override
public void addTags(final String... tags) {
if (this.tags == null && tags != null && tags.length > 0) {
this.tags = new ArrayList<>();
}
for (int i = 0; i < tags.length; i++) {
if (! this.tags.contains(tags[i])) {
this.tags.add(tags[i]);
}
}
}
@Override
public void removeTags(final String... tags) {
if (this.tags != null) {
this.tags.removeAll(Arrays.asList(tags));
}
}
}
package tdt4140.gr1800.app.core;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
public interface Timed {
public ZoneId getZone();
public void setZone(ZoneId zone);
default public void setZone(String zone) {
setZone(ZoneId.of(zone));
}
public LocalDate getDate();
public void setDate(LocalDate date);
default public void setDate(String date) {
setDate(LocalDate.parse(date));
}
public LocalTime getTime();
public void setTime(LocalTime time);
default public void setTime(String time) {
setTime(LocalTime.parse(time));
}
default public void setDateTime(LocalDateTime dateTime) {
setDate(dateTime.toLocalDate());
setTime(dateTime.toLocalTime());
}
}
package tdt4140.gr1800.app.core;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.ZoneId;
public class TimedImpl implements Timed {
private ZoneId zone;
public ZoneId getZone() {
return zone;
}
public void setZone(ZoneId zone) {
this.zone = zone;
}
private LocalDate date;
private LocalTime time;
public LocalDate getDate() {
return date;
}
public void setDate(LocalDate date) {
this.date = date;
}
public LocalTime getTime() {
return time;
}
public void setTime(LocalTime time) {
this.time = time;
}
}
package tdt4140.gr1800.app.core;
public class TimedTaggedImpl extends TimedImpl implements Tagged {
private Tags tags = null;
public TimedTaggedImpl() {
}
public TimedTaggedImpl(final Tagged tags) {
setTags(tags.getTags());
}
private static TimedTaggedImpl valueOf(final Tags tags) {
final TimedTaggedImpl timedTags = new TimedTaggedImpl();
timedTags.tags = tags;
return timedTags;
}
public static TimedTaggedImpl valueOf(final String tags) {
return valueOf(Tags.valueOf(tags));
}
public static TimedTaggedImpl valueOf(final String tags, final String separator) {
return valueOf(Tags.valueOf(tags, separator));
}
@Override
public boolean hasTags(final String... tags) {
return this.tags != null && this.tags.hasTags(tags);
}
@Override
public String[] getTags() {
return (tags != null ? tags.getTags() : Tags.EMPTY_STRINGS);
}
@Override
public String getTags(final String prefix, final String separator, final String suffix) {
return (tags != null ? tags.getTags(prefix, separator, suffix) : Tags.append(Tags.append(new StringBuilder(), prefix), suffix).toString());
}
@Override
public void setTags(final String... tags) {
this.tags = (tags != null && tags.length > 0 ? new Tags(tags) : null);
}
@Override
public void addTags(final String... tags) {
if (this.tags == null) {
this.tags = new Tags();
}
this.tags.addTags(tags);
}
@Override
public void removeTags(final String... tags) {
if (this.tags != null) {
this.tags.removeTags(tags);
if (this.tags.getTagCount() == 0) {
this.tags = null;
}
}
}
}
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 IdProvider<Person> getPersonIdProvider() {
return personIds;
}
public int getId(final Person person) {
return personIds.getId(person);
}
public int getId(final GeoLocations geoLocations) {
return geoLocationsIds.getId(geoLocations);
}
public int getId(final GeoLocation geoLocation) {
return geoLocationIds.getId(geoLocation);
}
@Override
public Person createPerson(final String name, final String email) {
final Person person = new Person();
person.setName(name);
person.setEmail(email);
return person;
}
@Override
public GeoLocations createGeoLocations(final Person owner) {
final GeoLocations geoLocations = new GeoLocations(owner);
owner.addGeolocations(geoLocations);
return geoLocations;
}
@Override
public GeoLocation addGeoLocation(final GeoLocations geoLocations, final GeoLocated geoLoc, final int elevation, final LocalTime time) {
final GeoLocation geoLocation = new GeoLocation();
geoLocation.setLatLong(geoLoc.getLatLong());
geoLocation.setElevation(elevation);
geoLocation.setTime(time);
geoLocations.addLocation(geoLoc);
return geoLocation;
}
@Override
public Collection<Person> getAllPersons(final boolean refresh) {
return new ArrayList<Person>(personIds.get());
}
@Override
public Person getPerson(final int id, final boolean refresh) {
final Person person = personIds.get(id);
return person;
}
@Override
public Person getPersonByName(final String name, final boolean refresh) {
for (final Person person : personIds.get()) {
if (name == person.getName() || (name != null && name.equals(person.getName()))) {
return person;
}
}
return null;
}
@Override
public Person getPersonByEmail(final String email, final boolean refresh) {
for (final Person person : personIds.get()) {
if (email == person.getEmail() || (email != null && email.equals(person.getEmail()))) {
return person;
}
}
return null;
}
@Override
public Collection<GeoLocations> getGeoLocations(final Person owner, final boolean refresh) {
return owner.getGeoLocations((String[]) null);
}
@Override
public void deletePerson(final Person person) {
personIds.remove(person);
}
@Override
public void deleteGeoLocations(final GeoLocations geoLocations) {
geoLocations.getOwner().removeGeolocations(geoLocations);
geoLocationsIds.remove(geoLocations);
}
@Override
public void deleteGeoLocation(final GeoLocations geoLocations, final GeoLocation geoLocation) {
geoLocationIds.remove(geoLocation);
}
}
package tdt4140.gr1800.app.db;
import java.sql.Connection;
import java.sql.Date;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Time;
import java.sql.Types;
import java.time.LocalDate;
import java.time.LocalTime;
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++) {
setStatementArgument(preparedStatement, args[argNum - 1], null, argNum);
}
} catch (SQLException e) {
throwException(e);
}
return preparedStatement;
}
protected void setStatementArgument(PreparedStatement preparedStatement, Object arg, Class<?> type, int argNum) throws SQLException {
if (arg == null) {
int sqlType = Types.VARCHAR;
if (type == String.class) { sqlType = Types.VARCHAR;
} else if (type == Double.class) { sqlType = Types.DECIMAL;
} else if (type == Integer.class) { sqlType = Types.INTEGER;
} else if (type == Boolean.class) { sqlType = Types.BOOLEAN;
} else if (type == Date.class) { sqlType = Types.DATE;
} else if (type == LocalDate.class) { sqlType = Types.DATE;
} else if (type == Time.class) { sqlType = Types.TIME;
} else if (type == LocalTime.class) { sqlType = Types.TIME;
}
preparedStatement.setNull(argNum, sqlType);
} else if (arg instanceof String || type == String.class) { preparedStatement.setString(argNum, (String) arg);
} else if (arg instanceof Double || type == Double.class) { preparedStatement.setDouble(argNum, (Double) arg);
} else if (arg instanceof Integer || type == Integer.class) { preparedStatement.setInt (argNum, (Integer) arg);
} else if (arg instanceof Boolean || type == Boolean.class) { preparedStatement.setBoolean(argNum, (Boolean) arg);
} else if (arg instanceof Date || type == Date.class) { preparedStatement.setDate (argNum, (Date) arg);
} else if (arg instanceof LocalDate || type == LocalDate.class) { preparedStatement.setDate (argNum, Date.valueOf((LocalDate) arg));
} else if (arg instanceof Time || type == Time.class) { preparedStatement.setTime (argNum, (Time) arg);
} else if (arg instanceof LocalTime || type == LocalTime.class) { preparedStatement.setTime (argNum, Time.valueOf((LocalTime) arg));
}
}
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.Date;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Time;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.ZoneId;
import java.util.Collection;
import java.util.Scanner;
import tdt4140.gr1800.app.core.GeoLocation;
import tdt4140.gr1800.app.core.GeoLocations;
import tdt4140.gr1800.app.core.Person;
public class DbAccessImpl extends AbstractDbAccessImpl {
private final DbAccessHelper helper;
private DbAccessImpl(final DbAccessHelper helper) {
this.helper = helper;
}
public DbAccessImpl(final Connection dbConnection) {
this(new DbAccessHelper(dbConnection));
}
public DbAccessImpl(final String connectionUri, final String user, final String pass) throws SQLException {
this(DriverManager.getConnection(connectionUri, user, pass));
}
public DbAccessImpl(final String connectionUri) throws SQLException {
this(connectionUri, "SA", "");
}
//
public void executeStatements(final String path, final boolean cleanUp) throws SQLException {
final Statement dbStatement = helper.getDbConnection().createStatement();
final StringBuilder buffer = new StringBuilder();
try (Scanner scanner = new Scanner(getClass().getResourceAsStream(path))) {
while (scanner.hasNextLine()) {
final String line = scanner.nextLine();
final int pos = line.indexOf(";");
if (pos >= 0) {
buffer.append(line.substring(0, pos + 1));
final String sql = buffer.toString();
buffer.setLength(0);
if (pos < line.length()) {
buffer.append(line.substring(pos + 1));
}
if (cleanUp || (! sql.startsWith("DROP"))) {
dbStatement.execute(sql);
}
} else {
buffer.append(line);
buffer.append("\n");
}
}
}
}
//
@Override
public synchronized Person createPerson(final String name, final String email) {
final Person person = super.createPerson(name, email);
final 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(final int id, final String name, final String email) {
final Person person = new Person();
person.setName(name);
person.setEmail(email);
personIds.remove(id);
personIds.set(person, id);
return person;
}
@Override
public Collection<Person> getAllPersons(final boolean refresh) {
if (refresh) {
personIds.clear();
final ResultSet result = helper.executeQuery("SELECT id, name, email FROM person");
try {
while (result.next()) {
final int id = result.getInt(1);
final String name = result.getString(2), email = result.getString(3);
createPerson(id, name, email);
}
} catch (final SQLException e) {
helper.throwException(e);
}
}
return super.getAllPersons(false);
}
@Override
public Person getPerson(final int id, final boolean refresh) {
Person person = null;
if (! refresh) {
person = super.getPerson(id, false);
}
if (person == null || refresh) {
final ResultSet result = helper.executeQuery("SELECT id, name, email FROM person WHERE id = ?", id);
try {
if (result.next()) {
final String name = result.getString(2), email = result.getString(3);
person = createPerson(id, name, email);
}
} catch (final SQLException e) {
helper.throwException(e);
}
}
return person;
}
@Override
public Person getPersonByName(final String name, final boolean refresh) {
Person person = null;
if (! refresh) {
person = super.getPersonByName(name, false);
}
if (person == null || refresh) {
final ResultSet result = helper.executeQuery("SELECT id, name, email FROM person WHERE name = ?", name);
try {
if (result.next()) {
final int id = result.getInt(1);
final String dbName = result.getString(2), email = result.getString(3);
person = createPerson(id, dbName, email);
}
} catch (final SQLException e) {
helper.throwException(e);
}
}
return person;
}
@Override
public Person getPersonByEmail(final String email, final boolean refresh) {
Person person = null;
if (! refresh) {
person = super.getPersonByEmail(email, false);
}
if (person == null || refresh) {
final ResultSet result = helper.executeQuery("SELECT id, name, email FROM person WHERE email = ?", email);
try {
if (result.next()) {
final int id = result.getInt(1);
final String name = result.getString(2), dbEmail = result.getString(3);
person = createPerson(id, name, dbEmail);
}
} catch (final SQLException e) {
helper.throwException(e);
}
}
return person;
}
@Override
public synchronized void updatePersonData(final Person person) {
helper.executeDbStatement("UPDATE person SET name = ?, email = ? WHERE id = ?", person.getName(), person.getEmail(), getId(person));
}
@Override
public synchronized void deletePerson(final Person person) {
final 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(final Person owner) {
final GeoLocations geoLocations = super.createGeoLocations(owner);
final 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(final Person owner, final boolean refresh) {
final Collection<GeoLocations> existingGeoLocations = super.getGeoLocations(owner, false);
if (refresh || existingGeoLocations.isEmpty()) {
owner.removeGeolocations((String[]) null);
geoLocationsIds.removeAll(existingGeoLocations);
existingGeoLocations.clear();
final int ownerId = getId(owner);
final ResultSet result = helper.executeQuery("SELECT id, path, name, description, date, time, zone FROM geoLocations WHERE ownerId = ?", ownerId);
try {
while (result.next()) {
final int id = result.getInt(1);
final boolean path = result.getBoolean(2);
final String name = result.getString(3), description = result.getString(4);
final GeoLocations geoLocations = new GeoLocations(owner);
owner.addGeolocations(geoLocations);
geoLocations.setPath(path);
geoLocations.setName(name);
geoLocations.setDescription(description);
final Date date = result.getDate(5);
final Time time = result.getTime(6);
final String zone = result.getString(7);
geoLocations.setDate(date != null ? date.toLocalDate() : null);
geoLocations.setTime(time != null ? time.toLocalTime() : null);
geoLocations.setZone(zone != null ? ZoneId.of(zone) : null);
existingGeoLocations.add(geoLocations);
geoLocationsIds.set(geoLocations, id);
final 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 (final SQLException e) {
helper.throwException(e);
}
final 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()) {
final int geoLocationsId = tagResult.getInt(1);
final String tag = tagResult.getString(2);
final GeoLocations geoLocations = geoLocationsIds.get(geoLocationsId);
if (geoLocations != null) {
geoLocations.addTags(tag);
}
}
} catch (final SQLException e) {
helper.throwException(e);
}
}
return existingGeoLocations;
}
@Override
public void updateGeoLocationsData(final GeoLocations geoLocations) {
final boolean path = geoLocations.isPath();
final String name = geoLocations.getName(), desc = geoLocations.getDescription();
final LocalDate date = geoLocations.getDate();
final LocalTime time = geoLocations.getTime();
final String zone = (geoLocations.getZone() != null ? geoLocations.getZone().getId() : null);
final int ownerId = getId(geoLocations);
helper.executeDbStatement("UPDATE geoLocations SET path = ?, name = ?, description = ?, date = ?, time = ?, zone = ? WHERE id = ?", path, name, desc, Date.valueOf(date), Time.valueOf(time), zone, ownerId);
deleteTags(ownerId, TagOwnerType.GLS);
String insertStatement = "INSERT INTO tag (ownerId, ownerType, tag) VALUES ";
final 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(final int ownerId, final TagOwnerType ownerType) {
helper.executeDbStatement(String.format("DELETE FROM tag WHERE ownerId = ? AND ownerType = '%s'", ownerType), ownerId);
}
@Override
public void deleteGeoLocations(final GeoLocations geoLocations) {
final int ownerId = getId(geoLocations);
super.deleteGeoLocations(geoLocations);
helper.executeDbStatement("DELETE FROM geoLocations WHERE id = ?", ownerId);
deleteTags(ownerId, TagOwnerType.GLS);
}
//
@Override
public void updateGeoLocationData(final GeoLocations geoLocations, final GeoLocation geoLocation) {
throw new UnsupportedOperationException("NYI");
}
}
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.Person;
/*
* class diagram:
*
* @startuml
* class GeoLocationsOwner {
* }
*
* class Person {
* String name
* String email
* }
*
* class TimedTaggedImpl {
* LocalDate date
* LocalTime time
* ZoneId zone
* String[] tags
* }
*
* GeoLocationsOwner <|-- Person
*
* GeoLocationsOwner *-- GeoLocations: owner
*
* class GeoLocations {
* String name
* String description
* LocalDate date
* LocalTime time
* ZoneId zone
* String[] tags
* }
*
* GeoLocations --|> TimedTaggedImpl
*
* class GeoLocation {
* int elevation
* LocalTime time
* String name
* String description
* }
* GeoLocation --|> TimedTaggedImpl
*
* GeoLocations *-- GeoLocation
* GeoLocation *-- LatLong
* @enduml
*/
/*
* ER diagram interface for our domain:
*
* @startuml
* entity person {
* * id INTEGER GENERATED
* * name varchar(80)
* * email varchar(80)
* }
*
* entity geoLocations {
* * id INTEGER GENERATED
* path boolean
* name varchar(80)
* description varchar(200)
* date date
* time time
* zone varchar(20)
* }
*
* person --{ geoLocations: ownerId
*
* entity geoLocation {
* * id INTEGER GENERATED
* name varchar(80)
* description varchar(200)
* * latitude decimal
* * longitude decimal
* elevation int
* date date
* time time
* zone varchar(20)
* }
*
* geoLocations --{ geoLocation: ownerId
*
* entity tags {
* * ownerType char(3)
* * tag varchar(15)
* }
*
* geoLocations --{ tags: ownerId
* geoLocation --{ tags: ownerId
*
* @enduml
*/
public interface IDbAccess {
public IdProvider<Person> getPersonIdProvider();
// 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, GeoLocation geoLocation);
// Delete
public void deletePerson(Person person);
public void deleteGeoLocations(GeoLocations geoLocations);
public void deleteGeoLocation(GeoLocations geoLocations, GeoLocation geoLocation);
}
package tdt4140.gr1800.app.db;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
public class IdMap<T> implements IdProvider<T> {
protected Map<Integer, T> id2o = new HashMap<Integer, T>();
protected Map<T, Integer> o2id = new HashMap<T, Integer>();
public int size() {
return o2id.size();
}
public T get(final int id) {
return id2o.get(id);
}
@Override
public boolean hasId(final T t) {
return o2id.containsKey(t);
}
@Override
public int getId(final T o) {
final Integer id = o2id.get(o);
return (id != null ? id : -1);
}
public Collection<T> get() {
return o2id.keySet();
}
public Collection<Integer> getIds() {
return id2o.keySet();
}
//
public void set(final T o, final 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);
}
public void clear() {
o2id.clear();
id2o.clear();
}
private void remove(final T o, final int id) {
o2id.remove(o);
id2o.remove(id);
}
public void remove(final T o) {
if (o2id.containsKey(o)) {
remove(o, o2id.get(o));
}
}
public void removeAll(final Iterable<T> os) {
for (final T o : os) {
remove(o);
}
}
public void remove(final int id) {
if (id2o.containsKey(id)) {
remove(id2o.get(id), id);
}
}
}
package tdt4140.gr1800.app.db;
public interface IdProvider<T> {
public boolean hasId(T t);
public int getId(T t);
}
package tdt4140.gr1800.app.doc;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
/**
* Incomplete implementation of **IDocumentStorage**, to simplify implementing ones for specific document and location types.
* The main missing methods are for getting and setting the current document, creating an empty one and
* creating an **InputStream** from a location.
* @author hal
*
* @param <D> the document type
* @param <L> the location type
*/
public abstract class AbstractDocumentStorageImpl<D, L> implements IDocumentStorage<L>, IDocumentPersistence<D, L> {
private L documentLocation;
@Override
public L getDocumentLocation() {
return documentLocation;
}
@Override
public void setDocumentLocation(final L documentLocation) {
final L oldDocumentLocation = this.documentLocation;
this.documentLocation = documentLocation;
fireDocumentLocationChanged(oldDocumentLocation);
}
protected void setDocumentAndLocation(final D document, final L documentLocation) {
setDocument(document);
setDocumentLocation(documentLocation);
}
/**
* Returns the current document.
* @return the current document
*/
protected abstract D getDocument();
/**
* Sets the current document
* @param document the new document
*/
protected abstract void setDocument(D document);
//
private final Collection<IDocumentStorageListener<L>> documentListeners = new ArrayList<IDocumentStorageListener<L>>();
@Override
public void addDocumentStorageListener(final IDocumentStorageListener<L> documentStorageListener) {
documentListeners.add(documentStorageListener);
}
@Override
public void removeDocumentStorageListener(final IDocumentStorageListener<L> documentStorageListener) {
documentListeners.remove(documentStorageListener);
}
protected void fireDocumentLocationChanged(final L oldDocumentLocation) {
for (final IDocumentStorageListener<L> documentStorageListener : documentListeners) {
documentStorageListener.documentLocationChanged(documentLocation, oldDocumentLocation);
}
}
protected void fireDocumentChanged(final D oldDocument) {
for (final IDocumentStorageListener<L> documentListener : documentListeners) {
if (documentListener instanceof IDocumentListener) {
((IDocumentListener<D, L>) documentListener).documentChanged(getDocument(), oldDocument);
}
}
}
/**
* Creates a new and empty document.
* @return
*/
protected abstract D createDocument();
@Override
public void newDocument() {
setDocumentAndLocation(createDocument(), null);
}
/**
* Creates an ImportStream from a location
* @param location
* @return
* @throws IOException
*/
protected abstract InputStream toInputStream(L location) throws IOException;
@Override
public void openDocument(final L storage) throws IOException {
try (InputStream input = toInputStream(storage)){
setDocumentAndLocation(loadDocument(input), storage);
} catch (final Exception e) {
throw new IOException(e);
}
}
@Override
public void saveDocument() throws IOException {
try {
saveDocument(getDocument(), getDocumentLocation());
} catch (final Exception e) {
throw new IOException(e);
}
}
public void saveDocumentAs(final L documentLocation) throws IOException {
final L oldDocumentLocation = getDocumentLocation();
setDocumentLocation(documentLocation);
try {
saveDocument();
} catch (final IOException e) {
setDocumentLocation(oldDocumentLocation);
throw e;
}
}
public void saveCopyAs(final L documentLocation) throws Exception {
saveDocument(getDocument(), documentLocation);
}
}
package tdt4140.gr1800.app.doc;
import java.io.IOException;
import java.io.InputStream;
/**
* An interface with a method for importing domain data from a location.
* The main use is supporting an **import** action in a **File** menu.
* @author hal
*
*/
public interface IDocumentImporter {
/**
* Loads a document from the input stream and sets it as the current document.
* @param inputStream
* @throws IOException
*/
public void importDocument(InputStream inputStream) throws IOException;
}
package tdt4140.gr1800.app.doc;
/**
* Listener interface for the (contents of) the (current) document of an IDocumentStorage, e.g.
* when an **open** action is performed.
* @author hal
*
* @param <D> the document type
* @param <L> the location type
*/
public interface IDocumentListener<D, L> extends IDocumentStorageListener<L> {
/**
* Notifies that the current document has changed.
* @param document the new document
* @param oldDocument the previous document
*/
public void documentChanged(D document, D oldDocument);
}
package tdt4140.gr1800.app.doc;
import java.io.InputStream;
/**
* An interface with a method for loading and returning a document (domain data container) from an InputStream.
* This allows various ways of loading or importing domain data, with different sources and formats.
* @author hal
*
* @param <D> the document type
*/
public interface IDocumentLoader<D> {
/**
* Loads and returns a new document from an InputStream
* @param inputStream
* @return
* @throws Exception
*/
public D loadDocument(InputStream inputStream) throws Exception;
}
package tdt4140.gr1800.app.doc;
public interface IDocumentPersistence<D, L> extends IDocumentLoader<D>, IDocumentSaver<D, L> {
}
package tdt4140.gr1800.app.doc;
/**
* An interface with a method for saving a document (domain data container) to a location.
* This allows various ways of saving or exporting domain data, to different locations and formats.
* @author hal
*
* @param <D> the document type
* @param <L> the location type
*/
public interface IDocumentSaver<D, L> {
/**
* Saves the provided document to the provided location
* @param document
* @param documentLocation
* @throws Exception
*/
public void saveDocument(D document, L documentLocation) throws Exception;
}
package tdt4140.gr1800.app.doc;
import java.io.IOException;
import java.util.Collection;
/**
* An interface with the methods necessary for supporting the standard File menu actions.
* The class representing the document (domain data container) is implicit in the implementation of this interface.
* The interface includes methods for getting and setting the location and creating, opening and saving the (current) document.
* @author hal
*
* @param <L> The type of the location, typically java.io.File.
*/
public interface IDocumentStorage<L> {
/**
* Returns the current location (of the current document).
* @return the current location
*/
public L getDocumentLocation();
/**
* Sets the current location (of the current document), can be used by a save-as action.
* @param documentLocation
*/
public void setDocumentLocation(L documentLocation);
/**
* Adds an IDocumentStorageListener that will be notified when the current location changes.
* @param documentStorageListener
*/
public void addDocumentStorageListener(IDocumentStorageListener<L> documentStorageListener);
/**
* Removes an IDocumentStorageListener.
* @param documentStorageListener
*/
public void removeDocumentStorageListener(IDocumentStorageListener<L> documentStorageListener);
/**
* Creates a new documents and sets it as the current one, can be used by a new action.
*/
public void newDocument();
/**
* Loads a documents from the provided location and sets it as the current one, can be used by an open action.
*/
public void openDocument(L documentLocation) throws IOException;
/**
* Saves the current document (to the current location), can be used by a save action.
*/
public void saveDocument() throws IOException;
/**
* Returns the set of IDocumentImporters, can be used by an import action.
* @return
*/
public Collection<IDocumentImporter> getDocumentImporters();
}