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

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
Show changes
Commits on Source (14)
Showing
with 318 additions and 119 deletions
......@@ -14,25 +14,28 @@ variables:
MAVEN_OPTS: "-Djava.awt.headless=true -Dmaven.repo.local=.m2/repository"
MAVEN_CLI_OPTS: "--batch-mode --errors --fail-at-end --show-version -Dgitlab-ci=true"
build-job:
stage: build
script:
- "mvn clean compile -f tdt4140-gr18nn/pom.xml $MAVEN_CLI_OPTS"
- "mvn clean compile -f tdt4140-gr1800/pom.xml $MAVEN_CLI_OPTS"
#build-job:
# stage: build
# script:
# - "mvn clean compile -f tdt4140-gr18nn/pom.xml $MAVEN_CLI_OPTS"
# - "mvn clean compile -f tdt4140-gr1800/pom.xml $MAVEN_CLI_OPTS"
unittest-job:
stage: test
dependencies:
- build-job
script:
- "mvn package -f tdt4140-gr18nn/pom.xml $MAVEN_CLI_OPTS"
- "mvn package -f tdt4140-gr1800/pom.xml $MAVEN_CLI_OPTS"
- "cat tdt4140-gr1800/app.core/target/site/jacoco/index.html"
#unittest-job:
# stage: test
# dependencies:
# - build-job
# script:
# - "mvn test -f tdt4140-gr18nn/pom.xml $MAVEN_CLI_OPTS"
# - "mvn test -f tdt4140-gr1800/pom.xml $MAVEN_CLI_OPTS"
# - "cat tdt4140-gr1800/app.core/target/site/jacoco/index.html"
integrationtest-job:
stage: test
dependencies:
- build-job
only:
- web
# dependencies:
# - build-job
script:
- "mvn verify -f tdt4140-gr18nn/pom.xml $MAVEN_CLI_OPTS"
- "mvn verify -f tdt4140-gr1800/pom.xml $MAVEN_CLI_OPTS"
- "cat tdt4140-gr1800/app.core/target/site/jacoco/index.html"
# Example repository for the TDT4140 course, Spring 2018
This repository contains templates and examples for the TDT4140 course, for Spring 2018. Currently, it contains two project, both using maven as build system and configured for using Eclipse:
* [tdt4140-gr18nn](tdt4140-gr18nn/README.md): Template for JavaFX project with two sub-modules, one for the model and one for the UI. To use the template, copy the whole structure and systematically rename files and edit file contents to match your group number.
* [tdt4140-gr1800](tdt4140-gr1800/README.md): Example project based on the template, and extended to include a web server module.
# Example project for the TDT4140 course, Spring 2018
This project is an example for Spring 2018, based on the [template project](../tdt4140-gr18nn/README.md). It is meant to illustrate the expected architecture, as well as demonstrate relevant implementation techniques, including project and build configuration and coding and library usage.
This project is about managing sets of geo-locations, like tracks from hiking og training, similar to what you get from apps like Strava. The project includes two systems:
* a JavaFX app for visualising, analysing and editing sets of geo-locations
* web server with a REST API for managing sets of geo-locations, primarily for collecting the geo-locations from apps, but also as persistence layer for the JavaFX app
## Getting startet
### Prerequisites
We develop using **Eclipse**, but other IDEs should also work. You also need **maven**, at least a standalone install, but you should also install maven support in Eclipse, by means of the m2e plugins, which are available in Eclipse's main update site.
We use Java 8 and JavaFX, so both these should be installed. Both JDK 8 and JDK 9 should work.
### Installing
The project uses maven as build system and is accordingly organised as a hierarchical project with a top-level module with several sub-modules. Most IDEs support importing it by point to the top-level module folder, so you should only need to clone the repository and import.
Eclipse will allow you to import using the **Import... > Existing Projects into Workspace** wizard. Make sure to import all sub-module projects (check the box for "nested projects" in the wizard). You should also view it in the **Project Explorer** with **Project Presentation** set to **Hierarchical**.
After importing, you should see the following sub-module projects (contained in the root/aggregator project):
* [fx-map-control](https://github.com/ClemensFischer/FX-Map-Control) (in FxMapControl folder): Copy of project from github, since it is not (yet?) release on maven central.
* [tdt4140.gr1800.app.core](app.core/README.md) (in app.core folder): Common domain classes and persistence support.
* [tdt4140.gr1800.app.ui](app.ui/README.md) (in app.ui folder): JavaFX app.
* [tdt4140.gr1800.web.server](web.server/README.md) (in web.server folder): Web server providing a REST API to domain data.
There is no web client project, yet, since that is outside the scope of the course. We may add this later for completeness, and to illustrate the REST API.
## Running the tests
The sub-modules include both ordinary tests and integration tests, use **mvn test** and **mvn integration-test** for running these. The latter is needed for fully testing the web-server project. Note that both kinds of test will be run with **mvn install**.
## Deployment
We have yet to configure deployment of the JavaFX app and the web server. The former must currently be run from the IDE with **Run as > Java Application**, and the latter using **mvn jetty:run**.
## Built with
* [Jackson](https://github.com/FasterXML/jackson) - [JSON](https://www.json.org) library
* [JPX](https://github.com/jenetics/jpx) - library for importing [GPX](https://en.wikipedia.org/wiki/GPS_Exchange_Format) files
* [geojson-jackson](https://github.com/opendatalab-de/geojson-jackson) - library for [GeoJson](http://geojson.org)
* [HSQLDB](http://www.hsqldb.org) - embedded database with SQL support
* [FX-Map-Control](https://github.com/ClemensFischer/FX-Map-Control)
* [TestFX](https://github.com/TestFX/TestFX) - test framework for JavaFX apps
* [Jetty](https://www.eclipse.org/jetty/) - embedded HTTP server
## Authors
* Hallvard Trætteberg
## License
Not yet decided, probably GPL
# app.core module - domain classes for example project
* [Domain model](doc/domain-model.md)
* [DB-based persistence](doc/db-persistence.md)
* [JSON-based serialization](doc/json-persistence.md)
* [Document storage](doc/document-storage.md)
tdt4140-gr1800/app.core/doc/db-persistence-classes.png

151 KiB

# DB-based persistence of domain data
DB-based persistence is provided by (an implementation of) the **IDbAccess** interface. It includes life-cycle methods corresponding to CRUD operations, so by using these methods, the corresponding DB operations may be performed to keep the DB in sync with the local domain model object structure.
The implementation is split in three:
* **AbstractDbAccessImpl**: Implements the DB-independent logic, i.e. life-cycle of collections of linked domain objects.
* **DbAccessImpl**: Inherits from **AbstractDbAccessImpl** and adds DB logic using SQL.
* **DbAccessHelper**: Helper class for the DB access.
Note that identifiers are not part of the domain model and are handled by the **IdMap** class, which provides a pair of maps from a String identifier to/from domain objects of some type.
A class diagram of the main classes related to db-based persistence is shown below.
<img src="db-persistence-classes.png" alt="DB-based persistence" style="width: 800px;"/>
# Document-based storage of domain data
By *document-based storage* we mean a storage model where a *document* containing domain data is loaded/saved *as a whole*, from/to some explicitly provided *location*. This storage model is typical for document-centric desktop apps with a **File** menu containing actions like **open**, **save**, **save-as** etc. The interfaces and implementation classes described here are designed to support such **File** menu actions. A class diagram of the main classes related to location-based storage is shown below.
* **IDocumentStorage**: An interface with the methods necessary for supporting the standard **File** menu actions. The interface is parameterized with the type used for representing the location to load from or save to. 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.
* **IDocumentImporter**: An interface with a method for importing domain data from a location. The interface is parameterized with the location type. The main use is supporting an **import** action in a **File** menu.
* **IDocumentLoader**: An interface with a method for loading and returning a document (domain data container) from an **InputStream**. The interface is parameterized with the document type. This allows various ways of loading or importing domain data, with different sources and formats.
* **IDocumentSaver**: An interface with a method for saving a document (domain data container) to a location. The interface is parameterized with the document and location types. This allows various ways of saving or exporting domain data, to different locations and formats.
* **IDocumentPersistence**: Combination of **IDocumentLoader** and **IDocumentSaver**.
* **IDocumentStorageListener**: Listener interface for the location of the (current) document of an IDocumentStorage, e.g. when a **save-as** action is performed.
* **IDocumentListener**: Listener interface for the contents of the (current) document of an IDocumentStorage, e.g. when a document is created, opened or imported.
* **AbstractDocumentStorageImpl**: 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.
<img src="location-based-storage.png" alt="Location-based persistence" style="width: 800px;"/>
tdt4140-gr1800/app.core/doc/document-storage.png

87.8 KiB

tdt4140-gr1800/app.core/doc/domain-classes.png

210 KiB

# Domain model for app and REST API
The project is about managing sets of geo-locations, so the domain model includes classes for representing geo-locations, sets of these and owners of such sets. A class diagram of the core model is shown below.
Main types related to geo-locations:
* **LatLong**: Value class representing a geo-location, i.e. latitude, longitude pair. Includes methods for distance calculations.
* **GeoLocated**: Interface for geo-located data, i.e. classes that can return a corresponding **LatLong** object.
* **GeoLocation**: Main implementation of **GeoLocated**. Combines a **LatLong** and *elevation* with generic values like name, description, time (implements **Timed**) and tags (implements **Tagged**).
* **GeoLocations** (unfortunate name): Container for **GeoLocated** objects. Includes a flag indicating of the geo-locations represents a *path* or not. Implements **Timed** and **Tagged**.
* **GeoLocationsOwner**: Container for **GeoLocations** objects. Meant as an abstract class, but is not since it is useful on its own.
* **Person**: Main subclass of **GeoLocationsOwner**. Includes *name* and *email* values.
Generally useful types
* **Timed**: Interface for time-related data, including *date*, *time* of day and time *zone*. The idea is that elements left out are filled in with (default) values from the container.
* **TimedImpl**: Main implementation of **Timed**.
* **Tagged**: Interface for tags, i.e. sets of string labels. Includes methods for checking, getting, setting, adding and removing tags.
* **Tags**: Main implementation of **Tagged**.
* **TimedTaggedImpl**: Implementation of both **Timed** and **Tagged**, among others used as superclass for **GeoLocation** and **GeoLocations**.
<img src="domain-classes.png" alt="Domain classes" style="width: 800px;"/>
# JSON-based persistence of domain data
JSON support is provided by means of the [Jackson library](https://github.com/FasterXML/jackson), and uses its technique for serializing/deserializing domain objects.
......@@ -84,6 +84,29 @@
</execution>
</executions>
</plugin>
<!--
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<id>verify</id>
<phase>verify</phase>
<configuration>
<configLocation>../checkstyle.xml</configLocation>
<failsOnError>false</failsOnError>
<encoding>UTF-8</encoding>
<consoleOutput>true</consoleOutput>
<linkXRef>false</linkXRef>
</configuration>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
-->
</plugins>
</build>
......
......@@ -17,11 +17,11 @@ import tdt4140.gr1800.app.doc.IDocumentLoader;
import tdt4140.gr1800.app.doc.IDocumentPersistence;
import tdt4140.gr1800.app.doc.IDocumentStorage;
import tdt4140.gr1800.app.gpx.GpxDocumentConverter;
import tdt4140.gr1800.app.json.GeoLocationsJsonPersistence;
import tdt4140.gr1800.app.json.GeoLocationsPersistence;
public class App {
private GeoLocationsStreamPersistence geoLocationsPersistence = new GeoLocationsJsonPersistence();
private GeoLocationsStreamPersistence geoLocationsPersistence = new GeoLocationsPersistence();
private Collection<GeoLocations> geoLocations = null;
......
package tdt4140.gr1800.app.core;
/**
* Interface for geo-located data, i.e. classes that can return a corresponding LatLong object.
* @author hal
*
*/
public interface GeoLocated {
/**
* @return the corresponding LatLong object
*/
public LatLong getLatLong();
/**
* @return the corresponding latitude
*/
default double getLatitude() {
return getLatLong().latitude;
}
/**
* @return the corresponding longitude
*/
default double getLongitude() {
return getLatLong().longitude;
}
default boolean equalsLatLong(GeoLocated geoLoc) {
/**
* Checks that the latitudes and longitudes are the same
* @param geoLoc
* @return true if the latitudes and longitudes are the same, false otherwise
*/
default boolean equalsLatLong(final GeoLocated geoLoc) {
return getLatitude() == geoLoc.getLatitude() && getLongitude() == geoLoc.getLongitude();
}
default double distance(GeoLocated geoLoc) {
/**
* @param geoLoc
* @return the distance between the LatLong of this GeoLocated and the one provided
*/
default double distance(final GeoLocated geoLoc) {
return getLatLong().distance(geoLoc.getLatLong());
}
}
package tdt4140.gr1800.app.core;
/**
* Main implementation of GeoLocated. Combines a LatLong and elevation with generic values
* like name, description, time (implements Timed) and tags (implements Tagged).
* @author hal
*
*/
public class GeoLocation extends TimedTaggedImpl implements GeoLocated, Timed, Tagged {
private LatLong latLong;
@Override
public LatLong getLatLong() {
return latLong;
}
public void setLatLong(LatLong latLong) {
public void setLatLong(final LatLong latLong) {
this.latLong = latLong;
}
......@@ -18,13 +25,17 @@ public class GeoLocation extends TimedTaggedImpl implements GeoLocated, Timed, T
return elevation;
}
public void setElevation(final int elevation) {
this.elevation = elevation;
}
private String name, description;
public String getName() {
return name;
}
public void setName(String name) {
public void setName(final String name) {
this.name = name;
}
......@@ -32,7 +43,7 @@ public class GeoLocation extends TimedTaggedImpl implements GeoLocated, Timed, T
return description;
}
public void setDescription(String description) {
public void setDescription(final String description) {
this.description = description;
}
}
......@@ -3,24 +3,31 @@ 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 {
public class Tags implements Tagged, Iterable<String> {
private Collection<String> tags = null;
public Tags(String... tags) {
@Override
public Iterator<String> iterator() {
return (tags != null ? tags.iterator() : Collections.<String>emptyList().iterator());
}
public Tags(final String... tags) {
setTags(tags);
}
public Tags(Tagged tags) {
public Tags(final Tagged tags) {
setTags(tags.getTags());
}
public static Tags valueOf(String tags) {
public static Tags valueOf(final String tags) {
return valueOf(tags, ",");
}
public static Tags valueOf(String tags, String separator) {
public static Tags valueOf(final String tags, final String separator) {
return new Tags(tags.split(separator));
}
......@@ -29,7 +36,7 @@ public class Tags implements Tagged {
}
@Override
public boolean hasTags(String... tags) {
public boolean hasTags(final String... tags) {
return (tags.length == 0 || (this.tags != null && this.tags.containsAll(Arrays.asList(tags))));
}
......@@ -41,11 +48,11 @@ public class Tags implements Tagged {
}
@Override
public String getTags(String prefix, String separator, String suffix) {
StringBuilder buffer = new StringBuilder();
public String getTags(final String prefix, final String separator, final String suffix) {
final StringBuilder buffer = new StringBuilder();
append(buffer, prefix);
int tagNum = 0;
for (String tag : tags) {
for (final String tag : tags) {
if (tagNum > 0 && separator != null) {
buffer.append(separator);
}
......@@ -56,7 +63,7 @@ public class Tags implements Tagged {
return buffer.toString();
}
static StringBuilder append(StringBuilder buffer, String s) {
static StringBuilder append(final StringBuilder buffer, final String s) {
if (s != null) {
buffer.append(s);
}
......@@ -64,12 +71,13 @@ public class Tags implements Tagged {
}
@Override
public void setTags(String... tags) {
public void setTags(final String... tags) {
this.tags = new ArrayList<>();
addTags(tags);
}
public void addTags(String... tags) {
@Override
public void addTags(final String... tags) {
if (this.tags == null && tags != null && tags.length > 0) {
this.tags = new ArrayList<>();
}
......@@ -80,7 +88,8 @@ public class Tags implements Tagged {
}
}
public void removeTags(String... tags) {
@Override
public void removeTags(final String... tags) {
if (this.tags != null) {
this.tags.removeAll(Arrays.asList(tags));
}
......
......@@ -7,26 +7,26 @@ public class TimedTaggedImpl extends TimedImpl implements Tagged {
public TimedTaggedImpl() {
}
public TimedTaggedImpl(Tagged tags) {
public TimedTaggedImpl(final Tagged tags) {
setTags(tags.getTags());
}
private static TimedTaggedImpl valueOf(Tags tags) {
TimedTaggedImpl timedTags = new TimedTaggedImpl();
private static TimedTaggedImpl valueOf(final Tags tags) {
final TimedTaggedImpl timedTags = new TimedTaggedImpl();
timedTags.tags = tags;
return timedTags;
}
public static TimedTaggedImpl valueOf(String tags) {
public static TimedTaggedImpl valueOf(final String tags) {
return valueOf(Tags.valueOf(tags));
}
public static TimedTaggedImpl valueOf(String tags, String separator) {
public static TimedTaggedImpl valueOf(final String tags, final String separator) {
return valueOf(Tags.valueOf(tags, separator));
}
@Override
public boolean hasTags(String... tags) {
public boolean hasTags(final String... tags) {
return this.tags != null && this.tags.hasTags(tags);
}
......@@ -36,23 +36,25 @@ public class TimedTaggedImpl extends TimedImpl implements Tagged {
}
@Override
public String getTags(String prefix, String separator, String suffix) {
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(String... tags) {
public void setTags(final String... tags) {
this.tags = (tags != null && tags.length > 0 ? new Tags(tags) : null);
}
public void addTags(String... tags) {
@Override
public void addTags(final String... tags) {
if (this.tags == null) {
this.tags = new Tags();
}
this.tags.addTags(tags);
}
public void removeTags(String... tags) {
@Override
public void removeTags(final String... tags) {
if (this.tags != null) {
this.tags.removeTags(tags);
if (this.tags.getTagCount() == 0) {
......
......@@ -15,53 +15,61 @@ public abstract class AbstractDbAccessImpl implements IDbAccess {
protected IdMap<GeoLocations> geoLocationsIds = new IdMap<GeoLocations>();
protected IdMap<GeoLocation> geoLocationIds = new IdMap<GeoLocation>();
public int getId(Person person) {
public IdProvider<Person> getPersonIdProvider() {
return personIds;
}
public int getId(final Person person) {
return personIds.getId(person);
}
public int getId(GeoLocations geoLocations) {
public int getId(final GeoLocations geoLocations) {
return geoLocationsIds.getId(geoLocations);
}
public int getId(GeoLocation geoLocation) {
public int getId(final GeoLocation geoLocation) {
return geoLocationIds.getId(geoLocation);
}
@Override
public Person createPerson(String name, String email) {
Person person = new Person();
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(Person owner) {
GeoLocations geoLocations = new GeoLocations(owner);
public GeoLocations createGeoLocations(final Person owner) {
final 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;
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(boolean refresh) {
public Collection<Person> getAllPersons(final boolean refresh) {
return new ArrayList<Person>(personIds.get());
}
@Override
public Person getPerson(int id, boolean refresh) {
Person person = personIds.get(id);
public Person getPerson(final int id, final boolean refresh) {
final Person person = personIds.get(id);
return person;
}
@Override
public Person getPersonByName(String name, boolean refresh) {
for (Person person : personIds.get()) {
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;
}
......@@ -70,8 +78,8 @@ public abstract class AbstractDbAccessImpl implements IDbAccess {
}
@Override
public Person getPersonByEmail(String email, boolean refresh) {
for (Person person : personIds.get()) {
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;
}
......@@ -80,41 +88,23 @@ public abstract class AbstractDbAccessImpl implements IDbAccess {
}
@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
public Collection<GeoLocations> getGeoLocations(final Person owner, final boolean refresh) {
return owner.getGeoLocations((String[]) null);
}
@Override
public void deletePerson(Person person) {
public void deletePerson(final Person person) {
personIds.remove(person);
}
@Override
public void deleteGeoLocations(GeoLocations geoLocations) {
public void deleteGeoLocations(final GeoLocations geoLocations) {
geoLocations.getOwner().removeGeolocations(geoLocations);
geoLocationsIds.remove(geoLocations);
}
@Override
public void deleteGeoLocation(GeoLocations geoLocations, GeoLocation geoLocation) {
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.SQLType;
import java.sql.Statement;
import java.sql.Time;
import java.sql.Types;
import java.time.LocalDate;
import java.time.LocalTime;
public class DbAccessHelper {
......@@ -64,18 +67,7 @@ public class DbAccessHelper {
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);
}
setStatementArgument(preparedStatement, args[argNum - 1], null, argNum);
}
} catch (SQLException e) {
throwException(e);
......@@ -83,6 +75,30 @@ public class DbAccessHelper {
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);
......