Author: timothyjward
Date: Thu Feb 18 18:05:30 2016
New Revision: 1731104

URL: http://svn.apache.org/viewvc?rev=1731104&view=rev
Log:
[tx-control] Extend iTests to include exception failures
* Possibly some API work needed for checked Exceptions
* Still no support for noRollbackFor
* Coordinator usage needs some work

Added:
    
aries/trunk/tx-control/tx-control-itests/src/test/java/org/apache/aries/tx/control/itests/ExceptionManagementTransactionTest.java
Modified:
    
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

Added: 
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=1731104&view=auto
==============================================================================
--- 
aries/trunk/tx-control/tx-control-itests/src/test/java/org/apache/aries/tx/control/itests/ExceptionManagementTransactionTest.java
 (added)
+++ 
aries/trunk/tx-control/tx-control-itests/src/test/java/org/apache/aries/tx/control/itests/ExceptionManagementTransactionTest.java
 Thu Feb 18 18:05:30 2016
@@ -0,0 +1,196 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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 WARRANTIESOR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.aries.tx.control.itests;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.fail;
+import static org.ops4j.pax.exam.CoreOptions.junitBundles;
+import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
+import static org.ops4j.pax.exam.CoreOptions.options;
+import static org.ops4j.pax.exam.CoreOptions.systemProperty;
+import static org.ops4j.pax.exam.CoreOptions.when;
+
+import java.net.URISyntaxException;
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.Properties;
+
+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;
+import org.ops4j.pax.exam.CoreOptions;
+import org.ops4j.pax.exam.Option;
+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.TransactionControl;
+import org.osgi.service.transaction.control.TransactionRolledBackException;
+import org.osgi.service.transaction.control.jdbc.JDBCConnectionProviderFactory;
+
+@RunWith(PaxExam.class)
+@ExamReactorStrategy(PerClass.class)
+public class ExceptionManagementTransactionTest extends 
AbstractIntegrationTest {
+
+       @Inject
+       TransactionControl txControl;
+
+       @Inject
+       JDBCConnectionProviderFactory resourceProviderFactory;
+       
+       @Inject
+       DataSourceFactory dsf;
+       
+       Connection connection;
+
+       @Before
+       public void setUp() {
+               Properties jdbc = new Properties();
+               
+               jdbc.setProperty(DataSourceFactory.JDBC_URL, 
"jdbc:h2:mem:test;DB_CLOSE_DELAY=-1");
+               
+               connection = resourceProviderFactory.getProviderFor(dsf, jdbc, 
null).getResource(txControl);
+               
+               
+               txControl.required(() -> {
+                               Statement s = connection.createStatement();
+                               try {
+                                       s.execute("DROP TABLE TEST_TABLE");
+                               } catch (SQLException sqle) {}
+                                       s.execute("CREATE TABLE TEST_TABLE ( 
message varchar(255) )");
+                                       return null;
+                       });
+       }
+       
+       @After
+       public void tearDown() {
+
+               txControl.required(() -> connection.createStatement()
+                               .execute("DROP TABLE TEST_TABLE"));
+
+       }
+       
+       @Test
+       public void testRuntimeException() {
+               
+               RuntimeException toThrow = new RuntimeException("Bang!");
+               
+               try {
+                       txControl.required(() -> {
+                                               connection.createStatement()
+                                                       .execute("Insert into 
TEST_TABLE values ( 'Hello World!' )");
+                                               throw toThrow;
+                                       });
+                       fail("An exception should occur!");
+               } catch (TransactionRolledBackException tre) {
+                       assertSame(toThrow, tre.getCause());
+               }
+
+               assertRollback();
+       }
+
+       @Test
+       public void testCheckedException() {
+               URISyntaxException toThrow = new URISyntaxException("yuck", 
"Bang!");
+               
+               try {
+                       txControl.required(() -> {
+                                               connection.createStatement()
+                                                       .execute("Insert into 
TEST_TABLE values ( 'Hello World!' )");
+                                               throw toThrow;
+                                       });
+                       fail("An exception should occur!");
+                       // We have to catch Exception as the compiler complains
+                       // otherwise
+               } catch (TransactionRolledBackException tre) {
+                       assertSame(toThrow, tre.getCause());
+               }
+
+               assertRollback();
+       }
+
+       //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!");
+               
+               try {
+                       txControl.required(() -> {
+                               txControl.getCurrentContext().preCompletion(() 
-> {
+                                               throw toThrow;
+                                       });
+                               return connection.createStatement()
+                                       .execute("Insert into TEST_TABLE values 
( 'Hello World!' )");
+                       });
+                       fail("An exception should occur!");
+                       // We have to catch Exception as the compiler complains
+                       // otherwise
+               } catch (TransactionRolledBackException tre) {
+                       assertSame(toThrow, tre.getCause());
+               }
+               
+               assertRollback();
+       }
+
+       private void assertRollback() {
+               assertEquals(Integer.valueOf(0), txControl.notSupported(() -> {
+                       ResultSet rs = connection.createStatement()
+                                       .executeQuery("Select count(*) from 
TEST_TABLE");
+                       rs.next();
+                       return rs.getInt(1);
+               }));
+       }
+
+       @Configuration
+       public Option[] configuration() {
+               String localRepo = System.getProperty("maven.repo.local");
+               if (localRepo == null) {
+                       localRepo = 
System.getProperty("org.ops4j.pax.url.mvn.localRepository");
+               }
+               return options(junitBundles(), 
systemProperty("org.ops4j.pax.logging.DefaultServiceLog.level").value("INFO"),
+                               when(localRepo != null)
+                                               
.useOptions(CoreOptions.vmOption("-Dorg.ops4j.pax.url.mvn.localRepository=" + 
localRepo)),
+                               mavenBundle("org.apache.aries.testsupport", 
"org.apache.aries.testsupport.unit").versionAsInProject(),
+                               mavenBundle("org.apache.felix", 
"org.apache.felix.coordinator").versionAsInProject(),
+                               mavenBundle("org.apache.aries.tx-control", 
"tx-control-service-local").versionAsInProject(),
+                               mavenBundle("com.h2database", 
"h2").versionAsInProject(),
+                               mavenBundle("org.apache.aries.tx-control", 
"tx-control-provider-jdbc-local").versionAsInProject(),
+                               mavenBundle("org.ops4j.pax.logging", 
"pax-logging-api").versionAsInProject(),
+                               mavenBundle("org.ops4j.pax.logging", 
"pax-logging-service").versionAsInProject()
+                               
+               /*
+                * vmOption
+                * 
("-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=5005"),
+                * waitForFrameworkStartup(),
+                */
+               );
+       }
+
+}

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=1731104&r1=1731103&r2=1731104&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 18 18:05:30 2016
@@ -1,20 +1,30 @@
 package org.apache.aries.tx.control.service.local.impl;
 
+import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.List;
 import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.Consumer;
 
 import org.osgi.service.coordinator.Coordination;
 import org.osgi.service.transaction.control.TransactionContext;
+import org.osgi.service.transaction.control.TransactionStatus;
 
 public abstract class AbstractTransactionContextImpl
                implements TransactionContext {
 
        protected static class TransactionVariablesKey {}
 
-       AtomicReference<Exception> unexpectedException = new 
AtomicReference<>();
+       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;
        }
@@ -23,7 +33,7 @@ public abstract class AbstractTransactio
        @Override
        public Object getScopedValue(Object key) {
                return ((HashMap<Object,Object>) coordination.getVariables()
-                               
.getOrDefault(AbstractTransactionContextImpl.TransactionVariablesKey.class, new 
HashMap<>()))
+                               .getOrDefault(TransactionVariablesKey.class, 
new HashMap<>()))
                                                .get(key);
        }
 
@@ -31,6 +41,22 @@ public abstract class AbstractTransactio
        @Override
        public void putScopedValue(Object key, Object value) {
                ((HashMap<Object,Object>) 
coordination.getVariables().computeIfAbsent(
-                               
AbstractTransactionContextImpl.TransactionVariablesKey.class, k -> new 
HashMap<>())).put(key, value);
+                               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)) {
+                                       onFirstError.run();
+                               } else {
+                                       subsequentExceptions.add(e);
+                               }
+                               // TODO log this
+                       }
+               });
        }
 }

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=1731104&r1=1731103&r2=1731104&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 18 18:05:30 2016
@@ -2,8 +2,6 @@ package org.apache.aries.tx.control.serv
 
 import static 
org.osgi.service.transaction.control.TransactionStatus.NO_TRANSACTION;
 
-import java.util.ArrayList;
-import java.util.List;
 import java.util.function.Consumer;
 
 import javax.transaction.xa.XAResource;
@@ -17,9 +15,6 @@ import org.osgi.service.transaction.cont
 public class NoTransactionContextImpl extends AbstractTransactionContextImpl
                implements TransactionContext {
 
-       final List<Runnable>                                    preCompletion   
        = new ArrayList<>();
-       final List<Consumer<TransactionStatus>> postCompletion          = new 
ArrayList<>();
-
        volatile boolean                                                
finished                        = false;
 
        public NoTransactionContextImpl(Coordination coordination) {
@@ -29,21 +24,17 @@ public class NoTransactionContextImpl ex
 
                        @Override
                        public void failed(Coordination coordination) throws 
Exception {
+                               finished();
+                       }
 
-                               beforeCompletion();
-
-                               afterCompletion();
+                       @Override
+                       public void ended(Coordination coordination) throws 
Exception {
+                               finished();
                        }
 
-                       private void beforeCompletion() {
-                               preCompletion.stream().forEach(r -> {
-                                       try {
-                                               r.run();
-                                       } catch (Exception e) {
-                                               
unexpectedException.compareAndSet(null, e);
-                                               // TODO log this
-                                       }
-                               });
+                       private void finished() {
+                               beforeCompletion(() -> {});
+                               afterCompletion();
                        }
 
                        private void afterCompletion() {
@@ -51,18 +42,11 @@ public class NoTransactionContextImpl ex
                                        try {
                                                c.accept(NO_TRANSACTION);
                                        } catch (Exception e) {
-                                               
unexpectedException.compareAndSet(null, e);
+                                               
firstUnexpectedException.compareAndSet(null, e);
                                                // TODO log this
                                        }
                                });
                        }
-
-                       @Override
-                       public void ended(Coordination coordination) throws 
Exception {
-                               beforeCompletion();
-
-                               afterCompletion();
-                       }
                });
        }
 

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=1731104&r1=1731103&r2=1731104&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 18 18:05:30 2016
@@ -23,9 +23,6 @@ public class TransactionContextImpl exte
 
        final List<LocalResource>                               resources       
                = new ArrayList<>();
 
-       final List<Runnable>                                    preCompletion   
        = new ArrayList<>();
-       final List<Consumer<TransactionStatus>> postCompletion          = new 
ArrayList<>();
-
        private volatile TransactionStatus              tranStatus;
 
        public TransactionContextImpl(Coordination coordination) {
@@ -62,15 +59,7 @@ public class TransactionContextImpl exte
                        }
 
                        private void beforeCompletion() {
-                               preCompletion.stream().forEach(r -> {
-                                       try {
-                                               r.run();
-                                       } catch (Exception e) {
-                                               
unexpectedException.compareAndSet(null, e);
-                                               setRollbackOnly();
-                                               // TODO log this
-                                       }
-                               });
+                               TransactionContextImpl.this.beforeCompletion(() 
-> setRollbackOnly());
                        }
 
                        private void afterCompletion() {
@@ -78,7 +67,7 @@ public class TransactionContextImpl exte
                                        try {
                                                c.accept(tranStatus);
                                        } catch (Exception e) {
-                                               
unexpectedException.compareAndSet(null, e);
+                                               
firstUnexpectedException.compareAndSet(null, e);
                                                // TODO log this
                                        }
                                });
@@ -107,7 +96,7 @@ public class TransactionContextImpl exte
                                                                
committed.add(lr);
                                                        }
                                                } catch (Exception e) {
-                                                       
unexpectedException.compareAndSet(null, e);
+                                                       
firstUnexpectedException.compareAndSet(null, e);
                                                        if 
(committed.isEmpty()) {
                                                                tranStatus = 
ROLLING_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=1731104&r1=1731103&r2=1731104&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 18 18:05:30 2016
@@ -6,6 +6,7 @@ import static org.osgi.service.transacti
 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.TransactionBuilder;
 import org.osgi.service.transaction.control.TransactionContext;
@@ -145,9 +146,18 @@ public class TransactionControlImpl impl
                                }
                                return result;
                        } catch (Throwable t) {
+                               //TODO handle noRollbackFor
+                               currentCoord.fail(t);
                                if (endCoordination) {
-                                       //TODO handle noRollbackFor
-                                       currentCoord.fail(t);
+                                       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;
+                                               }
+                                       }
                                }
                                TransactionControlImpl.<RuntimeException> 
throwException(t);
                        }


Reply via email to