Author: timothyjward
Date: Thu Feb 25 13:36:31 2016
New Revision: 1732302

URL: http://svn.apache.org/viewvc?rev=1732302&view=rev
Log:
[tx-control] Throw the correct Exception types on different kinds of error

Modified:
    
aries/trunk/tx-control/tx-control-itests/src/test/java/org/apache/aries/tx/control/itests/ExceptionManagementTransactionTest.java
    
aries/trunk/tx-control/tx-control-service-local/src/main/java/org/apache/aries/tx/control/service/local/impl/AbstractTransactionContextImpl.java
    
aries/trunk/tx-control/tx-control-service-local/src/main/java/org/apache/aries/tx/control/service/local/impl/NoTransactionContextImpl.java
    
aries/trunk/tx-control/tx-control-service-local/src/main/java/org/apache/aries/tx/control/service/local/impl/TransactionContextImpl.java
    
aries/trunk/tx-control/tx-control-service-local/src/main/java/org/apache/aries/tx/control/service/local/impl/TransactionControlImpl.java
    
aries/trunk/tx-control/tx-control-service-local/src/test/java/org/apache/aries/tx/control/service/local/impl/NoTransactionContextTest.java
    
aries/trunk/tx-control/tx-control-service-local/src/test/java/org/apache/aries/tx/control/service/local/impl/TransactionContextTest.java

Modified: 
aries/trunk/tx-control/tx-control-itests/src/test/java/org/apache/aries/tx/control/itests/ExceptionManagementTransactionTest.java
URL: 
http://svn.apache.org/viewvc/aries/trunk/tx-control/tx-control-itests/src/test/java/org/apache/aries/tx/control/itests/ExceptionManagementTransactionTest.java?rev=1732302&r1=1732301&r2=1732302&view=diff
==============================================================================
--- 
aries/trunk/tx-control/tx-control-itests/src/test/java/org/apache/aries/tx/control/itests/ExceptionManagementTransactionTest.java
 (original)
+++ 
aries/trunk/tx-control/tx-control-itests/src/test/java/org/apache/aries/tx/control/itests/ExceptionManagementTransactionTest.java
 Thu Feb 25 13:36:31 2016
@@ -39,7 +39,6 @@ import javax.inject.Inject;
 import org.apache.aries.itest.AbstractIntegrationTest;
 import org.junit.After;
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.ops4j.pax.exam.Configuration;
@@ -49,6 +48,7 @@ import org.ops4j.pax.exam.junit.PaxExam;
 import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
 import org.ops4j.pax.exam.spi.reactors.PerClass;
 import org.osgi.service.jdbc.DataSourceFactory;
+import org.osgi.service.transaction.control.ScopedWorkException;
 import org.osgi.service.transaction.control.TransactionControl;
 import org.osgi.service.transaction.control.TransactionRolledBackException;
 import org.osgi.service.transaction.control.jdbc.JDBCConnectionProviderFactory;
@@ -107,8 +107,8 @@ public class ExceptionManagementTransact
                                                throw toThrow;
                                        });
                        fail("An exception should occur!");
-               } catch (TransactionRolledBackException tre) {
-                       assertSame(toThrow, tre.getCause());
+               } catch (ScopedWorkException swe) {
+                       assertSame(toThrow, swe.getCause());
                }
 
                assertRollback();
@@ -127,8 +127,8 @@ public class ExceptionManagementTransact
                        fail("An exception should occur!");
                        // We have to catch Exception as the compiler complains
                        // otherwise
-               } catch (TransactionRolledBackException tre) {
-                       assertSame(toThrow, tre.getCause());
+               } catch (ScopedWorkException swe) {
+                       assertSame(toThrow, swe.getCause());
                }
 
                assertRollback();
@@ -137,7 +137,6 @@ public class ExceptionManagementTransact
        //This test currently fails - the local implementation should probably
        //use the coordinator a little differently
        @Test
-       @Ignore
        public void testPreCompletionException() {
                RuntimeException toThrow = new RuntimeException("Bang!");
                

Modified: 
aries/trunk/tx-control/tx-control-service-local/src/main/java/org/apache/aries/tx/control/service/local/impl/AbstractTransactionContextImpl.java
URL: 
http://svn.apache.org/viewvc/aries/trunk/tx-control/tx-control-service-local/src/main/java/org/apache/aries/tx/control/service/local/impl/AbstractTransactionContextImpl.java?rev=1732302&r1=1732301&r2=1732302&view=diff
==============================================================================
--- 
aries/trunk/tx-control/tx-control-service-local/src/main/java/org/apache/aries/tx/control/service/local/impl/AbstractTransactionContextImpl.java
 (original)
+++ 
aries/trunk/tx-control/tx-control-service-local/src/main/java/org/apache/aries/tx/control/service/local/impl/AbstractTransactionContextImpl.java
 Thu Feb 25 13:36:31 2016
@@ -7,50 +7,70 @@ import java.util.concurrent.atomic.Atomi
 import java.util.function.Consumer;
 
 import org.osgi.service.coordinator.Coordination;
+import org.osgi.service.coordinator.Participant;
 import org.osgi.service.transaction.control.TransactionContext;
 import org.osgi.service.transaction.control.TransactionStatus;
 
-public abstract class AbstractTransactionContextImpl
-               implements TransactionContext {
+public abstract class AbstractTransactionContextImpl implements 
TransactionContext {
 
-       protected static class TransactionVariablesKey {}
+       protected static class TransactionVariablesKey {
+       }
+
+       protected final AtomicReference<Throwable> firstUnexpectedException = 
new AtomicReference<>();
+
+       protected final List<Throwable> subsequentExceptions = new 
ArrayList<>();
 
-       protected final AtomicReference<Exception> firstUnexpectedException = 
new AtomicReference<>();
-       
-       protected final List<Exception> subsequentExceptions = new 
ArrayList<>();
-       
        protected final Coordination coordination;
-       
+
        protected final List<Runnable> preCompletion = new ArrayList<>();
-       
+
        protected final List<Consumer<TransactionStatus>> postCompletion = new 
ArrayList<>();
-       
+
        public AbstractTransactionContextImpl(Coordination coordination) {
                this.coordination = coordination;
+
+               coordination.addParticipant(new Participant() {
+
+                       @Override
+                       public void failed(Coordination coordination) throws 
Exception {
+                               Throwable failure = coordination.getFailure();
+                               recordFailure(failure);
+                               safeSetRollbackOnly();
+                       }
+
+                       @Override
+                       public void ended(Coordination coordination) throws 
Exception {
+                               if (isAlive()) {
+                                       // TODO log this
+                                       recordFailure(new IllegalStateException(
+                                                       "The surrounding 
coordination ended before the transaction completed"));
+                                       safeSetRollbackOnly();
+
+                               }
+                       }
+               });
        }
 
        @SuppressWarnings("unchecked")
        @Override
        public Object getScopedValue(Object key) {
-               return ((HashMap<Object,Object>) coordination.getVariables()
-                               .getOrDefault(TransactionVariablesKey.class, 
new HashMap<>()))
-                                               .get(key);
+               return ((HashMap<Object, Object>) 
coordination.getVariables().getOrDefault(TransactionVariablesKey.class,
+                               new HashMap<>())).get(key);
        }
 
        @SuppressWarnings("unchecked")
        @Override
        public void putScopedValue(Object key, Object value) {
-               ((HashMap<Object,Object>) 
coordination.getVariables().computeIfAbsent(
-                               TransactionVariablesKey.class, k -> new 
HashMap<>())).put(key, value);
+               ((HashMap<Object, Object>) 
coordination.getVariables().computeIfAbsent(TransactionVariablesKey.class,
+                               k -> new HashMap<>())).put(key, value);
        }
-       
-       
+
        protected void beforeCompletion(Runnable onFirstError) {
                preCompletion.stream().forEach(r -> {
                        try {
                                r.run();
                        } catch (Exception e) {
-                               if(firstUnexpectedException.compareAndSet(null, 
e)) {
+                               if 
(firstUnexpectedException.compareAndSet(null, e)) {
                                        onFirstError.run();
                                } else {
                                        subsequentExceptions.add(e);
@@ -59,4 +79,27 @@ public abstract class AbstractTransactio
                        }
                });
        }
+
+       protected void afterCompletion(TransactionStatus status) {
+               postCompletion.stream().forEach(c -> {
+                       try {
+                               c.accept(status);
+                       } catch (Exception e) {
+                               recordFailure(e);
+                               // TODO log this
+                       }
+               });
+       }
+
+       protected abstract boolean isAlive();
+
+       protected void recordFailure(Throwable failure) {
+               if (!firstUnexpectedException.compareAndSet(null, failure)) {
+                       subsequentExceptions.add(failure);
+               }
+       }
+
+       protected abstract void safeSetRollbackOnly();
+
+       public abstract void finish();
 }

Modified: 
aries/trunk/tx-control/tx-control-service-local/src/main/java/org/apache/aries/tx/control/service/local/impl/NoTransactionContextImpl.java
URL: 
http://svn.apache.org/viewvc/aries/trunk/tx-control/tx-control-service-local/src/main/java/org/apache/aries/tx/control/service/local/impl/NoTransactionContextImpl.java?rev=1732302&r1=1732301&r2=1732302&view=diff
==============================================================================
--- 
aries/trunk/tx-control/tx-control-service-local/src/main/java/org/apache/aries/tx/control/service/local/impl/NoTransactionContextImpl.java
 (original)
+++ 
aries/trunk/tx-control/tx-control-service-local/src/main/java/org/apache/aries/tx/control/service/local/impl/NoTransactionContextImpl.java
 Thu Feb 25 13:36:31 2016
@@ -2,12 +2,12 @@ package org.apache.aries.tx.control.serv
 
 import static 
org.osgi.service.transaction.control.TransactionStatus.NO_TRANSACTION;
 
+import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.function.Consumer;
 
 import javax.transaction.xa.XAResource;
 
 import org.osgi.service.coordinator.Coordination;
-import org.osgi.service.coordinator.Participant;
 import org.osgi.service.transaction.control.LocalResource;
 import org.osgi.service.transaction.control.TransactionContext;
 import org.osgi.service.transaction.control.TransactionStatus;
@@ -15,39 +15,10 @@ import org.osgi.service.transaction.cont
 public class NoTransactionContextImpl extends AbstractTransactionContextImpl
                implements TransactionContext {
 
-       volatile boolean                                                
finished                        = false;
+       private final AtomicBoolean finished = new AtomicBoolean(false);
 
        public NoTransactionContextImpl(Coordination coordination) {
                super(coordination);
-
-               coordination.addParticipant(new Participant() {
-
-                       @Override
-                       public void failed(Coordination coordination) throws 
Exception {
-                               finished();
-                       }
-
-                       @Override
-                       public void ended(Coordination coordination) throws 
Exception {
-                               finished();
-                       }
-
-                       private void finished() {
-                               beforeCompletion(() -> {});
-                               afterCompletion();
-                       }
-
-                       private void afterCompletion() {
-                               postCompletion.stream().forEach(c -> {
-                                       try {
-                                               c.accept(NO_TRANSACTION);
-                                       } catch (Exception e) {
-                                               
firstUnexpectedException.compareAndSet(null, e);
-                                               // TODO log this
-                                       }
-                               });
-                       }
-               });
        }
 
        @Override
@@ -76,6 +47,7 @@ public class NoTransactionContextImpl ex
                        throw new IllegalStateException(
                                        "The transaction context has finished");
                }
+               
                preCompletion.add(job);
        }
 
@@ -109,4 +81,21 @@ public class NoTransactionContextImpl ex
        public boolean supportsLocal() {
                return false;
        }
+
+       @Override
+       protected boolean isAlive() {
+               return !finished.get();
+       }
+       
+       @Override
+       public void finish() {
+               if(finished.compareAndSet(false, true)) {
+                       beforeCompletion(() -> {});
+                       afterCompletion(NO_TRANSACTION);
+               }
+       }
+
+       @Override
+       protected void safeSetRollbackOnly() {
+       }
 }

Modified: 
aries/trunk/tx-control/tx-control-service-local/src/main/java/org/apache/aries/tx/control/service/local/impl/TransactionContextImpl.java
URL: 
http://svn.apache.org/viewvc/aries/trunk/tx-control/tx-control-service-local/src/main/java/org/apache/aries/tx/control/service/local/impl/TransactionContextImpl.java?rev=1732302&r1=1732301&r2=1732302&view=diff
==============================================================================
--- 
aries/trunk/tx-control/tx-control-service-local/src/main/java/org/apache/aries/tx/control/service/local/impl/TransactionContextImpl.java
 (original)
+++ 
aries/trunk/tx-control/tx-control-service-local/src/main/java/org/apache/aries/tx/control/service/local/impl/TransactionContextImpl.java
 Thu Feb 25 13:36:31 2016
@@ -1,5 +1,6 @@
 package org.apache.aries.tx.control.service.local.impl;
 
+import static org.osgi.service.transaction.control.TransactionStatus.ACTIVE;
 import static org.osgi.service.transaction.control.TransactionStatus.COMMITTED;
 import static 
org.osgi.service.transaction.control.TransactionStatus.COMMITTING;
 import static 
org.osgi.service.transaction.control.TransactionStatus.MARKED_ROLLBACK;
@@ -8,107 +9,24 @@ import static org.osgi.service.transacti
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.concurrent.atomic.AtomicReference;
 import java.util.function.Consumer;
 
 import javax.transaction.xa.XAResource;
 
 import org.osgi.service.coordinator.Coordination;
-import org.osgi.service.coordinator.Participant;
 import org.osgi.service.transaction.control.LocalResource;
 import org.osgi.service.transaction.control.TransactionContext;
 import org.osgi.service.transaction.control.TransactionStatus;
 
-public class TransactionContextImpl extends AbstractTransactionContextImpl
-               implements TransactionContext {
+public class TransactionContextImpl extends AbstractTransactionContextImpl 
implements TransactionContext {
 
-       final List<LocalResource>                               resources       
                = new ArrayList<>();
+       final List<LocalResource> resources = new ArrayList<>();
 
-       private volatile TransactionStatus              tranStatus;
+       private AtomicReference<TransactionStatus> tranStatus = new 
AtomicReference<>(ACTIVE);
 
        public TransactionContextImpl(Coordination coordination) {
                super(coordination);
-
-               tranStatus = TransactionStatus.ACTIVE;
-
-               coordination.addParticipant(new Participant() {
-
-                       @Override
-                       public void failed(Coordination coordination) throws 
Exception {
-                               setRollbackOnly();
-
-                               beforeCompletion();
-
-                               vanillaRollback();
-
-                               afterCompletion();
-                       }
-
-                       private void vanillaRollback() {
-
-                               tranStatus = ROLLING_BACK;
-
-                               resources.stream().forEach(lr -> {
-                                       try {
-                                               lr.rollback();
-                                       } catch (Exception e) {
-                                               // TODO log this
-                                       }
-                               });
-
-                               tranStatus = ROLLED_BACK;
-                       }
-
-                       private void beforeCompletion() {
-                               TransactionContextImpl.this.beforeCompletion(() 
-> setRollbackOnly());
-                       }
-
-                       private void afterCompletion() {
-                               postCompletion.stream().forEach(c -> {
-                                       try {
-                                               c.accept(tranStatus);
-                                       } catch (Exception e) {
-                                               
firstUnexpectedException.compareAndSet(null, e);
-                                               // TODO log this
-                                       }
-                               });
-                       }
-
-                       @Override
-                       public void ended(Coordination coordination) throws 
Exception {
-                               beforeCompletion();
-
-                               if (getRollbackOnly()) {
-                                       vanillaRollback();
-                               } else {
-                                       tranStatus = COMMITTING;
-
-                                       List<LocalResource> committed = new 
ArrayList<>(
-                                                       resources.size());
-                                       List<LocalResource> rolledback = new 
ArrayList<>(0);
-
-                                       resources.stream().forEach(lr -> {
-                                               try {
-                                                       if (getRollbackOnly()) {
-                                                               lr.rollback();
-                                                               
rolledback.add(lr);
-                                                       } else {
-                                                               lr.commit();
-                                                               
committed.add(lr);
-                                                       }
-                                               } catch (Exception e) {
-                                                       
firstUnexpectedException.compareAndSet(null, e);
-                                                       if 
(committed.isEmpty()) {
-                                                               tranStatus = 
ROLLING_BACK;
-                                                       }
-                                                       rolledback.add(lr);
-                                               }
-                                       });
-                                       tranStatus = tranStatus == ROLLING_BACK 
? ROLLED_BACK
-                                                       : COMMITTED;
-                               }
-                               afterCompletion();
-                       }
-               });
        }
 
        @Override
@@ -118,63 +36,74 @@ public class TransactionContextImpl exte
 
        @Override
        public boolean getRollbackOnly() throws IllegalStateException {
-               switch (tranStatus) {
-                       case MARKED_ROLLBACK :
-                       case ROLLING_BACK :
-                       case ROLLED_BACK :
+               switch (tranStatus.get()) {
+                       case MARKED_ROLLBACK:
+                       case ROLLING_BACK:
+                       case ROLLED_BACK:
                                return true;
-                       default :
+                       default:
                                return false;
                }
        }
 
        @Override
        public void setRollbackOnly() throws IllegalStateException {
-               switch (tranStatus) {
-                       case ACTIVE :
-                       case MARKED_ROLLBACK :
-                               tranStatus = MARKED_ROLLBACK;
+               TransactionStatus status = tranStatus.get();
+               switch (status) {
+                       case ACTIVE:
+                       case MARKED_ROLLBACK:
+                               if(!tranStatus.compareAndSet(status, 
MARKED_ROLLBACK))
+                                       setRollbackOnly();
                                break;
-                       case COMMITTING :
+                       case COMMITTING:
                                // TODO something here? If it's the first 
resource then it might
                                // be ok to roll back?
-                               throw new IllegalStateException(
-                                               "The transaction is already 
being committed");
-                       case COMMITTED :
-                               throw new IllegalStateException(
-                                               "The transaction is already 
committed");
-
-                       case ROLLING_BACK :
-                       case ROLLED_BACK :
+                               throw new IllegalStateException("The 
transaction is already being committed");
+                       case COMMITTED:
+                               throw new IllegalStateException("The 
transaction is already committed");
+       
+                       case ROLLING_BACK:
+                       case ROLLED_BACK:
                                // A no op
                                break;
-                       default :
-                               throw new IllegalStateException(
-                                               "The transaction is in an 
unkown state");
+                       default:
+                               throw new IllegalStateException("The 
transaction is in an unkown state");
+               }
+       }
+       
+       @Override
+       protected void safeSetRollbackOnly() {
+               TransactionStatus status = tranStatus.get();
+               switch (status) {
+                       case ACTIVE:
+                       case MARKED_ROLLBACK:
+                               if(!tranStatus.compareAndSet(status, 
MARKED_ROLLBACK))
+                                       safeSetRollbackOnly();
+                               break;
+                       default:
+                               break;
                }
        }
 
        @Override
        public TransactionStatus getTransactionStatus() {
-               return tranStatus;
+               return tranStatus.get();
        }
 
        @Override
        public void preCompletion(Runnable job) throws IllegalStateException {
-               if (tranStatus.compareTo(MARKED_ROLLBACK) > 0) {
-                       throw new IllegalStateException(
-                                       "The current transaction is in state " 
+ tranStatus);
+               if (tranStatus.get().compareTo(MARKED_ROLLBACK) > 0) {
+                       throw new IllegalStateException("The current 
transaction is in state " + tranStatus);
                }
 
                preCompletion.add(job);
        }
 
        @Override
-       public void postCompletion(Consumer<TransactionStatus> job)
-                       throws IllegalStateException {
-               if (tranStatus == COMMITTED || tranStatus == ROLLED_BACK) {
-                       throw new IllegalStateException(
-                                       "The current transaction is in state " 
+ tranStatus);
+       public void postCompletion(Consumer<TransactionStatus> job) throws 
IllegalStateException {
+               TransactionStatus status = tranStatus.get();
+               if (status == COMMITTED || status == ROLLED_BACK) {
+                       throw new IllegalStateException("The current 
transaction is in state " + tranStatus);
                }
 
                postCompletion.add(job);
@@ -187,9 +116,8 @@ public class TransactionContextImpl exte
 
        @Override
        public void registerLocalResource(LocalResource resource) {
-               if (tranStatus.compareTo(MARKED_ROLLBACK) > 0) {
-                       throw new IllegalStateException(
-                                       "The current transaction is in state " 
+ tranStatus);
+               if (tranStatus.get().compareTo(MARKED_ROLLBACK) > 0) {
+                       throw new IllegalStateException("The current 
transaction is in state " + tranStatus);
                }
                resources.add(resource);
        }
@@ -203,4 +131,64 @@ public class TransactionContextImpl exte
        public boolean supportsLocal() {
                return true;
        }
+
+       @Override
+       protected boolean isAlive() {
+               TransactionStatus status = tranStatus.get();
+               return status != COMMITTED && status != ROLLED_BACK;
+       }
+
+       @Override
+       public void finish() {
+               
+               beforeCompletion(() -> setRollbackOnly());
+
+               TransactionStatus status;
+
+               if (getRollbackOnly()) {
+                       vanillaRollback();
+                       status = ROLLED_BACK;
+               } else {
+                       tranStatus.set(COMMITTING);
+
+                       List<LocalResource> committed = new 
ArrayList<>(resources.size());
+                       List<LocalResource> rolledback = new ArrayList<>(0);
+
+                       resources.stream().forEach(lr -> {
+                               try {
+                                       if (getRollbackOnly()) {
+                                               lr.rollback();
+                                               rolledback.add(lr);
+                                       } else {
+                                               lr.commit();
+                                               committed.add(lr);
+                                       }
+                               } catch (Exception e) {
+                                       
firstUnexpectedException.compareAndSet(null, e);
+                                       if (committed.isEmpty()) {
+                                               tranStatus.set(ROLLING_BACK);
+                                       }
+                                       rolledback.add(lr);
+                               }
+                       });
+                       status = tranStatus.updateAndGet(ts -> ts == 
ROLLING_BACK ? ROLLED_BACK : COMMITTED);
+               }
+               afterCompletion(status);
+       }
+       
+       private void vanillaRollback() {
+               
+               tranStatus.set(ROLLING_BACK);
+       
+               resources.stream().forEach(lr -> {
+                               try {
+                                       lr.rollback();
+                               } catch (Exception e) {
+                                       // TODO log this
+                                       recordFailure(e);
+                               }
+                       });
+               
+               tranStatus.set(ROLLED_BACK);
+       }
 }

Modified: 
aries/trunk/tx-control/tx-control-service-local/src/main/java/org/apache/aries/tx/control/service/local/impl/TransactionControlImpl.java
URL: 
http://svn.apache.org/viewvc/aries/trunk/tx-control/tx-control-service-local/src/main/java/org/apache/aries/tx/control/service/local/impl/TransactionControlImpl.java?rev=1732302&r1=1732301&r2=1732302&view=diff
==============================================================================
--- 
aries/trunk/tx-control/tx-control-service-local/src/main/java/org/apache/aries/tx/control/service/local/impl/TransactionControlImpl.java
 (original)
+++ 
aries/trunk/tx-control/tx-control-service-local/src/main/java/org/apache/aries/tx/control/service/local/impl/TransactionControlImpl.java
 Thu Feb 25 13:36:31 2016
@@ -2,12 +2,14 @@ package org.apache.aries.tx.control.serv
 
 import static java.util.Optional.ofNullable;
 import static 
org.osgi.service.transaction.control.TransactionStatus.NO_TRANSACTION;
+import static 
org.osgi.service.transaction.control.TransactionStatus.ROLLED_BACK;
 
 import java.util.concurrent.Callable;
 
 import org.osgi.service.coordinator.Coordination;
 import org.osgi.service.coordinator.CoordinationException;
 import org.osgi.service.coordinator.Coordinator;
+import org.osgi.service.transaction.control.ScopedWorkException;
 import org.osgi.service.transaction.control.TransactionBuilder;
 import org.osgi.service.transaction.control.TransactionContext;
 import org.osgi.service.transaction.control.TransactionControl;
@@ -50,18 +52,19 @@ public class TransactionControlImpl impl
                                throw re;
                        }
 
-                       return doWork(work, currentCoord, endCoordination);
+                       return doWork(work, currentTran, currentCoord, 
endCoordination);
                }
 
                @Override
                public <T> T requiresNew(Callable<T> work)
                                throws TransactionException, 
TransactionRolledBackException {
                        Coordination currentCoord = null;
+                       AbstractTransactionContextImpl currentTran;
                        try {
                                currentCoord = coordinator.begin(
                                                
"Resource-Local-Transaction.REQUIRES_NEW", 30000);
 
-                               AbstractTransactionContextImpl currentTran = 
new TransactionContextImpl(
+                               currentTran = new TransactionContextImpl(
                                                currentCoord);
                                
currentCoord.getVariables().put(TransactionContextKey.class,
                                                currentTran);
@@ -71,7 +74,7 @@ public class TransactionControlImpl impl
                                throw re;
                        }
 
-                       return doWork(work, currentCoord, true);
+                       return doWork(work, currentTran, currentCoord, true);
                }
 
                @Override
@@ -101,7 +104,7 @@ public class TransactionControlImpl impl
                                throw re;
                        }
 
-                       return doWork(work, currentCoord, endCoordination);
+                       return doWork(work, currentTran, currentCoord, 
endCoordination);
                }
 
                @Override
@@ -133,36 +136,71 @@ public class TransactionControlImpl impl
                                }
                                throw re;
                        }
-                       return doWork(work, currentCoord, endCoordination);
+                       return doWork(work, currentTran, currentCoord, 
endCoordination);
                }
 
                private <R> R doWork(Callable<R> transactionalWork,
-                               Coordination currentCoord, boolean 
endCoordination) {
+                               AbstractTransactionContextImpl currentTran, 
Coordination currentCoord, boolean endCoordination) {
+                       R result;
                        try {
-                               R result = transactionalWork.call();
+                               result = transactionalWork.call();
 
-                               if (endCoordination) {
-                                       currentCoord.end();
-                               }
-                               return result;
                        } catch (Throwable t) {
                                //TODO handle noRollbackFor
                                currentCoord.fail(t);
+                               try {
+                                       currentTran.finish();
+                               } catch (Exception e) {
+                                       currentTran.recordFailure(e);
+                               }
                                if (endCoordination) {
                                        try {
                                                currentCoord.end();
                                        } catch (CoordinationException ce) {
-                                               if(ce.getType() == 
CoordinationException.FAILED) {
-                                                       throw new 
TransactionRolledBackException("The transaction was rolled back due to a 
failure", ce.getCause());
-                                               } else {
-                                                       throw ce;
+                                               if(ce.getType() != 
CoordinationException.FAILED) {
+                                                       
currentTran.recordFailure(ce);
                                                }
                                        }
                                }
-                               TransactionControlImpl.<RuntimeException> 
throwException(t);
+                               ScopedWorkException workException = new 
ScopedWorkException("The scoped work threw an exception", t, 
+                                               endCoordination ? null : 
currentTran);
+                               Throwable throwable = 
currentTran.firstUnexpectedException.get();
+                               if(throwable != null) {
+                                       workException.addSuppressed(throwable);
+                               }
+                               
currentTran.subsequentExceptions.stream().forEach(workException::addSuppressed);
+                               
+                               throw workException;
+                       }
+                       
+                       try {
+                               currentTran.finish();
+                       } catch (Exception e) {
+                               currentTran.recordFailure(e);
+                               currentCoord.fail(e);
+                       }
+                       try {
+                               if (endCoordination) {
+                                       currentCoord.end();
+                               }
+                       } catch (CoordinationException ce) {
+                               if(ce.getType() != 
CoordinationException.FAILED) {
+                                       currentTran.recordFailure(ce);
+                               }
+                       }
+                       
+                       Throwable throwable = 
currentTran.firstUnexpectedException.get();
+                       if(throwable != null) {
+                               TransactionException te = 
currentTran.getTransactionStatus() == ROLLED_BACK ?
+                                               new 
TransactionRolledBackException("The transaction rolled back due to a failure", 
throwable) :
+                                               new TransactionException("There 
was an error in the Transaction completion.", throwable);
+                               
+                               
currentTran.subsequentExceptions.stream().forEach(te::addSuppressed);
+                               
+                               throw te;
                        }
-                       throw new TransactionException(
-                                       "The code here should never be 
reached");
+                       
+                       return result;
                }
        }
 
@@ -244,21 +282,6 @@ public class TransactionControlImpl impl
                return toUse;
        }
 
-       /**
-        * Borrowed from the netty project as a way to avoid wrapping checked
-        * exceptions Viewable at https://github.com/netty/netty/
-        * 
netty/common/src/main/java/io/netty/util/internal/PlatformDependent.java
-        * 
-        * @param t
-        * @return
-        * @throws T
-        */
-       @SuppressWarnings("unchecked")
-       private static <T extends Throwable> T throwException(Throwable t)
-                       throws T {
-               throw (T) t;
-       }
-
        @Override
        public void ignoreException(Throwable t) throws IllegalStateException {
                // TODO Auto-generated method stub

Modified: 
aries/trunk/tx-control/tx-control-service-local/src/test/java/org/apache/aries/tx/control/service/local/impl/NoTransactionContextTest.java
URL: 
http://svn.apache.org/viewvc/aries/trunk/tx-control/tx-control-service-local/src/test/java/org/apache/aries/tx/control/service/local/impl/NoTransactionContextTest.java?rev=1732302&r1=1732301&r2=1732302&view=diff
==============================================================================
--- 
aries/trunk/tx-control/tx-control-service-local/src/test/java/org/apache/aries/tx/control/service/local/impl/NoTransactionContextTest.java
 (original)
+++ 
aries/trunk/tx-control/tx-control-service-local/src/test/java/org/apache/aries/tx/control/service/local/impl/NoTransactionContextTest.java
 Thu Feb 25 13:36:31 2016
@@ -22,7 +22,6 @@ import org.mockito.runners.MockitoJUnitR
 import org.osgi.service.coordinator.Coordination;
 import org.osgi.service.coordinator.Participant;
 import org.osgi.service.transaction.control.LocalResource;
-import org.osgi.service.transaction.control.TransactionContext;
 
 @RunWith(MockitoJUnitRunner.class)
 public class NoTransactionContextTest {
@@ -36,7 +35,7 @@ public class NoTransactionContextTest {
        
        Map<Class<?>, Object> variables;
        
-       TransactionContext ctx;
+       AbstractTransactionContextImpl ctx;
        
        @Before
        public void setUp() {
@@ -97,7 +96,7 @@ public class NoTransactionContextTest {
        }
        
        @Test
-       public void testPreCompletionEnd() throws Exception {
+       public void testPreCompletion() throws Exception {
                
                AtomicInteger value = new AtomicInteger(0);
                
@@ -105,8 +104,7 @@ public class NoTransactionContextTest {
                
                assertEquals(0, value.getAndSet(1));
                
-               Participant participant = getParticipant();
-               participant.ended(coordination);
+               ctx.finish();
                
                assertEquals(5, value.get());
        }
@@ -123,11 +121,13 @@ public class NoTransactionContextTest {
                Participant participant = getParticipant();
                participant.failed(coordination);
                
+               ctx.finish();
+               
                assertEquals(5, value.get());
        }
 
        @Test
-       public void testPostCompletionEnd() throws Exception {
+       public void testPostCompletion() throws Exception {
                
                AtomicInteger value = new AtomicInteger(0);
                
@@ -138,8 +138,7 @@ public class NoTransactionContextTest {
                
                assertEquals(0, value.getAndSet(1));
                
-               Participant participant = getParticipant();
-               participant.ended(coordination);
+               ctx.finish();
                
                assertEquals(5, value.get());
        }
@@ -159,11 +158,13 @@ public class NoTransactionContextTest {
                Participant participant = getParticipant();
                participant.failed(coordination);
                
+               ctx.finish();
+               
                assertEquals(5, value.get());
        }
 
        @Test
-       public void testPostCompletionIsAfterPreCompletionEnd() throws 
Exception {
+       public void testPostCompletionIsAfterPreCompletion() throws Exception {
                
                AtomicInteger value = new AtomicInteger(0);
                
@@ -173,8 +174,7 @@ public class NoTransactionContextTest {
                        value.compareAndSet(3, 5);
                });
                
-               Participant participant = getParticipant();
-               participant.ended(coordination);
+               ctx.finish();
                
                assertEquals(5, value.get());
        }
@@ -193,6 +193,8 @@ public class NoTransactionContextTest {
                Participant participant = getParticipant();
                participant.failed(coordination);
                
+               ctx.finish();
+               
                assertEquals(5, value.get());
        }
 
@@ -210,8 +212,7 @@ public class NoTransactionContextTest {
                        value.compareAndSet(3, 5);
                });
                
-               Participant participant = getParticipant();
-               participant.ended(coordination);
+               ctx.finish();
                
                assertEquals(5, value.get());
        }

Modified: 
aries/trunk/tx-control/tx-control-service-local/src/test/java/org/apache/aries/tx/control/service/local/impl/TransactionContextTest.java
URL: 
http://svn.apache.org/viewvc/aries/trunk/tx-control/tx-control-service-local/src/test/java/org/apache/aries/tx/control/service/local/impl/TransactionContextTest.java?rev=1732302&r1=1732301&r2=1732302&view=diff
==============================================================================
--- 
aries/trunk/tx-control/tx-control-service-local/src/test/java/org/apache/aries/tx/control/service/local/impl/TransactionContextTest.java
 (original)
+++ 
aries/trunk/tx-control/tx-control-service-local/src/test/java/org/apache/aries/tx/control/service/local/impl/TransactionContextTest.java
 Thu Feb 25 13:36:31 2016
@@ -29,7 +29,6 @@ import org.mockito.runners.MockitoJUnitR
 import org.osgi.service.coordinator.Coordination;
 import org.osgi.service.coordinator.Participant;
 import org.osgi.service.transaction.control.LocalResource;
-import org.osgi.service.transaction.control.TransactionContext;
 import org.osgi.service.transaction.control.TransactionException;
 
 @RunWith(MockitoJUnitRunner.class)
@@ -44,7 +43,7 @@ public class TransactionContextTest {
        
        Map<Class<?>, Object> variables;
        
-       TransactionContext ctx;
+       AbstractTransactionContextImpl ctx;
        
        @Before
        public void setUp() {
@@ -107,7 +106,7 @@ public class TransactionContextTest {
        }
        
        @Test
-       public void testPreCompletionEnd() throws Exception {
+       public void testPreCompletion() throws Exception {
                
                AtomicInteger value = new AtomicInteger(0);
                
@@ -118,10 +117,7 @@ public class TransactionContextTest {
                
                assertEquals(0, value.getAndSet(1));
                
-               ArgumentCaptor<Participant> captor = 
ArgumentCaptor.forClass(Participant.class);
-               Mockito.verify(coordination).addParticipant(captor.capture());
-               
-               captor.getValue().ended(coordination);
+               ctx.finish();
                
                assertEquals(5, value.get());
        }
@@ -138,16 +134,19 @@ public class TransactionContextTest {
                
                assertEquals(0, value.getAndSet(1));
                
+               
                ArgumentCaptor<Participant> captor = 
ArgumentCaptor.forClass(Participant.class);
                Mockito.verify(coordination).addParticipant(captor.capture());
                
                captor.getValue().failed(coordination);
                
+               ctx.finish();
+
                assertEquals(5, value.get());
        }
 
        @Test
-       public void testPostCompletionEnd() throws Exception {
+       public void testPostCompletion() throws Exception {
                
                AtomicInteger value = new AtomicInteger(0);
                
@@ -158,10 +157,7 @@ public class TransactionContextTest {
                
                assertEquals(0, value.getAndSet(1));
                
-               ArgumentCaptor<Participant> captor = 
ArgumentCaptor.forClass(Participant.class);
-               Mockito.verify(coordination).addParticipant(captor.capture());
-               
-               captor.getValue().ended(coordination);
+               ctx.finish();
                
                assertEquals(5, value.get());
        }
@@ -183,6 +179,8 @@ public class TransactionContextTest {
                
                captor.getValue().failed(coordination);
                
+               ctx.finish();
+               
                assertEquals(5, value.get());
        }
 
@@ -200,10 +198,7 @@ public class TransactionContextTest {
                        value.compareAndSet(3, 5);
                });
                
-               ArgumentCaptor<Participant> captor = 
ArgumentCaptor.forClass(Participant.class);
-               Mockito.verify(coordination).addParticipant(captor.capture());
-               
-               captor.getValue().ended(coordination);
+               ctx.finish();
                
                assertEquals(5, value.get());
        }
@@ -222,10 +217,7 @@ public class TransactionContextTest {
                        value.compareAndSet(3, 5);
                });
                
-               ArgumentCaptor<Participant> captor = 
ArgumentCaptor.forClass(Participant.class);
-               Mockito.verify(coordination).addParticipant(captor.capture());
-               
-               captor.getValue().ended(coordination);
+               ctx.finish();
                
                assertEquals(5, value.get());
        }
@@ -241,9 +233,8 @@ public class TransactionContextTest {
        @Test(expected=IllegalStateException.class)
        public void testPreCompletionAfterEnd() throws Exception {
                
-               getParticipant().ended(coordination);
+               ctx.finish();
                
-               Mockito.when(coordination.isTerminated()).thenReturn(true);
                ctx.preCompletion(() -> {});
        }
 
@@ -252,16 +243,16 @@ public class TransactionContextTest {
                
                getParticipant().failed(coordination);
                
-               Mockito.when(coordination.isTerminated()).thenReturn(true);
+               ctx.finish();
+               
                ctx.preCompletion(() -> {});
        }
 
        @Test(expected=IllegalStateException.class)
        public void testPostCompletionAfterEnd() throws Exception {
                
-               getParticipant().ended(coordination);
+               ctx.finish();
                
-               Mockito.when(coordination.isTerminated()).thenReturn(true);
                ctx.postCompletion(x -> {});
        }
 
@@ -270,12 +261,13 @@ public class TransactionContextTest {
                
                getParticipant().failed(coordination);
                
-               Mockito.when(coordination.isTerminated()).thenReturn(true);
+               ctx.finish();
+               
                ctx.postCompletion(x -> {});
        }
 
        @Test
-       public void testLocalResourceEnd() throws Exception {
+       public void testLocalResource() throws Exception {
                ctx.registerLocalResource(localResource);
                
                Mockito.doAnswer(i -> {
@@ -283,13 +275,29 @@ public class TransactionContextTest {
                        return null;
                }).when(localResource).commit();
                
-               getParticipant().ended(coordination);
+               ctx.finish();
                
                Mockito.verify(localResource).commit();
        }
+       
+       @Test
+       public void testLocalResourceEarlyEnd() throws Exception {
+               ctx.registerLocalResource(localResource);
+               
+               Mockito.doAnswer(i -> {
+                       assertEquals(COMMITTING, ctx.getTransactionStatus());
+                       return null;
+               }).when(localResource).commit();
+               
+               getParticipant().ended(coordination);
+               
+               ctx.finish();
+               
+               Mockito.verify(localResource).rollback();
+       }
 
        @Test
-       public void testLocalResourceEndRollbackOnly() throws Exception {
+       public void testLocalResourceRollbackOnly() throws Exception {
                ctx.registerLocalResource(localResource);
                ctx.setRollbackOnly();
                
@@ -298,7 +306,7 @@ public class TransactionContextTest {
                        return null;
                }).when(localResource).rollback();
                
-               getParticipant().ended(coordination);
+               ctx.finish();
                
                Mockito.verify(localResource).rollback();
        }
@@ -314,11 +322,13 @@ public class TransactionContextTest {
                
                getParticipant().failed(coordination);
                
+               ctx.finish();
+               
                Mockito.verify(localResource).rollback();
        }
        
        @Test
-       public void testLocalResourceEndPreCommitException() throws Exception {
+       public void testLocalResourcePreCommitException() throws Exception {
                ctx.registerLocalResource(localResource);
                
                Mockito.doAnswer(i -> {
@@ -328,13 +338,13 @@ public class TransactionContextTest {
                
                ctx.preCompletion(() -> { throw new IllegalArgumentException(); 
});
                
-               getParticipant().ended(coordination);
+               ctx.finish();
                
                Mockito.verify(localResource).rollback();
        }
 
        @Test
-       public void testLocalResourceEndPostCommitException() throws Exception {
+       public void testLocalResourcePostCommitException() throws Exception {
                ctx.registerLocalResource(localResource);
                
                Mockito.doAnswer(i -> {
@@ -347,7 +357,7 @@ public class TransactionContextTest {
                                throw new IllegalArgumentException(); 
                        });
                
-               getParticipant().ended(coordination);
+               ctx.finish();
                
                Mockito.verify(localResource).commit();
        }
@@ -370,7 +380,7 @@ public class TransactionContextTest {
                        return null;
                }).when(localResource2).rollback();
                
-               getParticipant().ended(coordination);
+               ctx.finish();
                
                Mockito.verify(localResource).commit();
                Mockito.verify(localResource2).rollback();



Reply via email to