Skip to content

Commit

Permalink
[WFLY-10229] Remove dependency on Narayana internal classes to ensure…
Browse files Browse the repository at this point in the history
… correct synch order and execution
  • Loading branch information
dmlloyd committed May 7, 2018
1 parent 47f66f5 commit d99e930
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 64 deletions.
Expand Up @@ -40,7 +40,6 @@
import org.jboss.tm.TransactionManagerLocator; import org.jboss.tm.TransactionManagerLocator;
import org.jboss.tm.usertx.UserTransactionRegistry; import org.jboss.tm.usertx.UserTransactionRegistry;
import org.omg.CORBA.ORB; import org.omg.CORBA.ORB;
import org.wildfly.transaction.client.ContextTransactionSynchronizationRegistry;
import org.wildfly.transaction.client.LocalUserTransaction; import org.wildfly.transaction.client.LocalUserTransaction;


import java.lang.reflect.Field; import java.lang.reflect.Field;
Expand Down Expand Up @@ -103,7 +102,7 @@ public synchronized void start(final StartContext context) throws StartException
final LocalUserTransaction userTransaction = LocalUserTransaction.getInstance(); final LocalUserTransaction userTransaction = LocalUserTransaction.getInstance();
jtaEnvironmentBean.getValue().setUserTransaction(userTransaction); jtaEnvironmentBean.getValue().setUserTransaction(userTransaction);
service.setJbossXATerminator(xaTerminatorInjector.getValue()); service.setJbossXATerminator(xaTerminatorInjector.getValue());
service.setTransactionSynchronizationRegistry(new TransactionSynchronizationRegistryWrapper(ContextTransactionSynchronizationRegistry.getInstance())); service.setTransactionSynchronizationRegistry(new TransactionSynchronizationRegistryWrapper());


try { try {
service.create(); service.create();
Expand All @@ -121,7 +120,7 @@ public synchronized void start(final StartContext context) throws StartException
final LocalUserTransaction userTransaction = LocalUserTransaction.getInstance(); final LocalUserTransaction userTransaction = LocalUserTransaction.getInstance();
jtaEnvironmentBean.getValue().setUserTransaction(userTransaction); jtaEnvironmentBean.getValue().setUserTransaction(userTransaction);
service.setJbossXATerminator(xaTerminatorInjector.getValue()); service.setJbossXATerminator(xaTerminatorInjector.getValue());
service.setTransactionSynchronizationRegistry(new TransactionSynchronizationRegistryWrapper(ContextTransactionSynchronizationRegistry.getInstance())); service.setTransactionSynchronizationRegistry(new TransactionSynchronizationRegistryWrapper());
service.setPropagateFullContext(true); service.setPropagateFullContext(true);


// this is not great, but it's the only way presently to influence the behavior of com.arjuna.ats.internal.jbossatx.jts.InboundTransactionCurrentImple // this is not great, but it's the only way presently to influence the behavior of com.arjuna.ats.internal.jbossatx.jts.InboundTransactionCurrentImple
Expand Down
Expand Up @@ -22,16 +22,14 @@
package org.jboss.as.txn.service.internal.tsr; package org.jboss.as.txn.service.internal.tsr;


import java.util.ArrayList; import java.util.ArrayList;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.Map.Entry;


import javax.transaction.Synchronization; import javax.transaction.Synchronization;
import javax.transaction.SystemException; import javax.transaction.SystemException;
import javax.transaction.Transaction;


import org.jboss.as.txn.logging.TransactionLogger; import org.jboss.as.txn.logging.TransactionLogger;
import org.wildfly.transaction.client.ContextTransactionManager;
import org.wildfly.transaction.client.ContextTransactionSynchronizationRegistry;


/** /**
* This class was added to: * This class was added to:
Expand All @@ -48,15 +46,10 @@
* "Resources can be closed but no transactional work can be performed with them" * "Resources can be closed but no transactional work can be performed with them"
*/ */
public class JCAOrderedLastSynchronizationList implements Synchronization { public class JCAOrderedLastSynchronizationList implements Synchronization {
private final com.arjuna.ats.jta.transaction.Transaction tx;
private final Map<Transaction, JCAOrderedLastSynchronizationList> jcaOrderedLastSynchronizations;
private final List<Synchronization> preJcaSyncs = new ArrayList<Synchronization>(); private final List<Synchronization> preJcaSyncs = new ArrayList<Synchronization>();
private final List<Synchronization> jcaSyncs = new ArrayList<Synchronization>(); private final List<Synchronization> jcaSyncs = new ArrayList<Synchronization>();


public JCAOrderedLastSynchronizationList(com.arjuna.ats.jta.transaction.Transaction tx, public JCAOrderedLastSynchronizationList() {
Map<Transaction, JCAOrderedLastSynchronizationList> jcaOrderedLastSynchronizations) {
this.tx = tx;
this.jcaOrderedLastSynchronizations = jcaOrderedLastSynchronizations;
} }


/** /**
Expand All @@ -67,7 +60,7 @@ public JCAOrderedLastSynchronizationList(com.arjuna.ats.jta.transaction.Transact
* @throws SystemException In case the transaction status was not known * @throws SystemException In case the transaction status was not known
*/ */
public void registerInterposedSynchronization(Synchronization synchronization) throws IllegalStateException, SystemException { public void registerInterposedSynchronization(Synchronization synchronization) throws IllegalStateException, SystemException {
int status = tx.getStatus(); int status = ContextTransactionSynchronizationRegistry.getInstance().getTransactionStatus();
switch (status) { switch (status) {
case javax.transaction.Status.STATUS_ACTIVE: case javax.transaction.Status.STATUS_ACTIVE:
case javax.transaction.Status.STATUS_PREPARING: case javax.transaction.Status.STATUS_PREPARING:
Expand Down Expand Up @@ -148,7 +141,7 @@ public void afterCompletion(int status) {
} catch (Exception e) { } catch (Exception e) {
// Trap these exceptions so the rest of the synchronizations get the chance to complete // Trap these exceptions so the rest of the synchronizations get the chance to complete
// https://github.com/jbosstm/narayana/blob/5.0.4.Final/ArjunaJTA/jta/classes/com/arjuna/ats/internal/jta/resources/arjunacore/SynchronizationImple.java#L102 // https://github.com/jbosstm/narayana/blob/5.0.4.Final/ArjunaJTA/jta/classes/com/arjuna/ats/internal/jta/resources/arjunacore/SynchronizationImple.java#L102
TransactionLogger.ROOT_LOGGER.preJcaSyncAfterCompletionFailed(preJcaSync, tx, e); TransactionLogger.ROOT_LOGGER.preJcaSyncAfterCompletionFailed(preJcaSync, ContextTransactionManager.getInstance().getTransaction(), e);
} }
} }
for (int i = jcaSyncs.size() - 1; i>= 0; --i) { for (int i = jcaSyncs.size() - 1; i>= 0; --i) {
Expand All @@ -164,29 +157,7 @@ public void afterCompletion(int status) {
} catch (Exception e) { } catch (Exception e) {
// Trap these exceptions so the rest of the synchronizations get the chance to complete // Trap these exceptions so the rest of the synchronizations get the chance to complete
// https://github.com/jbosstm/narayana/blob/5.0.4.Final/ArjunaJTA/jta/classes/com/arjuna/ats/internal/jta/resources/arjunacore/SynchronizationImple.java#L102 // https://github.com/jbosstm/narayana/blob/5.0.4.Final/ArjunaJTA/jta/classes/com/arjuna/ats/internal/jta/resources/arjunacore/SynchronizationImple.java#L102
TransactionLogger.ROOT_LOGGER.jcaSyncAfterCompletionFailed(jcaSync, tx, e); TransactionLogger.ROOT_LOGGER.jcaSyncAfterCompletionFailed(jcaSync, ContextTransactionManager.getInstance().getTransaction(), e);
}
}

if (jcaOrderedLastSynchronizations.remove(tx) == null) {
// The identifier wasn't stable - scan for it - this can happen in JTS propagation when the UID needs retrieving
// from the parent and the parent has been deactivated
Transaction altKey = null;
Iterator<Entry<Transaction, JCAOrderedLastSynchronizationList>> iterator = jcaOrderedLastSynchronizations.entrySet().iterator();
while (altKey == null && iterator.hasNext()) {
Map.Entry<Transaction, JCAOrderedLastSynchronizationList> next = iterator.next();
if (next.getValue().equals(this)) {
altKey = next.getKey();
iterator.remove();
if (TransactionLogger.ROOT_LOGGER.isTraceEnabled()) {
TransactionLogger.ROOT_LOGGER.tracef("Removed: %s [%s]", System.identityHashCode(tx), tx.toString());
}
break;
}
}

if (altKey == null) {
TransactionLogger.ROOT_LOGGER.transactionNotFound(tx);
} }
} }
} }
Expand Down
Expand Up @@ -21,14 +21,14 @@
*/ */
package org.jboss.as.txn.service.internal.tsr; package org.jboss.as.txn.service.internal.tsr;


import java.util.concurrent.ConcurrentHashMap;

import javax.transaction.Synchronization; import javax.transaction.Synchronization;
import javax.transaction.SystemException; import javax.transaction.SystemException;
import javax.transaction.Transaction;
import javax.transaction.TransactionManager;
import javax.transaction.TransactionSynchronizationRegistry; import javax.transaction.TransactionSynchronizationRegistry;


import org.wildfly.transaction.client.AbstractTransaction;
import org.wildfly.transaction.client.ContextTransactionManager;
import org.wildfly.transaction.client.ContextTransactionSynchronizationRegistry;

/** /**
* Most of this implementation delegates down to the underlying transactions implementation to provide the services of the * Most of this implementation delegates down to the underlying transactions implementation to provide the services of the
* TransactionSynchronizationRegistry. The one area it modifies is the registration of the interposed Synchronizations. The * TransactionSynchronizationRegistry. The one area it modifies is the registration of the interposed Synchronizations. The
Expand All @@ -51,28 +51,26 @@
*/ */
public class TransactionSynchronizationRegistryWrapper implements TransactionSynchronizationRegistry { public class TransactionSynchronizationRegistryWrapper implements TransactionSynchronizationRegistry {


private TransactionSynchronizationRegistry delegate; private final Object key = new Object();
private TransactionManager transactionManager;
private ConcurrentHashMap<Transaction, JCAOrderedLastSynchronizationList> interposedSyncs = new ConcurrentHashMap<Transaction, JCAOrderedLastSynchronizationList>();


public TransactionSynchronizationRegistryWrapper(TransactionSynchronizationRegistry delegate) { public TransactionSynchronizationRegistryWrapper() {
this.delegate = delegate;
transactionManager = com.arjuna.ats.jta.TransactionManager
.transactionManager();
} }


@Override @Override
public void registerInterposedSynchronization(Synchronization sync) public void registerInterposedSynchronization(Synchronization sync)
throws IllegalStateException { throws IllegalStateException {
try { try {
Transaction tx = transactionManager.getTransaction(); AbstractTransaction tx = ContextTransactionManager.getInstance().getTransaction();
JCAOrderedLastSynchronizationList jcaOrderedLastSynchronization = interposedSyncs.get(tx); JCAOrderedLastSynchronizationList jcaOrderedLastSynchronization = (JCAOrderedLastSynchronizationList) tx.getResource(key);
if (jcaOrderedLastSynchronization == null) { if (jcaOrderedLastSynchronization == null) {
JCAOrderedLastSynchronizationList toPut = new JCAOrderedLastSynchronizationList((com.arjuna.ats.jta.transaction.Transaction) tx, interposedSyncs); final ContextTransactionSynchronizationRegistry tsr = ContextTransactionSynchronizationRegistry.getInstance();
jcaOrderedLastSynchronization = interposedSyncs.putIfAbsent(tx, toPut); synchronized (key) {
if (jcaOrderedLastSynchronization == null) { jcaOrderedLastSynchronization = (JCAOrderedLastSynchronizationList) tx.getResource(key);
jcaOrderedLastSynchronization = toPut; if (jcaOrderedLastSynchronization == null) {
delegate.registerInterposedSynchronization(jcaOrderedLastSynchronization); jcaOrderedLastSynchronization = new JCAOrderedLastSynchronizationList();
tx.putResource(key, jcaOrderedLastSynchronization);
tsr.registerInterposedSynchronization(jcaOrderedLastSynchronization);
}
} }
} }
jcaOrderedLastSynchronization.registerInterposedSynchronization(sync); jcaOrderedLastSynchronization.registerInterposedSynchronization(sync);
Expand All @@ -83,33 +81,33 @@ public void registerInterposedSynchronization(Synchronization sync)


@Override @Override
public Object getTransactionKey() { public Object getTransactionKey() {
return delegate.getTransactionKey(); return ContextTransactionSynchronizationRegistry.getInstance().getTransactionKey();
} }


@Override @Override
public int getTransactionStatus() { public int getTransactionStatus() {
return delegate.getTransactionStatus(); return ContextTransactionSynchronizationRegistry.getInstance().getTransactionStatus();
} }


@Override @Override
public boolean getRollbackOnly() throws IllegalStateException { public boolean getRollbackOnly() throws IllegalStateException {
return delegate.getRollbackOnly(); return ContextTransactionSynchronizationRegistry.getInstance().getRollbackOnly();
} }


@Override @Override
public void setRollbackOnly() throws IllegalStateException { public void setRollbackOnly() throws IllegalStateException {
delegate.setRollbackOnly(); ContextTransactionSynchronizationRegistry.getInstance().setRollbackOnly();
} }


@Override @Override
public Object getResource(Object key) throws IllegalStateException { public Object getResource(Object key) throws IllegalStateException {
return delegate.getResource(key); return ContextTransactionSynchronizationRegistry.getInstance().getResource(key);
} }


@Override @Override
public void putResource(Object key, Object value) public void putResource(Object key, Object value)
throws IllegalStateException { throws IllegalStateException {
delegate.putResource(key, value); ContextTransactionSynchronizationRegistry.getInstance().putResource(key, value);
} }


} }
14 changes: 12 additions & 2 deletions transactions/src/test/java/org/jboss/as/txn/TestWildFlyTSR.java
Expand Up @@ -11,10 +11,14 @@
import javax.transaction.TransactionManager; import javax.transaction.TransactionManager;
import javax.transaction.TransactionSynchronizationRegistry; import javax.transaction.TransactionSynchronizationRegistry;


import com.arjuna.ats.internal.jta.transaction.arjunacore.jca.XATerminatorImple;
import org.jboss.as.txn.service.internal.tsr.TransactionSynchronizationRegistryWrapper; import org.jboss.as.txn.service.internal.tsr.TransactionSynchronizationRegistryWrapper;
import org.junit.Test; import org.junit.Test;


import com.arjuna.ats.jta.common.jtaPropertyManager; import com.arjuna.ats.jta.common.jtaPropertyManager;
import org.wildfly.transaction.client.ContextTransactionManager;
import org.wildfly.transaction.client.LocalTransactionContext;
import org.wildfly.transaction.client.provider.jboss.JBossLocalTransactionProvider;


public class TestWildFlyTSR { public class TestWildFlyTSR {
boolean innerSyncCalled = false; boolean innerSyncCalled = false;
Expand All @@ -23,8 +27,14 @@ public class TestWildFlyTSR {
public void test() throws NotSupportedException, SystemException, SecurityException, IllegalStateException, RollbackException, HeuristicMixedException, HeuristicRollbackException { public void test() throws NotSupportedException, SystemException, SecurityException, IllegalStateException, RollbackException, HeuristicMixedException, HeuristicRollbackException {
jtaPropertyManager.getJTAEnvironmentBean().setTransactionManagerClassName("com.arjuna.ats.internal.jta.transaction.arjunacore.TransactionManagerImple"); jtaPropertyManager.getJTAEnvironmentBean().setTransactionManagerClassName("com.arjuna.ats.internal.jta.transaction.arjunacore.TransactionManagerImple");
final TransactionSynchronizationRegistry tsr = final TransactionSynchronizationRegistry tsr =
new TransactionSynchronizationRegistryWrapper(new com.arjuna.ats.internal.jta.transaction.arjunacore.TransactionSynchronizationRegistryImple()); new TransactionSynchronizationRegistryWrapper();
TransactionManager transactionManager = com.arjuna.ats.jta.TransactionManager.transactionManager(); final JBossLocalTransactionProvider.Builder builder = JBossLocalTransactionProvider.builder();
builder.setTransactionManager(com.arjuna.ats.jta.TransactionManager.transactionManager());
builder.setExtendedJBossXATerminator(new XATerminatorImple());
LocalTransactionContext.getContextManager().setGlobalDefault(new LocalTransactionContext(
builder.build()
));
TransactionManager transactionManager = ContextTransactionManager.getInstance();
transactionManager.begin(); transactionManager.begin();
tsr.registerInterposedSynchronization(new Synchronization() { tsr.registerInterposedSynchronization(new Synchronization() {
@Override @Override
Expand Down

0 comments on commit d99e930

Please sign in to comment.