diff --git a/org.springframework.transaction/src/main/java/org/springframework/transaction/jta/JtaTransactionManager.java b/org.springframework.transaction/src/main/java/org/springframework/transaction/jta/JtaTransactionManager.java index 11eb94425521fb97ced0db6ac8ce8e566dcd6142..e08d8a5503b522bb2a3561716fd2fd81ee84ed45 100644 --- a/org.springframework.transaction/src/main/java/org/springframework/transaction/jta/JtaTransactionManager.java +++ b/org.springframework.transaction/src/main/java/org/springframework/transaction/jta/JtaTransactionManager.java @@ -50,7 +50,6 @@ import org.springframework.transaction.support.AbstractPlatformTransactionManage import org.springframework.transaction.support.DefaultTransactionStatus; import org.springframework.transaction.support.TransactionSynchronization; import org.springframework.util.Assert; -import org.springframework.util.ClassUtils; import org.springframework.util.StringUtils; /** @@ -66,61 +65,37 @@ import org.springframework.util.StringUtils; * and for accessing a single resource with Hibernate (including transactional cache), * HibernateTransactionManager is appropriate, for example. * - *

Transaction synchronization is active by default, to allow data access support - * classes to register resources that are opened within the transaction for closing at - * transaction completion time. Spring's support classes for JDBC, Hibernate, JDO etc - * all perform such registration, allowing for reuse of the same Hibernate Session etc - * within the transaction. Standard JTA does not even guarantee that for Connections - * from a transactional JDBC DataSource: Spring's synchronization solves those issues. - * *

For typical JTA transactions (REQUIRED, SUPPORTS, MANDATORY, NEVER), a plain - * JtaTransactionManager definition is all you need, completely portable across all - * J2EE servers. This corresponds to the functionality of the JTA UserTransaction, - * for which J2EE specifies a standard JNDI name ("java:comp/UserTransaction"). - * There is no need to configure a server-specific TransactionManager lookup for this - * kind of JTA usage. - * - *

Note: Advanced JTA usage below. Dealing with these mechanisms is not - * necessary for typical usage scenarios. - * - *

Transaction suspension (REQUIRES_NEW, NOT_SUPPORTED) is just available with - * a JTA TransactionManager being registered, via the "transactionManagerName" or - * "transactionManager" property. The location of this well-defined JTA object is - * not specified by J2EE; it is specific to each J2EE server, often kept - * in JNDI like the JTA UserTransaction. Some well-known JNDI locations are: - *

+ * JtaTransactionManager definition is all you need, portable across all J2EE servers. + * This corresponds to the functionality of the JTA UserTransaction, for which J2EE + * specifies a standard JNDI name ("java:comp/UserTransaction"). There is no need to + * configure a server-specific TransactionManager lookup for this kind of JTA usage. * - *

All of these cases are autodetected by JtaTransactionManager, provided that the - * "autodetectTransactionManager" flag is set to "true" (which it is by default). + *

Transaction suspension (REQUIRES_NEW, NOT_SUPPORTED) is just available with a + * JTA TransactionManager being registered. Common TransactionManager locations are + * autodetected by JtaTransactionManager, provided that the "autodetectTransactionManager" + * flag is set to "true" (which it is by default). * - *

Note: Support for the JTA TransactionManager interface is not required by J2EE. + *

Note: Support for the JTA TransactionManager interface is not required by J2EE. * Almost all J2EE servers expose it, but do so as extension to J2EE. There might be some - * issues with compatibility, despite the TransactionManager interface being part of JTA. + * issues with compatibility, despite the TransactionManager interface being part of JTA. * As a consequence, Spring provides various vendor-specific PlatformTransactionManagers, * which are recommended to be used if appropriate: {@link WebLogicJtaTransactionManager}, * {@link WebSphereUowTransactionManager} and {@link OC4JJtaTransactionManager}. * For all other J2EE servers, the standard JtaTransactionManager is sufficient. * - *

Consider using Spring 2.5's tx:jta-transaction-manager configuration - * element for automatically picking the appropriate JTA platform transaction manager - * (automatically detecting WebLogic, WebSphere and OC4J). - * - *

This pure JtaTransactionManager supports timeouts but not per-transaction - * isolation levels. Custom subclasses may override {@link #doJtaBegin} for + *

This pure JtaTransactionManager class supports timeouts but not per-transaction + * isolation levels. Custom subclasses may override the {@link #doJtaBegin} method for * specific JTA extensions in order to provide this functionality; Spring includes * corresponding {@link WebLogicJtaTransactionManager} and {@link OC4JJtaTransactionManager} * classes, for BEA's WebLogic Server and Oracle's OC4J, respectively. Such adapters * for specific J2EE transaction coordinators may also expose transaction names for * monitoring; with standard JTA, transaction names will simply be ignored. * + *

Consider using Spring's tx:jta-transaction-manager configuration + * element for automatically picking the appropriate JTA platform transaction manager + * (automatically detecting WebLogic, WebSphere and OC4J). + * *

JTA 1.1 adds the TransactionSynchronizationRegistry facility, as public Java EE 5 * API in addition to the standard JTA UserTransaction handle. As of Spring 2.5, this * JtaTransactionManager autodetects the TransactionSynchronizationRegistry and uses @@ -129,8 +104,7 @@ import org.springframework.util.StringUtils; * is available (or the JTA 1.1 API isn't available), then such synchronizations * will be registered via the (non-J2EE) JTA TransactionManager handle. * - *

This class is serializable. However, active synchronizations do not survive - * serialization. + *

This class is serializable. However, active synchronizations do not survive serialization. * * @author Juergen Hoeller * @since 24.03.2003 @@ -176,6 +150,18 @@ public class JtaTransactionManager extends AbstractPlatformTransactionManager private static final String TRANSACTION_SYNCHRONIZATION_REGISTRY_CLASS_NAME = "javax.transaction.TransactionSynchronizationRegistry"; + private static Class transactionSynchronizationRegistryClass; + + static { + ClassLoader cl = JtaTransactionManager.class.getClassLoader(); + try { + transactionSynchronizationRegistryClass = cl.loadClass(TRANSACTION_SYNCHRONIZATION_REGISTRY_CLASS_NAME); + } + catch (ClassNotFoundException ex) { + // JTA 1.1 API not available... simply proceed the JTA 1.0 way. + } + } + private transient JndiTemplate jndiTemplate = new JndiTemplate(); @@ -495,8 +481,7 @@ public class JtaTransactionManager extends AbstractPlatformTransactionManager } } else { - logger.warn("No JTA TransactionManager found: " + - "transaction suspension and synchronization with existing JTA transactions not available"); + logger.warn("No JTA TransactionManager found: transaction suspension not available"); } } @@ -599,19 +584,16 @@ public class JtaTransactionManager extends AbstractPlatformTransactionManager * @see #setJndiTemplate * @see #setTransactionSynchronizationRegistryName */ - protected Object lookupTransactionSynchronizationRegistry(String registryName) - throws TransactionSystemException { + protected Object lookupTransactionSynchronizationRegistry(String registryName) throws TransactionSystemException { + if (transactionSynchronizationRegistryClass == null) { + throw new TransactionSystemException( + "JTA 1.1 [" + TRANSACTION_SYNCHRONIZATION_REGISTRY_CLASS_NAME + "] API not available"); + } try { if (logger.isDebugEnabled()) { logger.debug("Retrieving JTA TransactionSynchronizationRegistry from JNDI location [" + registryName + "]"); } - Class registryClass = ClassUtils.forName(TRANSACTION_SYNCHRONIZATION_REGISTRY_CLASS_NAME, - JtaTransactionManager.class.getClassLoader()); - return getJndiTemplate().lookup(registryName, registryClass); - } - catch (ClassNotFoundException ex) { - throw new TransactionSystemException( - "JTA 1.1 [" + TRANSACTION_SYNCHRONIZATION_REGISTRY_CLASS_NAME + "] not available"); + return getJndiTemplate().lookup(registryName, transactionSynchronizationRegistryClass); } catch (NamingException ex) { throw new TransactionSystemException( @@ -731,46 +713,43 @@ public class JtaTransactionManager extends AbstractPlatformTransactionManager protected Object findTransactionSynchronizationRegistry(UserTransaction ut, TransactionManager tm) throws TransactionSystemException { - try { - Class registryClass = ClassUtils.forName(TRANSACTION_SYNCHRONIZATION_REGISTRY_CLASS_NAME, - JtaTransactionManager.class.getClassLoader()); - - // If we came here, we might be on Java EE 5, since the JTA 1.1 API is present. - if (this.userTransactionObtainedFromJndi) { - // UserTransaction has already been obtained from JNDI, so the - // TransactionSynchronizationRegistry probably sits there as well. - String jndiName = DEFAULT_TRANSACTION_SYNCHRONIZATION_REGISTRY_NAME; - try { - Object tsr = getJndiTemplate().lookup(jndiName, registryClass); - if (logger.isDebugEnabled()) { - logger.debug("JTA TransactionSynchronizationRegistry found at default JNDI location [" + jndiName + "]"); - } - return tsr; - } - catch (NamingException ex) { - if (logger.isDebugEnabled()) { - logger.debug( - "No JTA TransactionSynchronizationRegistry found at default JNDI location [" + jndiName + "]", ex); - } - } + if (transactionSynchronizationRegistryClass == null) { + // JTA 1.1 API not present - skip. + if (logger.isDebugEnabled()) { + logger.debug("JTA 1.1 [" + TRANSACTION_SYNCHRONIZATION_REGISTRY_CLASS_NAME + "] API not available"); } + return null; + } - // Check whether the UserTransaction or TransactionManager implements it... - if (registryClass.isInstance(ut)) { - return ut; + // If we came here, we might be on Java EE 5, since the JTA 1.1 API is present. + if (this.userTransactionObtainedFromJndi) { + // UserTransaction has already been obtained from JNDI, so the + // TransactionSynchronizationRegistry probably sits there as well. + String jndiName = DEFAULT_TRANSACTION_SYNCHRONIZATION_REGISTRY_NAME; + try { + Object tsr = getJndiTemplate().lookup(jndiName, transactionSynchronizationRegistryClass); + if (logger.isDebugEnabled()) { + logger.debug("JTA TransactionSynchronizationRegistry found at default JNDI location [" + jndiName + "]"); + } + return tsr; } - if (registryClass.isInstance(tm)) { - return tm; + catch (NamingException ex) { + if (logger.isDebugEnabled()) { + logger.debug( + "No JTA TransactionSynchronizationRegistry found at default JNDI location [" + jndiName + "]", ex); + } } - - // OK, so no JTA 1.1 TransactionSynchronizationRegistry is available, - // despite the API being present... - return null; } - catch (ClassNotFoundException ex) { - logger.debug("JTA 1.1 [" + TRANSACTION_SYNCHRONIZATION_REGISTRY_CLASS_NAME + "] not available"); - return null; + // Check whether the UserTransaction or TransactionManager implements it... + if (transactionSynchronizationRegistryClass.isInstance(ut)) { + return ut; } + if (transactionSynchronizationRegistryClass.isInstance(tm)) { + return tm; + } + // OK, so no JTA 1.1 TransactionSynchronizationRegistry is available, + // despite the API being present... + return null; }