Skip to content
This repository has been archived by the owner on Jul 11, 2019. It is now read-only.

Redid JtaTransaction classes #26

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,36 +1,28 @@
package org.axonframework.cdi.transaction;

import java.lang.invoke.MethodHandles;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.transaction.HeuristicMixedException;
import javax.transaction.HeuristicRollbackException;
import javax.transaction.NotSupportedException;
import javax.transaction.RollbackException;
import javax.transaction.Status;
import javax.transaction.SystemException;
import javax.transaction.TransactionSynchronizationRegistry;
import javax.transaction.UserTransaction;
import org.axonframework.common.transaction.Transaction;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class JtaTransaction implements Transaction {
import javax.transaction.*;
import java.lang.invoke.MethodHandles;

private static final String USER_TRANSACTION_LOCATION = "java:comp/UserTransaction";
private static final String JBOSS_USER_TRANSACTION_LOCATION
= "java:jboss/UserTransaction";
private static final String TRANSACTION_SYNCHRONIZATION_REGISTRY_LOCATION
= "java:comp/TransactionSynchronizationRegistry";
/**
*
*/
public class JtaTransaction implements Transaction {

private static final Logger logger = LoggerFactory.getLogger(
MethodHandles.lookup().lookupClass());

private UserTransaction userTransaction = null;
private TransactionSynchronizationRegistry registry;
private final UserTransaction userTransaction;
private final TransactionSynchronizationRegistry registry;
private boolean owned = true;

public JtaTransaction() {
JtaTransaction(final UserTransaction userTransaction, final TransactionSynchronizationRegistry registry) {
this.userTransaction = userTransaction;
this.registry = registry;

detectContext();
attemptBegin();
}
Expand All @@ -45,30 +37,27 @@ public void rollback() {
attemptRollback();
}

/**
* Detect how we're going to do transactions and what the current transaction's status is.
*/
private void detectContext() {
userTransaction = getUserTransaction();

if (userTransaction != null) {
logger.debug("In a BMT compatible context, using UserTransaction.");

try {
if (userTransaction.getStatus() != Status.STATUS_NO_TRANSACTION) {
logger.debug("We cannot own the BMT transaction, the current transaction status is {}.",
logger.warn("We cannot own the BMT transaction, the current transaction status is {}.",
statusToString(userTransaction.getStatus()));
owned = false;
}
} catch (SystemException ex) {
logger.warn("Had trouble trying to get BMT transaction status.", ex);
owned = false;
}
} else if (registry != null) {
logger.debug("Most likely in a CMT compatible context, using TransactionSynchronizationRegistry.");
} else {
registry = getTransactionSynchronizationRegistry();

if (registry != null) {
logger.debug("Most likely in a CMT compatible context, using TransactionSynchronizationRegistry.");
} else {
logger.warn("No JTA APIs available in this context. No transation managment can be performed.");
}
logger.warn("No JTA APIs available in this context. No transation managment can be performed.");
}
}

Expand All @@ -81,18 +70,16 @@ private void attemptBegin() {
logger.debug("Beginning BMT transaction.");
userTransaction.begin();
} else {
logger.debug("Did not try to begin non-owned BMT transaction.");
logger.warn("Did not try to begin non-owned BMT transaction.");
}
} catch (SystemException | NotSupportedException ex) {
logger.warn("Had trouble trying to start BMT transaction.", ex);
}
} else if (registry != null) {
logger.error("Not allowed to begin CMT transaction, the current transaction status is {}.",
statusToString(registry.getTransactionStatus()));
} else {
if (registry != null) {
logger.debug("Not allowed to begin CMT transaction, the current transaction status is {}.",
statusToString(registry.getTransactionStatus()));
} else {
logger.warn("No JTA APIs available in this context. No begin done.");
}
logger.warn("No JTA APIs available in this context. No begin done.");
}
}

Expand All @@ -110,20 +97,18 @@ private void attemptCommit() {
statusToString(userTransaction.getStatus()));
}
} else {
logger.debug("Cannot commit non-owned BMT transaction.");
logger.error("Cannot commit non-owned BMT transaction.");
}
} catch (SystemException | RollbackException
| HeuristicMixedException | HeuristicRollbackException
| SecurityException | IllegalStateException ex) {
logger.warn("Had trouble trying to commit BMT transaction.", ex);
}
} else if (registry != null) {
logger.error("Not allowed to commit CMT transaction, the current transaction status is {}.",
statusToString(registry.getTransactionStatus()));
} else {
if (registry != null) {
logger.debug("Not allowed to commit CMT transaction, the current transaction status is {}.",
statusToString(registry.getTransactionStatus()));
} else {
logger.warn("No JTA APIs available in this context. No commit done.");
}
logger.warn("No JTA APIs available in this context. No commit done.");
}
}

Expand All @@ -147,50 +132,17 @@ private void attemptRollback() {
} catch (SystemException | SecurityException | IllegalStateException ex) {
logger.warn("Had trouble trying to roll back BMT transaction.", ex);
}
} else {
if (registry != null) {
if (registry.getTransactionStatus() == Status.STATUS_ACTIVE) {
logger.debug("Setting CMT transaction to roll back.");
registry.setRollbackOnly();
} else {
logger.warn("Cannot roll back CMT transaction, current transaction status is {}.",
statusToString(registry.getTransactionStatus()));
}
} else if (registry != null) {
if (registry.getTransactionStatus() == Status.STATUS_ACTIVE) {
logger.warn("Setting CMT transaction to roll back.");
registry.setRollbackOnly();
} else {
logger.warn("No JTA APIs available in this context. No rollback performed.");
}
}
}

private UserTransaction getUserTransaction() {
try {
logger.debug("Attempting to look up standard UserTransaction.");
return (UserTransaction) new InitialContext().lookup(
USER_TRANSACTION_LOCATION);
} catch (NamingException ex) {
logger.debug("Could not look up standard UserTransaction.", ex);

try {
logger.debug("Attempting to look up JBoss proprietary UserTransaction.");
return (UserTransaction) new InitialContext().lookup(
JBOSS_USER_TRANSACTION_LOCATION);
} catch (NamingException ex1) {
logger.debug("Could not look up JBoss proprietary UserTransaction.", ex1);
logger.warn("Cannot roll back CMT transaction, current transaction status is {}.",
statusToString(registry.getTransactionStatus()));
}
} else {
logger.warn("No JTA APIs available in this context. No rollback performed.");
}

return null;
}

private TransactionSynchronizationRegistry getTransactionSynchronizationRegistry() {
try {
return (TransactionSynchronizationRegistry) new InitialContext().lookup(
TRANSACTION_SYNCHRONIZATION_REGISTRY_LOCATION);
} catch (NamingException ex) {
logger.debug("Could not look up TransactionSynchronizationRegistry.", ex);
}

return null;
}

private String statusToString(int status) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,138 @@

import org.axonframework.common.transaction.Transaction;
import org.axonframework.common.transaction.TransactionManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.transaction.TransactionSynchronizationRegistry;
import javax.transaction.UserTransaction;
import java.lang.invoke.MethodHandles;


/**
*
*/
public class JtaTransactionManager implements TransactionManager {

private static final String USER_TRANSACTION_LOCATION = "java:comp/UserTransaction";
private static final String JBOSS_USER_TRANSACTION_LOCATION
= "java:jboss/UserTransaction";

private static final String TRANSACTION_SYNCHRONIZATION_REGISTRY_LOCATION
= "java:comp/TransactionSynchronizationRegistry";

private static final Logger logger = LoggerFactory.getLogger(
MethodHandles.lookup().lookupClass());

/**
* Attempt to obtain an object from the JNDI. If complain is set to true, failure results in an error being logged.
* If not, a debug message is generated instead with the Exception added. If complain is false and the lookup
* succeeds, then an info-level message is generated to tell of this. The object is returned if found, null otherwise.
*
* @param path The JNDI path.
* @param desc A description of what kind of object is requested.
* @param complain True if an error should be logged if the object is not found.
* @return The object requested, or null if not found.
*/
private static Object getFromJNDI(final String path, final String desc, boolean complain) {
Object result = null;
try {
logger.debug("Attempting to look up {}.", desc);

result = new InitialContext().lookup(path);

if (!complain) {
logger.info("{} will be used.", desc);
}
} catch (NamingException ex1) {
if (complain) {
logger.error("Failed to look up {}");
} else {
logger.debug("Could not look up {}.", ex1);
}
}
return result;
}

private static final class TransactionPath {
final String path;
final String description;

TransactionPath(String path, String description) {
this.path = path;
this.description = description;
}
}
private static final TransactionPath userTransactionPaths[] = {
new TransactionPath(USER_TRANSACTION_LOCATION, "Standard User Transactions"),
new TransactionPath(JBOSS_USER_TRANSACTION_LOCATION, "JBoss User Transactions")
};
private static boolean utLookupDone = false;
private static TransactionPath jndiPathUT = null;

/**
* Get the {@Link javax.transaction.UserTransaction} object if available. The first time we'll iterate through different options, after that
* we'll reuse this nowledge, or else complain if we found nothing.
* @return The UserTransaction object if available.
*/
private UserTransaction getUT() {
UserTransaction result = null;
if ((jndiPathTSR == null) && !utLookupDone) { // Only bother if we don't have CMT
for (TransactionPath tp: userTransactionPaths) {
result = (UserTransaction) getFromJNDI(tp.path, tp.description, false);

if (result != null) {
jndiPathUT = tp; // First to be found will henceforth be used.
break;
}
}
if (result == null) {
logger.warn("Could not find either standard, nor JBoss proprietary, UserTransaction. BMT Transactions cannot be used!.");
}
utLookupDone = true;
} else if (jndiPathTSR == null ) { // Only bother if we have no alternative
result = (UserTransaction) getFromJNDI(jndiPathUT.path, "User Transaction", true);
}
return result;
}

private static final TransactionPath transactionsynchronizationRegistryPaths[] = {
new TransactionPath(TRANSACTION_SYNCHRONIZATION_REGISTRY_LOCATION, "CMT Transaction Synchronization Registry")
};
private static boolean tsrLookupDone = false;
private static TransactionPath jndiPathTSR = null;

/**
* Get the {@Link javax.transaction.TransactionSynchronisationRegistry} object if available. The first time we'll iterate through different options, after that
* we'll reuse this nowledge, or else complain if we found nothing.
* @return The TransactionSynchronizationRegistry object if available.
*/
private TransactionSynchronizationRegistry getTSR() {
TransactionSynchronizationRegistry result = null;
if ((jndiPathUT == null) && !tsrLookupDone) { // Only bother if we don't have BMT
for (TransactionPath tp: transactionsynchronizationRegistryPaths) {
result = (TransactionSynchronizationRegistry) getFromJNDI(tp.path, tp.description, false);

if (result != null) {
jndiPathTSR = tp; // First to be found will henceforth be used.
break;
}
}
if (result == null) {
logger.error("Could not find a Transaction Synchronization Registry. CMT Transactions cannot be used.");
}

tsrLookupDone = true;
} else if (jndiPathUT == null) { // Only bother if we need CMT
result = (TransactionSynchronizationRegistry) getFromJNDI(jndiPathTSR.path, "Transaction Synchronization Registry", true);
}
return result;
}

@Override
public Transaction startTransaction() {
return new JtaTransaction();
return new JtaTransaction(getUT(), getTSR());
}
}