/* * Copyright 2002-2015 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.springframework.transaction.jta; import java.util.List; import javax.naming.NamingException; import com.ibm.websphere.uow.UOWSynchronizationRegistry; import com.ibm.wsspi.uow.UOWAction; import com.ibm.wsspi.uow.UOWActionException; import com.ibm.wsspi.uow.UOWException; import com.ibm.wsspi.uow.UOWManager; import com.ibm.wsspi.uow.UOWManagerFactory; import org.springframework.transaction.IllegalTransactionStateException; import org.springframework.transaction.InvalidTimeoutException; import org.springframework.transaction.NestedTransactionNotSupportedException; import org.springframework.transaction.TransactionDefinition; import org.springframework.transaction.TransactionException; import org.springframework.transaction.TransactionSystemException; import org.springframework.transaction.support.CallbackPreferringPlatformTransactionManager; import org.springframework.transaction.support.DefaultTransactionDefinition; import org.springframework.transaction.support.DefaultTransactionStatus; import org.springframework.transaction.support.SmartTransactionObject; import org.springframework.transaction.support.TransactionCallback; import org.springframework.transaction.support.TransactionSynchronization; import org.springframework.transaction.support.TransactionSynchronizationManager; import org.springframework.transaction.support.TransactionSynchronizationUtils; import org.springframework.util.ReflectionUtils; /** * WebSphere-specific PlatformTransactionManager implementation that delegates * to a {@link com.ibm.wsspi.uow.UOWManager} instance, obtained from WebSphere's * JNDI environment. This allows Spring to leverage the full power of the WebSphere * transaction coordinator, including transaction suspension, in a manner that is * perfectly compliant with officially supported WebSphere API. * *
The {@link CallbackPreferringPlatformTransactionManager} interface * implemented by this class indicates that callers should preferably pass in * a {@link TransactionCallback} through the {@link #execute} method, which * will be handled through the callback-based WebSphere UOWManager API instead * of through standard JTA API (UserTransaction / TransactionManager). This avoids * the use of the non-public {@code javax.transaction.TransactionManager} * API on WebSphere, staying within supported WebSphere API boundaries. * *
This transaction manager implementation derives from Spring's standard * {@link JtaTransactionManager}, inheriting the capability to support programmatic * transaction demarcation via {@code getTransaction} / {@code commit} / * {@code rollback} calls through a JTA UserTransaction handle, for callers * that do not use the TransactionCallback-based {@link #execute} method. However, * transaction suspension is not supported in this {@code getTransaction} * style (unless you explicitly specify a {@link #setTransactionManager} reference, * despite the official WebSphere recommendations). Use the {@link #execute} style * for any code that might require transaction suspension. * *
This transaction manager is compatible with WebSphere 6.1.0.9 and above. * The default JNDI location for the UOWManager is "java:comp/websphere/UOWManager". * If the location happens to differ according to your WebSphere documentation, * simply specify the actual location through this transaction manager's * "uowManagerName" bean property. * *
NOTE: This JtaTransactionManager is intended to refine specific transaction * demarcation behavior on Spring's side. It will happily co-exist with independently * configured WebSphere transaction strategies in your persistence provider, with no * need to specifically connect those setups in any way. * * @author Juergen Hoeller * @since 2.5 * @see #setUowManager * @see #setUowManagerName * @see com.ibm.wsspi.uow.UOWManager */ @SuppressWarnings("serial") public class WebSphereUowTransactionManager extends JtaTransactionManager implements CallbackPreferringPlatformTransactionManager { /** * Default JNDI location for the WebSphere UOWManager. * @see #setUowManagerName */ public static final String DEFAULT_UOW_MANAGER_NAME = "java:comp/websphere/UOWManager"; private UOWManager uowManager; private String uowManagerName; /** * Create a new WebSphereUowTransactionManager. */ public WebSphereUowTransactionManager() { setAutodetectTransactionManager(false); } /** * Create a new WebSphereUowTransactionManager for the given UOWManager. * @param uowManager the WebSphere UOWManager to use as direct reference */ public WebSphereUowTransactionManager(UOWManager uowManager) { this(); this.uowManager = uowManager; } /** * Set the WebSphere UOWManager to use as direct reference. *
Typically just used for test setups; in a Java EE environment,
* the UOWManager will always be fetched from JNDI.
* @see #setUserTransactionName
*/
public void setUowManager(UOWManager uowManager) {
this.uowManager = uowManager;
}
/**
* Set the JNDI name of the WebSphere UOWManager.
* The default "java:comp/websphere/UOWManager" is used if not set.
* @see #DEFAULT_USER_TRANSACTION_NAME
* @see #setUowManager
*/
public void setUowManagerName(String uowManagerName) {
this.uowManagerName = uowManagerName;
}
@Override
public void afterPropertiesSet() throws TransactionSystemException {
initUserTransactionAndTransactionManager();
// Fetch UOWManager handle from JNDI, if necessary.
if (this.uowManager == null) {
if (this.uowManagerName != null) {
this.uowManager = lookupUowManager(this.uowManagerName);
}
else {
this.uowManager = lookupDefaultUowManager();
}
}
}
/**
* Look up the WebSphere UOWManager in JNDI via the configured name.
* @param uowManagerName the JNDI name of the UOWManager
* @return the UOWManager object
* @throws TransactionSystemException if the JNDI lookup failed
* @see #setJndiTemplate
* @see #setUowManagerName
*/
protected UOWManager lookupUowManager(String uowManagerName) throws TransactionSystemException {
try {
if (logger.isDebugEnabled()) {
logger.debug("Retrieving WebSphere UOWManager from JNDI location [" + uowManagerName + "]");
}
return getJndiTemplate().lookup(uowManagerName, UOWManager.class);
}
catch (NamingException ex) {
throw new TransactionSystemException(
"WebSphere UOWManager is not available at JNDI location [" + uowManagerName + "]", ex);
}
}
/**
* Obtain the WebSphere UOWManager from the default JNDI location
* "java:comp/websphere/UOWManager".
* @return the UOWManager object
* @throws TransactionSystemException if the JNDI lookup failed
* @see #setJndiTemplate
*/
protected UOWManager lookupDefaultUowManager() throws TransactionSystemException {
try {
logger.debug("Retrieving WebSphere UOWManager from default JNDI location [" + DEFAULT_UOW_MANAGER_NAME + "]");
return getJndiTemplate().lookup(DEFAULT_UOW_MANAGER_NAME, UOWManager.class);
}
catch (NamingException ex) {
logger.debug("WebSphere UOWManager is not available at default JNDI location [" +
DEFAULT_UOW_MANAGER_NAME + "] - falling back to UOWManagerFactory lookup");
return UOWManagerFactory.getUOWManager();
}
}
/**
* Registers the synchronizations as interposed JTA Synchronization on the UOWManager.
*/
@Override
protected void doRegisterAfterCompletionWithJtaTransaction(
JtaTransactionObject txObject, List