You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@aries.apache.org by ti...@apache.org on 2016/03/10 12:28:17 UTC
svn commit: r1734385 [2/2] - in /aries/trunk/tx-control: ./
tx-control-itests/
tx-control-itests/src/test/java/org/apache/aries/tx/control/itests/
tx-control-provider-jdbc-common/ tx-control-provider-jdbc-common/src/
tx-control-provider-jdbc-common/src...
Added: aries/trunk/tx-control/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/impl/XAConnectionWrapper.java
URL: http://svn.apache.org/viewvc/aries/trunk/tx-control/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/impl/XAConnectionWrapper.java?rev=1734385&view=auto
==============================================================================
--- aries/trunk/tx-control/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/impl/XAConnectionWrapper.java (added)
+++ aries/trunk/tx-control/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/impl/XAConnectionWrapper.java Thu Mar 10 11:27:48 2016
@@ -0,0 +1,30 @@
+package org.apache.aries.tx.control.jdbc.xa.impl;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+
+import javax.sql.XAConnection;
+import javax.transaction.xa.XAResource;
+
+import org.apache.aries.tx.control.jdbc.common.impl.ConnectionWrapper;
+
+public class XAConnectionWrapper extends ConnectionWrapper {
+
+ private final Connection connection;
+
+ private final XAResource xaResource;
+
+ public XAConnectionWrapper(XAConnection xaConnection) throws SQLException {
+ this.connection = xaConnection.getConnection();
+ this.xaResource = xaConnection.getXAResource();
+ }
+
+ @Override
+ protected Connection getDelegate() {
+ return connection;
+ }
+
+ public XAResource getXaResource() {
+ return xaResource;
+ }
+}
Added: aries/trunk/tx-control/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/impl/XADataSourceMapper.java
URL: http://svn.apache.org/viewvc/aries/trunk/tx-control/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/impl/XADataSourceMapper.java?rev=1734385&view=auto
==============================================================================
--- aries/trunk/tx-control/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/impl/XADataSourceMapper.java (added)
+++ aries/trunk/tx-control/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/impl/XADataSourceMapper.java Thu Mar 10 11:27:48 2016
@@ -0,0 +1,70 @@
+package org.apache.aries.tx.control.jdbc.xa.impl;
+
+import java.io.PrintWriter;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.sql.SQLFeatureNotSupportedException;
+import java.util.logging.Logger;
+
+import javax.sql.DataSource;
+import javax.sql.XADataSource;
+
+public class XADataSourceMapper implements DataSource {
+
+ private final XADataSource xaDataSource;
+
+ public XADataSourceMapper(XADataSource xaDataSource) {
+ super();
+ this.xaDataSource = xaDataSource;
+ }
+
+ @Override
+ public PrintWriter getLogWriter() throws SQLException {
+ return xaDataSource.getLogWriter();
+ }
+
+ @Override
+ public void setLogWriter(PrintWriter out) throws SQLException {
+ xaDataSource.setLogWriter(out);
+ }
+
+ @Override
+ public void setLoginTimeout(int seconds) throws SQLException {
+ xaDataSource.setLoginTimeout(seconds);
+ }
+
+ @Override
+ public int getLoginTimeout() throws SQLException {
+ return xaDataSource.getLoginTimeout();
+ }
+
+ @Override
+ public Logger getParentLogger() throws SQLFeatureNotSupportedException {
+ return xaDataSource.getParentLogger();
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public <T> T unwrap(Class<T> iface) throws SQLException {
+ if(isWrapperFor(iface)) {
+ return (T) xaDataSource;
+ }
+ throw new SQLException("This datasource is not a wrapper for " + iface);
+ }
+
+ @Override
+ public boolean isWrapperFor(Class<?> iface) throws SQLException {
+ return iface == XADataSource.class || iface.isInstance(xaDataSource);
+ }
+
+ @Override
+ public Connection getConnection() throws SQLException {
+ return new XAConnectionWrapper(xaDataSource.getXAConnection());
+ }
+
+ @Override
+ public Connection getConnection(String username, String password) throws SQLException {
+ return new XAConnectionWrapper(xaDataSource.getXAConnection(username, password));
+ }
+
+}
Added: aries/trunk/tx-control/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/impl/XAEnabledTxContextBindingConnection.java
URL: http://svn.apache.org/viewvc/aries/trunk/tx-control/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/impl/XAEnabledTxContextBindingConnection.java?rev=1734385&view=auto
==============================================================================
--- aries/trunk/tx-control/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/impl/XAEnabledTxContextBindingConnection.java (added)
+++ aries/trunk/tx-control/tx-control-provider-jdbc-xa/src/main/java/org/apache/aries/tx/control/jdbc/xa/impl/XAEnabledTxContextBindingConnection.java Thu Mar 10 11:27:48 2016
@@ -0,0 +1,127 @@
+package org.apache.aries.tx.control.jdbc.xa.impl;
+
+import static org.osgi.service.transaction.control.TransactionStatus.NO_TRANSACTION;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.UUID;
+
+import javax.sql.DataSource;
+import javax.transaction.xa.XAResource;
+
+import org.apache.aries.tx.control.jdbc.common.impl.ConnectionWrapper;
+import org.apache.aries.tx.control.jdbc.common.impl.ScopedConnectionWrapper;
+import org.apache.aries.tx.control.jdbc.common.impl.TxConnectionWrapper;
+import org.osgi.service.transaction.control.LocalResource;
+import org.osgi.service.transaction.control.TransactionContext;
+import org.osgi.service.transaction.control.TransactionControl;
+import org.osgi.service.transaction.control.TransactionException;
+
+public class XAEnabledTxContextBindingConnection extends ConnectionWrapper {
+
+ private final TransactionControl txControl;
+ private final UUID resourceId;
+ private final DataSource dataSource;
+ private final boolean xaEnabled;
+ private final boolean localEnabled;
+
+ public XAEnabledTxContextBindingConnection(TransactionControl txControl,
+ DataSource dataSource, UUID resourceId, boolean xaEnabled, boolean localEnabled) {
+ this.txControl = txControl;
+ this.dataSource = dataSource;
+ this.resourceId = resourceId;
+ this.xaEnabled = xaEnabled;
+ this.localEnabled = localEnabled;
+ }
+
+ @Override
+ protected final Connection getDelegate() {
+
+ TransactionContext txContext = txControl.getCurrentContext();
+
+ if (txContext == null) {
+ throw new TransactionException("The resource " + dataSource
+ + " cannot be accessed outside of an active Transaction Context");
+ }
+
+ Connection existing = (Connection) txContext.getScopedValue(resourceId);
+
+ if (existing != null) {
+ return existing;
+ }
+
+ Connection toReturn;
+ Connection toClose;
+
+ try {
+ if (txContext.getTransactionStatus() == NO_TRANSACTION) {
+ toClose = dataSource.getConnection();
+ toReturn = new ScopedConnectionWrapper(toClose);
+ } else if (txContext.supportsXA() && xaEnabled) {
+ toClose = dataSource.getConnection();
+ toReturn = new TxConnectionWrapper(toClose);
+ txContext.registerXAResource(getXAResource(toClose));
+ } else if (txContext.supportsLocal() && localEnabled) {
+ toClose = dataSource.getConnection();
+ toReturn = new TxConnectionWrapper(toClose);
+ txContext.registerLocalResource(getLocalResource(toClose));
+ } else {
+ throw new TransactionException(
+ "There is a transaction active, but it does not support local participants");
+ }
+ } catch (Exception sqle) {
+ throw new TransactionException(
+ "There was a problem getting hold of a database connection",
+ sqle);
+ }
+
+
+ txContext.postCompletion(x -> {
+ try {
+ toClose.close();
+ } catch (SQLException sqle) {
+ // TODO log this
+ }
+ });
+
+ txContext.putScopedValue(resourceId, toReturn);
+
+ return toReturn;
+ }
+
+
+ private XAResource getXAResource(Connection conn) throws SQLException {
+ if(conn instanceof XAConnectionWrapper) {
+ return ((XAConnectionWrapper)conn).getXaResource();
+ } else if(conn.isWrapperFor(XAConnectionWrapper.class)){
+ return conn.unwrap(XAConnectionWrapper.class).getXaResource();
+ } else {
+ throw new IllegalArgumentException("The XAResource for the connection cannot be found");
+ }
+ }
+
+ private LocalResource getLocalResource(Connection conn) {
+ return new LocalResource() {
+ @Override
+ public void commit() throws TransactionException {
+ try {
+ conn.commit();
+ } catch (SQLException e) {
+ throw new TransactionException(
+ "An error occurred when committing the connection", e);
+ }
+ }
+
+ @Override
+ public void rollback() throws TransactionException {
+ try {
+ conn.rollback();
+ } catch (SQLException e) {
+ throw new TransactionException(
+ "An error occurred when rolling back the connection", e);
+ }
+ }
+
+ };
+ }
+}
Added: aries/trunk/tx-control/tx-control-provider-jdbc-xa/src/test/java/org/apache/aries/tx/control/jdbc/xa/impl/XAEnabledTxContextBindingConnectionTest.java
URL: http://svn.apache.org/viewvc/aries/trunk/tx-control/tx-control-provider-jdbc-xa/src/test/java/org/apache/aries/tx/control/jdbc/xa/impl/XAEnabledTxContextBindingConnectionTest.java?rev=1734385&view=auto
==============================================================================
--- aries/trunk/tx-control/tx-control-provider-jdbc-xa/src/test/java/org/apache/aries/tx/control/jdbc/xa/impl/XAEnabledTxContextBindingConnectionTest.java (added)
+++ aries/trunk/tx-control/tx-control-provider-jdbc-xa/src/test/java/org/apache/aries/tx/control/jdbc/xa/impl/XAEnabledTxContextBindingConnectionTest.java Thu Mar 10 11:27:48 2016
@@ -0,0 +1,224 @@
+package org.apache.aries.tx.control.jdbc.xa.impl;
+
+import static org.mockito.Mockito.times;
+import static org.osgi.service.transaction.control.TransactionStatus.ACTIVE;
+import static org.osgi.service.transaction.control.TransactionStatus.NO_TRANSACTION;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+import javax.sql.DataSource;
+import javax.sql.XAConnection;
+import javax.sql.XADataSource;
+import javax.transaction.xa.XAResource;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.runners.MockitoJUnitRunner;
+import org.osgi.service.transaction.control.LocalResource;
+import org.osgi.service.transaction.control.TransactionContext;
+import org.osgi.service.transaction.control.TransactionControl;
+import org.osgi.service.transaction.control.TransactionException;
+
+@RunWith(MockitoJUnitRunner.class)
+public class XAEnabledTxContextBindingConnectionTest {
+
+ @Mock
+ TransactionControl control;
+
+ @Mock
+ TransactionContext context;
+
+ @Mock
+ DataSource dataSource;
+
+ @Mock
+ XADataSource xaDataSource;
+
+ @Mock
+ XAConnection xaMock;
+
+ @Mock
+ XAResource xaResource;
+
+ @Mock
+ Connection rawConnection;
+
+ Map<Object, Object> variables = new HashMap<>();
+
+ UUID id = UUID.randomUUID();
+
+ XAEnabledTxContextBindingConnection localConn;
+ XAEnabledTxContextBindingConnection xaConn;
+
+ @Before
+ public void setUp() throws SQLException {
+ Mockito.when(dataSource.getConnection()).thenReturn(rawConnection).thenReturn(null);
+
+ Mockito.doAnswer(i -> variables.put(i.getArguments()[0], i.getArguments()[1]))
+ .when(context).putScopedValue(Mockito.any(), Mockito.any());
+ Mockito.when(context.getScopedValue(Mockito.any()))
+ .thenAnswer(i -> variables.get(i.getArguments()[0]));
+
+ Mockito.when(xaDataSource.getXAConnection()).thenReturn(xaMock);
+ Mockito.when(xaMock.getConnection()).thenReturn(rawConnection);
+ Mockito.when(xaMock.getXAResource()).thenReturn(xaResource);
+
+ localConn = new XAEnabledTxContextBindingConnection(control, dataSource, id, false, true);
+ xaConn = new XAEnabledTxContextBindingConnection(control, new XADataSourceMapper(xaDataSource),
+ id, true, false);
+ }
+
+ private void setupNoTransaction() {
+ Mockito.when(control.getCurrentContext()).thenReturn(context);
+ Mockito.when(context.getTransactionStatus()).thenReturn(NO_TRANSACTION);
+ }
+
+ private void setupLocalTransaction() {
+ Mockito.when(control.getCurrentContext()).thenReturn(context);
+ Mockito.when(context.supportsLocal()).thenReturn(true);
+ Mockito.when(context.getTransactionStatus()).thenReturn(ACTIVE);
+ }
+
+ private void setupXATransaction() {
+ Mockito.when(control.getCurrentContext()).thenReturn(context);
+ Mockito.when(context.supportsXA()).thenReturn(true);
+ Mockito.when(context.getTransactionStatus()).thenReturn(ACTIVE);
+ }
+
+
+ @Test(expected=TransactionException.class)
+ public void testUnscopedLocal() throws SQLException {
+ localConn.isValid(500);
+ }
+
+ @Test(expected=TransactionException.class)
+ public void testUnscopedXA() throws SQLException {
+ xaConn.isValid(500);
+ }
+
+ @Test
+ public void testNoTransaction() throws SQLException {
+ setupNoTransaction();
+
+ localConn.isValid(500);
+ localConn.isValid(500);
+
+ Mockito.verify(rawConnection, times(2)).isValid(500);
+ Mockito.verify(context, times(0)).registerLocalResource(Mockito.any());
+
+ Mockito.verify(context).postCompletion(Mockito.any());
+ }
+
+ @Test
+ public void testNoTransactionXA() throws SQLException {
+ setupNoTransaction();
+
+ xaConn.isValid(500);
+ xaConn.isValid(500);
+
+ Mockito.verify(rawConnection, times(2)).isValid(500);
+ Mockito.verify(context, times(0)).registerLocalResource(Mockito.any());
+
+ Mockito.verify(context).postCompletion(Mockito.any());
+ }
+
+ @Test
+ public void testLocalTransactionCommit() throws SQLException {
+ setupLocalTransaction();
+
+ localConn.isValid(500);
+ localConn.isValid(500);
+
+ ArgumentCaptor<LocalResource> captor = ArgumentCaptor.forClass(LocalResource.class);
+
+ Mockito.verify(rawConnection, times(2)).isValid(500);
+ Mockito.verify(context).registerLocalResource(captor.capture());
+
+ Mockito.verify(context).postCompletion(Mockito.any());
+
+ captor.getValue().commit();
+
+ Mockito.verify(rawConnection).commit();
+ }
+
+ @Test
+ public void testLocalTransactionRollback() throws SQLException {
+ setupLocalTransaction();
+
+ localConn.isValid(500);
+ localConn.isValid(500);
+
+ ArgumentCaptor<LocalResource> captor = ArgumentCaptor.forClass(LocalResource.class);
+
+ Mockito.verify(rawConnection, times(2)).isValid(500);
+ Mockito.verify(context).registerLocalResource(captor.capture());
+
+ Mockito.verify(context).postCompletion(Mockito.any());
+
+ captor.getValue().rollback();
+
+ Mockito.verify(rawConnection).rollback();
+ }
+
+ @Test(expected=TransactionException.class)
+ public void testLocalTransactionNoLocal() throws SQLException {
+ setupLocalTransaction();
+
+ Mockito.when(context.supportsLocal()).thenReturn(false);
+ localConn.isValid(500);
+ }
+
+ @Test(expected=TransactionException.class)
+ public void testLocalConnWithXATransaction() throws SQLException {
+ setupXATransaction();
+
+ localConn.isValid(500);
+ }
+
+ @Test
+ public void testXATransactionCommit() throws SQLException {
+ setupXATransaction();
+
+ xaConn.isValid(500);
+ xaConn.isValid(500);
+
+
+ Mockito.verify(rawConnection, times(2)).isValid(500);
+ Mockito.verify(context).registerXAResource(xaResource);
+
+ Mockito.verify(context).postCompletion(Mockito.any());
+
+ Mockito.verify(rawConnection, times(0)).commit();
+ }
+
+ @Test
+ public void testXATransactionRollback() throws SQLException {
+ setupXATransaction();
+
+ xaConn.isValid(500);
+ xaConn.isValid(500);
+
+ Mockito.verify(rawConnection, times(2)).isValid(500);
+ Mockito.verify(context).registerXAResource(xaResource);
+
+ Mockito.verify(context).postCompletion(Mockito.any());
+
+ Mockito.verify(rawConnection, times(0)).rollback();
+ }
+
+ @Test(expected=TransactionException.class)
+ public void testXAConnTransactionWithLocal() throws SQLException {
+ setupLocalTransaction();
+
+ xaConn.isValid(500);
+ }
+
+}
Modified: aries/trunk/tx-control/tx-control-service-xa/pom.xml
URL: http://svn.apache.org/viewvc/aries/trunk/tx-control/tx-control-service-xa/pom.xml?rev=1734385&r1=1734384&r2=1734385&view=diff
==============================================================================
--- aries/trunk/tx-control/tx-control-service-xa/pom.xml (original)
+++ aries/trunk/tx-control/tx-control-service-xa/pom.xml Thu Mar 10 11:27:48 2016
@@ -48,9 +48,15 @@
org.apache.aries.tx.control.service.xa.*,
org.apache.geronimo.transaction.*
</aries.osgi.private.pkg>
- <!-- No transaction log at the moment -->
+ <!--
+ No transaction log at the moment.
+ Also we must explicitly import javax.transaction.xa at zero so that we can pick it
+ up from the JRE.
+ -->
<aries.osgi.import.pkg>
+ !javax.resource.*,
!org.objectweb.howl.*,
+ javax.transaction.xa;version=0,
org.osgi.service.transaction.control;version="[0.0.1,0.0.2)",
*
</aries.osgi.import.pkg>