diff --git a/challenger/src/main/java/uk/co/compendiumdev/challenge/ChallengeMain.java b/challenger/src/main/java/uk/co/compendiumdev/challenge/ChallengeMain.java
index 544debd7..da97aa03 100644
--- a/challenger/src/main/java/uk/co/compendiumdev/challenge/ChallengeMain.java
+++ b/challenger/src/main/java/uk/co/compendiumdev/challenge/ChallengeMain.java
@@ -5,8 +5,8 @@
import uk.co.compendiumdev.challenge.apimodel.ChallengeApiModel;
import uk.co.compendiumdev.challenge.challengers.Challengers;
import uk.co.compendiumdev.thingifier.Thingifier;
-import uk.co.compendiumdev.thingifier.adapter.http.ThingifierHttpApiRoutings;
import uk.co.compendiumdev.thingifier.adapter.spark.MainImplementation;
+import uk.co.compendiumdev.thingifier.adapter.spark.ThingifierHttpApiRoutings;
import uk.co.compendiumdev.thingifier.core.repository.ThingStoreProviderConfig;
public class ChallengeMain {
diff --git a/challenger/src/main/java/uk/co/compendiumdev/challenge/ChallengeRouteHandler.java b/challenger/src/main/java/uk/co/compendiumdev/challenge/ChallengeRouteHandler.java
index 1f092b0b..dd86ddb1 100644
--- a/challenger/src/main/java/uk/co/compendiumdev/challenge/ChallengeRouteHandler.java
+++ b/challenger/src/main/java/uk/co/compendiumdev/challenge/ChallengeRouteHandler.java
@@ -10,7 +10,7 @@
import uk.co.compendiumdev.challenge.practicemodes.simpleapi.SimpleApiRoutes;
import uk.co.compendiumdev.challenge.practicemodes.simulation.SimulationRoutes;
import uk.co.compendiumdev.thingifier.Thingifier;
-import uk.co.compendiumdev.thingifier.adapter.http.ThingifierHttpApiRoutings;
+import uk.co.compendiumdev.thingifier.adapter.spark.ThingifierHttpApiRoutings;
import uk.co.compendiumdev.thingifier.api.docgen.ThingifierApiDocumentationDefn;
import uk.co.compendiumdev.thingifier.htmlgui.htmlgen.DefaultGUIHTML;
diff --git a/challenger/src/main/java/uk/co/compendiumdev/challenge/challengesrouting/AuthRoutes.java b/challenger/src/main/java/uk/co/compendiumdev/challenge/challengesrouting/AuthRoutes.java
index a8e396a4..350009cd 100644
--- a/challenger/src/main/java/uk/co/compendiumdev/challenge/challengesrouting/AuthRoutes.java
+++ b/challenger/src/main/java/uk/co/compendiumdev/challenge/challengesrouting/AuthRoutes.java
@@ -10,8 +10,9 @@
import uk.co.compendiumdev.thingifier.adapter.internalhttp.InternalHttpRequest;
import uk.co.compendiumdev.thingifier.adapter.internalhttp.conversion.HttpApiResponseToInternalHttpResponse;
import uk.co.compendiumdev.thingifier.adapter.internalhttp.conversion.InternalHttpRequestToHttpApiRequest;
-import uk.co.compendiumdev.thingifier.adapter.internalhttp.conversion.InternalHttpResponseToSpark;
-import uk.co.compendiumdev.thingifier.adapter.internalhttp.conversion.SparkToInternalHttpRequest;
+import uk.co.compendiumdev.thingifier.adapter.spark.SimpleSparkRouteCreator;
+import uk.co.compendiumdev.thingifier.adapter.spark.conversion.InternalHttpResponseToSpark;
+import uk.co.compendiumdev.thingifier.adapter.spark.conversion.SparkToInternalHttpRequest;
import uk.co.compendiumdev.thingifier.api.docgen.RoutingDefinition;
import uk.co.compendiumdev.thingifier.api.docgen.RoutingStatus;
import uk.co.compendiumdev.thingifier.api.docgen.RoutingVerb;
@@ -33,7 +34,6 @@
import uk.co.compendiumdev.thingifier.core.domain.instances.EntityInstanceDraft;
import uk.co.compendiumdev.thingifier.core.domain.instances.validation.EntityInstanceStateValidator;
import uk.co.compendiumdev.thingifier.core.reporting.ValidationReport;
-import uk.co.compendiumdev.thingifier.spark.SimpleSparkRouteCreator;
// TODO: This should be using a Thingifier to do the work of XML JSON etc... like the simulation
public class AuthRoutes {
diff --git a/challenger/src/main/java/uk/co/compendiumdev/challenge/challengesrouting/ChallengerTrackingRoutes.java b/challenger/src/main/java/uk/co/compendiumdev/challenge/challengesrouting/ChallengerTrackingRoutes.java
index da7c73d3..8e5aaeb3 100644
--- a/challenger/src/main/java/uk/co/compendiumdev/challenge/challengesrouting/ChallengerTrackingRoutes.java
+++ b/challenger/src/main/java/uk/co/compendiumdev/challenge/challengesrouting/ChallengerTrackingRoutes.java
@@ -10,12 +10,12 @@
import uk.co.compendiumdev.challenge.challenges.ChallengeDefinitions;
import uk.co.compendiumdev.challenge.persistence.PersistenceLayer;
import uk.co.compendiumdev.thingifier.Thingifier;
+import uk.co.compendiumdev.thingifier.adapter.spark.SimpleSparkRouteCreator;
import uk.co.compendiumdev.thingifier.api.docgen.*;
import uk.co.compendiumdev.thingifier.api.response.ApiResponseAsJson;
import uk.co.compendiumdev.thingifier.api.response.ApiResponseError;
import uk.co.compendiumdev.thingifier.core.domain.definitions.field.definition.Field;
import uk.co.compendiumdev.thingifier.core.domain.definitions.field.definition.FieldType;
-import uk.co.compendiumdev.thingifier.spark.SimpleSparkRouteCreator;
public class ChallengerTrackingRoutes {
diff --git a/challenger/src/main/java/uk/co/compendiumdev/challenge/challengesrouting/ChallengesRoutes.java b/challenger/src/main/java/uk/co/compendiumdev/challenge/challengesrouting/ChallengesRoutes.java
index 2fd649cf..6a455576 100644
--- a/challenger/src/main/java/uk/co/compendiumdev/challenge/challengesrouting/ChallengesRoutes.java
+++ b/challenger/src/main/java/uk/co/compendiumdev/challenge/challengesrouting/ChallengesRoutes.java
@@ -7,8 +7,9 @@
import uk.co.compendiumdev.challenge.apimodel.ChallengeThingifier;
import uk.co.compendiumdev.challenge.challengers.Challengers;
import uk.co.compendiumdev.challenge.challenges.ChallengeDefinitions;
-import uk.co.compendiumdev.thingifier.adapter.http.routehandlers.SparkApiRequestResponseHandler;
import uk.co.compendiumdev.thingifier.adapter.spark.AdhocDocumentedSparkRouteConfigurer;
+import uk.co.compendiumdev.thingifier.adapter.spark.SimpleSparkRouteCreator;
+import uk.co.compendiumdev.thingifier.adapter.spark.routehandlers.SparkApiRequestResponseHandler;
import uk.co.compendiumdev.thingifier.api.docgen.RoutingDefinition;
import uk.co.compendiumdev.thingifier.api.docgen.RoutingStatus;
import uk.co.compendiumdev.thingifier.api.docgen.RoutingVerb;
@@ -17,7 +18,6 @@
import uk.co.compendiumdev.thingifier.core.domain.definitions.EntityDefinition;
import uk.co.compendiumdev.thingifier.core.query.FilterBy;
import uk.co.compendiumdev.thingifier.core.query.QueryFilterParams;
-import uk.co.compendiumdev.thingifier.spark.SimpleSparkRouteCreator;
public class ChallengesRoutes {
diff --git a/challenger/src/main/java/uk/co/compendiumdev/challenge/challengesrouting/HeartBeatRoutes.java b/challenger/src/main/java/uk/co/compendiumdev/challenge/challengesrouting/HeartBeatRoutes.java
index 4f7c0f9f..42a31d16 100644
--- a/challenger/src/main/java/uk/co/compendiumdev/challenge/challengesrouting/HeartBeatRoutes.java
+++ b/challenger/src/main/java/uk/co/compendiumdev/challenge/challengesrouting/HeartBeatRoutes.java
@@ -2,9 +2,9 @@
import java.util.List;
import uk.co.compendiumdev.thingifier.adapter.spark.AdhocDocumentedSparkRouteConfigurer;
+import uk.co.compendiumdev.thingifier.adapter.spark.SimpleSparkRouteCreator;
import uk.co.compendiumdev.thingifier.api.docgen.RoutingVerb;
import uk.co.compendiumdev.thingifier.api.docgen.ThingifierApiDocumentationDefn;
-import uk.co.compendiumdev.thingifier.spark.SimpleSparkRouteCreator;
public class HeartBeatRoutes {
diff --git a/challenger/src/main/java/uk/co/compendiumdev/challenge/practicemodes/mirror/MirrorRoutes.java b/challenger/src/main/java/uk/co/compendiumdev/challenge/practicemodes/mirror/MirrorRoutes.java
index f241fc45..da33d30f 100644
--- a/challenger/src/main/java/uk/co/compendiumdev/challenge/practicemodes/mirror/MirrorRoutes.java
+++ b/challenger/src/main/java/uk/co/compendiumdev/challenge/practicemodes/mirror/MirrorRoutes.java
@@ -6,12 +6,12 @@
import java.util.List;
import spark.Route;
import uk.co.compendiumdev.thingifier.Thingifier;
-import uk.co.compendiumdev.thingifier.adapter.http.ThingifierAutoDocGenRouting;
import uk.co.compendiumdev.thingifier.adapter.spark.AdhocDocumentedSparkRouteConfigurer;
+import uk.co.compendiumdev.thingifier.adapter.spark.SimpleSparkRouteCreator;
+import uk.co.compendiumdev.thingifier.adapter.spark.ThingifierAutoDocGenRouting;
import uk.co.compendiumdev.thingifier.api.docgen.RoutingVerb;
import uk.co.compendiumdev.thingifier.api.docgen.ThingifierApiDocumentationDefn;
import uk.co.compendiumdev.thingifier.htmlgui.htmlgen.DefaultGUIHTML;
-import uk.co.compendiumdev.thingifier.spark.SimpleSparkRouteCreator;
/*
Create a set of custom end points that do not use a thingifier, but
diff --git a/challenger/src/main/java/uk/co/compendiumdev/challenge/practicemodes/mirror/RequestMirror.java b/challenger/src/main/java/uk/co/compendiumdev/challenge/practicemodes/mirror/RequestMirror.java
index 4668fc5d..7703a1a7 100644
--- a/challenger/src/main/java/uk/co/compendiumdev/challenge/practicemodes/mirror/RequestMirror.java
+++ b/challenger/src/main/java/uk/co/compendiumdev/challenge/practicemodes/mirror/RequestMirror.java
@@ -4,7 +4,7 @@
import spark.Response;
import uk.co.compendiumdev.challenge.spark.SparkMessageLengthValidator;
import uk.co.compendiumdev.thingifier.Thingifier;
-import uk.co.compendiumdev.thingifier.adapter.http.routehandlers.SparkApiRequestResponseHandler;
+import uk.co.compendiumdev.thingifier.adapter.spark.routehandlers.SparkApiRequestResponseHandler;
import uk.co.compendiumdev.thingifier.api.http.headers.headerparser.AcceptHeaderParser;
import uk.co.compendiumdev.thingifier.core.domain.definitions.EntityDefinition;
import uk.co.compendiumdev.thingifier.core.domain.definitions.field.definition.Field;
diff --git a/challenger/src/main/java/uk/co/compendiumdev/challenge/practicemodes/simpleapi/SimpleApiRoutes.java b/challenger/src/main/java/uk/co/compendiumdev/challenge/practicemodes/simpleapi/SimpleApiRoutes.java
index c1d1f3e1..6d9906dc 100644
--- a/challenger/src/main/java/uk/co/compendiumdev/challenge/practicemodes/simpleapi/SimpleApiRoutes.java
+++ b/challenger/src/main/java/uk/co/compendiumdev/challenge/practicemodes/simpleapi/SimpleApiRoutes.java
@@ -4,8 +4,9 @@
import java.util.List;
import uk.co.compendiumdev.thingifier.Thingifier;
-import uk.co.compendiumdev.thingifier.adapter.http.ThingifierAutoDocGenRouting;
-import uk.co.compendiumdev.thingifier.adapter.http.ThingifierHttpApiRoutings;
+import uk.co.compendiumdev.thingifier.adapter.spark.SimpleSparkRouteCreator;
+import uk.co.compendiumdev.thingifier.adapter.spark.ThingifierAutoDocGenRouting;
+import uk.co.compendiumdev.thingifier.adapter.spark.ThingifierHttpApiRoutings;
import uk.co.compendiumdev.thingifier.api.docgen.RoutingDefinition;
import uk.co.compendiumdev.thingifier.api.docgen.RoutingStatus;
import uk.co.compendiumdev.thingifier.api.docgen.RoutingVerb;
@@ -19,7 +20,6 @@
import uk.co.compendiumdev.thingifier.core.domain.definitions.validation.MaximumLengthValidationRule;
import uk.co.compendiumdev.thingifier.htmlgui.htmlgen.DefaultGUIHTML;
import uk.co.compendiumdev.thingifier.htmlgui.routing.DefaultGuiRoutings;
-import uk.co.compendiumdev.thingifier.spark.SimpleSparkRouteCreator;
/*
The simple API is a no-auth API where anyone can amend, create, delete items.
diff --git a/challenger/src/main/java/uk/co/compendiumdev/challenge/practicemodes/simulation/SimulationRoutes.java b/challenger/src/main/java/uk/co/compendiumdev/challenge/practicemodes/simulation/SimulationRoutes.java
index 76c5195d..71c2522d 100644
--- a/challenger/src/main/java/uk/co/compendiumdev/challenge/practicemodes/simulation/SimulationRoutes.java
+++ b/challenger/src/main/java/uk/co/compendiumdev/challenge/practicemodes/simulation/SimulationRoutes.java
@@ -5,9 +5,10 @@
import java.util.List;
import uk.co.compendiumdev.challenge.ChallengerConfig;
import uk.co.compendiumdev.thingifier.Thingifier;
-import uk.co.compendiumdev.thingifier.adapter.http.ThingifierAutoDocGenRouting;
import uk.co.compendiumdev.thingifier.adapter.http.routehandlers.HttpApiRequestHandler;
-import uk.co.compendiumdev.thingifier.adapter.http.routehandlers.SparkApiRequestResponseHandler;
+import uk.co.compendiumdev.thingifier.adapter.spark.SimpleSparkRouteCreator;
+import uk.co.compendiumdev.thingifier.adapter.spark.ThingifierAutoDocGenRouting;
+import uk.co.compendiumdev.thingifier.adapter.spark.routehandlers.SparkApiRequestResponseHandler;
import uk.co.compendiumdev.thingifier.api.docgen.ThingifierApiDocumentationDefn;
import uk.co.compendiumdev.thingifier.api.http.HttpApiRequest;
import uk.co.compendiumdev.thingifier.api.response.ApiResponse;
@@ -26,7 +27,6 @@
import uk.co.compendiumdev.thingifier.core.repository.ThingStore;
import uk.co.compendiumdev.thingifier.core.repository.ThingStoreProviderConfig;
import uk.co.compendiumdev.thingifier.htmlgui.htmlgen.DefaultGUIHTML;
-import uk.co.compendiumdev.thingifier.spark.SimpleSparkRouteCreator;
public class SimulationRoutes {
diff --git a/challenger/src/main/java/uk/co/compendiumdev/challenge/spark/SparkMessageLengthValidator.java b/challenger/src/main/java/uk/co/compendiumdev/challenge/spark/SparkMessageLengthValidator.java
index 23a403c1..8a4e8fdc 100644
--- a/challenger/src/main/java/uk/co/compendiumdev/challenge/spark/SparkMessageLengthValidator.java
+++ b/challenger/src/main/java/uk/co/compendiumdev/challenge/spark/SparkMessageLengthValidator.java
@@ -5,8 +5,8 @@
import uk.co.compendiumdev.thingifier.adapter.internalhttp.InternalHttpRequest;
import uk.co.compendiumdev.thingifier.adapter.internalhttp.conversion.HttpApiResponseToInternalHttpResponse;
import uk.co.compendiumdev.thingifier.adapter.internalhttp.conversion.InternalHttpRequestToHttpApiRequest;
-import uk.co.compendiumdev.thingifier.adapter.internalhttp.conversion.InternalHttpResponseToSpark;
-import uk.co.compendiumdev.thingifier.adapter.internalhttp.conversion.SparkToInternalHttpRequest;
+import uk.co.compendiumdev.thingifier.adapter.spark.conversion.InternalHttpResponseToSpark;
+import uk.co.compendiumdev.thingifier.adapter.spark.conversion.SparkToInternalHttpRequest;
import uk.co.compendiumdev.thingifier.api.ermodelconversion.JsonThing;
import uk.co.compendiumdev.thingifier.api.http.HttpApiRequest;
import uk.co.compendiumdev.thingifier.api.http.HttpApiResponse;
diff --git a/challengerAuto/src/test/java/uk/co/compendiumdev/challenger/restassured/_11_accept_challenges/C030GetTodosNotAcceptableHeader406Test.java b/challengerAuto/src/test/java/uk/co/compendiumdev/challenger/restassured/_11_accept_challenges/C030GetTodosNotAcceptableHeader406Test.java
index 91549b06..6a13d103 100644
--- a/challengerAuto/src/test/java/uk/co/compendiumdev/challenger/restassured/_11_accept_challenges/C030GetTodosNotAcceptableHeader406Test.java
+++ b/challengerAuto/src/test/java/uk/co/compendiumdev/challenger/restassured/_11_accept_challenges/C030GetTodosNotAcceptableHeader406Test.java
@@ -2,7 +2,6 @@
import io.restassured.RestAssured;
import io.restassured.http.ContentType;
-import io.restassured.response.Response;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import uk.co.compendiumdev.challenger.restassured.api.ChallengesStatus;
@@ -13,16 +12,13 @@ public class C030GetTodosNotAcceptableHeader406Test extends RestAssuredBaseTest
@Test
void canGet406WhenUnsupportedAcceptHeaderSent() {
- final Response response =
- RestAssured.given()
- .header("X-CHALLENGER", xChallenger)
- .accept("application/gzip")
- .get(apiPath("/todos"))
- .then()
- .statusCode(406)
- .contentType(ContentType.JSON)
- .extract()
- .response();
+ RestAssured.given()
+ .header("X-CHALLENGER", xChallenger)
+ .accept("application/gzip")
+ .get(apiPath("/todos"))
+ .then()
+ .statusCode(406)
+ .contentType(ContentType.JSON);
ChallengesStatus statuses = new ChallengesStatus();
statuses.get();
diff --git a/challengerAuto/src/test/java/uk/co/compendiumdev/challenger/restassured/_13_restore_session_challenges/C035PutRestoreChallengerSessionTest.java b/challengerAuto/src/test/java/uk/co/compendiumdev/challenger/restassured/_13_restore_session_challenges/C035PutRestoreChallengerSessionTest.java
index b97dc30b..697f8c19 100644
--- a/challengerAuto/src/test/java/uk/co/compendiumdev/challenger/restassured/_13_restore_session_challenges/C035PutRestoreChallengerSessionTest.java
+++ b/challengerAuto/src/test/java/uk/co/compendiumdev/challenger/restassured/_13_restore_session_challenges/C035PutRestoreChallengerSessionTest.java
@@ -80,18 +80,14 @@ public void canPutChallengerSessionToReset() {
challengerResponse.challengeStatus.CREATE_NEW_CHALLENGER = true;
- nResponse =
- RestAssured.given()
- .header("X-CHALLENGER", xChallenger)
- .accept("application/json")
- .body(challengerResponse)
- .put(apiPath("/challenger/" + xChallenger))
- .then()
- .statusCode(200)
- . // updated existing
- contentType(ContentType.JSON)
- .and()
- .extract()
- .response();
+ RestAssured.given()
+ .header("X-CHALLENGER", xChallenger)
+ .accept("application/json")
+ .body(challengerResponse)
+ .put(apiPath("/challenger/" + xChallenger))
+ .then()
+ .statusCode(200)
+ . // updated existing
+ contentType(ContentType.JSON);
}
}
diff --git a/challengerAuto/src/test/java/uk/co/compendiumdev/challenger/restassured/_13_restore_session_challenges/C038PutRestoreChallengerTodosTest.java b/challengerAuto/src/test/java/uk/co/compendiumdev/challenger/restassured/_13_restore_session_challenges/C038PutRestoreChallengerTodosTest.java
index 62e7ae04..e40754d3 100644
--- a/challengerAuto/src/test/java/uk/co/compendiumdev/challenger/restassured/_13_restore_session_challenges/C038PutRestoreChallengerTodosTest.java
+++ b/challengerAuto/src/test/java/uk/co/compendiumdev/challenger/restassured/_13_restore_session_challenges/C038PutRestoreChallengerTodosTest.java
@@ -18,18 +18,13 @@ public void canGetAllTodosAndPutTodosToRestore() {
Assertions.assertNotNull(xChallenger);
Assertions.assertTrue(xChallenger.length() > 5);
- Todos todosResponse =
- RestAssured.given()
- .header("X-CHALLENGER", xChallenger)
- .accept("application/json")
- .get(apiPath("/challenger/database/" + xChallenger))
- .then()
- .statusCode(200)
- .contentType(ContentType.JSON)
- .and()
- .extract()
- .response()
- .as(Todos.class);
+ RestAssured.given()
+ .header("X-CHALLENGER", xChallenger)
+ .accept("application/json")
+ .get(apiPath("/challenger/database/" + xChallenger))
+ .then()
+ .statusCode(200)
+ .contentType(ContentType.JSON);
ChallengesStatus statuses = new ChallengesStatus();
statuses.get();
diff --git a/checkstyle-project-fqn.xml b/checkstyle-project-fqn.xml
index 35b0fbd9..001e0e7a 100644
--- a/checkstyle-project-fqn.xml
+++ b/checkstyle-project-fqn.xml
@@ -68,7 +68,136 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ercoremodel/src/main/java/uk/co/compendiumdev/thingifier/core/repository/ThingStore.java b/ercoremodel/src/main/java/uk/co/compendiumdev/thingifier/core/repository/ThingStore.java
index d4290ed8..da42cc04 100644
--- a/ercoremodel/src/main/java/uk/co/compendiumdev/thingifier/core/repository/ThingStore.java
+++ b/ercoremodel/src/main/java/uk/co/compendiumdev/thingifier/core/repository/ThingStore.java
@@ -12,6 +12,8 @@ public interface ThingStore extends AutoCloseable {
RepositoryAdministration administration();
+ ThingStoreTransaction beginTransaction();
+
@Override
default void close() {
// Most store implementations do not own closeable resources.
diff --git a/ercoremodel/src/main/java/uk/co/compendiumdev/thingifier/core/repository/ThingStoreTransaction.java b/ercoremodel/src/main/java/uk/co/compendiumdev/thingifier/core/repository/ThingStoreTransaction.java
new file mode 100644
index 00000000..2382fb55
--- /dev/null
+++ b/ercoremodel/src/main/java/uk/co/compendiumdev/thingifier/core/repository/ThingStoreTransaction.java
@@ -0,0 +1,11 @@
+package uk.co.compendiumdev.thingifier.core.repository;
+
+public interface ThingStoreTransaction extends AutoCloseable {
+
+ void commit();
+
+ void rollback();
+
+ @Override
+ void close();
+}
diff --git a/ercoremodel/src/main/java/uk/co/compendiumdev/thingifier/core/repository/inmemory/InMemoryEntityInstanceCollection.java b/ercoremodel/src/main/java/uk/co/compendiumdev/thingifier/core/repository/inmemory/InMemoryEntityInstanceCollection.java
index 587b34d0..34d1e564 100644
--- a/ercoremodel/src/main/java/uk/co/compendiumdev/thingifier/core/repository/inmemory/InMemoryEntityInstanceCollection.java
+++ b/ercoremodel/src/main/java/uk/co/compendiumdev/thingifier/core/repository/inmemory/InMemoryEntityInstanceCollection.java
@@ -282,6 +282,27 @@ public Map getCounters() {
return counters;
}
+ Snapshot snapshot() {
+ Map counterValues = new HashMap<>();
+ ensureCountersInitialized();
+ for (Map.Entry counter : counters.entrySet()) {
+ counterValues.put(counter.getKey(), counter.getValue().peekNextValue());
+ }
+ return new Snapshot(definition, new ArrayList<>(instances.values()), counterValues);
+ }
+
+ void restore(final Snapshot snapshot) {
+ instances.clear();
+ for (EntityInstance instance : snapshot.instances) {
+ instances.put(instance.getInternalId(), instance);
+ }
+
+ counters.clear();
+ for (Map.Entry counter : snapshot.counterValues.entrySet()) {
+ counters.put(counter.getKey(), new AutoIncrement(counter.getKey(), counter.getValue()));
+ }
+ }
+
public ValidationReport checkFieldsForUniqueNess(EntityInstance instance, boolean isAmendment) {
ValidationReport report = new ValidationReport();
@@ -319,4 +340,20 @@ public ValidationReport checkFieldsForUniqueNess(EntityInstance instance, boolea
return report;
}
+
+ static final class Snapshot {
+
+ final EntityDefinition definition;
+ private final List instances;
+ private final Map counterValues;
+
+ private Snapshot(
+ final EntityDefinition definition,
+ final List instances,
+ final Map counterValues) {
+ this.definition = definition;
+ this.instances = instances;
+ this.counterValues = counterValues;
+ }
+ }
}
diff --git a/ercoremodel/src/main/java/uk/co/compendiumdev/thingifier/core/repository/inmemory/InMemoryEntityInstanceStore.java b/ercoremodel/src/main/java/uk/co/compendiumdev/thingifier/core/repository/inmemory/InMemoryEntityInstanceStore.java
index d24dad67..5f42726e 100644
--- a/ercoremodel/src/main/java/uk/co/compendiumdev/thingifier/core/repository/inmemory/InMemoryEntityInstanceStore.java
+++ b/ercoremodel/src/main/java/uk/co/compendiumdev/thingifier/core/repository/inmemory/InMemoryEntityInstanceStore.java
@@ -2,6 +2,7 @@
import java.util.ArrayList;
import java.util.List;
+import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import uk.co.compendiumdev.thingifier.core.domain.definitions.ERSchema;
import uk.co.compendiumdev.thingifier.core.domain.definitions.EntityDefinition;
@@ -96,4 +97,37 @@ void clearInstanceDataFor(String instanceName) {
deleteEntityInstance(instance);
}
}
+
+ Snapshot snapshot() {
+ ConcurrentHashMap snapshots =
+ new ConcurrentHashMap<>();
+ for (Map.Entry collection :
+ instanceCollections.entrySet()) {
+ snapshots.put(collection.getKey(), collection.getValue().snapshot());
+ }
+ return new Snapshot(snapshots);
+ }
+
+ void restore(final Snapshot snapshot) {
+ instanceCollections.clear();
+ for (Map.Entry entry :
+ snapshot.collections.entrySet()) {
+ InMemoryEntityInstanceCollection collection =
+ new InMemoryEntityInstanceCollection(entry.getValue().definition);
+ collection.restore(entry.getValue());
+ instanceCollections.put(entry.getKey(), collection);
+ }
+ }
+
+ static final class Snapshot {
+
+ private final ConcurrentHashMap
+ collections;
+
+ private Snapshot(
+ final ConcurrentHashMap
+ collections) {
+ this.collections = collections;
+ }
+ }
}
diff --git a/ercoremodel/src/main/java/uk/co/compendiumdev/thingifier/core/repository/inmemory/InMemoryRelationshipStore.java b/ercoremodel/src/main/java/uk/co/compendiumdev/thingifier/core/repository/inmemory/InMemoryRelationshipStore.java
index f1763ae4..a3094234 100644
--- a/ercoremodel/src/main/java/uk/co/compendiumdev/thingifier/core/repository/inmemory/InMemoryRelationshipStore.java
+++ b/ercoremodel/src/main/java/uk/co/compendiumdev/thingifier/core/repository/inmemory/InMemoryRelationshipStore.java
@@ -126,6 +126,15 @@ void clear() {
rows.clear();
}
+ Snapshot snapshot() {
+ return new Snapshot(new LinkedHashMap<>(rows));
+ }
+
+ void restore(final Snapshot snapshot) {
+ rows.clear();
+ rows.putAll(snapshot.rows);
+ }
+
private List rowsInvolving(final EntityInstance instance) {
List involving = new ArrayList<>();
for (RelationshipRow row : rows.values()) {
@@ -170,4 +179,13 @@ private String rowKey(
+ "|"
+ toInternalId;
}
+
+ static final class Snapshot {
+
+ private final Map rows;
+
+ private Snapshot(final Map rows) {
+ this.rows = rows;
+ }
+ }
}
diff --git a/ercoremodel/src/main/java/uk/co/compendiumdev/thingifier/core/repository/inmemory/InMemoryThingStore.java b/ercoremodel/src/main/java/uk/co/compendiumdev/thingifier/core/repository/inmemory/InMemoryThingStore.java
index 48447e7f..ae4a70a6 100644
--- a/ercoremodel/src/main/java/uk/co/compendiumdev/thingifier/core/repository/inmemory/InMemoryThingStore.java
+++ b/ercoremodel/src/main/java/uk/co/compendiumdev/thingifier/core/repository/inmemory/InMemoryThingStore.java
@@ -21,6 +21,7 @@
import uk.co.compendiumdev.thingifier.core.repository.RelationshipRepository;
import uk.co.compendiumdev.thingifier.core.repository.RepositoryAdministration;
import uk.co.compendiumdev.thingifier.core.repository.ThingStore;
+import uk.co.compendiumdev.thingifier.core.repository.ThingStoreTransaction;
import uk.co.compendiumdev.thingifier.core.repository.validation.EntityInstanceWriteValidator;
public class InMemoryThingStore implements ThingStore {
@@ -74,6 +75,11 @@ public RepositoryAdministration administration() {
return administration;
}
+ @Override
+ public ThingStoreTransaction beginTransaction() {
+ return new InMemoryThingStoreTransaction(instanceData.snapshot(), relationships.snapshot());
+ }
+
void initializeFrom(final ERSchema schema) {
refreshSchema(schema);
}
@@ -362,4 +368,40 @@ private EntityInstance findByInternalId(
}
return collection.findInstanceByInternalID(internalId);
}
+
+ private final class InMemoryThingStoreTransaction implements ThingStoreTransaction {
+
+ private final InMemoryEntityInstanceStore.Snapshot instanceSnapshot;
+ private final InMemoryRelationshipStore.Snapshot relationshipSnapshot;
+ private boolean completed;
+
+ private InMemoryThingStoreTransaction(
+ final InMemoryEntityInstanceStore.Snapshot instanceSnapshot,
+ final InMemoryRelationshipStore.Snapshot relationshipSnapshot) {
+ this.instanceSnapshot = instanceSnapshot;
+ this.relationshipSnapshot = relationshipSnapshot;
+ }
+
+ @Override
+ public void commit() {
+ completed = true;
+ }
+
+ @Override
+ public void rollback() {
+ if (completed) {
+ return;
+ }
+ relationships.restore(relationshipSnapshot);
+ instanceData.restore(instanceSnapshot);
+ completed = true;
+ }
+
+ @Override
+ public void close() {
+ if (!completed) {
+ rollback();
+ }
+ }
+ }
}
diff --git a/ercoremodel/src/main/java/uk/co/compendiumdev/thingifier/core/repository/sqlite/SqliteThingStore.java b/ercoremodel/src/main/java/uk/co/compendiumdev/thingifier/core/repository/sqlite/SqliteThingStore.java
index a104106d..691d308b 100644
--- a/ercoremodel/src/main/java/uk/co/compendiumdev/thingifier/core/repository/sqlite/SqliteThingStore.java
+++ b/ercoremodel/src/main/java/uk/co/compendiumdev/thingifier/core/repository/sqlite/SqliteThingStore.java
@@ -42,6 +42,7 @@
import uk.co.compendiumdev.thingifier.core.repository.RelationshipRepository;
import uk.co.compendiumdev.thingifier.core.repository.RepositoryAdministration;
import uk.co.compendiumdev.thingifier.core.repository.ThingStore;
+import uk.co.compendiumdev.thingifier.core.repository.ThingStoreTransaction;
import uk.co.compendiumdev.thingifier.core.repository.relationship.RelationshipEndpoint;
import uk.co.compendiumdev.thingifier.core.repository.relationship.RelationshipRow;
import uk.co.compendiumdev.thingifier.core.repository.relationship.RelationshipRules;
@@ -114,6 +115,23 @@ public RepositoryAdministration administration() {
return administration;
}
+ @Override
+ public ThingStoreTransaction beginTransaction() {
+ openConnection();
+ try {
+ boolean originalAutoCommit = connection.getAutoCommit();
+ Map materializedSnapshot = new HashMap<>(materializedInstances);
+ Map> counterSnapshot = snapshotCounters();
+ if (originalAutoCommit) {
+ connection.setAutoCommit(false);
+ }
+ return new SqliteThingStoreTransaction(
+ originalAutoCommit, materializedSnapshot, counterSnapshot);
+ } catch (SQLException e) {
+ throw new IllegalStateException("Could not begin SQLite transaction", e);
+ }
+ }
+
void initializeFrom(final ERSchema schema) {
this.schema = schema;
openConnection();
@@ -1488,6 +1506,10 @@ private void executePreparedSql(final String sql, final List