From 5ccb8b034a69b3730bbbdc1a7fad6136eb48c047 Mon Sep 17 00:00:00 2001 From: Bert Laverman Date: Sun, 18 Nov 2018 10:05:43 +0100 Subject: [PATCH] Redid JtaTransaction classes Lookup to detect runtime is now only done once, so no longer complaining about failed lookups that are not relevant. --- .../cdi/transaction/JtaTransaction.java | 122 +++++------------ .../transaction/JtaTransactionManager.java | 129 +++++++++++++++++- 2 files changed, 165 insertions(+), 86 deletions(-) diff --git a/extension/src/main/java/org/axonframework/cdi/transaction/JtaTransaction.java b/extension/src/main/java/org/axonframework/cdi/transaction/JtaTransaction.java index c689b86..ca8029a 100644 --- a/extension/src/main/java/org/axonframework/cdi/transaction/JtaTransaction.java +++ b/extension/src/main/java/org/axonframework/cdi/transaction/JtaTransaction.java @@ -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(); } @@ -45,15 +37,16 @@ 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; } @@ -61,14 +54,10 @@ private void detectContext() { 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."); } } @@ -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."); } } @@ -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."); } } @@ -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) { diff --git a/extension/src/main/java/org/axonframework/cdi/transaction/JtaTransactionManager.java b/extension/src/main/java/org/axonframework/cdi/transaction/JtaTransactionManager.java index 90b3f10..289d1ec 100644 --- a/extension/src/main/java/org/axonframework/cdi/transaction/JtaTransactionManager.java +++ b/extension/src/main/java/org/axonframework/cdi/transaction/JtaTransactionManager.java @@ -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()); } }