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);
}