Author: rmannibucau
Date: Mon Jul 23 20:49:19 2012
New Revision: 1364794
URL: http://svn.apache.org/viewvc?rev=1364794&view=rev
Log:
fixing multiple usage of ds and multiple tx context for managed local ds
Modified:
openejb/branches/openejb-pool/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/managed/ManagedConnection.java
openejb/branches/openejb-pool/container/openejb-core/src/test/java/org/apache/openejb/resource/jdbc/ManagedDataSourceTest.java
openejb/branches/openejb-pool/container/openejb-jee/src/main/java/org/apache/openejb/jee/EjbJar.java
openejb/branches/openejb-pool/container/openejb-jee/src/main/java/org/apache/openejb/jee/SessionBean.java
Modified:
openejb/branches/openejb-pool/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/managed/ManagedConnection.java
URL:
http://svn.apache.org/viewvc/openejb/branches/openejb-pool/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/managed/ManagedConnection.java?rev=1364794&r1=1364793&r2=1364794&view=diff
==============================================================================
---
openejb/branches/openejb-pool/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/managed/ManagedConnection.java
(original)
+++
openejb/branches/openejb-pool/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/managed/ManagedConnection.java
Mon Jul 23 20:49:19 2012
@@ -37,6 +37,19 @@ public class ManagedConnection implement
@Override
public Object invoke(final Object proxy, final Method method, final
Object[] args) throws Throwable {
+ // first some Object method management
+ final String mtdName = method.getName();
+ if ("toString".equals(mtdName)) {
+ return "ManagedConnection{" + delegate.toString() + "}";
+ }
+ if ("hashCode".equals(mtdName)) {
+ return delegate.hashCode();
+ }
+ if ("equals".equals(mtdName)) {
+ return delegate.equals(args[0]);
+ }
+
+ // here the real logic starts
try {
final TransactionManager transactionManager =
OpenEJB.getTransactionManager();
final Transaction transaction =
transactionManager.getTransaction();
@@ -45,6 +58,7 @@ public class ManagedConnection implement
return method.invoke(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 != transaction) {
@@ -52,44 +66,46 @@ public class ManagedConnection implement
}
return invokeUnderTransaction(delegate, method, args);
} else {
- System.out.println("no tx close");
close(delegate);
}
}
+ // get the already bound connection to the current transaction
+ // or enlist this one in the tx
int status = transaction.getStatus();
if (isUnderTransaction(status)) {
final Connection connection =
CONNECTION_BY_TX.get(transaction);
- if (connection != null) { // shared one
- System.out.println("conn != null close");
- delegate.close(); // return to pool
- delegate = connection;
- } else {
- CONNECTION_BY_TX.put(transaction, delegate);
- currentTransaction = transaction;
- try {
- transaction.enlistResource(xaResource);
- } catch (RollbackException ignored) {
- // no-op
- } catch (SystemException e) {
- throw new SQLException("Unable to enlist connection
the transaction", e);
+ if (connection != delegate) {
+ if (connection != null) { // use already existing one
+ delegate.close(); // return to pool
+ delegate = connection;
+ } else {
+ CONNECTION_BY_TX.put(transaction, delegate);
+ currentTransaction = transaction;
+ try {
+ transaction.enlistResource(xaResource);
+ } catch (RollbackException ignored) {
+ // no-op
+ } catch (SystemException e) {
+ throw new SQLException("Unable to enlist
connection the transaction", e);
+ }
+
+ transaction.registerSynchronization(new
ClosingSynchronization(delegate));
+
+ delegate.setAutoCommit(false);
}
}
- transaction.registerSynchronization(new
ClosingSynchronization(delegate));
-
- delegate.setAutoCommit(false); // TODO: previous value?
return invokeUnderTransaction(delegate, method, args);
}
-
return method.invoke(delegate, args);
} catch (InvocationTargetException ite) {
throw ite.getTargetException();
}
}
- private static Object invokeUnderTransaction(final Connection delegate,
final Method method, final Object[] args) throws Exception,
IllegalAccessException {
+ private static Object invokeUnderTransaction(final Connection delegate,
final Method method, final Object[] args) throws Exception {
final String mtdName = method.getName();
if ("setAutoCommit".equals(mtdName)
|| "commit".equals(mtdName)
@@ -100,12 +116,17 @@ public class ManagedConnection implement
}
if ("close".equals(mtdName)) {
// will be done later
- // we need to differ it in case of rollback
- return null;
+ // we need to delay it in case of rollback
+ return noop();
}
return method.invoke(delegate, args);
}
+ // just to give a better semantiv to a trivial operation
+ private static Object noop() {
+ return null;
+ }
+
private static boolean isUnderTransaction(int status) {
return status == Status.STATUS_ACTIVE || status ==
Status.STATUS_MARKED_ROLLBACK;
}
Modified:
openejb/branches/openejb-pool/container/openejb-core/src/test/java/org/apache/openejb/resource/jdbc/ManagedDataSourceTest.java
URL:
http://svn.apache.org/viewvc/openejb/branches/openejb-pool/container/openejb-core/src/test/java/org/apache/openejb/resource/jdbc/ManagedDataSourceTest.java?rev=1364794&r1=1364793&r2=1364794&view=diff
==============================================================================
---
openejb/branches/openejb-pool/container/openejb-core/src/test/java/org/apache/openejb/resource/jdbc/ManagedDataSourceTest.java
(original)
+++
openejb/branches/openejb-pool/container/openejb-core/src/test/java/org/apache/openejb/resource/jdbc/ManagedDataSourceTest.java
Mon Jul 23 20:49:19 2012
@@ -1,6 +1,6 @@
package org.apache.openejb.resource.jdbc;
-import org.apache.openejb.jee.Empty;
+import org.apache.openejb.jee.EjbJar;
import org.apache.openejb.jee.SingletonBean;
import org.apache.openejb.junit.ApplicationComposer;
import org.apache.openejb.junit.Configuration;
@@ -14,8 +14,11 @@ 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.ejb.TransactionAttribute;
+import javax.ejb.TransactionAttributeType;
import javax.sql.DataSource;
import java.lang.reflect.Field;
import java.sql.Connection;
@@ -32,13 +35,13 @@ import static org.junit.Assert.assertTru
@RunWith(ApplicationComposer.class)
public class ManagedDataSourceTest {
- private static final String URL = "jdbc:hsqldb:mem:managed";
+ private static final String URL =
"jdbc:hsqldb:mem:managed;hsqldb.tx=MVCC"; // mvcc otherwise multiple
transaction tests will fail
private static final String USER = "sa";
private static final String PASSWORD = "";
private static final String TABLE = "PUBLIC.MANAGED_DATASOURCE_TEST";
@EJB
- private PersistManager persistManager;
+ private Persister persistManager;
@BeforeClass
public static void createTable() throws SQLException,
ClassNotFoundException {
@@ -67,37 +70,72 @@ public class ManagedDataSourceTest {
}
@Module
- public SingletonBean app() throws Exception {
- final SingletonBean bean = new SingletonBean(PersistManager.class);
- bean.setLocalBean(new Empty());
- return bean;
+ public EjbJar app() throws Exception {
+ return new EjbJar()
+ .enterpriseBean(new SingletonBean(Persister.class).localBean())
+ .enterpriseBean(new
SingletonBean(OtherPersister.class).localBean());
}
@LocalBean
@Singleton
- public static class PersistManager {
+ @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
+ public static class OtherPersister {
@Resource(name = "managed")
private DataSource ds;
+ @Resource
+ private EJBContext context;
+
public void save() throws SQLException {
- save(1);
+ ManagedDataSourceTest.save(ds, 10);
}
public void saveAndRollback() throws SQLException {
- save(2);
- throw new RuntimeException();
+ ManagedDataSourceTest.save(ds, 11);
+ context.setRollbackOnly();
}
+ }
- private void save(int id) throws SQLException {
- execute("INSERT INTO " + TABLE + "(ID) VALUES(" + id + ")");
+ @LocalBean
+ @Singleton
+ public static class Persister {
+ @Resource(name = "managed")
+ private DataSource ds;
+
+ @Resource
+ private EJBContext context;
+
+ @EJB
+ private OtherPersister other;
+
+ public void save() throws SQLException {
+ ManagedDataSourceTest.save(ds, 1);
}
- private void execute(final String sql) throws SQLException {
- final Connection connection = ds.getConnection();
- final Statement statement = connection.createStatement();
- statement.executeUpdate(sql);
- statement.close();
- connection.close();
+ public void saveAndRollback() throws SQLException {
+ ManagedDataSourceTest.save(ds, 2);
+ context.setRollbackOnly();
+ }
+
+ public void saveTwice() throws SQLException {
+ ManagedDataSourceTest.save(ds, 3);
+ ManagedDataSourceTest.save(ds, 4);
+ }
+
+ public void rollbackMultipleSave() throws SQLException {
+ ManagedDataSourceTest.save(ds, 5);
+ ManagedDataSourceTest.save(ds, 6);
+ context.setRollbackOnly();
+ }
+
+ public void saveInThisTxAndAnotherOne() throws SQLException {
+ ManagedDataSourceTest.save(ds, 7);
+ other.save();
+ }
+
+ public void saveInThisTxAndRollbackInAnotherOne() throws SQLException {
+ ManagedDataSourceTest.save(ds, 8);
+ other.saveAndRollback();
}
}
@@ -109,16 +147,40 @@ public class ManagedDataSourceTest {
@Test
public void rollback() throws SQLException {
- try {
- persistManager.saveAndRollback();
- } catch (Exception ignored) {
- System.out.println(ignored);
- }
+ persistManager.saveAndRollback();
assertFalse(exists(2));
}
+ @Test
+ public void commit2() throws SQLException {
+ persistManager.saveTwice();
+ assertTrue(exists(3));
+ assertTrue(exists(4));
+ }
+
+ @Test
+ public void rollback2() throws SQLException {
+ persistManager.rollbackMultipleSave();
+ assertFalse(exists(5));
+ assertFalse(exists(6));
+ }
+
+ @Test
+ public void saveDifferentTx() throws SQLException {
+ persistManager.saveInThisTxAndAnotherOne();
+ assertTrue(exists(7));
+ assertTrue(exists(10));
+ }
+
+ @Test
+ public void saveRollbackDifferentTx() throws SQLException {
+ persistManager.saveInThisTxAndRollbackInAnotherOne();
+ assertTrue(exists(8));
+ assertFalse(exists(12));
+ }
+
@After
- public void checkTxMapIsEmpty() throws Exception {
+ public void checkTxMapIsEmpty() throws Exception { // avoid memory leak
final Field map =
ManagedConnection.class.getDeclaredField("CONNECTION_BY_TX");
map.setAccessible(true);
final Map<?, ?> instance = (Map<?, ?>) map.get(null);
@@ -137,4 +199,16 @@ public class ManagedDataSourceTest {
connection.close();
}
}
+
+ private static void save(final DataSource ds, int id) throws SQLException {
+ execute(ds, "INSERT INTO " + TABLE + "(ID) VALUES(" + id + ")");
+ }
+
+ private static void execute(final DataSource ds, final String sql) throws
SQLException {
+ final Connection connection = ds.getConnection();
+ final Statement statement = connection.createStatement();
+ statement.executeUpdate(sql);
+ statement.close();
+ connection.close();
+ }
}
Modified:
openejb/branches/openejb-pool/container/openejb-jee/src/main/java/org/apache/openejb/jee/EjbJar.java
URL:
http://svn.apache.org/viewvc/openejb/branches/openejb-pool/container/openejb-jee/src/main/java/org/apache/openejb/jee/EjbJar.java?rev=1364794&r1=1364793&r2=1364794&view=diff
==============================================================================
---
openejb/branches/openejb-pool/container/openejb-jee/src/main/java/org/apache/openejb/jee/EjbJar.java
(original)
+++
openejb/branches/openejb-pool/container/openejb-jee/src/main/java/org/apache/openejb/jee/EjbJar.java
Mon Jul 23 20:49:19 2012
@@ -194,6 +194,11 @@ public class EjbJar implements NamedModu
return bean;
}
+ public <T extends EnterpriseBean> EjbJar enterpriseBean(T bean) {
+ addEnterpriseBean(bean);
+ return this;
+ }
+
public EnterpriseBean removeEnterpriseBean(EnterpriseBean bean){
return removeEnterpriseBean(bean.getEjbName());
}
Modified:
openejb/branches/openejb-pool/container/openejb-jee/src/main/java/org/apache/openejb/jee/SessionBean.java
URL:
http://svn.apache.org/viewvc/openejb/branches/openejb-pool/container/openejb-jee/src/main/java/org/apache/openejb/jee/SessionBean.java?rev=1364794&r1=1364793&r2=1364794&view=diff
==============================================================================
---
openejb/branches/openejb-pool/container/openejb-jee/src/main/java/org/apache/openejb/jee/SessionBean.java
(original)
+++
openejb/branches/openejb-pool/container/openejb-jee/src/main/java/org/apache/openejb/jee/SessionBean.java
Mon Jul 23 20:49:19 2012
@@ -913,4 +913,9 @@ public class SessionBean implements Remo
public Collection<String> getParents() {
return parents;
}
+
+ public EnterpriseBean localBean() {
+ setLocalBean(new Empty());
+ return this;
+ }
}