diff --git a/li.strolch.agent/src/main/java/li/strolch/persistence/api/AbstractTransaction.java b/li.strolch.agent/src/main/java/li/strolch/persistence/api/AbstractTransaction.java
index 362e42f16..85df9fedd 100644
--- a/li.strolch.agent/src/main/java/li/strolch/persistence/api/AbstractTransaction.java
+++ b/li.strolch.agent/src/main/java/li/strolch/persistence/api/AbstractTransaction.java
@@ -448,12 +448,25 @@ public abstract class AbstractTransaction implements StrolchTransaction {
return getResourceMap().getBy(this, refP, assertExists);
}
+ @Override
+ public void flush() {
+ try {
+ validateCommands();
+ doCommands();
+ writeChanges(this.txResult);
+ this.commands.clear();
+ } catch (Exception e) {
+ this.closeStrategy = TransactionCloseStrategy.ROLLBACK;
+
+ String msg = "Strolch Transaction for realm {0} failed due to {1}"; //$NON-NLS-1$
+ msg = MessageFormat.format(msg, getRealmName(), e.getMessage());
+ throw new StrolchPersistenceException(msg, e);
+ }
+ }
+
@Override
public void autoCloseableCommit() {
long start = System.nanoTime();
- if (logger.isDebugEnabled()) {
- logger.info(MessageFormat.format("Committing TX for realm {0}...", getRealmName())); //$NON-NLS-1$
- }
try {
this.txResult.setState(TransactionState.COMMITTING);
diff --git a/li.strolch.agent/src/main/java/li/strolch/persistence/api/StrolchTransaction.java b/li.strolch.agent/src/main/java/li/strolch/persistence/api/StrolchTransaction.java
index 2b7daaa10..ff37e569f 100644
--- a/li.strolch.agent/src/main/java/li/strolch/persistence/api/StrolchTransaction.java
+++ b/li.strolch.agent/src/main/java/li/strolch/persistence/api/StrolchTransaction.java
@@ -17,7 +17,6 @@ package li.strolch.persistence.api;
import java.util.List;
-import ch.eitchnet.privilege.model.Certificate;
import li.strolch.agent.api.AuditTrail;
import li.strolch.agent.api.OrderMap;
import li.strolch.agent.api.ResourceMap;
@@ -46,6 +45,7 @@ import li.strolch.model.query.OrderQuery;
import li.strolch.model.query.ResourceQuery;
import li.strolch.runtime.StrolchConstants;
import li.strolch.service.api.Command;
+import ch.eitchnet.privilege.model.Certificate;
/**
*
@@ -174,6 +174,17 @@ public interface StrolchTransaction extends AutoCloseable {
@Override
public void close() throws StrolchPersistenceException;
+ /**
+ *
+ * Performs all registered commands
+ *
+ *
+ *
+ * This method does not release any locks, nor does it notify any observers
+ *
+ */
+ public void flush();
+
/**
* @return true if the transaction is still open, i.e. not being closed or rolling back, committing, etc.
*/
diff --git a/li.strolch.persistence.postgresql/src/main/java/li/strolch/persistence/postgresql/PostgresqlDao.java b/li.strolch.persistence.postgresql/src/main/java/li/strolch/persistence/postgresql/PostgresqlDao.java
index 885847d4f..292fd34f5 100644
--- a/li.strolch.persistence.postgresql/src/main/java/li/strolch/persistence/postgresql/PostgresqlDao.java
+++ b/li.strolch.persistence.postgresql/src/main/java/li/strolch/persistence/postgresql/PostgresqlDao.java
@@ -388,6 +388,7 @@ public abstract class PostgresqlDao implements Strolch
for (DaoCommand command : this.commands) {
command.doComand(txResult);
}
+ this.commands.clear();
}
void rollback() {
diff --git a/li.strolch.service/src/test/java/li/strolch/service/FlushTxTest.java b/li.strolch.service/src/test/java/li/strolch/service/FlushTxTest.java
new file mode 100644
index 000000000..0f278a320
--- /dev/null
+++ b/li.strolch.service/src/test/java/li/strolch/service/FlushTxTest.java
@@ -0,0 +1,104 @@
+package li.strolch.service;
+
+import li.strolch.command.AddResourceCommand;
+import li.strolch.command.RemoveResourceCommand;
+import li.strolch.model.ModelGenerator;
+import li.strolch.model.Resource;
+import li.strolch.persistence.api.StrolchTransaction;
+import li.strolch.persistence.api.TransactionCloseStrategy;
+import li.strolch.service.api.AbstractService;
+import li.strolch.service.api.ServiceArgument;
+import li.strolch.service.api.ServiceResult;
+import li.strolch.service.test.AbstractRealmServiceTest;
+
+import org.junit.Test;
+
+import ch.eitchnet.utils.dbc.DBC;
+
+public class FlushTxTest extends AbstractRealmServiceTest {
+
+ @Test
+ public void shouldFlushSuccessfully() {
+
+ runServiceInAllRealmTypes(FlushingCommandsService.class, new ServiceArgument());
+ }
+
+ @Test
+ public void shouldRollbackSuccessfully() {
+
+ runServiceInAllRealmTypes(RollbackAfterFlushCommandsService.class, new ServiceArgument());
+ }
+
+ public static class FlushingCommandsService extends AbstractService {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ protected ServiceResult getResultInstance() {
+ return new ServiceResult();
+ }
+
+ @Override
+ protected ServiceResult internalDoService(ServiceArgument arg) throws Exception {
+
+ String id = "flushSuccessfully";
+ Resource resource = ModelGenerator.createResource(id, id, id);
+
+ try (StrolchTransaction tx = openTx(arg.realm)) {
+
+ DBC.PRE.assertNull("Did not expect resource with id " + id, tx.getResourceBy(id, id));
+
+ AddResourceCommand addResCmd = new AddResourceCommand(getContainer(), tx);
+ addResCmd.setResource(resource);
+ tx.addCommand(addResCmd);
+ tx.flush();
+ DBC.PRE.assertNotNull("Expected resource with id " + id, tx.getResourceBy(id, id));
+
+ RemoveResourceCommand rmResCmd = new RemoveResourceCommand(getContainer(), tx);
+ rmResCmd.setResource(resource);
+ tx.addCommand(rmResCmd);
+ tx.flush();
+ DBC.PRE.assertNull("Expect to remove resource with id " + id, tx.getResourceBy(id, id));
+ }
+
+ return ServiceResult.success();
+ }
+ }
+
+ public static class RollbackAfterFlushCommandsService extends AbstractService {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ protected ServiceResult getResultInstance() {
+ return new ServiceResult();
+ }
+
+ @Override
+ protected ServiceResult internalDoService(ServiceArgument arg) throws Exception {
+
+ String id = "flushSuccessfully2";
+ Resource resource = ModelGenerator.createResource(id, id, id);
+
+ try (StrolchTransaction tx = openTx(arg.realm)) {
+
+ DBC.PRE.assertNull("Did not expect resource with id " + id, tx.getResourceBy(id, id));
+
+ AddResourceCommand addResCmd = new AddResourceCommand(getContainer(), tx);
+ addResCmd.setResource(resource);
+ tx.addCommand(addResCmd);
+ tx.flush();
+ DBC.PRE.assertNotNull("Expected resource with id " + id, tx.getResourceBy(id, id));
+
+ // now force a rollback
+ tx.setCloseStrategy(TransactionCloseStrategy.ROLLBACK);
+ }
+
+ // now make sure the new resource does not exist
+ try (StrolchTransaction tx = openTx(arg.realm)) {
+ DBC.PRE.assertNull("Did not expect resource with id after rolling back previous TX " + id,
+ tx.getResourceBy(id, id));
+ }
+
+ return ServiceResult.success();
+ }
+ }
+}