Wrap XAConnection's underlying connections to ensure they go back into the 
pool. Add tests for XA functionality. Ensure connections are created correctly 
for XA datasource when using InitialSize.


Project: http://git-wip-us.apache.org/repos/asf/tomee/repo
Commit: http://git-wip-us.apache.org/repos/asf/tomee/commit/9e19d4a4
Tree: http://git-wip-us.apache.org/repos/asf/tomee/tree/9e19d4a4
Diff: http://git-wip-us.apache.org/repos/asf/tomee/diff/9e19d4a4

Branch: refs/heads/tomee-1.7.x
Commit: 9e19d4a441109ffb0583fdb365d32a03e9a062c2
Parents: 75ac9b4
Author: Jonathan Gallimore <[email protected]>
Authored: Wed Aug 10 00:29:59 2016 +0100
Committer: Jonathan Gallimore <[email protected]>
Committed: Wed Aug 10 00:29:59 2016 +0100

----------------------------------------------------------------------
 .../jdbc/managed/local/ManagedConnection.java   | 36 +++++++-
 .../openejb/resource/jdbc/XADataSourceTest.java | 24 ++++-
 examples/xa-datasource/pom.xml                  |  4 +-
 .../superbiz/injection/jpa/MoviesXATest.java    | 95 +-------------------
 .../tomee/jdbc/TomEEDataSourceCreator.java      | 34 +++++--
 .../tomee/jdbc/TomcatXADataSourceTest.java      | 23 ++++-
 6 files changed, 109 insertions(+), 107 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tomee/blob/9e19d4a4/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 1e2edfe..bb24f0f 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
@@ -23,6 +23,7 @@ import org.apache.openejb.util.Logger;
 import java.lang.reflect.InvocationHandler;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
 import java.sql.Connection;
 import java.sql.SQLException;
 import java.sql.Wrapper;
@@ -164,7 +165,7 @@ public class ManagedConnection implements InvocationHandler 
{
                 (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();
+            delegate = wrapDelegate(xaConnection, 
xaConnection.getConnection());
             xaResource = xaConnection.getXAResource();
         } else {
             delegate = Connection.class.cast(connection);
@@ -173,6 +174,13 @@ public class ManagedConnection implements 
InvocationHandler {
         return connection;
     }
 
+    private Connection wrapDelegate(final XAConnection xaConnection, final 
Connection connection) {
+        return (Connection) Proxy.newProxyInstance(
+                Thread.currentThread().getContextClassLoader(),
+                new Class<?>[] { Connection.class },
+                new XAConnectionWrapper(xaConnection, connection));
+    }
+
     protected void setAutoCommit(final boolean value) throws SQLException {
         if (delegate == null) {
             newConnection();
@@ -233,8 +241,8 @@ public class ManagedConnection implements InvocationHandler 
{
     private static class ClosingSynchronization implements Synchronization {
         private final Connection connection;
 
-        public ClosingSynchronization(final Connection delegate) {
-            this.connection = delegate;
+        public ClosingSynchronization(final Connection connection) {
+            this.connection = connection;
         }
 
         @Override
@@ -285,4 +293,24 @@ public class ManagedConnection implements 
InvocationHandler {
             return hash;
         }
     }
-}
\ No newline at end of file
+
+    private class XAConnectionWrapper implements InvocationHandler {
+        private final XAConnection xaConnection;
+        private final Connection delegate;
+
+        public XAConnectionWrapper(final XAConnection xaConnection, final 
Connection delegate) {
+            this.xaConnection = xaConnection;
+            this.delegate = delegate;
+        }
+
+        @Override
+        public Object invoke(final Object proxy, final Method method, final 
Object[] args) throws Throwable {
+            if ("close".equals(method.getName()) && (args == null || 
args.length == 0)) {
+                xaConnection.close();
+                return null;
+            } else {
+                return method.invoke(delegate, args);
+            }
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/tomee/blob/9e19d4a4/container/openejb-core/src/test/java/org/apache/openejb/resource/jdbc/XADataSourceTest.java
----------------------------------------------------------------------
diff --git 
a/container/openejb-core/src/test/java/org/apache/openejb/resource/jdbc/XADataSourceTest.java
 
b/container/openejb-core/src/test/java/org/apache/openejb/resource/jdbc/XADataSourceTest.java
index d01407a..25016b4 100644
--- 
a/container/openejb-core/src/test/java/org/apache/openejb/resource/jdbc/XADataSourceTest.java
+++ 
b/container/openejb-core/src/test/java/org/apache/openejb/resource/jdbc/XADataSourceTest.java
@@ -33,25 +33,37 @@ import org.junit.runner.RunWith;
 import javax.ejb.EJB;
 import javax.ejb.EJBException;
 import javax.ejb.Singleton;
+import javax.management.AttributeNotFoundException;
+import javax.management.InstanceNotFoundException;
+import javax.management.MBeanException;
+import javax.management.MBeanServer;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+import javax.management.ReflectionException;
 import javax.persistence.Entity;
 import javax.persistence.EntityManager;
 import javax.persistence.GeneratedValue;
 import javax.persistence.Id;
 import javax.persistence.PersistenceContext;
 import java.io.File;
+import java.lang.management.ManagementFactory;
 import java.util.Properties;
 
 import static org.hamcrest.CoreMatchers.instanceOf;
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertThat;
 
 @RunWith(ApplicationComposer.class)
 public class XADataSourceTest {
+
+    private static final MBeanServer server = 
ManagementFactory.getPlatformMBeanServer();
+
     @EJB
     private XAEJB ejb;
 
     @Test
-    public void checkOperationsWork() {
+    public void checkOperationsWork() throws Exception {
         ejb.doSthg();
         ejb.assertPersisted();
         try {
@@ -59,6 +71,16 @@ public class XADataSourceTest {
         } catch (final EJBException ejbEx) {
             assertThat(ejbEx.getCause(), 
instanceOf(IllegalArgumentException.class));
         }
+
+        assertEquals(0, getActiveConnections("xadbn"));
+        assertEquals(0, getActiveConnections("xadbn2"));
+    }
+
+    private int getActiveConnections(final String dataSourceName)
+            throws MalformedObjectNameException, MBeanException, 
AttributeNotFoundException, InstanceNotFoundException, ReflectionException {
+        final ObjectName objectName = new 
ObjectName("openejb.management:ObjectType=datasources,DataSource=" + 
dataSourceName);
+        final Object activeConnectionsAttribute = 
server.getAttribute(objectName, "numActive");
+        return (int) (Integer) activeConnectionsAttribute;
     }
 
     @Configuration

http://git-wip-us.apache.org/repos/asf/tomee/blob/9e19d4a4/examples/xa-datasource/pom.xml
----------------------------------------------------------------------
diff --git a/examples/xa-datasource/pom.xml b/examples/xa-datasource/pom.xml
index fc46986..f73ec8c 100644
--- a/examples/xa-datasource/pom.xml
+++ b/examples/xa-datasource/pom.xml
@@ -70,9 +70,9 @@
     code is dependent on any OpenEJB classes.
     -->
     <dependency>
-      <groupId>org.apache.tomee</groupId>
+      <groupId>org.apache.openejb</groupId>
       <artifactId>openejb-core</artifactId>
-      <version>4.7.5-SNAPSHOT</version>
+      <version>4.7.5-TT.6</version>
       <scope>test</scope>
     </dependency>
 

http://git-wip-us.apache.org/repos/asf/tomee/blob/9e19d4a4/examples/xa-datasource/src/test/java/org/superbiz/injection/jpa/MoviesXATest.java
----------------------------------------------------------------------
diff --git 
a/examples/xa-datasource/src/test/java/org/superbiz/injection/jpa/MoviesXATest.java
 
b/examples/xa-datasource/src/test/java/org/superbiz/injection/jpa/MoviesXATest.java
index 995a8cb..56ee0c6 100644
--- 
a/examples/xa-datasource/src/test/java/org/superbiz/injection/jpa/MoviesXATest.java
+++ 
b/examples/xa-datasource/src/test/java/org/superbiz/injection/jpa/MoviesXATest.java
@@ -48,7 +48,7 @@ public class MoviesXATest {
         final PersistenceUnit unit = new PersistenceUnit("movie-unit");
         unit.setJtaDataSource("movieDatabase");
         unit.setNonJtaDataSource("movieDatabaseUnmanaged");
-        unit.setProperty("openjpa.jdbc.SynchronizeMappings", "buildSchema");
+        unit.setProperty("openjpa.jdbc.SynchronizeMappings", 
"buildSchema(foreignKeys=true,schemaAction='dropDB,add')");
         unit.addClass(Movie.class);
         return unit;
     }
@@ -70,6 +70,7 @@ public class MoviesXATest {
         p.put("movieDatabase.UserName", "admin");
         p.put("movieDatabase.Password", "admin");
         p.put("movieDatabase.MaxActive", "128");
+        p.put("movieDatabase.InitialSize", "2");
         p.put("movieDatabase.MaxIdle", "25");
         p.put("movieDatabase.MinIdle", "10");
         p.put("movieDatabase.AccessToUnderlyingConnectionAllowed", "true");
@@ -88,6 +89,7 @@ public class MoviesXATest {
         p.put("movieDatabaseUnmanaged.UserName", "admin");
         p.put("movieDatabaseUnmanaged.Password", "admin");
         p.put("movieDatabaseUnmanaged.JtaManaged", "false");
+        p.put("movieDatabaseUnmanaged.InitialSize", "2");
         p.put("movieDatabaseUnmanaged.MaxActive", "128");
         p.put("movieDatabaseUnmanaged.MaxIdle", "25");
         p.put("movieDatabaseUnmanaged.MinIdle", "10");
@@ -100,97 +102,6 @@ public class MoviesXATest {
         p.put("movieDatabaseUnmanaged.MaxOpenPreparedStatements", "1024");
         p.put("movieDatabaseUnmanaged.ValidationQuery", "values 1");
 
-        /*
-
-        Configuration for MS SQL Server
-
-        p.put("movieDatabaseXA", 
"new://Resource?type=javax.sql.XADataSource&class-name=com.microsoft.sqlserver.jdbc.SQLServerXADataSource");
-        p.put("movieDatabaseXA.DatabaseName", "moviefun");
-        p.put("movieDatabaseXA.URL", 
"jdbc:sqlserver://localhost:1433;databaseName=moviefun;SelectMethod=cursor;sendStringParametersAsUnicode=false");
-
-        p.put("movieDatabase", "new://Resource?type=DataSource");
-        p.put("movieDatabase.XaDataSource", "movieDatabaseXA");
-        p.put("movieDatabase.UserName", "sa");
-        p.put("movieDatabase.Password", "XXX");
-        p.put("movieDatabase.JtaManaged", "true");
-        p.put("movieDatabase.MaxActive", "128");
-        p.put("movieDatabase.MaxIdle", "25");
-        p.put("movieDatabase.MinIdle", "10");
-        p.put("movieDatabase.AccessToUnderlyingConnectionAllowed", "true");
-        p.put("movieDatabase.TestOnBorrow", "false");
-        p.put("movieDatabase.TestWhileIdle", "true");
-        p.put("movieDatabase.TimeBetweenEvictionRuns", "1 minute");
-        p.put("movieDatabase.MaxWaitTime", "0 seconds");
-        p.put("movieDatabase.PoolPreparedStatements", "true");
-        p.put("movieDatabase.MaxOpenPreparedStatements", "1024");
-        p.put("movieDatabase.ValidationQuery", "select 1");
-
-        p.put("movieDatabaseUnmanaged", "new://Resource?type=DataSource");
-        p.put("movieDatabaseUnmanaged.LogSql", "true");
-        p.put("movieDatabaseUnmanaged.JdbcDriver", 
"com.microsoft.sqlserver.jdbc.SQLServerDriver");
-        p.put("movieDatabaseUnmanaged.JdbcUrl", 
"jdbc:sqlserver://localhost:1433;databaseName=moviefun;SelectMethod=cursor;sendStringParametersAsUnicode=false");
-        p.put("movieDatabaseUnmanaged.UserName", "sa");
-        p.put("movieDatabaseUnmanaged.Password", "XXX");
-        p.put("movieDatabaseUnmanaged.JtaManaged", "false");
-        p.put("movieDatabaseUnmanaged.MaxActive", "128");
-        p.put("movieDatabaseUnmanaged.MaxIdle", "25");
-        p.put("movieDatabaseUnmanaged.MinIdle", "10");
-        p.put("movieDatabaseUnmanaged.AccessToUnderlyingConnectionAllowed", 
"true");
-        p.put("movieDatabaseUnmanaged.TestOnBorrow", "false");
-        p.put("movieDatabaseUnmanaged.TestWhileIdle", "true");
-        p.put("movieDatabaseUnmanaged.TimeBetweenEvictionRuns", "1 minute");
-        p.put("movieDatabaseUnmanaged.MaxWaitTime", "0 seconds");
-        p.put("movieDatabaseUnmanaged.PoolPreparedStatements", "true");
-        p.put("movieDatabaseUnmanaged.MaxOpenPreparedStatements", "1024");
-        p.put("movieDatabaseUnmanaged.ValidationQuery", "select 1");
-
-        p.put("movieDatabaseXA", 
"new://Resource?type=javax.sql.XADataSource&class-name=oracle.jdbc.xa.client.OracleXADataSource");
-        p.put("movieDatabaseXA.url", 
"jdbc:oracle:thin:@//localhost:1521/orcl");
-
-        */
-
-        /*
-
-        Configuration for Oracle
-
-        p.put("movieDatabase", "new://Resource?type=DataSource");
-        p.put("movieDatabase.XaDataSource", "movieDatabaseXA");
-        p.put("movieDatabase.JtaManaged", "true");
-        p.put("movieDatabase.UserName", "system");
-        p.put("movieDatabase.Password", "oracle");
-        p.put("movieDatabase.MaxActive", "128");
-        p.put("movieDatabase.MaxIdle", "25");
-        p.put("movieDatabase.MinIdle", "10");
-        p.put("movieDatabase.AccessToUnderlyingConnectionAllowed", "true");
-        p.put("movieDatabase.TestOnBorrow", "false");
-        p.put("movieDatabase.TestWhileIdle", "true");
-        p.put("movieDatabase.TimeBetweenEvictionRuns", "1 minute");
-        p.put("movieDatabase.MaxWaitTime", "0 seconds");
-        p.put("movieDatabase.PoolPreparedStatements", "true");
-        p.put("movieDatabase.MaxOpenPreparedStatements", "1024");
-        p.put("movieDatabase.ValidationQuery", "select 1 from dual");
-
-        p.put("movieDatabaseUnmanaged", "new://Resource?type=DataSource");
-        p.put("movieDatabaseUnmanaged.LogSql", "true");
-        p.put("movieDatabaseUnmanaged.JdbcDriver", 
"oracle.jdbc.driver.OracleDriver");
-        p.put("movieDatabaseUnmanaged.JdbcUrl", 
"jdbc:oracle:thin:@//localhost:1521/orcl");
-        p.put("movieDatabaseUnmanaged.UserName", "system");
-        p.put("movieDatabaseUnmanaged.Password", "oracle");
-        p.put("movieDatabaseUnmanaged.JtaManaged", "false");
-        p.put("movieDatabaseUnmanaged.MaxActive", "128");
-        p.put("movieDatabaseUnmanaged.MaxIdle", "25");
-        p.put("movieDatabaseUnmanaged.MinIdle", "10");
-        p.put("movieDatabaseUnmanaged.AccessToUnderlyingConnectionAllowed", 
"true");
-        p.put("movieDatabaseUnmanaged.TestOnBorrow", "false");
-        p.put("movieDatabaseUnmanaged.TestWhileIdle", "true");
-        p.put("movieDatabaseUnmanaged.TimeBetweenEvictionRuns", "1 minute");
-        p.put("movieDatabaseUnmanaged.MaxWaitTime", "0 seconds");
-        p.put("movieDatabaseUnmanaged.PoolPreparedStatements", "true");
-        p.put("movieDatabaseUnmanaged.MaxOpenPreparedStatements", "1024");
-        p.put("movieDatabaseUnmanaged.ValidationQuery", "select 1 from dual");
-
-        */
-
         System.out.println("Using db: " + db);
 
         return p;

http://git-wip-us.apache.org/repos/asf/tomee/blob/9e19d4a4/tomee/tomee-jdbc/src/main/java/org/apache/tomee/jdbc/TomEEDataSourceCreator.java
----------------------------------------------------------------------
diff --git 
a/tomee/tomee-jdbc/src/main/java/org/apache/tomee/jdbc/TomEEDataSourceCreator.java
 
b/tomee/tomee-jdbc/src/main/java/org/apache/tomee/jdbc/TomEEDataSourceCreator.java
index 73b6043..4ca7529 100644
--- 
a/tomee/tomee-jdbc/src/main/java/org/apache/tomee/jdbc/TomEEDataSourceCreator.java
+++ 
b/tomee/tomee-jdbc/src/main/java/org/apache/tomee/jdbc/TomEEDataSourceCreator.java
@@ -40,13 +40,16 @@ import org.apache.tomcat.jdbc.pool.PooledConnection;
 import javax.management.ObjectName;
 import javax.sql.CommonDataSource;
 import javax.sql.DataSource;
+import javax.sql.XAConnection;
 import javax.sql.XADataSource;
 import java.lang.reflect.InvocationHandler;
 import java.lang.reflect.Method;
 import java.lang.reflect.Proxy;
+import java.sql.Connection;
 import java.sql.SQLException;
 import java.util.Map;
 import java.util.Properties;
+import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
 
 public class TomEEDataSourceCreator extends PoolDataSourceCreator {
@@ -80,17 +83,17 @@ public class TomEEDataSourceCreator extends 
PoolDataSourceCreator {
 
         updateProperties(prop, converted, driver);
         final PoolConfiguration config = build(PoolProperties.class, 
converted);
-        final TomEEDataSource ds = build(TomEEDataSource.class, new 
TomEEDataSource(config, name), converted);
-
         final String xa = String.class.cast(properties.remove("XaDataSource"));
         if (xa != null) {
-            cleanProperty(ds, "xadatasource");
-
             final XADataSource xaDs = 
XADataSourceResource.proxy(Thread.currentThread().getContextClassLoader(), xa);
-            ds.setDataSource(xaDs);
+            final TomEEDataSource instance = new TomEEDataSource(config, name, 
xaDs);
+            return build(TomEEDataSource.class, instance, converted);
+
+        } else {
+            final TomEEDataSource instance = new TomEEDataSource(config, name);
+            return build(TomEEDataSource.class, instance, converted);
         }
 
-        return ds;
     }
 
     private void updateProperties(final SuperProperties properties, final 
Properties converted, final String driver) {
@@ -215,7 +218,15 @@ public class TomEEDataSourceCreator extends 
PoolDataSourceCreator {
         }
 
         public TomEEDataSource(final PoolConfiguration poolConfiguration, 
final String name) {
+            this(poolConfiguration, name, null);
+        }
+
+        public TomEEDataSource(final PoolConfiguration poolConfiguration, 
final String name, final XADataSource xaDs) {
             super(readOnly(poolConfiguration));
+            if (xaDs != null) {
+                this.setDataSource(xaDs);
+            }
+
             try { // just to force the pool to be created and be able to 
register the mbean
                 createPool();
                 initJmx(name);
@@ -297,6 +308,16 @@ public class TomEEDataSourceCreator extends 
PoolDataSourceCreator {
                 }
             }
         }
+
+        @Override
+        public Connection getConnection() throws SQLException {
+            return super.getConnection();
+        }
+
+        @Override
+        public Connection getConnection(final String username, final String 
password) throws SQLException {
+            return super.getConnection(username, password);
+        }
     }
 
     private static class ReadOnlyConnectionpool implements InvocationHandler {
@@ -330,6 +351,7 @@ public class TomEEDataSourceCreator extends 
PoolDataSourceCreator {
         @Override
         protected PooledConnection create(final boolean incrementCounter) {
             final PooledConnection con = super.create(incrementCounter);
+
             if (getPoolProperties().getDataSource() == null) { // using driver
                 // init driver with TCCL
                 ClassLoader cl = 
Thread.currentThread().getContextClassLoader();

http://git-wip-us.apache.org/repos/asf/tomee/blob/9e19d4a4/tomee/tomee-jdbc/src/test/java/org/apache/tomee/jdbc/TomcatXADataSourceTest.java
----------------------------------------------------------------------
diff --git 
a/tomee/tomee-jdbc/src/test/java/org/apache/tomee/jdbc/TomcatXADataSourceTest.java
 
b/tomee/tomee-jdbc/src/test/java/org/apache/tomee/jdbc/TomcatXADataSourceTest.java
index f44b0bb..68892e5 100644
--- 
a/tomee/tomee-jdbc/src/test/java/org/apache/tomee/jdbc/TomcatXADataSourceTest.java
+++ 
b/tomee/tomee-jdbc/src/test/java/org/apache/tomee/jdbc/TomcatXADataSourceTest.java
@@ -27,17 +27,27 @@ import org.junit.Test;
 import org.junit.runner.RunWith;
 
 import javax.annotation.Resource;
+import javax.management.AttributeNotFoundException;
+import javax.management.InstanceNotFoundException;
+import javax.management.MBeanException;
+import javax.management.MBeanServer;
+import javax.management.MalformedObjectNameException;
+import javax.management.ObjectName;
+import javax.management.ReflectionException;
 import javax.sql.DataSource;
+import java.lang.management.ManagementFactory;
 import java.sql.Connection;
-import java.sql.SQLException;
 import java.util.Properties;
 
 import static org.hamcrest.CoreMatchers.instanceOf;
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertThat;
 
 @RunWith(ApplicationComposer.class)
 public class TomcatXADataSourceTest {
+    private static final MBeanServer server = 
ManagementFactory.getPlatformMBeanServer();
+
     @Resource(name = "xadb")
     private DataSource ds;
 
@@ -70,12 +80,21 @@ public class TomcatXADataSourceTest {
     }
 
     @Test
-    public void check() throws SQLException {
+    public void check() throws Exception {
         assertNotNull(ds);
         final Connection c = ds.getConnection();
         assertNotNull(c);
         assertThat(c.getMetaData().getConnection(), 
instanceOf(JDBCXAConnectionWrapper.class));
         c.close();
 
+        assertEquals(0, getActiveConnections("xadb"));
+    }
+
+
+    private int getActiveConnections(final String dataSourceName)
+            throws MalformedObjectNameException, MBeanException, 
AttributeNotFoundException, InstanceNotFoundException, ReflectionException {
+        final ObjectName objectName = new 
ObjectName("openejb.management:ObjectType=datasources,DataSource=" + 
dataSourceName);
+        final Object activeConnectionsAttribute = 
server.getAttribute(objectName, "Active");
+        return (int) (Integer) activeConnectionsAttribute;
     }
 }

Reply via email to