Skip to content
Permalink
Browse files

[Major] Refactored how a TX is closed

- So sadly just auto closing a TX using try-resource from Java7 is a bad idea.
- Doing that leads to problems when an exception is thrown, then the close is called (duh) but this leads to commit being called.
- Since the Java language does not offer a decent way to detect if the close is being called in the context of an exception i was forced to add a tx.commitOnClose() and tx.rollbackOnClose().
- The default is that when a TX is opened, then the close strategy is rollback; the API user must call tx.commitOnClose() before the TX is closed by the braces, or as late as possible, to make sure that if an exception is thrown the transaction is rolled back, and not committed.
- The API was also extended with a tx.fail(msg):StrolchTransactionException so that if the implementor detects an unrecoverable error, one can write: throw tx.fail(“my reason”);

This was sadly an unavoidable late 1.0.0 change
Conflicts:
	li.strolch.agent/src/main/java/li/strolch/persistence/api/AbstractTransaction.java
  • Loading branch information
eitch committed Feb 3, 2015
1 parent 9532c97 commit 46ccb921dfa94f140cbaa3f459c2e434c913d720
Showing with 257 additions and 35 deletions.
  1. +4 −0 li.strolch.agent/src/main/java/li/strolch/agent/impl/CachedRealm.java
  2. +2 −0 li.strolch.agent/src/main/java/li/strolch/agent/impl/TransactionalRealm.java
  3. +1 −0 li.strolch.agent/src/main/java/li/strolch/agent/impl/TransientRealm.java
  4. +21 −6 li.strolch.agent/src/main/java/li/strolch/persistence/api/AbstractTransaction.java
  5. +31 −19 li.strolch.agent/src/main/java/li/strolch/persistence/api/StrolchTransaction.java
  6. +39 −0 li.strolch.agent/src/main/java/li/strolch/persistence/api/StrolchTransactionException.java
  7. +6 −6 li.strolch.agent/src/main/java/li/strolch/persistence/api/TransactionCloseStrategy.java
  8. +1 −0 li.strolch.agent/src/main/java/li/strolch/runtime/query/enums/DefaultEnumHandler.java
  9. +7 −0 li.strolch.agent/src/test/java/li/strolch/agent/ComponentContainerTest.java
  10. +2 −0 li.strolch.agent/src/test/java/li/strolch/runtime/query/inmemory/FindByLocatorTest.java
  11. +16 −0 li.strolch.agent/src/test/java/li/strolch/runtime/query/inmemory/QueryTest.java
  12. +1 −0 ...persistence.postgresql/src/main/java/li/strolch/persistence/postgresql/PostgreSqlInitializer.java
  13. +2 −0 ...rsistence.postgresql/src/test/java/li/strolch/persistence/postgresql/dao/test/AuditQueryTest.java
  14. +2 −0 ...tence.postgresql/src/test/java/li/strolch/persistence/postgresql/dao/test/ObserverUpdateTest.java
  15. +2 −0 ...ch.persistence.postgresql/src/test/java/li/strolch/persistence/postgresql/dao/test/QueryTest.java
  16. +5 −0 ...ch.persistence.postgresql/src/test/java/li/strolch/persistence/postgresql/dao/test/RealmTest.java
  17. +1 −0 li.strolch.persistence.xml/src/test/java/li/strolch/persistence/impl/dao/test/ExistingDbTest.java
  18. +2 −0 ...trolch.persistence.xml/src/test/java/li/strolch/persistence/impl/dao/test/ObserverUpdateTest.java
  19. +9 −0 li.strolch.rest/src/main/java/li/strolch/rest/endpoint/Inspector.java
  20. +1 −0 li.strolch.service/src/main/java/li/strolch/service/AddOrderCollectionService.java
  21. +1 −0 li.strolch.service/src/main/java/li/strolch/service/AddOrderService.java
  22. +1 −0 li.strolch.service/src/main/java/li/strolch/service/AddResourceCollectionService.java
  23. +1 −0 li.strolch.service/src/main/java/li/strolch/service/AddResourceService.java
  24. +1 −1 li.strolch.service/src/main/java/li/strolch/service/ClearModelService.java
  25. +2 −0 li.strolch.service/src/main/java/li/strolch/service/RemoveOrderCollectionService.java
  26. +2 −0 li.strolch.service/src/main/java/li/strolch/service/RemoveOrderService.java
  27. +2 −0 li.strolch.service/src/main/java/li/strolch/service/RemoveResourceCollectionService.java
  28. +2 −0 li.strolch.service/src/main/java/li/strolch/service/RemoveResourceService.java
  29. +2 −0 li.strolch.service/src/main/java/li/strolch/service/UpdateOrderCollectionService.java
  30. +2 −0 li.strolch.service/src/main/java/li/strolch/service/UpdateOrderService.java
  31. +2 −0 li.strolch.service/src/main/java/li/strolch/service/UpdateResourceCollectionService.java
  32. +2 −0 li.strolch.service/src/main/java/li/strolch/service/UpdateResourceService.java
  33. +2 −0 li.strolch.service/src/main/java/li/strolch/service/XmlExportModelService.java
  34. +2 −0 li.strolch.service/src/main/java/li/strolch/service/XmlImportModelService.java
  35. +2 −0 li.strolch.service/src/main/java/li/strolch/service/parameter/AddParameterService.java
  36. +2 −0 li.strolch.service/src/main/java/li/strolch/service/parameter/RemoveParameterService.java
  37. +1 −0 li.strolch.service/src/main/java/li/strolch/service/parameter/SetParameterService.java
  38. +3 −2 li.strolch.service/src/test/java/li/strolch/command/AbstractRealmCommandTest.java
  39. +3 −1 li.strolch.service/src/test/java/li/strolch/service/ClearModelServiceTest.java
  40. +2 −0 li.strolch.service/src/test/java/li/strolch/service/test/LockingTest.java
  41. +1 −0 li.strolch.testbase/src/main/java/li/strolch/testbase/runtime/AbstractModelTest.java
  42. +20 −0 li.strolch.testbase/src/main/java/li/strolch/testbase/runtime/AuditModelTestRunner.java
  43. +22 −0 li.strolch.testbase/src/main/java/li/strolch/testbase/runtime/OrderModelTestRunner.java
  44. +22 −0 li.strolch.testbase/src/main/java/li/strolch/testbase/runtime/ResourceModelTestRunner.java
@@ -115,6 +115,8 @@ public void start(PrivilegeContext privilegeContext) {
nrOfResources++;
}
}

tx.commitOnClose();
}

try (StrolchTransaction tx = openTx(privilegeContext.getCertificate(), DefaultRealmHandler.AGENT_BOOT)) {
@@ -127,6 +129,8 @@ public void start(PrivilegeContext privilegeContext) {
nrOfOrders++;
}
}

tx.commitOnClose();
}

long duration = System.nanoTime() - start;
@@ -101,10 +101,12 @@ public void start(PrivilegeContext privilegeContext) {

try (StrolchTransaction tx = openTx(privilegeContext.getCertificate(), DefaultRealmHandler.AGENT_BOOT)) {
nrOfOrders = this.orderMap.getAllKeys(tx).size();
tx.commitOnClose();
}

try (StrolchTransaction tx = openTx(privilegeContext.getCertificate(), DefaultRealmHandler.AGENT_BOOT)) {
nrOfResources = this.resourceMap.getAllKeys(tx).size();
tx.commitOnClose();
}

long duration = System.nanoTime() - start;
@@ -118,6 +118,7 @@ public void start(PrivilegeContext privilegeContext) {
XmlModelSaxFileReader handler = new XmlModelSaxFileReader(elementListener, this.modelFile);
handler.parseFile();
statistics = handler.getStatistics();
tx.commitOnClose();
}

String durationS = StringHelper.formatNanoDuration(statistics.durationNanos);
@@ -112,7 +112,7 @@ public AbstractTransaction(PrivilegeHandler privilegeHandler, StrolchRealm realm

this.commands = new ArrayList<>();
this.lockedElements = new HashSet<>();
this.closeStrategy = TransactionCloseStrategy.COMMIT;
this.closeStrategy = TransactionCloseStrategy.ROLLBACK;
this.txResult = new TransactionResult(getRealmName(), System.nanoTime(), new Date());
this.txResult.setState(TransactionState.OPEN);
}
@@ -156,16 +156,31 @@ public Certificate getCertificate() {
return certificate;
}

@Override
public void setCloseStrategy(TransactionCloseStrategy closeStrategy) {
private void setCloseStrategy(TransactionCloseStrategy closeStrategy) {
this.closeStrategy = closeStrategy;
}

@Override
public void close() throws StrolchPersistenceException {
public void close() throws StrolchTransactionException {
this.closeStrategy.close(this);
}

@Override
public void commitOnClose() {
setCloseStrategy(TransactionCloseStrategy.COMMIT);
}

@Override
public void rollbackOnClose() {
setCloseStrategy(TransactionCloseStrategy.ROLLBACK);
}

@Override
public StrolchTransactionException fail(String string) {
rollbackOnClose();
return new StrolchTransactionException(string);
}

@Override
public void setSuppressUpdates(boolean suppressUpdates) {
this.suppressUpdates = suppressUpdates;
@@ -492,7 +507,7 @@ public void autoCloseableCommit() {

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);
throw new StrolchTransactionException(msg, e);

} finally {
releaseElementLocks();
@@ -620,7 +635,7 @@ protected void handleFailure(long closeStartNanos, Exception e) {

String msg = "Strolch Transaction for realm {0} failed due to {1}\n{2}"; //$NON-NLS-1$
msg = MessageFormat.format(msg, getRealmName(), e.getMessage(), sb.toString());
throw new StrolchPersistenceException(msg, e);
throw new StrolchTransactionException(msg, e);
}

private boolean isAuditTrailEnabled() {
@@ -61,6 +61,7 @@
* StrolchRealm realm = strolchAgent.getContainer().getRealm(StrolchConstants.DEFAULT_REALM);
* try(StrolchTransaction tx = realm.openTx(certificate, getClass())){
* // do work e.g. add commands
* tx.commitOnClose();
* }
* </code>
*
@@ -132,28 +133,18 @@
public PersistenceHandler getPersistenceHandler();

/**
* Sets the strategy to be used when closing the transaction when {@link #close()} is called. The default is
* {@link TransactionCloseStrategy#COMMIT}, but if the user of the transaction decides it wants to use a different
* strategy, then it may set it using this method
*
* @param closeStrategy
* the new {@link TransactionCloseStrategy} to use
*/
public void setCloseStrategy(TransactionCloseStrategy closeStrategy);

/**
* If the currently set close strategy is {@link TransactionCloseStrategy#COMMIT}, then when the transaction is
* closed, this method is called and all registered {@link Command} are performed, locks on objects are released and
* any other resources are released
* DO NOT CALL THIS METHOD. If the currently set close strategy is {@link TransactionCloseStrategy#COMMIT}, then
* when the transaction is closed, this method is called and all registered {@link Command} are performed, locks on
* objects are released and any other resources are released
*/
public void autoCloseableCommit();
public void autoCloseableCommit() throws StrolchTransactionException;

/**
* If the currently set close strategy is {@link TransactionCloseStrategy#ROLLBACK}, then when the transaction is
* closed, no further actions are performed and any {@link Command} which were performed have their
* {@link Command#undo()} method called and any DB connections are also rolled back
* DO NOT CALL THIS METHOD. If the currently set close strategy is {@link TransactionCloseStrategy#ROLLBACK}, then
* when the transaction is closed, no further actions are performed and any {@link Command} which were performed
* have their {@link Command#undo()} method called and any DB connections are also rolled back
*/
public void autoCloseableRollback();
public void autoCloseableRollback() throws StrolchTransactionException;

/**
* <p>
@@ -166,13 +157,34 @@
* StrolchRealm realm = strolchAgent.getContainer().getRealm("defaultRealm");
* try(StrolchTransaction tx = realm.openTx(certificate, getClass())){
* // do work
* tx.commitOnClose();
* }
* </code>
*
* After the block is closed, the transaction is automatically closed and all allocated resources are released
*/
@Override
public void close() throws StrolchPersistenceException;
public void close() throws StrolchTransactionException;

/**
* Sets the {@link TransactionCloseStrategy} to {@link TransactionCloseStrategy#COMMIT}
*/
public void commitOnClose();

/**
* Sets the {@link TransactionCloseStrategy} to {@link TransactionCloseStrategy#ROLLBACK}
*/
public void rollbackOnClose();

/**
* Sets the {@link TransactionCloseStrategy} to {@link TransactionCloseStrategy#ROLLBACK} and returns a
* {@link StrolchTransactionException} which can be thrown by the caller to stop the exception
*
* @param exceptionMessage
*
* @return a {@link StrolchTransactionException} to be thrown by the caller
*/
public StrolchTransactionException fail(String exceptionMessage);

/**
* @return true if the transaction is still open, i.e. not being closed or rolling back, committing, etc.
@@ -0,0 +1,39 @@
/*
* Copyright 2013 Robert von Burg <eitch@eitchnet.ch>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package li.strolch.persistence.api;

/**
* @author Robert von Burg <eitch@eitchnet.ch>
*/
public class StrolchTransactionException extends RuntimeException {

private static final long serialVersionUID = 1L;

/**
* @param message
*/
public StrolchTransactionException(String message) {
super(message);
}

/**
* @param message
* @param cause
*/
public StrolchTransactionException(String message, Throwable cause) {
super(message, cause);
}
}
@@ -15,23 +15,23 @@
*/
package li.strolch.persistence.api;

import li.strolch.exception.StrolchException;

public enum TransactionCloseStrategy {

COMMIT() {
@Override
public void close(StrolchTransaction tx) {
public void close(StrolchTransaction tx) throws StrolchException {
tx.autoCloseableCommit();
}
},

ROLLBACK() {
@Override
public void close(StrolchTransaction tx) {
public void close(StrolchTransaction tx) throws StrolchException {
tx.autoCloseableRollback();
}
};

/**
* @param tx
*/
public abstract void close(StrolchTransaction tx);
public abstract void close(StrolchTransaction tx) throws StrolchException;
}
@@ -97,6 +97,7 @@ public StrolchEnum getEnum(Certificate certificate, String name, Locale locale)
}

StrolchEnum strolchEnum = new StrolchEnum(name, locale, values);
tx.commitOnClose();
return strolchEnum;
}
}
@@ -201,6 +201,7 @@ public static void testPersistenceContainer(StrolchAgent agent) {
Resource queriedRes = resourceDao.queryBy("Test", "@testRes0");
assertNotNull(queriedRes);
assertEquals("@testRes0", queriedRes.getId());
tx.commitOnClose();
}

try (StrolchTransaction tx = container.getRealm(StrolchConstants.DEFAULT_REALM).openTx(certificate, "test")) {
@@ -209,6 +210,7 @@ public static void testPersistenceContainer(StrolchAgent agent) {
Order queriedOrder = orderDao.queryBy("Test", "@testOrder0");
assertNotNull(queriedOrder);
assertEquals("@testOrder0", queriedOrder.getId());
tx.commitOnClose();
}
}

@@ -223,6 +225,7 @@ public static void testElementMaps(StrolchAgent agent) {
Resource queriedRes = resourceMap.getBy(tx, "Test", "@testRes1");
assertNotNull(queriedRes);
assertEquals("@testRes1", queriedRes.getId());
tx.commitOnClose();
}

try (StrolchTransaction tx = container.getRealm(StrolchConstants.DEFAULT_REALM).openTx(certificate, "test")) {
@@ -231,6 +234,7 @@ public static void testElementMaps(StrolchAgent agent) {
Order queriedOrder = orderMap.getBy(tx, "Test", "@testOrder1");
assertNotNull(queriedOrder);
assertEquals("@testOrder1", queriedOrder.getId());
tx.commitOnClose();
}
}

@@ -251,6 +255,7 @@ public static void testRealms(StrolchAgent agent) {
Order queriedOrder = orderMap.getBy(tx, "Test", "@testOrder1");
assertNotNull(queriedOrder);
assertEquals("@testOrder1", queriedOrder.getId());
tx.commitOnClose();
}

try (StrolchTransaction tx = container.getRealm("myRealm").openTx(certificate, "test")) {
@@ -267,6 +272,7 @@ public static void testRealms(StrolchAgent agent) {
assertEquals("MyRealmOrder", myRealmOrder.getId());
Order otherRealmOrder = orderMap.getBy(tx, "TestType", "OtherRealmOrder");
assertNull(otherRealmOrder);
tx.commitOnClose();
}
try (StrolchTransaction tx = container.getRealm("otherRealm").openTx(certificate, "test")) {
ResourceMap resourceMap = tx.getResourceMap();
@@ -282,6 +288,7 @@ public static void testRealms(StrolchAgent agent) {
assertEquals("OtherRealmOrder", otherRealmOrder.getId());
Order myRealmOrder = orderMap.getBy(tx, "TestType", "MyRealmOrder");
assertNull(myRealmOrder);
tx.commitOnClose();
}
}

@@ -86,6 +86,8 @@ public void shouldFindByLocator() {
Locator locResIntegerState = Locator.valueOf("Resource/TestType/MyTestResource/State/@integerState");
IntegerTimedState integerS = tx.findElement(locResIntegerState);
assertNotNull("Should have found a IntegerTimedState with the locator " + locResIntegerState, integerS);

tx.commitOnClose();
}
}
}

0 comments on commit 46ccb92

Please sign in to comment.
You can’t perform that action at this time.