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>