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

org.springframework.jca.cci.connection.CciLocalTransactionManager Maven / Gradle / Ivy

There is a newer version: 6.1.11
Show newest version
/*
 * Copyright 2002-2017 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.jca.cci.connection;

import javax.resource.NotSupportedException;
import javax.resource.ResourceException;
import javax.resource.cci.Connection;
import javax.resource.cci.ConnectionFactory;
import javax.resource.spi.LocalTransactionException;

import org.springframework.beans.factory.InitializingBean;
import org.springframework.lang.Nullable;
import org.springframework.transaction.CannotCreateTransactionException;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionException;
import org.springframework.transaction.TransactionSystemException;
import org.springframework.transaction.support.AbstractPlatformTransactionManager;
import org.springframework.transaction.support.DefaultTransactionStatus;
import org.springframework.transaction.support.ResourceTransactionManager;
import org.springframework.transaction.support.TransactionSynchronizationManager;
import org.springframework.util.Assert;

/**
 * {@link org.springframework.transaction.PlatformTransactionManager} implementation
 * that manages local transactions for a single CCI ConnectionFactory.
 * Binds a CCI Connection from the specified ConnectionFactory to the thread,
 * potentially allowing for one thread-bound Connection per ConnectionFactory.
 *
 * 

Application code is required to retrieve the CCI Connection via * {@link ConnectionFactoryUtils#getConnection(ConnectionFactory)} instead of a standard * Java EE-style {@link ConnectionFactory#getConnection()} call. Spring classes such as * {@link org.springframework.jca.cci.core.CciTemplate} use this strategy implicitly. * If not used in combination with this transaction manager, the * {@link ConnectionFactoryUtils} lookup strategy behaves exactly like the native * DataSource lookup; it can thus be used in a portable fashion. * *

Alternatively, you can allow application code to work with the standard * Java EE lookup pattern {@link ConnectionFactory#getConnection()}, for example * for legacy code that is not aware of Spring at all. In that case, define a * {@link TransactionAwareConnectionFactoryProxy} for your target ConnectionFactory, * which will automatically participate in Spring-managed transactions. * * @author Thierry Templier * @author Juergen Hoeller * @since 1.2 * @see ConnectionFactoryUtils#getConnection(javax.resource.cci.ConnectionFactory) * @see ConnectionFactoryUtils#releaseConnection * @see TransactionAwareConnectionFactoryProxy * @see org.springframework.jca.cci.core.CciTemplate */ @SuppressWarnings("serial") public class CciLocalTransactionManager extends AbstractPlatformTransactionManager implements ResourceTransactionManager, InitializingBean { @Nullable private ConnectionFactory connectionFactory; /** * Create a new CciLocalTransactionManager instance. * A ConnectionFactory has to be set to be able to use it. * @see #setConnectionFactory */ public CciLocalTransactionManager() { } /** * Create a new CciLocalTransactionManager instance. * @param connectionFactory CCI ConnectionFactory to manage local transactions for */ public CciLocalTransactionManager(ConnectionFactory connectionFactory) { setConnectionFactory(connectionFactory); afterPropertiesSet(); } /** * Set the CCI ConnectionFactory that this instance should manage local * transactions for. */ public void setConnectionFactory(@Nullable ConnectionFactory cf) { if (cf instanceof TransactionAwareConnectionFactoryProxy) { // If we got a TransactionAwareConnectionFactoryProxy, we need to perform transactions // for its underlying target ConnectionFactory, else JMS access code won't see // properly exposed transactions (i.e. transactions for the target ConnectionFactory). this.connectionFactory = ((TransactionAwareConnectionFactoryProxy) cf).getTargetConnectionFactory(); } else { this.connectionFactory = cf; } } /** * Return the CCI ConnectionFactory that this instance manages local * transactions for. */ @Nullable public ConnectionFactory getConnectionFactory() { return this.connectionFactory; } private ConnectionFactory obtainConnectionFactory() { ConnectionFactory connectionFactory = getConnectionFactory(); Assert.state(connectionFactory != null, "No ConnectionFactory set"); return connectionFactory; } @Override public void afterPropertiesSet() { if (getConnectionFactory() == null) { throw new IllegalArgumentException("Property 'connectionFactory' is required"); } } @Override public Object getResourceFactory() { return obtainConnectionFactory(); } @Override protected Object doGetTransaction() { CciLocalTransactionObject txObject = new CciLocalTransactionObject(); ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(obtainConnectionFactory()); txObject.setConnectionHolder(conHolder); return txObject; } @Override protected boolean isExistingTransaction(Object transaction) { CciLocalTransactionObject txObject = (CciLocalTransactionObject) transaction; // Consider a pre-bound connection as transaction. return txObject.hasConnectionHolder(); } @Override protected void doBegin(Object transaction, TransactionDefinition definition) { CciLocalTransactionObject txObject = (CciLocalTransactionObject) transaction; ConnectionFactory connectionFactory = obtainConnectionFactory(); Connection con = null; try { con = connectionFactory.getConnection(); if (logger.isDebugEnabled()) { logger.debug("Acquired Connection [" + con + "] for local CCI transaction"); } ConnectionHolder connectionHolder = new ConnectionHolder(con); connectionHolder.setSynchronizedWithTransaction(true); con.getLocalTransaction().begin(); int timeout = determineTimeout(definition); if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) { connectionHolder.setTimeoutInSeconds(timeout); } txObject.setConnectionHolder(connectionHolder); TransactionSynchronizationManager.bindResource(connectionFactory, connectionHolder); } catch (NotSupportedException ex) { ConnectionFactoryUtils.releaseConnection(con, connectionFactory); throw new CannotCreateTransactionException("CCI Connection does not support local transactions", ex); } catch (LocalTransactionException ex) { ConnectionFactoryUtils.releaseConnection(con, connectionFactory); throw new CannotCreateTransactionException("Could not begin local CCI transaction", ex); } catch (Throwable ex) { ConnectionFactoryUtils.releaseConnection(con, connectionFactory); throw new TransactionSystemException("Unexpected failure on begin of CCI local transaction", ex); } } @Override protected Object doSuspend(Object transaction) { CciLocalTransactionObject txObject = (CciLocalTransactionObject) transaction; txObject.setConnectionHolder(null); return TransactionSynchronizationManager.unbindResource(obtainConnectionFactory()); } @Override protected void doResume(@Nullable Object transaction, Object suspendedResources) { ConnectionHolder conHolder = (ConnectionHolder) suspendedResources; TransactionSynchronizationManager.bindResource(obtainConnectionFactory(), conHolder); } protected boolean isRollbackOnly(Object transaction) throws TransactionException { CciLocalTransactionObject txObject = (CciLocalTransactionObject) transaction; return txObject.getConnectionHolder().isRollbackOnly(); } @Override protected void doCommit(DefaultTransactionStatus status) { CciLocalTransactionObject txObject = (CciLocalTransactionObject) status.getTransaction(); Connection con = txObject.getConnectionHolder().getConnection(); if (status.isDebug()) { logger.debug("Committing CCI local transaction on Connection [" + con + "]"); } try { con.getLocalTransaction().commit(); } catch (LocalTransactionException ex) { throw new TransactionSystemException("Could not commit CCI local transaction", ex); } catch (ResourceException ex) { throw new TransactionSystemException("Unexpected failure on commit of CCI local transaction", ex); } } @Override protected void doRollback(DefaultTransactionStatus status) { CciLocalTransactionObject txObject = (CciLocalTransactionObject) status.getTransaction(); Connection con = txObject.getConnectionHolder().getConnection(); if (status.isDebug()) { logger.debug("Rolling back CCI local transaction on Connection [" + con + "]"); } try { con.getLocalTransaction().rollback(); } catch (LocalTransactionException ex) { throw new TransactionSystemException("Could not roll back CCI local transaction", ex); } catch (ResourceException ex) { throw new TransactionSystemException("Unexpected failure on rollback of CCI local transaction", ex); } } @Override protected void doSetRollbackOnly(DefaultTransactionStatus status) { CciLocalTransactionObject txObject = (CciLocalTransactionObject) status.getTransaction(); if (status.isDebug()) { logger.debug("Setting CCI local transaction [" + txObject.getConnectionHolder().getConnection() + "] rollback-only"); } txObject.getConnectionHolder().setRollbackOnly(); } @Override protected void doCleanupAfterCompletion(Object transaction) { CciLocalTransactionObject txObject = (CciLocalTransactionObject) transaction; ConnectionFactory connectionFactory = obtainConnectionFactory(); // Remove the connection holder from the thread. TransactionSynchronizationManager.unbindResource(connectionFactory); txObject.getConnectionHolder().clear(); Connection con = txObject.getConnectionHolder().getConnection(); if (logger.isDebugEnabled()) { logger.debug("Releasing CCI Connection [" + con + "] after transaction"); } ConnectionFactoryUtils.releaseConnection(con, connectionFactory); } /** * CCI local transaction object, representing a ConnectionHolder. * Used as transaction object by CciLocalTransactionManager. * @see ConnectionHolder */ private static class CciLocalTransactionObject { @Nullable private ConnectionHolder connectionHolder; public void setConnectionHolder(@Nullable ConnectionHolder connectionHolder) { this.connectionHolder = connectionHolder; } public ConnectionHolder getConnectionHolder() { Assert.state(this.connectionHolder != null, "No ConnectionHolder available"); return this.connectionHolder; } public boolean hasConnectionHolder() { return (this.connectionHolder != null); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy