Author: rmannibucau
Date: Mon Jul 23 14:01:37 2012
New Revision: 1364638
URL: http://svn.apache.org/viewvc?rev=1364638&view=rev
Log:
clean a bit jta connection before working in a branch on it
Modified:
openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/managed/ManagedConnection.java
openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/managed/ManagedDataSource.java
openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/managed/local/LocalXAResource.java
openejb/trunk/openejb/container/openejb-core/src/test/java/org/apache/openejb/resource/jdbc/ManagedDataSourceTest.java
Modified:
openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/managed/ManagedConnection.java
URL:
http://svn.apache.org/viewvc/openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/managed/ManagedConnection.java?rev=1364638&r1=1364637&r2=1364638&view=diff
==============================================================================
---
openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/managed/ManagedConnection.java
(original)
+++
openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/managed/ManagedConnection.java
Mon Jul 23 14:01:37 2012
@@ -3,20 +3,28 @@ package org.apache.openejb.resource.jdbc
import org.apache.openejb.OpenEJB;
import org.apache.openejb.resource.jdbc.managed.local.LocalXAResource;
+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.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 {
- protected final Connection delegate;
- protected final XAResource xaResource;
- private boolean previousAutoCommit;
+ private static final Map<Transaction, Connection> CONNECTION_BY_TX = new
ConcurrentHashMap<Transaction, Connection>();
+
+ protected Connection delegate;
+ protected XAResource xaResource;
+
+ private Transaction currentTransaction;
protected ManagedConnection(final Connection connection, final XAResource
resource) {
delegate = connection;
@@ -29,37 +37,91 @@ public class ManagedConnection implement
@Override
public Object invoke(final Object proxy, final Method method, final
Object[] args) throws Throwable {
- final TransactionManager transactionManager =
OpenEJB.getTransactionManager();
- final Transaction transaction = transactionManager.getTransaction();
- if (transaction == null) { // shouldn't be possible
- return method.invoke(delegate, args);
- }
+ try {
+ final TransactionManager transactionManager =
OpenEJB.getTransactionManager();
+ final Transaction transaction =
transactionManager.getTransaction();
+
+ if (transaction == null) { // shouldn't be possible
+ return method.invoke(delegate, args);
+ }
+
+ if (currentTransaction != null) {
+ if (isUnderTransaction(currentTransaction.getStatus())) {
+ if (currentTransaction != transaction) {
+ throw new SQLException("Connection can not be used
while enlisted in another transaction");
+ }
+ return invokeUnderTransaction(delegate, method, args);
+ } else {
+ System.out.println("no tx close");
+ close(delegate);
+ }
+ }
+
+ 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);
+ }
+ }
+ transaction.registerSynchronization(new
ClosingSynchronization(delegate));
+
+ delegate.setAutoCommit(false); // TODO: previous value?
+
+ return invokeUnderTransaction(delegate, method, args);
+ }
+
- int status = transaction.getStatus();
- if (status != Status.STATUS_ACTIVE && status !=
Status.STATUS_MARKED_ROLLBACK) {
return method.invoke(delegate, args);
+ } catch (InvocationTargetException ite) {
+ throw ite.getTargetException();
}
+ }
- // TODO: manage it properly
- previousAutoCommit = delegate.getAutoCommit();
- delegate.setAutoCommit(false);
-
+ private static Object invokeUnderTransaction(final Connection delegate,
final Method method, final Object[] args) throws Exception,
IllegalAccessException {
final String mtdName = method.getName();
- if ("setAutoCommit".equals(mtdName)) {
- throw new SQLException("TODO");
- } else if ("commit".equals(mtdName)) {
- throw new SQLException("TODO");
- } else if ("rollback".equals(mtdName)) {
- throw new SQLException("TODO");
- } else if ("setReadOnly".equals(mtdName)) {
- throw new SQLException("TODO");
+ if ("setAutoCommit".equals(mtdName)
+ || "commit".equals(mtdName)
+ || "rollback".equals(mtdName)
+ || "setSavepoint".equals(mtdName)
+ || "setReadOnly".equals(mtdName)) {
+ throw forbiddenCall(mtdName);
+ }
+ if ("close".equals(mtdName)) {
+ // will be done later
+ // we need to differ it in case of rollback
+ return null;
}
+ return method.invoke(delegate, args);
+ }
- // TODO: manage share connection
+ private static boolean isUnderTransaction(int status) {
+ return status == Status.STATUS_ACTIVE || status ==
Status.STATUS_MARKED_ROLLBACK;
+ }
- transaction.registerSynchronization(new
ClosingSynchronization(delegate));
+ private static SQLException forbiddenCall(final String mtdName) {
+ return new SQLException("can't call " + mtdName + " when the
connection is JtaManaged");
+ }
- return method.invoke(delegate, args);
+ private static void close(final Connection connection) {
+ try {
+ if (!connection.isClosed()) {
+ connection.close();
+ }
+ } catch (SQLException e) {
+ // no-op
+ }
}
private static class ClosingSynchronization implements Synchronization {
@@ -76,9 +138,11 @@ public class ManagedConnection implement
@Override
public void afterCompletion(int status) {
+ close(connection);
try {
- connection.close();
- } catch (SQLException e) {
+ final Transaction tx =
OpenEJB.getTransactionManager().getTransaction();
+ CONNECTION_BY_TX.remove(tx);
+ } catch (SystemException ignored) {
// no-op
}
}
Modified:
openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/managed/ManagedDataSource.java
URL:
http://svn.apache.org/viewvc/openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/managed/ManagedDataSource.java?rev=1364638&r1=1364637&r2=1364638&view=diff
==============================================================================
---
openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/managed/ManagedDataSource.java
(original)
+++
openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/managed/ManagedDataSource.java
Mon Jul 23 14:01:37 2012
@@ -28,26 +28,7 @@ public class ManagedDataSource implement
@Override
public Connection getConnection() throws SQLException {
- final Connection connection = delegate.getConnection();
- final XAResource xaResource = new LocalXAResource(connection);
- final TransactionManager transactionManager =
OpenEJB.getTransactionManager();
- final Transaction transaction;
- try {
- transaction = transactionManager.getTransaction();
- } catch (SystemException e) {
- return managed(connection);
- }
- if (transaction != null) {
- try {
- transaction.enlistResource(xaResource);
- } catch (RollbackException e) {
- e.printStackTrace(); //To change body of catch statement use
File | Settings | File Templates.
- } catch (SystemException e) {
- e.printStackTrace(); //To change body of catch statement use
File | Settings | File Templates.
- }
- }
-
- return managed(connection);
+ return managed(delegate.getConnection());
}
@Override
Modified:
openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/managed/local/LocalXAResource.java
URL:
http://svn.apache.org/viewvc/openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/managed/local/LocalXAResource.java?rev=1364638&r1=1364637&r2=1364638&view=diff
==============================================================================
---
openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/managed/local/LocalXAResource.java
(original)
+++
openejb/trunk/openejb/container/openejb-core/src/main/java/org/apache/openejb/resource/jdbc/managed/local/LocalXAResource.java
Mon Jul 23 14:01:37 2012
@@ -104,8 +104,12 @@ public class LocalXAResource implements
@Override
public synchronized void rollback(final Xid xid) throws XAException {
- if (xid == null) throw new NullPointerException("xid is null");
- if (!this.currentXid.equals(xid)) throw new XAException("Invalid Xid:
expected " + this.currentXid + ", but was " + xid);
+ if (xid == null) {
+ throw new NullPointerException("xid is null");
+ }
+ if (!this.currentXid.equals(xid)) {
+ throw new XAException("Invalid Xid: expected " + this.currentXid +
", but was " + xid);
+ }
try {
connection.rollback();
Modified:
openejb/trunk/openejb/container/openejb-core/src/test/java/org/apache/openejb/resource/jdbc/ManagedDataSourceTest.java
URL:
http://svn.apache.org/viewvc/openejb/trunk/openejb/container/openejb-core/src/test/java/org/apache/openejb/resource/jdbc/ManagedDataSourceTest.java?rev=1364638&r1=1364637&r2=1364638&view=diff
==============================================================================
---
openejb/trunk/openejb/container/openejb-core/src/test/java/org/apache/openejb/resource/jdbc/ManagedDataSourceTest.java
(original)
+++
openejb/trunk/openejb/container/openejb-core/src/test/java/org/apache/openejb/resource/jdbc/ManagedDataSourceTest.java
Mon Jul 23 14:01:37 2012
@@ -5,9 +5,10 @@ import org.apache.openejb.jee.SingletonB
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.ManagedConnection;
import org.apache.openejb.resource.jdbc.pool.DbcpDataSourceCreator;
+import org.junit.After;
import org.junit.BeforeClass;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -16,17 +17,19 @@ import javax.ejb.EJB;
import javax.ejb.LocalBean;
import javax.ejb.Singleton;
import javax.sql.DataSource;
+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;
-@Ignore("to implement")
@RunWith(ApplicationComposer.class)
public class ManagedDataSourceTest {
private static final String URL = "jdbc:hsqldb:mem:managed";
@@ -63,7 +66,8 @@ public class ManagedDataSourceTest {
return p;
}
- @Module public SingletonBean app() throws Exception {
+ @Module
+ public SingletonBean app() throws Exception {
final SingletonBean bean = new SingletonBean(PersistManager.class);
bean.setLocalBean(new Empty());
return bean;
@@ -113,6 +117,14 @@ public class ManagedDataSourceTest {
assertFalse(exists(2));
}
+ @After
+ public void checkTxMapIsEmpty() throws Exception {
+ final Field map =
ManagedConnection.class.getDeclaredField("CONNECTION_BY_TX");
+ map.setAccessible(true);
+ final Map<?, ?> instance = (Map<?, ?>) map.get(null);
+ assertEquals(0, instance.size());
+ }
+
private static boolean exists(int id) throws SQLException {
final Connection connection = DriverManager.getConnection(URL, USER,
PASSWORD);
final Statement statement = connection.createStatement();