Repository: tomee Updated Branches: refs/heads/master 9be09db04 -> abbed04ac
TOMEE-1615 avoid to create N connections for the same datasource in the same transaction - very good catch from Jon. Also using TransactionSynchronizationRegistry instead of a static Map Project: http://git-wip-us.apache.org/repos/asf/tomee/repo Commit: http://git-wip-us.apache.org/repos/asf/tomee/commit/abbed04a Tree: http://git-wip-us.apache.org/repos/asf/tomee/tree/abbed04a Diff: http://git-wip-us.apache.org/repos/asf/tomee/diff/abbed04a Branch: refs/heads/master Commit: abbed04acc02c3222b632115ccd0efc0cd1e66a3 Parents: 9be09db Author: Romain Manni-Bucau <[email protected]> Authored: Thu Jul 16 13:50:20 2015 +0200 Committer: Romain Manni-Bucau <[email protected]> Committed: Thu Jul 16 13:50:20 2015 +0200 ---------------------------------------------------------------------- .../openejb/assembler/classic/Assembler.java | 5 - .../persistence/PersistenceUnitInfoImpl.java | 8 +- .../jdbc/FlushableDataSourceHandler.java | 7 +- .../resource/jdbc/SimpleDataSourceCreator.java | 6 +- .../jdbc/dbcp/DbcpDataSourceCreator.java | 6 +- .../managed/JTADataSourceWrapperFactory.java | 5 +- .../jdbc/managed/local/ManagedConnection.java | 216 +++++---- .../jdbc/managed/local/ManagedDataSource.java | 43 +- .../managed/xa/CommonDataSourceAdapter.java | 9 + .../jdbc/managed/xa/DataSourceXADataSource.java | 5 +- .../jdbc/managed/xa/ManagedXAConnection.java | 21 +- .../jdbc/managed/xa/ManagedXADataSource.java | 26 +- .../jdbc/pool/PoolDataSourceCreator.java | 18 +- .../jdbc/ManagedConnectionBehaviorTest.java | 461 +++++++++++++++++++ .../resource/jdbc/ManagedDataSourceTest.java | 27 +- .../MultiThreadedManagedDataSourceTest.java | 26 +- .../openejb/bonecp/BoneCPDataSourceCreator.java | 4 +- .../BoneCPPooledDataSourceFromPoolTest.java | 28 +- .../bonecp/BoneCPPooledDataSourceTest.java | 25 +- .../org/apache/openejb/bonecp/XABoneCPTest.java | 4 +- .../jdbc/TomcatDataSourceFromPoolTest.java | 27 +- .../org/apache/tomee/jdbc/TomcatPoolTest.java | 27 +- 22 files changed, 722 insertions(+), 282 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/tomee/blob/abbed04a/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/Assembler.java ---------------------------------------------------------------------- diff --git a/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/Assembler.java b/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/Assembler.java index 118f2b7..a83542a 100644 --- a/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/Assembler.java +++ b/container/openejb-core/src/main/java/org/apache/openejb/assembler/classic/Assembler.java @@ -1893,11 +1893,6 @@ public class Assembler extends AssemblerTool implements org.apache.openejb.spi.A } catch (final Throwable t) { //Ignore } - - if (object instanceof ManagedDataSource) { - ((ManagedDataSource) object).clean(); - } - } else if (object instanceof ConnectorReference) { final ConnectorReference cr = (ConnectorReference) object; try { http://git-wip-us.apache.org/repos/asf/tomee/blob/abbed04a/container/openejb-core/src/main/java/org/apache/openejb/persistence/PersistenceUnitInfoImpl.java ---------------------------------------------------------------------- diff --git a/container/openejb-core/src/main/java/org/apache/openejb/persistence/PersistenceUnitInfoImpl.java b/container/openejb-core/src/main/java/org/apache/openejb/persistence/PersistenceUnitInfoImpl.java index efb17b8..6b4eb6b 100644 --- a/container/openejb-core/src/main/java/org/apache/openejb/persistence/PersistenceUnitInfoImpl.java +++ b/container/openejb-core/src/main/java/org/apache/openejb/persistence/PersistenceUnitInfoImpl.java @@ -19,6 +19,7 @@ package org.apache.openejb.persistence; import org.apache.openejb.OpenEJB; +import org.apache.openejb.loader.SystemInstance; import org.apache.openejb.resource.jdbc.managed.xa.DataSourceXADataSource; import org.apache.openejb.util.URLs; import org.apache.openejb.util.classloader.URLClassLoaderFirst; @@ -31,6 +32,7 @@ import javax.persistence.spi.PersistenceUnitTransactionType; import javax.sql.CommonDataSource; import javax.sql.DataSource; import javax.sql.XADataSource; +import javax.transaction.TransactionSynchronizationRegistry; import java.io.File; import java.io.IOException; import java.lang.instrument.ClassFileTransformer; @@ -194,7 +196,8 @@ public class PersistenceUnitInfoImpl implements PersistenceUnitInfo { public void setJtaDataSource(final CommonDataSource jtaDataSource) { if (XADataSource.class.isInstance(jtaDataSource)) { - this.jtaDataSource = new DataSourceXADataSource(jtaDataSource, OpenEJB.getTransactionManager()); + this.jtaDataSource = new DataSourceXADataSource( + jtaDataSource, OpenEJB.getTransactionManager(), SystemInstance.get().getComponent(TransactionSynchronizationRegistry.class)); } else { this.jtaDataSource = DataSource.class.cast(jtaDataSource); } @@ -206,7 +209,8 @@ public class PersistenceUnitInfoImpl implements PersistenceUnitInfo { public void setNonJtaDataSource(final CommonDataSource nonJtaDataSource) { if (XADataSource.class.isInstance(nonJtaDataSource)) { - this.nonJtaDataSource = new DataSourceXADataSource(nonJtaDataSource, OpenEJB.getTransactionManager()); + this.nonJtaDataSource = new DataSourceXADataSource( + nonJtaDataSource, OpenEJB.getTransactionManager(), SystemInstance.get().getComponent(TransactionSynchronizationRegistry.class)); } else { this.nonJtaDataSource = DataSource.class.cast(nonJtaDataSource); } http://git-wip-us.apache.org/repos/asf/tomee/blob/abbed04a/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/FlushableDataSourceHandler.java ---------------------------------------------------------------------- diff --git a/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/FlushableDataSourceHandler.java b/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/FlushableDataSourceHandler.java index 79c9510..316565b 100644 --- a/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/FlushableDataSourceHandler.java +++ b/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/FlushableDataSourceHandler.java @@ -16,12 +16,10 @@ */ package org.apache.openejb.resource.jdbc; -import org.apache.openejb.resource.jdbc.managed.local.ManagedDataSource; import org.apache.openejb.util.Duration; import org.apache.openejb.util.LogCategory; import org.apache.openejb.util.Logger; -import javax.sql.CommonDataSource; import java.io.Flushable; import java.lang.reflect.InvocationHandler; import java.lang.reflect.InvocationTargetException; @@ -29,6 +27,7 @@ import java.lang.reflect.Method; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; +import javax.sql.CommonDataSource; public class FlushableDataSourceHandler implements InvocationHandler { private static final Logger LOGGER = Logger.getInstance(LogCategory.OPENEJB, FlushableDataSourceHandler.class); @@ -58,10 +57,6 @@ public class FlushableDataSourceHandler implements InvocationHandler { } catch (final Throwable t) { //Ignore } - - if (ManagedDataSource.class.isInstance(old)) { - ManagedDataSource.class.cast(old).clean(); - } } } http://git-wip-us.apache.org/repos/asf/tomee/blob/abbed04a/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/SimpleDataSourceCreator.java ---------------------------------------------------------------------- diff --git a/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/SimpleDataSourceCreator.java b/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/SimpleDataSourceCreator.java index 47b774c..c16787b 100644 --- a/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/SimpleDataSourceCreator.java +++ b/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/SimpleDataSourceCreator.java @@ -18,6 +18,7 @@ package org.apache.openejb.resource.jdbc; import org.apache.openejb.OpenEJB; +import org.apache.openejb.loader.SystemInstance; import org.apache.openejb.resource.XAResourceWrapper; import org.apache.openejb.resource.jdbc.managed.local.ManagedDataSource; import org.apache.openejb.resource.jdbc.managed.xa.ManagedXADataSource; @@ -28,6 +29,7 @@ import javax.sql.CommonDataSource; import javax.sql.DataSource; import javax.sql.XADataSource; import javax.transaction.TransactionManager; +import javax.transaction.TransactionSynchronizationRegistry; import java.util.Properties; public class SimpleDataSourceCreator implements DataSourceCreator { @@ -35,9 +37,9 @@ public class SimpleDataSourceCreator implements DataSourceCreator { public DataSource managed(final String name, final CommonDataSource ds) { final TransactionManager transactionManager = OpenEJB.getTransactionManager(); if (XADataSource.class.isInstance(ds)) { - return new ManagedXADataSource(XADataSource.class.cast(ds), transactionManager); + return new ManagedXADataSource(XADataSource.class.cast(ds), transactionManager, SystemInstance.get().getComponent(TransactionSynchronizationRegistry.class)); } - return new ManagedDataSource(DataSource.class.cast(ds), transactionManager); + return new ManagedDataSource(DataSource.class.cast(ds), transactionManager, SystemInstance.get().getComponent(TransactionSynchronizationRegistry.class)); } @Override http://git-wip-us.apache.org/repos/asf/tomee/blob/abbed04a/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/dbcp/DbcpDataSourceCreator.java ---------------------------------------------------------------------- diff --git a/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/dbcp/DbcpDataSourceCreator.java b/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/dbcp/DbcpDataSourceCreator.java index 7306655..bc0ca31 100644 --- a/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/dbcp/DbcpDataSourceCreator.java +++ b/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/dbcp/DbcpDataSourceCreator.java @@ -18,6 +18,7 @@ package org.apache.openejb.resource.jdbc.dbcp; import org.apache.openejb.OpenEJB; +import org.apache.openejb.loader.SystemInstance; import org.apache.openejb.resource.jdbc.managed.local.ManagedDataSource; import org.apache.openejb.resource.jdbc.managed.xa.ManagedXADataSource; import org.apache.openejb.resource.jdbc.pool.PoolDataSourceCreator; @@ -27,6 +28,7 @@ import javax.sql.CommonDataSource; import javax.sql.DataSource; import javax.sql.XADataSource; import javax.transaction.TransactionManager; +import javax.transaction.TransactionSynchronizationRegistry; import java.util.Properties; // just a sample showing how to implement a datasourcecreator @@ -41,9 +43,9 @@ public class DbcpDataSourceCreator extends PoolDataSourceCreator { public DataSource managed(final String name, final CommonDataSource ds) { final TransactionManager transactionManager = OpenEJB.getTransactionManager(); if (ds instanceof XADataSource) { - return new ManagedXADataSource(ds, transactionManager); + return new ManagedXADataSource(ds, transactionManager, SystemInstance.get().getComponent(TransactionSynchronizationRegistry.class)); } - return new ManagedDataSource(DataSource.class.cast(ds), transactionManager); + return new ManagedDataSource(DataSource.class.cast(ds), transactionManager, SystemInstance.get().getComponent(TransactionSynchronizationRegistry.class)); } @Override http://git-wip-us.apache.org/repos/asf/tomee/blob/abbed04a/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/managed/JTADataSourceWrapperFactory.java ---------------------------------------------------------------------- diff --git a/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/managed/JTADataSourceWrapperFactory.java b/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/managed/JTADataSourceWrapperFactory.java index 48e29fc..cfdf927 100644 --- a/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/managed/JTADataSourceWrapperFactory.java +++ b/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/managed/JTADataSourceWrapperFactory.java @@ -30,6 +30,7 @@ import javax.sql.CommonDataSource; import javax.sql.DataSource; import javax.sql.XADataSource; import javax.transaction.TransactionManager; +import javax.transaction.TransactionSynchronizationRegistry; public class JTADataSourceWrapperFactory { private String delegate = "datasource"; @@ -41,9 +42,9 @@ public class JTADataSourceWrapperFactory { CommonDataSource cds = findDelegate(); if (cds instanceof XADataSource) { - cds = new ManagedXADataSource(cds, transactionManager); + cds = new ManagedXADataSource(cds, transactionManager, SystemInstance.get().getComponent(TransactionSynchronizationRegistry.class)); } else { - cds = new ManagedDataSource(DataSource.class.cast(cds), transactionManager); + cds = new ManagedDataSource(DataSource.class.cast(cds), transactionManager, SystemInstance.get().getComponent(TransactionSynchronizationRegistry.class)); } if (logSql) { http://git-wip-us.apache.org/repos/asf/tomee/blob/abbed04a/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/managed/local/ManagedConnection.java ---------------------------------------------------------------------- diff --git a/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/managed/local/ManagedConnection.java b/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/managed/local/ManagedConnection.java index 59d7116..5fc283b 100644 --- a/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/managed/local/ManagedConnection.java +++ b/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/managed/local/ManagedConnection.java @@ -17,48 +17,52 @@ package org.apache.openejb.resource.jdbc.managed.local; -import org.apache.openejb.OpenEJB; import org.apache.openejb.util.LogCategory; import org.apache.openejb.util.Logger; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.sql.Connection; +import java.sql.SQLException; +import java.sql.Wrapper; import javax.sql.CommonDataSource; +import javax.sql.DataSource; +import javax.sql.XAConnection; +import javax.sql.XADataSource; import javax.transaction.RollbackException; import javax.transaction.Status; import javax.transaction.Synchronization; import javax.transaction.SystemException; import javax.transaction.Transaction; import javax.transaction.TransactionManager; +import javax.transaction.TransactionSynchronizationRegistry; import javax.transaction.xa.XAResource; -import java.lang.reflect.InvocationHandler; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.sql.Connection; -import java.sql.SQLException; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; public class ManagedConnection implements InvocationHandler { - private static final Logger LOGGER = Logger.getInstance(LogCategory.OPENEJB_RESOURCE_JDBC, ManagedConnection.class); - - private static final Map<Integer, Map<Transaction, Connection>> CONNECTION_BY_TX_BY_DS = new ConcurrentHashMap<Integer, Map<Transaction, Connection>>(); - private final TransactionManager transactionManager; - private final LocalXAResource xaResource; + private final Key key; + private final TransactionSynchronizationRegistry registry; + protected XAResource xaResource; protected Connection delegate; + protected XAConnection xaConnection; private Transaction currentTransaction; private boolean closed; - private final Map<Transaction, Connection> connectionByTx; - - public ManagedConnection(final CommonDataSource ds, final Connection connection, final TransactionManager txMgr) { - delegate = connection; + public ManagedConnection(final CommonDataSource ds, + final TransactionManager txMgr, + final TransactionSynchronizationRegistry txRegistry, + final String user, final String password) { transactionManager = txMgr; + registry = txRegistry; closed = false; - xaResource = new LocalXAResource(delegate); - connectionByTx = CONNECTION_BY_TX_BY_DS.get(ds.hashCode()); + key = new Key(ds, user, password); } public XAResource getXAResource() throws SQLException { + if (xaResource == null) { + newConnection(); + } return xaResource; } @@ -70,77 +74,108 @@ public class ManagedConnection implements InvocationHandler { return "ManagedConnection{" + delegate + "}"; } if ("hashCode".equals(mtdName)) { - return delegate.hashCode(); + return hashCode(); } if ("equals".equals(mtdName)) { - return delegate.equals(args[0]); + return args[0] == this || (delegate != null && delegate.equals(args[0])); + } + + // allow to get delegate if needed by the underlying program + if (Wrapper.class == method.getDeclaringClass() && args.length == 1 && Connection.class == args[0]) { + if ("isWrapperFor".equals(mtdName)) { + return true; + } + if ("unwrap".equals(mtdName)) { + return delegate; + } } // here the real logic starts try { final Transaction transaction = transactionManager.getTransaction(); - if (transaction == null) { // shouldn't be possible + // shouldn't be used without a transaction but if so just delegate to the actual connection + if (transaction == null) { + if (delegate == null) { + newConnection(); + } return invoke(method, delegate, args); } // if we have a tx check it is the same this connection is linked to - if (currentTransaction != null) { - if (isUnderTransaction(currentTransaction.getStatus())) { - if (!currentTransaction.equals(transaction)) { - throw new SQLException("Connection can not be used while enlisted in another transaction"); - } - return invokeUnderTransaction(delegate, method, args); - } else { - close(delegate); + if (currentTransaction != null && isUnderTransaction(currentTransaction.getStatus())) { + if (!currentTransaction.equals(transaction)) { + throw new SQLException("Connection can not be used while enlisted in another transaction"); } + return invokeUnderTransaction(delegate, method, args); } - // get the already bound connection to the current transaction - // or enlist this one in the tx - final int status = transaction.getStatus(); - if (isUnderTransaction(status)) { - final Connection connection = connectionByTx.get(transaction); - if (connection != delegate) { - if (connection != null) { // use already existing one - delegate.close(); // return to pool - delegate = connection; - } else { - connectionByTx.put(transaction, delegate); - currentTransaction = transaction; - try { - transaction.enlistResource(getXAResource()); - } catch (final RollbackException ignored) { - // no-op - } catch (final SystemException e) { - throw new SQLException("Unable to enlist connection the transaction", e); - } + // get the already bound connection to the current transaction or enlist this one in the tx + if (isUnderTransaction(transaction.getStatus())) { + Connection connection = Connection.class.cast(registry.getResource(key)); + if (connection == null && delegate == null) { + newConnection(); + connection = delegate; + + registry.putResource(transaction, delegate); + currentTransaction = transaction; + try { + transaction.enlistResource(getXAResource()); + } catch (final RollbackException ignored) { + // no-op + } catch (final SystemException e) { + throw new SQLException("Unable to enlist connection the transaction", e); + } + + transaction.registerSynchronization(new ClosingSynchronization(delegate)); - transaction.registerSynchronization(new ClosingSynchronization(delegate, connectionByTx)); - - try { - setAutoCommit(false); - } catch (final SQLException xae) { // we are alreay in a transaction so this can't be called from a user perspective - some XA DataSource prevents it in their code - final String message = "Can't set auto commit to false cause the XA datasource doesn't support it, this is likely an issue"; - if (LOGGER.isDebugEnabled()) { // we don't want to print the exception by default - LOGGER.warning(message, xae); - } else { - LOGGER.warning(message); - } + try { + setAutoCommit(false); + } catch (final SQLException xae) { // we are alreay in a transaction so this can't be called from a user perspective - some XA DataSource prevents it in their code + final String message = "Can't set auto commit to false cause the XA datasource doesn't support it, this is likely an issue"; + final Logger logger = Logger.getInstance(LogCategory.OPENEJB_RESOURCE_JDBC, ManagedConnection.class) + if (logger.isDebugEnabled()) { // we don't want to print the exception by default + logger.warning(message, xae); + } else { + logger.warning(message); } } + } else if (delegate == null) { // shouldn't happen + delegate = connection; } - return invokeUnderTransaction(delegate, method, args); + return invokeUnderTransaction(connection, method, args); } + // we shouldn't come here, tempted to just throw an exception + if (delegate == null) { + newConnection(); + } return invoke(method, delegate, args); } catch (final InvocationTargetException ite) { throw ite.getTargetException(); } } + protected Object newConnection() throws SQLException { + final Object connection = DataSource.class.isInstance(key.ds) ? + (key.user == null ? DataSource.class.cast(key.ds).getConnection() : DataSource.class.cast(key.ds).getConnection(key.user, key.pwd)) : + (key.user == null ? XADataSource.class.cast(key.ds).getXAConnection() : XADataSource.class.cast(key.ds).getXAConnection(key.user, key.pwd)); + if (XAConnection.class.isInstance(connection)) { + xaConnection = XAConnection.class.cast(connection); + delegate = xaConnection.getConnection(); + xaResource = xaConnection.getXAResource(); + } else { + delegate = Connection.class.cast(connection); + xaResource = new LocalXAResource(delegate); + } + return connection; + } + protected void setAutoCommit(final boolean value) throws SQLException { + if (delegate == null) { + newConnection(); + } delegate.setAutoCommit(value); } @@ -195,24 +230,11 @@ public class ManagedConnection implements InvocationHandler { } } - public static void pushDataSource(final CommonDataSource ds) { - CONNECTION_BY_TX_BY_DS.put(ds.hashCode(), new ConcurrentHashMap<Transaction, Connection>()); - } - - public static void cleanDataSource(final CommonDataSource ds) { - final Map<Transaction, Connection> map = CONNECTION_BY_TX_BY_DS.remove(ds.hashCode()); - if (map != null) { - map.clear(); - } - } - private static class ClosingSynchronization implements Synchronization { private final Connection connection; - private final Map<Transaction, Connection> mapToCleanup; - public ClosingSynchronization(final Connection delegate, final Map<Transaction, Connection> connByTx) { - connection = delegate; - mapToCleanup = connByTx; + public ClosingSynchronization(final Connection delegate) { + this.connection = delegate; } @Override @@ -223,12 +245,44 @@ public class ManagedConnection implements InvocationHandler { @Override public void afterCompletion(final int status) { close(connection); - try { - final Transaction tx = OpenEJB.getTransactionManager().getTransaction(); - mapToCleanup.remove(tx); - } catch (final SystemException ignored) { - // no-op + } + } + + private static class Key { + private final CommonDataSource ds; + private final String user; + private final String pwd; + private final int hash; + + private Key(final CommonDataSource ds, final String user, final String pwd) { + this.ds = ds; + this.user = user; + this.pwd = pwd; + + int result = ds.hashCode(); + result = 31 * result + (user != null ? user.hashCode() : 0); + result = 31 * result + (pwd != null ? pwd.hashCode() : 0); + hash = result; + } + + @Override + public boolean equals(final Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; } + + Key key = Key.class.cast(o); + return (ds == key.ds || ds.equals(key.ds)) && + !(user != null ? !user.equals(key.user) : key.user != null) && + !(pwd != null ? !pwd.equals(key.pwd) : key.pwd != null); + } + + @Override + public int hashCode() { + return hash; } } } http://git-wip-us.apache.org/repos/asf/tomee/blob/abbed04a/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/managed/local/ManagedDataSource.java ---------------------------------------------------------------------- diff --git a/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/managed/local/ManagedDataSource.java b/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/managed/local/ManagedDataSource.java index 196fae7..5335fef 100644 --- a/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/managed/local/ManagedDataSource.java +++ b/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/managed/local/ManagedDataSource.java @@ -17,11 +17,6 @@ package org.apache.openejb.resource.jdbc.managed.local; -import org.apache.openejb.util.reflection.Reflections; - -import javax.sql.CommonDataSource; -import javax.sql.DataSource; -import javax.transaction.TransactionManager; import java.io.ObjectStreamException; import java.io.PrintWriter; import java.io.Serializable; @@ -30,33 +25,38 @@ import java.sql.Connection; import java.sql.SQLException; import java.sql.SQLFeatureNotSupportedException; import java.util.logging.Logger; +import javax.sql.CommonDataSource; +import javax.sql.DataSource; +import javax.transaction.TransactionManager; +import javax.transaction.TransactionSynchronizationRegistry; public class ManagedDataSource implements DataSource, Serializable { private static final Class<?>[] CONNECTION_CLASS = new Class<?>[]{Connection.class}; - protected final DataSource delegate; + protected final CommonDataSource delegate; protected final TransactionManager transactionManager; + protected final TransactionSynchronizationRegistry registry; protected final int hashCode; - protected ManagedDataSource(final DataSource ds, final TransactionManager txMgr, final int hc) { + protected ManagedDataSource(final CommonDataSource ds, final TransactionManager txMgr, final TransactionSynchronizationRegistry txRegistry, final int hc) { delegate = ds; hashCode = hc; transactionManager = txMgr; - ManagedConnection.pushDataSource(this); + registry = txRegistry; } - public ManagedDataSource(final DataSource ds, final TransactionManager txMgr) { - this(ds, txMgr, ds.hashCode()); + public ManagedDataSource(final DataSource ds, final TransactionManager txMgr, final TransactionSynchronizationRegistry txRegistry) { + this(ds, txMgr, txRegistry, ds.hashCode()); } @Override public Connection getConnection() throws SQLException { - return managed(delegate.getConnection()); + return managed(null, null); } @Override public Connection getConnection(final String username, final String password) throws SQLException { - return managed(delegate.getConnection(username, password)); + return managed(username, password); } @Override @@ -81,31 +81,28 @@ public class ManagedDataSource implements DataSource, Serializable { @Override public <T> T unwrap(final Class<T> iface) throws SQLException { - return delegate.unwrap(iface); + return DataSource.class.isInstance(delegate) ? DataSource.class.cast(delegate).unwrap(iface) : null; } @Override public boolean isWrapperFor(final Class<?> iface) throws SQLException { - return delegate.isWrapperFor(iface); + return DataSource.class.isInstance(delegate) && DataSource.class.cast(delegate).isWrapperFor(iface); } - // @Override JDK7 + @Override public Logger getParentLogger() throws SQLFeatureNotSupportedException { - return (Logger) Reflections.invokeByReflection(delegate, "getParentLogger", new Class<?>[0], null); + return delegate.getParentLogger(); } - private Connection managed(final Connection connection) { - return (Connection) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), CONNECTION_CLASS, new ManagedConnection(this, connection, transactionManager)); + private Connection managed(final String u, final String p) { + return (Connection) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), CONNECTION_CLASS, + new ManagedConnection(delegate, transactionManager, registry, u, p)); } - public DataSource getDelegate() { + public CommonDataSource getDelegate() { return delegate; } - public void clean() { - ManagedConnection.cleanDataSource(this); - } - @Override public boolean equals(final Object o) { return CommonDataSource.class.isInstance(o) && hashCode == o.hashCode(); http://git-wip-us.apache.org/repos/asf/tomee/blob/abbed04a/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/managed/xa/CommonDataSourceAdapter.java ---------------------------------------------------------------------- diff --git a/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/managed/xa/CommonDataSourceAdapter.java b/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/managed/xa/CommonDataSourceAdapter.java index bab9a55..59e7bb9 100644 --- a/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/managed/xa/CommonDataSourceAdapter.java +++ b/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/managed/xa/CommonDataSourceAdapter.java @@ -36,6 +36,15 @@ public class CommonDataSourceAdapter implements InvocationHandler { @Override public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable { + if (Object.class == method.getDeclaringClass() && "equals".equals(method.getName())) { + if (delegate == args[0]) { + return true; + } + } return method.invoke(delegate, args); // we suppose missing methods are not called - it is the case thanks to ManagedXADataSource } + + public CommonDataSource getDelegate() { + return delegate; + } } http://git-wip-us.apache.org/repos/asf/tomee/blob/abbed04a/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/managed/xa/DataSourceXADataSource.java ---------------------------------------------------------------------- diff --git a/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/managed/xa/DataSourceXADataSource.java b/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/managed/xa/DataSourceXADataSource.java index 5ec6aea..ddbcf65 100644 --- a/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/managed/xa/DataSourceXADataSource.java +++ b/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/managed/xa/DataSourceXADataSource.java @@ -23,14 +23,15 @@ import javax.sql.CommonDataSource; import javax.sql.XAConnection; import javax.sql.XADataSource; import javax.transaction.TransactionManager; +import javax.transaction.TransactionSynchronizationRegistry; import java.sql.Connection; import java.sql.SQLException; public class DataSourceXADataSource extends ManagedDataSource { private final XADataSource xaDataSource; - public DataSourceXADataSource(final CommonDataSource ds, final TransactionManager txMgr) { - super(CommonDataSourceAdapter.wrap(ds), txMgr, ds.hashCode()); + public DataSourceXADataSource(final CommonDataSource ds, final TransactionManager txMgr, final TransactionSynchronizationRegistry registry) { + super(CommonDataSourceAdapter.wrap(ds), txMgr, registry, ds.hashCode()); xaDataSource = XADataSource.class.cast(ds); } http://git-wip-us.apache.org/repos/asf/tomee/blob/abbed04a/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/managed/xa/ManagedXAConnection.java ---------------------------------------------------------------------- diff --git a/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/managed/xa/ManagedXAConnection.java b/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/managed/xa/ManagedXAConnection.java index 9980793..c39cb7c 100644 --- a/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/managed/xa/ManagedXAConnection.java +++ b/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/managed/xa/ManagedXAConnection.java @@ -19,24 +19,25 @@ package org.apache.openejb.resource.jdbc.managed.xa; import org.apache.openejb.resource.jdbc.managed.local.ManagedConnection; -import javax.sql.DataSource; -import javax.sql.XAConnection; +import java.sql.SQLException; +import javax.sql.CommonDataSource; import javax.transaction.TransactionManager; +import javax.transaction.TransactionSynchronizationRegistry; import javax.transaction.xa.XAResource; -import java.sql.Connection; -import java.sql.SQLException; public class ManagedXAConnection extends ManagedConnection { - private final XAConnection xaConnection; - - public ManagedXAConnection(final DataSource ds, final XAConnection xa, final Connection connection, final TransactionManager txMgr) throws SQLException { - super(ds, connection, txMgr); - this.xaConnection = xa; + public ManagedXAConnection(final CommonDataSource ds, final TransactionManager txMgr, + final TransactionSynchronizationRegistry txRegistry, + final String user, final String password) throws SQLException { + super(ds, txMgr, txRegistry, user, password); } @Override public XAResource getXAResource() throws SQLException { - return xaConnection.getXAResource(); + if (xaResource == null) { + newConnection(); + } + return xaResource; } @Override http://git-wip-us.apache.org/repos/asf/tomee/blob/abbed04a/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/managed/xa/ManagedXADataSource.java ---------------------------------------------------------------------- diff --git a/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/managed/xa/ManagedXADataSource.java b/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/managed/xa/ManagedXADataSource.java index 6e51eb8..c2ccced 100644 --- a/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/managed/xa/ManagedXADataSource.java +++ b/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/managed/xa/ManagedXADataSource.java @@ -19,37 +19,35 @@ package org.apache.openejb.resource.jdbc.managed.xa; import org.apache.openejb.resource.jdbc.managed.local.ManagedDataSource; -import javax.sql.CommonDataSource; -import javax.sql.XAConnection; -import javax.sql.XADataSource; -import javax.transaction.TransactionManager; import java.lang.reflect.Proxy; import java.sql.Connection; import java.sql.SQLException; +import javax.sql.CommonDataSource; +import javax.transaction.TransactionManager; +import javax.transaction.TransactionSynchronizationRegistry; public class ManagedXADataSource extends ManagedDataSource { private static final Class<?>[] CONNECTION_CLASS = new Class<?>[]{Connection.class}; - private final XADataSource xaDataSource; + private final TransactionManager txMgr; - public ManagedXADataSource(final CommonDataSource ds, final TransactionManager txMgr) { - super(CommonDataSourceAdapter.wrap(ds), txMgr, ds.hashCode()); - xaDataSource = XADataSource.class.cast(ds); + public ManagedXADataSource(final CommonDataSource ds, final TransactionManager txMgr, final TransactionSynchronizationRegistry registry) { + super(ds, txMgr, registry, ds.hashCode()); + this.txMgr = txMgr; // ObjectRecipe and our logic will setTxMgr but we want the original one (wrapper) } @Override public Connection getConnection() throws SQLException { - final XAConnection xaConnection = xaDataSource.getXAConnection(); - return managedXA(xaConnection, xaConnection.getConnection()); + return managedXA(null, null); } @Override public Connection getConnection(final String username, final String password) throws SQLException { - final XAConnection xaConnection = xaDataSource.getXAConnection(username, password); - return managedXA(xaConnection, xaConnection.getConnection()); + return managedXA(username, password); } - private Connection managedXA(final XAConnection xaConnection, final Connection connection) throws SQLException { - return Connection.class.cast(Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), CONNECTION_CLASS, new ManagedXAConnection(delegate, xaConnection, connection, transactionManager))); + private Connection managedXA(final String u, final String p) throws SQLException { + return Connection.class.cast(Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), CONNECTION_CLASS, + new ManagedXAConnection(delegate, txMgr, registry, u, p))); } } http://git-wip-us.apache.org/repos/asf/tomee/blob/abbed04a/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/pool/PoolDataSourceCreator.java ---------------------------------------------------------------------- diff --git a/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/pool/PoolDataSourceCreator.java b/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/pool/PoolDataSourceCreator.java index f041a88..1e1dba4 100644 --- a/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/pool/PoolDataSourceCreator.java +++ b/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/pool/PoolDataSourceCreator.java @@ -18,6 +18,7 @@ package org.apache.openejb.resource.jdbc.pool; import org.apache.openejb.OpenEJB; +import org.apache.openejb.loader.SystemInstance; import org.apache.openejb.resource.TransactionManagerWrapper; import org.apache.openejb.resource.XAResourceWrapper; import org.apache.openejb.resource.jdbc.managed.local.ManagedDataSource; @@ -26,14 +27,15 @@ import org.apache.openejb.util.PassthroughFactory; import org.apache.xbean.recipe.ObjectRecipe; import org.apache.xbean.recipe.Option; -import javax.sql.CommonDataSource; -import javax.sql.DataSource; -import javax.sql.XADataSource; -import javax.transaction.TransactionManager; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Properties; +import javax.sql.CommonDataSource; +import javax.sql.DataSource; +import javax.sql.XADataSource; +import javax.transaction.TransactionManager; +import javax.transaction.TransactionSynchronizationRegistry; public abstract class PoolDataSourceCreator implements DataSourceCreator { protected final Map<Object, ObjectRecipe> recipes = new HashMap<Object, ObjectRecipe>(); @@ -53,9 +55,9 @@ public abstract class PoolDataSourceCreator implements DataSourceCreator { public DataSource managed(final String name, final CommonDataSource ds) { final TransactionManager transactionManager = OpenEJB.getTransactionManager(); if (ds instanceof XADataSource) { - return new ManagedXADataSource(ds, transactionManager); + return new ManagedXADataSource(ds, transactionManager, SystemInstance.get().getComponent(TransactionSynchronizationRegistry.class)); } - return new ManagedDataSource(DataSource.class.cast(ds), transactionManager); + return new ManagedDataSource(DataSource.class.cast(ds), transactionManager, SystemInstance.get().getComponent(TransactionSynchronizationRegistry.class)); } @Override @@ -63,9 +65,9 @@ public abstract class PoolDataSourceCreator implements DataSourceCreator { final TransactionManager transactionManager = new TransactionManagerWrapper(OpenEJB.getTransactionManager(), name, xaResourceWrapper); final CommonDataSource ds = pool(name, driver, properties); if (ds instanceof XADataSource) { - return new ManagedXADataSource(ds, transactionManager); + return new ManagedXADataSource(ds, transactionManager, SystemInstance.get().getComponent(TransactionSynchronizationRegistry.class)); } - return new ManagedDataSource(DataSource.class.cast(ds), transactionManager); + return new ManagedDataSource(DataSource.class.cast(ds), transactionManager, SystemInstance.get().getComponent(TransactionSynchronizationRegistry.class)); } @Override http://git-wip-us.apache.org/repos/asf/tomee/blob/abbed04a/container/openejb-core/src/test/java/org/apache/openejb/resource/jdbc/ManagedConnectionBehaviorTest.java ---------------------------------------------------------------------- diff --git a/container/openejb-core/src/test/java/org/apache/openejb/resource/jdbc/ManagedConnectionBehaviorTest.java b/container/openejb-core/src/test/java/org/apache/openejb/resource/jdbc/ManagedConnectionBehaviorTest.java new file mode 100644 index 0000000..a5e65cd --- /dev/null +++ b/container/openejb-core/src/test/java/org/apache/openejb/resource/jdbc/ManagedConnectionBehaviorTest.java @@ -0,0 +1,461 @@ +/* + * 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 WARRANTIES OR 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.openejb.resource.jdbc; + +import org.apache.geronimo.transaction.manager.GeronimoTransactionManager; +import org.apache.openejb.resource.GeronimoTransactionManagerFactory; +import org.apache.openejb.resource.TransactionManagerWrapper; +import org.apache.openejb.resource.jdbc.managed.local.ManagedDataSource; +import org.junit.Test; + +import java.io.PrintWriter; +import java.sql.Array; +import java.sql.Blob; +import java.sql.CallableStatement; +import java.sql.Clob; +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.NClob; +import java.sql.PreparedStatement; +import java.sql.SQLClientInfoException; +import java.sql.SQLException; +import java.sql.SQLFeatureNotSupportedException; +import java.sql.SQLWarning; +import java.sql.SQLXML; +import java.sql.Savepoint; +import java.sql.Statement; +import java.sql.Struct; +import java.util.Collection; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.Map; +import java.util.Properties; +import java.util.concurrent.Executor; +import java.util.concurrent.TimeUnit; +import java.util.logging.Logger; +import javax.sql.DataSource; +import javax.transaction.Transaction; +import javax.transaction.TransactionManager; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +public class ManagedConnectionBehaviorTest { + @Test + public void run() throws Exception { + final GeronimoTransactionManager geronimoTransactionManager = new GeronimoTransactionManager((int) TimeUnit.MINUTES.toMillis(10)); + final TransactionManager mgr = new TransactionManagerWrapper( + geronimoTransactionManager, "ManagedConnectionBehaviorTest", new GeronimoTransactionManagerFactory.GeronimoXAResourceWrapper()); + + final MyDs myDs = new MyDs(); + final DataSource ds = new ManagedDataSource(myDs, geronimoTransactionManager, geronimoTransactionManager); + + { // no tx + final Connection connection = ds.getConnection(); + assertTrue(myDs.connections.isEmpty()); // not yet needed + connection.createBlob(); // just to call something + assertFalse(myDs.connections.iterator().next().closed); + connection.close(); + assertTrue(myDs.connections.iterator().next().closed); + myDs.connections.clear(); + } + { // tx + mgr.begin(); + final Connection connection = ds.getConnection(); + assertTrue(myDs.connections.isEmpty()); // not yet needed + connection.createBlob(); // just to call something + assertFalse(myDs.connections.iterator().next().closed); + mgr.commit(); + assertTrue(myDs.connections.iterator().next().closed); + assertTrue(myDs.connections.iterator().next().commit); + assertFalse(myDs.connections.iterator().next().rollback); + myDs.connections.clear(); + } + { // tx already init + mgr.begin(); + final Connection connection = ds.getConnection(); + assertTrue(myDs.connections.isEmpty()); // not yet needed + connection.createBlob(); // just to call something + assertFalse(myDs.connections.iterator().next().closed); + for (int i = 0; i < 5; i++) { // here the connection is already created, ensure we dont leak other connections + connection.createBlob(); + } + assertEquals(1, myDs.connections.size()); + mgr.commit(); + assertTrue(myDs.connections.iterator().next().closed); + assertTrue(myDs.connections.iterator().next().commit); + assertFalse(myDs.connections.iterator().next().rollback); + myDs.connections.clear(); + } + { // multiple tx + mgr.begin(); + final Connection connection = ds.getConnection(); + assertTrue(myDs.connections.isEmpty()); // not yet needed + connection.createBlob(); // just to call something + assertFalse(myDs.connections.iterator().next().closed); + final Transaction previous = mgr.suspend(); + mgr.begin(); + final Connection connection2 = ds.getConnection(); + connection2.createBlob(); + assertEquals(2, myDs.connections.size()); + mgr.commit(); + mgr.resume(previous); + mgr.commit(); + final Iterator<MyConn> iterator = myDs.connections.iterator(); + final MyConn first = iterator.next(); + assertTrue(first.closed); + assertTrue(first.commit); + assertTrue(myDs.connections.iterator().next().commit); + myDs.connections.clear(); + } + + } + + public static class MyDs implements DataSource { + private final Collection<MyConn> connections = new LinkedList<>(); + + @Override + public Connection getConnection() throws SQLException { + final MyConn myConn = new MyConn(this); + connections.add(myConn); + return myConn; + } + + @Override + public Connection getConnection(final String username, final String password) throws SQLException { + return null; + } + + @Override + public PrintWriter getLogWriter() throws SQLException { + return null; + } + + @Override + public void setLogWriter(final PrintWriter out) throws SQLException { + // no-op + } + + @Override + public void setLoginTimeout(final int seconds) throws SQLException { + // no-op + } + + @Override + public int getLoginTimeout() throws SQLException { + return 0; + } + + @Override + public Logger getParentLogger() throws SQLFeatureNotSupportedException { + return null; + } + + @Override + public <T> T unwrap(final Class<T> iface) throws SQLException { + return null; + } + + @Override + public boolean isWrapperFor(final Class<?> iface) throws SQLException { + return false; + } + } + + public static class MyConn implements Connection { + private final MyDs parent; + private Boolean autoCommit; + private boolean commit; + private boolean rollback; + private boolean closed; + + public MyConn(final MyDs myDs) { + this.parent = myDs; + } + + @Override + public Statement createStatement() throws SQLException { + return null; + } + + @Override + public PreparedStatement prepareStatement(String sql) throws SQLException { + return null; + } + + @Override + public CallableStatement prepareCall(String sql) throws SQLException { + return null; + } + + @Override + public String nativeSQL(String sql) throws SQLException { + return null; + } + + @Override + public void setAutoCommit(boolean autoCommit) throws SQLException { + this.autoCommit = autoCommit; + } + + @Override + public boolean getAutoCommit() throws SQLException { + return false; + } + + @Override + public void commit() throws SQLException { + commit = true; + } + + @Override + public void rollback() throws SQLException { + rollback = true; + } + + @Override + public void close() throws SQLException { + closed = true; + } + + @Override + public boolean isClosed() throws SQLException { + return closed; + } + + @Override + public DatabaseMetaData getMetaData() throws SQLException { + return null; + } + + @Override + public void setReadOnly(final boolean readOnly) throws SQLException { + + } + + @Override + public boolean isReadOnly() throws SQLException { + return false; + } + + @Override + public void setCatalog(final String catalog) throws SQLException { + + } + + @Override + public String getCatalog() throws SQLException { + return null; + } + + @Override + public void setTransactionIsolation(final int level) throws SQLException { + + } + + @Override + public int getTransactionIsolation() throws SQLException { + return 0; + } + + @Override + public SQLWarning getWarnings() throws SQLException { + return null; + } + + @Override + public void clearWarnings() throws SQLException { + + } + + @Override + public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException { + return null; + } + + @Override + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + return null; + } + + @Override + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + return null; + } + + @Override + public Map<String, Class<?>> getTypeMap() throws SQLException { + return null; + } + + @Override + public void setTypeMap(Map<String, Class<?>> map) throws SQLException { + + } + + @Override + public void setHoldability(int holdability) throws SQLException { + + } + + @Override + public int getHoldability() throws SQLException { + return 0; + } + + @Override + public Savepoint setSavepoint() throws SQLException { + return null; + } + + @Override + public Savepoint setSavepoint(String name) throws SQLException { + return null; + } + + @Override + public void rollback(Savepoint savepoint) throws SQLException { + + } + + @Override + public void releaseSavepoint(Savepoint savepoint) throws SQLException { + + } + + @Override + public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + return null; + } + + @Override + public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + return null; + } + + @Override + public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + return null; + } + + @Override + public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException { + return null; + } + + @Override + public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException { + return null; + } + + @Override + public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException { + return null; + } + + @Override + public Clob createClob() throws SQLException { + return null; + } + + @Override + public Blob createBlob() throws SQLException { + return null; + } + + @Override + public NClob createNClob() throws SQLException { + return null; + } + + @Override + public SQLXML createSQLXML() throws SQLException { + return null; + } + + @Override + public boolean isValid(int timeout) throws SQLException { + return false; + } + + @Override + public void setClientInfo(String name, String value) throws SQLClientInfoException { + + } + + @Override + public void setClientInfo(Properties properties) throws SQLClientInfoException { + + } + + @Override + public String getClientInfo(String name) throws SQLException { + return null; + } + + @Override + public Properties getClientInfo() throws SQLException { + return null; + } + + @Override + public Array createArrayOf(String typeName, Object[] elements) throws SQLException { + return null; + } + + @Override + public Struct createStruct(String typeName, Object[] attributes) throws SQLException { + return null; + } + + @Override + public void setSchema(String schema) throws SQLException { + + } + + @Override + public String getSchema() throws SQLException { + return null; + } + + @Override + public void abort(Executor executor) throws SQLException { + + } + + @Override + public void setNetworkTimeout(Executor executor, int milliseconds) throws SQLException { + + } + + @Override + public int getNetworkTimeout() throws SQLException { + return 0; + } + + @Override + public <T> T unwrap(Class<T> iface) throws SQLException { + return null; + } + + @Override + public boolean isWrapperFor(Class<?> iface) throws SQLException { + return false; + } + } +} http://git-wip-us.apache.org/repos/asf/tomee/blob/abbed04a/container/openejb-core/src/test/java/org/apache/openejb/resource/jdbc/ManagedDataSourceTest.java ---------------------------------------------------------------------- diff --git a/container/openejb-core/src/test/java/org/apache/openejb/resource/jdbc/ManagedDataSourceTest.java b/container/openejb-core/src/test/java/org/apache/openejb/resource/jdbc/ManagedDataSourceTest.java index e959693..f2005f5 100644 --- a/container/openejb-core/src/test/java/org/apache/openejb/resource/jdbc/ManagedDataSourceTest.java +++ b/container/openejb-core/src/test/java/org/apache/openejb/resource/jdbc/ManagedDataSourceTest.java @@ -19,14 +19,18 @@ package org.apache.openejb.resource.jdbc; import org.apache.openejb.jee.EjbJar; import org.apache.openejb.jee.SingletonBean; import org.apache.openejb.junit.ApplicationComposer; -import org.apache.openejb.resource.jdbc.managed.local.ManagedConnection; import org.apache.openejb.testing.Configuration; import org.apache.openejb.testing.Module; -import org.junit.After; import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.Properties; import javax.annotation.Resource; import javax.ejb.EJB; import javax.ejb.EJBContext; @@ -35,17 +39,7 @@ import javax.ejb.Singleton; import javax.ejb.TransactionAttribute; import javax.ejb.TransactionAttributeType; import javax.sql.DataSource; -import javax.transaction.Transaction; -import java.lang.reflect.Field; -import java.sql.Connection; -import java.sql.DriverManager; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; -import java.util.Map; -import java.util.Properties; -import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -198,15 +192,6 @@ public class ManagedDataSourceTest { assertFalse(exists(12)); } - @After - public void checkTxMapIsEmpty() throws Exception { // avoid memory leak - final Field map = ManagedConnection.class.getDeclaredField("CONNECTION_BY_TX_BY_DS"); - map.setAccessible(true); - final Map<DataSource, Map<Transaction, Connection>> instance = (Map<DataSource, Map<Transaction, Connection>>) map.get(null); - assertEquals(1, instance.size()); - assertEquals(0, instance.values().iterator().next().size()); - } - private static boolean exists(final int id) throws SQLException { final Connection connection = DriverManager.getConnection(URL, USER, PASSWORD); final Statement statement = connection.createStatement(); http://git-wip-us.apache.org/repos/asf/tomee/blob/abbed04a/container/openejb-core/src/test/java/org/apache/openejb/resource/jdbc/MultiThreadedManagedDataSourceTest.java ---------------------------------------------------------------------- diff --git a/container/openejb-core/src/test/java/org/apache/openejb/resource/jdbc/MultiThreadedManagedDataSourceTest.java b/container/openejb-core/src/test/java/org/apache/openejb/resource/jdbc/MultiThreadedManagedDataSourceTest.java index 15288fe..7f908c6 100644 --- a/container/openejb-core/src/test/java/org/apache/openejb/resource/jdbc/MultiThreadedManagedDataSourceTest.java +++ b/container/openejb-core/src/test/java/org/apache/openejb/resource/jdbc/MultiThreadedManagedDataSourceTest.java @@ -19,35 +19,30 @@ package org.apache.openejb.resource.jdbc; import org.apache.openejb.jee.EjbJar; import org.apache.openejb.jee.SingletonBean; import org.apache.openejb.junit.ApplicationComposer; -import org.apache.openejb.resource.jdbc.managed.local.ManagedConnection; import org.apache.openejb.testing.Configuration; import org.apache.openejb.testing.Module; -import org.junit.After; import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; -import javax.annotation.Resource; -import javax.ejb.EJB; -import javax.ejb.EJBContext; -import javax.ejb.LocalBean; -import javax.ejb.Singleton; -import javax.sql.DataSource; -import javax.transaction.Transaction; -import java.lang.reflect.Field; import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.List; -import java.util.Map; import java.util.Properties; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; +import javax.annotation.Resource; +import javax.ejb.EJB; +import javax.ejb.EJBContext; +import javax.ejb.LocalBean; +import javax.ejb.Singleton; +import javax.sql.DataSource; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; @@ -192,15 +187,6 @@ public class MultiThreadedManagedDataSourceTest { assertEquals(ok.get(), count("") - count); } - @After - public void checkTxMapIsEmpty() throws Exception { // avoid memory leak - final Field map = ManagedConnection.class.getDeclaredField("CONNECTION_BY_TX_BY_DS"); - map.setAccessible(true); - final Map<DataSource, Map<Transaction, Connection>> instance = (Map<DataSource, Map<Transaction, Connection>>) map.get(null); - assertEquals(1, instance.size()); - assertEquals(0, instance.values().iterator().next().size()); - } - private static boolean exists(final int id) throws SQLException { return count(" WHERE ID = " + id) == 1; } http://git-wip-us.apache.org/repos/asf/tomee/blob/abbed04a/server/openejb-bonecp/src/main/java/org/apache/openejb/bonecp/BoneCPDataSourceCreator.java ---------------------------------------------------------------------- diff --git a/server/openejb-bonecp/src/main/java/org/apache/openejb/bonecp/BoneCPDataSourceCreator.java b/server/openejb-bonecp/src/main/java/org/apache/openejb/bonecp/BoneCPDataSourceCreator.java index 674b6b1..748d619 100644 --- a/server/openejb-bonecp/src/main/java/org/apache/openejb/bonecp/BoneCPDataSourceCreator.java +++ b/server/openejb-bonecp/src/main/java/org/apache/openejb/bonecp/BoneCPDataSourceCreator.java @@ -21,6 +21,7 @@ import com.jolbox.bonecp.BoneCPConfig; import com.jolbox.bonecp.BoneCPDataSource; import org.apache.openejb.OpenEJB; import org.apache.openejb.OpenEJBRuntimeException; +import org.apache.openejb.loader.SystemInstance; import org.apache.openejb.resource.jdbc.BasicDataSourceUtil; import org.apache.openejb.resource.jdbc.managed.xa.ManagedXADataSource; import org.apache.openejb.resource.jdbc.plugin.DataSourcePlugin; @@ -32,6 +33,7 @@ import org.apache.openejb.util.Strings; import javax.sql.CommonDataSource; import javax.sql.DataSource; import javax.sql.XADataSource; +import javax.transaction.TransactionSynchronizationRegistry; import java.lang.reflect.Field; import java.sql.SQLException; import java.sql.SQLFeatureNotSupportedException; @@ -128,7 +130,7 @@ public class BoneCPDataSourceCreator extends PoolDataSourceCreator { cleanProperty(ds, "xadatasource"); final XADataSource xaDs = XADataSourceResource.proxy(Thread.currentThread().getContextClassLoader(), xa); - ds.setDatasourceBean(new ManagedXADataSource(xaDs, OpenEJB.getTransactionManager())); + ds.setDatasourceBean(new ManagedXADataSource(xaDs, OpenEJB.getTransactionManager(), SystemInstance.get().getComponent(TransactionSynchronizationRegistry.class))); } return ds; http://git-wip-us.apache.org/repos/asf/tomee/blob/abbed04a/server/openejb-bonecp/src/test/java/org/apache/openejb/bonecp/BoneCPPooledDataSourceFromPoolTest.java ---------------------------------------------------------------------- diff --git a/server/openejb-bonecp/src/test/java/org/apache/openejb/bonecp/BoneCPPooledDataSourceFromPoolTest.java b/server/openejb-bonecp/src/test/java/org/apache/openejb/bonecp/BoneCPPooledDataSourceFromPoolTest.java index 27f7b35..8ae4dc6 100644 --- a/server/openejb-bonecp/src/test/java/org/apache/openejb/bonecp/BoneCPPooledDataSourceFromPoolTest.java +++ b/server/openejb-bonecp/src/test/java/org/apache/openejb/bonecp/BoneCPPooledDataSourceFromPoolTest.java @@ -21,13 +21,16 @@ import org.apache.openejb.jee.SingletonBean; import org.apache.openejb.junit.ApplicationComposer; import org.apache.openejb.junit.Configuration; import org.apache.openejb.junit.Module; -import org.apache.openejb.resource.jdbc.managed.local.ManagedConnection; -import org.hsqldb.jdbc.JDBCDataSource; -import org.junit.After; import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.Properties; import javax.annotation.Resource; import javax.annotation.sql.DataSourceDefinition; import javax.ejb.EJB; @@ -37,17 +40,7 @@ import javax.ejb.Singleton; import javax.ejb.TransactionAttribute; import javax.ejb.TransactionAttributeType; import javax.sql.DataSource; -import javax.transaction.Transaction; -import java.lang.reflect.Field; -import java.sql.Connection; -import java.sql.DriverManager; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; -import java.util.Map; -import java.util.Properties; -import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -195,15 +188,6 @@ public class BoneCPPooledDataSourceFromPoolTest { assertFalse(exists(12)); } - @After - public void checkTxMapIsEmpty() throws Exception { // avoid memory leak - final Field map = ManagedConnection.class.getDeclaredField("CONNECTION_BY_TX_BY_DS"); - map.setAccessible(true); - final Map<DataSource, Map<Transaction, Connection>> instance = (Map<DataSource, Map<Transaction, Connection>>) map.get(null); - assertEquals(1, instance.size()); - assertEquals(0, instance.values().iterator().next().size()); - } - private static boolean exists(int id) throws SQLException { final Connection connection = DriverManager.getConnection(URL, USER, PASSWORD); final Statement statement = connection.createStatement(); http://git-wip-us.apache.org/repos/asf/tomee/blob/abbed04a/server/openejb-bonecp/src/test/java/org/apache/openejb/bonecp/BoneCPPooledDataSourceTest.java ---------------------------------------------------------------------- diff --git a/server/openejb-bonecp/src/test/java/org/apache/openejb/bonecp/BoneCPPooledDataSourceTest.java b/server/openejb-bonecp/src/test/java/org/apache/openejb/bonecp/BoneCPPooledDataSourceTest.java index 0973917..5e275db 100644 --- a/server/openejb-bonecp/src/test/java/org/apache/openejb/bonecp/BoneCPPooledDataSourceTest.java +++ b/server/openejb-bonecp/src/test/java/org/apache/openejb/bonecp/BoneCPPooledDataSourceTest.java @@ -27,6 +27,14 @@ import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; +import java.lang.reflect.Field; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.Map; +import java.util.Properties; import javax.annotation.Resource; import javax.ejb.EJB; import javax.ejb.EJBContext; @@ -36,14 +44,6 @@ import javax.ejb.TransactionAttribute; import javax.ejb.TransactionAttributeType; import javax.sql.DataSource; import javax.transaction.Transaction; -import java.lang.reflect.Field; -import java.sql.Connection; -import java.sql.DriverManager; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; -import java.util.Map; -import java.util.Properties; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -196,15 +196,6 @@ public class BoneCPPooledDataSourceTest { assertFalse(exists(12)); } - @After - public void checkTxMapIsEmpty() throws Exception { // avoid memory leak - final Field map = ManagedConnection.class.getDeclaredField("CONNECTION_BY_TX_BY_DS"); - map.setAccessible(true); - final Map<DataSource, Map<Transaction, Connection>> instance = (Map<DataSource, Map<Transaction, Connection>>) map.get(null); - assertEquals(1, instance.size()); - assertEquals(0, instance.values().iterator().next().size()); - } - private static boolean exists(int id) throws SQLException { final Connection connection = DriverManager.getConnection(URL, USER, PASSWORD); final Statement statement = connection.createStatement(); http://git-wip-us.apache.org/repos/asf/tomee/blob/abbed04a/server/openejb-bonecp/src/test/java/org/apache/openejb/bonecp/XABoneCPTest.java ---------------------------------------------------------------------- diff --git a/server/openejb-bonecp/src/test/java/org/apache/openejb/bonecp/XABoneCPTest.java b/server/openejb-bonecp/src/test/java/org/apache/openejb/bonecp/XABoneCPTest.java index 8677b9f..b9d3279 100644 --- a/server/openejb-bonecp/src/test/java/org/apache/openejb/bonecp/XABoneCPTest.java +++ b/server/openejb-bonecp/src/test/java/org/apache/openejb/bonecp/XABoneCPTest.java @@ -26,11 +26,11 @@ import org.hsqldb.jdbc.pool.JDBCXADataSource; import org.junit.Test; import org.junit.runner.RunWith; -import javax.annotation.Resource; -import javax.sql.DataSource; import java.sql.Connection; import java.sql.SQLException; import java.util.Properties; +import javax.annotation.Resource; +import javax.sql.DataSource; import static org.hamcrest.CoreMatchers.instanceOf; import static org.junit.Assert.assertNotNull; http://git-wip-us.apache.org/repos/asf/tomee/blob/abbed04a/tomee/tomee-jdbc/src/test/java/org/apache/tomee/jdbc/TomcatDataSourceFromPoolTest.java ---------------------------------------------------------------------- diff --git a/tomee/tomee-jdbc/src/test/java/org/apache/tomee/jdbc/TomcatDataSourceFromPoolTest.java b/tomee/tomee-jdbc/src/test/java/org/apache/tomee/jdbc/TomcatDataSourceFromPoolTest.java index 856c8e3..6cc369b 100644 --- a/tomee/tomee-jdbc/src/test/java/org/apache/tomee/jdbc/TomcatDataSourceFromPoolTest.java +++ b/tomee/tomee-jdbc/src/test/java/org/apache/tomee/jdbc/TomcatDataSourceFromPoolTest.java @@ -21,12 +21,16 @@ import org.apache.openejb.jee.SingletonBean; import org.apache.openejb.junit.ApplicationComposer; import org.apache.openejb.junit.Configuration; import org.apache.openejb.junit.Module; -import org.apache.openejb.resource.jdbc.managed.local.ManagedConnection; -import org.junit.After; import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.Properties; import javax.annotation.Resource; import javax.annotation.sql.DataSourceDefinition; import javax.ejb.EJB; @@ -36,17 +40,7 @@ import javax.ejb.Singleton; import javax.ejb.TransactionAttribute; import javax.ejb.TransactionAttributeType; import javax.sql.DataSource; -import javax.transaction.Transaction; -import java.lang.reflect.Field; -import java.sql.Connection; -import java.sql.DriverManager; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; -import java.util.Map; -import java.util.Properties; -import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -194,15 +188,6 @@ public class TomcatDataSourceFromPoolTest { assertFalse(exists(12)); } - @After - public void checkTxMapIsEmpty() throws Exception { // avoid memory leak - final Field map = ManagedConnection.class.getDeclaredField("CONNECTION_BY_TX_BY_DS"); - map.setAccessible(true); - final Map<DataSource, Map<Transaction, Connection>> instance = (Map<DataSource, Map<Transaction, Connection>> ) map.get(null); - assertEquals(1, instance.size()); - assertEquals(0, instance.values().iterator().next().size()); - } - private static boolean exists(final int id) throws SQLException { final Connection connection = DriverManager.getConnection(URL, USER, PASSWORD); final Statement statement = connection.createStatement(); http://git-wip-us.apache.org/repos/asf/tomee/blob/abbed04a/tomee/tomee-jdbc/src/test/java/org/apache/tomee/jdbc/TomcatPoolTest.java ---------------------------------------------------------------------- diff --git a/tomee/tomee-jdbc/src/test/java/org/apache/tomee/jdbc/TomcatPoolTest.java b/tomee/tomee-jdbc/src/test/java/org/apache/tomee/jdbc/TomcatPoolTest.java index 7c8e959..658333f 100644 --- a/tomee/tomee-jdbc/src/test/java/org/apache/tomee/jdbc/TomcatPoolTest.java +++ b/tomee/tomee-jdbc/src/test/java/org/apache/tomee/jdbc/TomcatPoolTest.java @@ -21,12 +21,16 @@ import org.apache.openejb.jee.SingletonBean; import org.apache.openejb.junit.ApplicationComposer; import org.apache.openejb.junit.Configuration; import org.apache.openejb.junit.Module; -import org.apache.openejb.resource.jdbc.managed.local.ManagedConnection; -import org.junit.After; import org.junit.BeforeClass; import org.junit.Test; import org.junit.runner.RunWith; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.Properties; import javax.annotation.Resource; import javax.ejb.EJB; import javax.ejb.EJBContext; @@ -35,17 +39,7 @@ import javax.ejb.Singleton; import javax.ejb.TransactionAttribute; import javax.ejb.TransactionAttributeType; import javax.sql.DataSource; -import javax.transaction.Transaction; -import java.lang.reflect.Field; -import java.sql.Connection; -import java.sql.DriverManager; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; -import java.util.Map; -import java.util.Properties; -import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -196,15 +190,6 @@ public class TomcatPoolTest { assertFalse(exists(12)); } - @After - public void checkTxMapIsEmpty() throws Exception { // avoid memory leak - final Field map = ManagedConnection.class.getDeclaredField("CONNECTION_BY_TX_BY_DS"); - map.setAccessible(true); - final Map<DataSource, Map<Transaction, Connection>> instance = (Map<DataSource, Map<Transaction, Connection>> ) map.get(null); - assertEquals(1, instance.size()); - assertEquals(0, instance.values().iterator().next().size()); - } - private static boolean exists(final int id) throws SQLException { final Connection connection = DriverManager.getConnection(URL, USER, PASSWORD); final Statement statement = connection.createStatement();
