All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.springframework.transaction.jta.WebSphereUowTransactionManager Maven / Gradle / Ivy

There is a newer version: 6.2.0
Show newest version
/*
 * Copyright 2002-2020 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
 *
 *      https://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.lang.Nullable;
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.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.Assert;
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"; @Nullable private UOWManager uowManager; @Nullable 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(); } } private UOWManager obtainUOWManager() { Assert.state(this.uowManager != null, "No UOWManager set"); return this.uowManager; } /** * Registers the synchronizations as interposed JTA Synchronization on the UOWManager. */ @Override protected void doRegisterAfterCompletionWithJtaTransaction( JtaTransactionObject txObject, List synchronizations) { obtainUOWManager().registerInterposedSynchronization(new JtaAfterCompletionSynchronization(synchronizations)); } /** * Returns {@code true} since WebSphere ResourceAdapters (as exposed in JNDI) * implicitly perform transaction enlistment if the MessageEndpointFactory's * {@code isDeliveryTransacted} method returns {@code true}. * In that case we'll simply skip the {@link #createTransaction} call. * @see javax.resource.spi.endpoint.MessageEndpointFactory#isDeliveryTransacted * @see org.springframework.jca.endpoint.AbstractMessageEndpointFactory * @see TransactionFactory#createTransaction */ @Override public boolean supportsResourceAdapterManagedTransactions() { return true; } @Override @Nullable public T execute(@Nullable TransactionDefinition definition, TransactionCallback callback) throws TransactionException { // Use defaults if no transaction definition given. TransactionDefinition def = (definition != null ? definition : TransactionDefinition.withDefaults()); if (def.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) { throw new InvalidTimeoutException("Invalid transaction timeout", def.getTimeout()); } UOWManager uowManager = obtainUOWManager(); int pb = def.getPropagationBehavior(); boolean existingTx = (uowManager.getUOWStatus() != UOWSynchronizationRegistry.UOW_STATUS_NONE && uowManager.getUOWType() != UOWSynchronizationRegistry.UOW_TYPE_LOCAL_TRANSACTION); int uowType = UOWSynchronizationRegistry.UOW_TYPE_GLOBAL_TRANSACTION; boolean joinTx = false; boolean newSynch = false; if (existingTx) { if (pb == TransactionDefinition.PROPAGATION_NEVER) { throw new IllegalTransactionStateException( "Transaction propagation 'never' but existing transaction found"); } if (pb == TransactionDefinition.PROPAGATION_NESTED) { throw new NestedTransactionNotSupportedException( "Transaction propagation 'nested' not supported for WebSphere UOW transactions"); } if (pb == TransactionDefinition.PROPAGATION_SUPPORTS || pb == TransactionDefinition.PROPAGATION_REQUIRED || pb == TransactionDefinition.PROPAGATION_MANDATORY) { joinTx = true; newSynch = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER); } else if (pb == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) { uowType = UOWSynchronizationRegistry.UOW_TYPE_LOCAL_TRANSACTION; newSynch = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS); } else { newSynch = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER); } } else { if (pb == TransactionDefinition.PROPAGATION_MANDATORY) { throw new IllegalTransactionStateException( "Transaction propagation 'mandatory' but no existing transaction found"); } if (pb == TransactionDefinition.PROPAGATION_SUPPORTS || pb == TransactionDefinition.PROPAGATION_NOT_SUPPORTED || pb == TransactionDefinition.PROPAGATION_NEVER) { uowType = UOWSynchronizationRegistry.UOW_TYPE_LOCAL_TRANSACTION; newSynch = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS); } else { newSynch = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER); } } boolean debug = logger.isDebugEnabled(); if (debug) { logger.debug("Creating new transaction with name [" + def.getName() + "]: " + def); } SuspendedResourcesHolder suspendedResources = (!joinTx ? suspend(null) : null); UOWActionAdapter action = null; try { boolean actualTransaction = (uowType == UOWManager.UOW_TYPE_GLOBAL_TRANSACTION); if (actualTransaction && def.getTimeout() > TransactionDefinition.TIMEOUT_DEFAULT) { uowManager.setUOWTimeout(uowType, def.getTimeout()); } if (debug) { logger.debug("Invoking WebSphere UOW action: type=" + uowType + ", join=" + joinTx); } action = new UOWActionAdapter<>(def, callback, actualTransaction, !joinTx, newSynch, debug); uowManager.runUnderUOW(uowType, joinTx, action); if (debug) { logger.debug("Returned from WebSphere UOW action: type=" + uowType + ", join=" + joinTx); } return action.getResult(); } catch (UOWException | UOWActionException ex) { TransactionSystemException tse = new TransactionSystemException("UOWManager transaction processing failed", ex); Throwable appEx = action.getException(); if (appEx != null) { logger.error("Application exception overridden by rollback exception", appEx); tse.initApplicationException(appEx); } throw tse; } finally { if (suspendedResources != null) { resume(null, suspendedResources); } } } /** * Adapter that executes the given Spring transaction within the WebSphere UOWAction shape. */ private class UOWActionAdapter implements UOWAction, SmartTransactionObject { private final TransactionDefinition definition; private final TransactionCallback callback; private final boolean actualTransaction; private final boolean newTransaction; private final boolean newSynchronization; private boolean debug; @Nullable private T result; @Nullable private Throwable exception; public UOWActionAdapter(TransactionDefinition definition, TransactionCallback callback, boolean actualTransaction, boolean newTransaction, boolean newSynchronization, boolean debug) { this.definition = definition; this.callback = callback; this.actualTransaction = actualTransaction; this.newTransaction = newTransaction; this.newSynchronization = newSynchronization; this.debug = debug; } @Override public void run() { UOWManager uowManager = obtainUOWManager(); DefaultTransactionStatus status = prepareTransactionStatus( this.definition, (this.actualTransaction ? this : null), this.newTransaction, this.newSynchronization, this.debug, null); try { this.result = this.callback.doInTransaction(status); triggerBeforeCommit(status); } catch (Throwable ex) { this.exception = ex; if (status.isDebug()) { logger.debug("Rolling back on application exception from transaction callback", ex); } uowManager.setRollbackOnly(); } finally { if (status.isLocalRollbackOnly()) { if (status.isDebug()) { logger.debug("Transaction callback has explicitly requested rollback"); } uowManager.setRollbackOnly(); } triggerBeforeCompletion(status); if (status.isNewSynchronization()) { List synchronizations = TransactionSynchronizationManager.getSynchronizations(); TransactionSynchronizationManager.clear(); if (!synchronizations.isEmpty()) { uowManager.registerInterposedSynchronization(new JtaAfterCompletionSynchronization(synchronizations)); } } } } @Nullable public T getResult() { if (this.exception != null) { ReflectionUtils.rethrowRuntimeException(this.exception); } return this.result; } @Nullable public Throwable getException() { return this.exception; } @Override public boolean isRollbackOnly() { return obtainUOWManager().getRollbackOnly(); } @Override public void flush() { TransactionSynchronizationUtils.triggerFlush(); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy