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: 5.3.34
Show newest version
/*
 * Copyright 2002-2007 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.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.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.TransactionSynchronizationManager;
import org.springframework.transaction.support.ResourceTransactionManager;

/**
 * {@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 * J2EE-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 * J2EE 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 */ public class CciLocalTransactionManager extends AbstractPlatformTransactionManager implements ResourceTransactionManager, InitializingBean { 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(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. */ public ConnectionFactory getConnectionFactory() { return this.connectionFactory; } public void afterPropertiesSet() { if (getConnectionFactory() == null) { throw new IllegalArgumentException("Property 'connectionFactory' is required"); } } public Object getResourceFactory() { return getConnectionFactory(); } protected Object doGetTransaction() { CciLocalTransactionObject txObject = new CciLocalTransactionObject(); ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(getConnectionFactory()); txObject.setConnectionHolder(conHolder); return txObject; } protected boolean isExistingTransaction(Object transaction) { CciLocalTransactionObject txObject = (CciLocalTransactionObject) transaction; // Consider a pre-bound connection as transaction. return (txObject.getConnectionHolder() != null); } protected void doBegin(Object transaction, TransactionDefinition definition) { CciLocalTransactionObject txObject = (CciLocalTransactionObject) transaction; Connection con = null; try { con = getConnectionFactory().getConnection(); if (logger.isDebugEnabled()) { logger.debug("Acquired Connection [" + con + "] for local CCI transaction"); } txObject.setConnectionHolder(new ConnectionHolder(con)); txObject.getConnectionHolder().setSynchronizedWithTransaction(true); con.getLocalTransaction().begin(); int timeout = determineTimeout(definition); if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) { txObject.getConnectionHolder().setTimeoutInSeconds(timeout); } TransactionSynchronizationManager.bindResource(getConnectionFactory(), txObject.getConnectionHolder()); } catch (NotSupportedException ex) { ConnectionFactoryUtils.releaseConnection(con, getConnectionFactory()); throw new CannotCreateTransactionException("CCI Connection does not support local transactions", ex); } catch (LocalTransactionException ex) { ConnectionFactoryUtils.releaseConnection(con, getConnectionFactory()); throw new CannotCreateTransactionException("Could not begin local CCI transaction", ex); } catch (ResourceException ex) { ConnectionFactoryUtils.releaseConnection(con, getConnectionFactory()); throw new TransactionSystemException("Unexpected failure on begin of CCI local transaction", ex); } } protected Object doSuspend(Object transaction) { CciLocalTransactionObject txObject = (CciLocalTransactionObject) transaction; txObject.setConnectionHolder(null); return TransactionSynchronizationManager.unbindResource(getConnectionFactory()); } protected void doResume(Object transaction, Object suspendedResources) { ConnectionHolder conHolder = (ConnectionHolder) suspendedResources; TransactionSynchronizationManager.bindResource(getConnectionFactory(), conHolder); } protected boolean isRollbackOnly(Object transaction) throws TransactionException { CciLocalTransactionObject txObject = (CciLocalTransactionObject) transaction; return txObject.getConnectionHolder().isRollbackOnly(); } 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); } } 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); } } 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(); } protected void doCleanupAfterCompletion(Object transaction) { CciLocalTransactionObject txObject = (CciLocalTransactionObject) transaction; // Remove the connection holder from the thread. TransactionSynchronizationManager.unbindResource(getConnectionFactory()); txObject.getConnectionHolder().clear(); Connection con = txObject.getConnectionHolder().getConnection(); if (logger.isDebugEnabled()) { logger.debug("Releasing CCI Connection [" + con + "] after transaction"); } ConnectionFactoryUtils.releaseConnection(con, getConnectionFactory()); } /** * CCI local transaction object, representing a ConnectionHolder. * Used as transaction object by CciLocalTransactionManager. * @see ConnectionHolder */ private static class CciLocalTransactionObject { private ConnectionHolder connectionHolder; public void setConnectionHolder(ConnectionHolder connectionHolder) { this.connectionHolder = connectionHolder; } public ConnectionHolder getConnectionHolder() { return connectionHolder; } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy