KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > springframework > jca > cci > connection > CciLocalTransactionManager


1 /*
2  * Copyright 2002-2007 the original author or authors.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package org.springframework.jca.cci.connection;
18
19 import javax.resource.NotSupportedException JavaDoc;
20 import javax.resource.ResourceException JavaDoc;
21 import javax.resource.cci.Connection JavaDoc;
22 import javax.resource.cci.ConnectionFactory JavaDoc;
23 import javax.resource.spi.LocalTransactionException JavaDoc;
24
25 import org.springframework.beans.factory.InitializingBean;
26 import org.springframework.transaction.CannotCreateTransactionException;
27 import org.springframework.transaction.TransactionDefinition;
28 import org.springframework.transaction.TransactionException;
29 import org.springframework.transaction.TransactionSystemException;
30 import org.springframework.transaction.support.AbstractPlatformTransactionManager;
31 import org.springframework.transaction.support.DefaultTransactionStatus;
32 import org.springframework.transaction.support.TransactionSynchronizationManager;
33 import org.springframework.transaction.support.ResourceTransactionManager;
34
35 /**
36  * {@link org.springframework.transaction.PlatformTransactionManager} implementation
37  * that manages local transactions for a single CCI ConnectionFactory.
38  * Binds a CCI Connection from the specified ConnectionFactory to the thread,
39  * potentially allowing for one thread-bound Connection per ConnectionFactory.
40  *
41  * <p>Application code is required to retrieve the CCI Connection via
42  * {@link ConnectionFactoryUtils#getConnection(ConnectionFactory)} instead of a standard
43  * J2EE-style {@link ConnectionFactory#getConnection()} call. Spring classes such as
44  * {@link org.springframework.jca.cci.core.CciTemplate} use this strategy implicitly.
45  * If not used in combination with this transaction manager, the
46  * {@link ConnectionFactoryUtils} lookup strategy behaves exactly like the native
47  * DataSource lookup; it can thus be used in a portable fashion.
48  *
49  * <p>Alternatively, you can allow application code to work with the standard
50  * J2EE lookup pattern {@link ConnectionFactory#getConnection()}, for example
51  * for legacy code that is not aware of Spring at all. In that case, define a
52  * {@link TransactionAwareConnectionFactoryProxy} for your target ConnectionFactory,
53  * which will automatically participate in Spring-managed transactions.
54  *
55  * @author Thierry Templier
56  * @author Juergen Hoeller
57  * @since 1.2
58  * @see ConnectionFactoryUtils#getConnection(javax.resource.cci.ConnectionFactory)
59  * @see ConnectionFactoryUtils#releaseConnection
60  * @see TransactionAwareConnectionFactoryProxy
61  * @see org.springframework.jca.cci.core.CciTemplate
62  */

63 public class CciLocalTransactionManager extends AbstractPlatformTransactionManager
64         implements ResourceTransactionManager, InitializingBean {
65
66     private ConnectionFactory JavaDoc connectionFactory;
67
68
69     /**
70      * Create a new CciLocalTransactionManager instance.
71      * A ConnectionFactory has to be set to be able to use it.
72      * @see #setConnectionFactory
73      */

74     public CciLocalTransactionManager() {
75     }
76
77     /**
78      * Create a new CciLocalTransactionManager instance.
79      * @param connectionFactory CCI ConnectionFactory to manage local transactions for
80      */

81     public CciLocalTransactionManager(ConnectionFactory JavaDoc connectionFactory) {
82         setConnectionFactory(connectionFactory);
83         afterPropertiesSet();
84     }
85
86
87     /**
88      * Set the CCI ConnectionFactory that this instance should manage local
89      * transactions for.
90      */

91     public void setConnectionFactory(ConnectionFactory JavaDoc cf) {
92         if (cf instanceof TransactionAwareConnectionFactoryProxy) {
93             // If we got a TransactionAwareConnectionFactoryProxy, we need to perform transactions
94
// for its underlying target ConnectionFactory, else JMS access code won't see
95
// properly exposed transactions (i.e. transactions for the target ConnectionFactory).
96
this.connectionFactory = ((TransactionAwareConnectionFactoryProxy) cf).getTargetConnectionFactory();
97         }
98         else {
99             this.connectionFactory = cf;
100         }
101     }
102
103     /**
104      * Return the CCI ConnectionFactory that this instance manages local
105      * transactions for.
106      */

107     public ConnectionFactory JavaDoc getConnectionFactory() {
108         return this.connectionFactory;
109     }
110
111     public void afterPropertiesSet() {
112         if (getConnectionFactory() == null) {
113             throw new IllegalArgumentException JavaDoc("Property 'connectionFactory' is required");
114         }
115     }
116
117
118     public Object JavaDoc getResourceFactory() {
119         return getConnectionFactory();
120     }
121
122     protected Object JavaDoc doGetTransaction() {
123         CciLocalTransactionObject txObject = new CciLocalTransactionObject();
124         ConnectionHolder conHolder =
125             (ConnectionHolder) TransactionSynchronizationManager.getResource(getConnectionFactory());
126         txObject.setConnectionHolder(conHolder);
127         return txObject;
128     }
129
130     protected boolean isExistingTransaction(Object JavaDoc transaction) {
131         CciLocalTransactionObject txObject = (CciLocalTransactionObject) transaction;
132         // Consider a pre-bound connection as transaction.
133
return (txObject.getConnectionHolder() != null);
134     }
135
136     protected void doBegin(Object JavaDoc transaction, TransactionDefinition definition) {
137         CciLocalTransactionObject txObject = (CciLocalTransactionObject) transaction;
138
139         Connection JavaDoc con = null;
140
141         try {
142             con = getConnectionFactory().getConnection();
143             if (logger.isDebugEnabled()) {
144                 logger.debug("Acquired Connection [" + con + "] for local CCI transaction");
145             }
146
147             txObject.setConnectionHolder(new ConnectionHolder(con));
148             txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
149
150             con.getLocalTransaction().begin();
151             int timeout = determineTimeout(definition);
152             if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
153                 txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
154             }
155             TransactionSynchronizationManager.bindResource(getConnectionFactory(), txObject.getConnectionHolder());
156         }
157
158         catch (NotSupportedException JavaDoc ex) {
159             ConnectionFactoryUtils.releaseConnection(con, getConnectionFactory());
160             throw new CannotCreateTransactionException("CCI Connection does not support local transactions", ex);
161         }
162         catch (LocalTransactionException JavaDoc ex) {
163             ConnectionFactoryUtils.releaseConnection(con, getConnectionFactory());
164             throw new CannotCreateTransactionException("Could not begin local CCI transaction", ex);
165         }
166         catch (ResourceException JavaDoc ex) {
167             ConnectionFactoryUtils.releaseConnection(con, getConnectionFactory());
168             throw new TransactionSystemException("Unexpected failure on begin of CCI local transaction", ex);
169         }
170     }
171
172     protected Object JavaDoc doSuspend(Object JavaDoc transaction) {
173         CciLocalTransactionObject txObject = (CciLocalTransactionObject) transaction;
174         txObject.setConnectionHolder(null);
175         return TransactionSynchronizationManager.unbindResource(getConnectionFactory());
176     }
177
178     protected void doResume(Object JavaDoc transaction, Object JavaDoc suspendedResources) {
179         ConnectionHolder conHolder = (ConnectionHolder) suspendedResources;
180         TransactionSynchronizationManager.bindResource(getConnectionFactory(), conHolder);
181     }
182
183     protected boolean isRollbackOnly(Object JavaDoc transaction) throws TransactionException JavaDoc {
184         CciLocalTransactionObject txObject = (CciLocalTransactionObject) transaction;
185         return txObject.getConnectionHolder().isRollbackOnly();
186     }
187
188     protected void doCommit(DefaultTransactionStatus status) {
189         CciLocalTransactionObject txObject = (CciLocalTransactionObject) status.getTransaction();
190         Connection JavaDoc con = txObject.getConnectionHolder().getConnection();
191         if (status.isDebug()) {
192             logger.debug("Committing CCI local transaction on Connection [" + con + "]");
193         }
194         try {
195             con.getLocalTransaction().commit();
196         }
197         catch (LocalTransactionException JavaDoc ex) {
198             throw new TransactionSystemException("Could not commit CCI local transaction", ex);
199         }
200         catch (ResourceException JavaDoc ex) {
201             throw new TransactionSystemException("Unexpected failure on commit of CCI local transaction", ex);
202         }
203     }
204
205     protected void doRollback(DefaultTransactionStatus status) {
206         CciLocalTransactionObject txObject = (CciLocalTransactionObject) status.getTransaction();
207         Connection JavaDoc con = txObject.getConnectionHolder().getConnection();
208         if (status.isDebug()) {
209             logger.debug("Rolling back CCI local transaction on Connection [" + con + "]");
210         }
211         try {
212             con.getLocalTransaction().rollback();
213         }
214         catch (LocalTransactionException JavaDoc ex) {
215             throw new TransactionSystemException("Could not roll back CCI local transaction", ex);
216         }
217         catch (ResourceException JavaDoc ex) {
218             throw new TransactionSystemException("Unexpected failure on rollback of CCI local transaction", ex);
219         }
220     }
221
222     protected void doSetRollbackOnly(DefaultTransactionStatus status) {
223         CciLocalTransactionObject txObject = (CciLocalTransactionObject) status.getTransaction();
224         if (status.isDebug()) {
225             logger.debug("Setting CCI local transaction [" + txObject.getConnectionHolder().getConnection() +
226                     "] rollback-only");
227         }
228         txObject.getConnectionHolder().setRollbackOnly();
229     }
230
231     protected void doCleanupAfterCompletion(Object JavaDoc transaction) {
232         CciLocalTransactionObject txObject = (CciLocalTransactionObject) transaction;
233
234         // Remove the connection holder from the thread.
235
TransactionSynchronizationManager.unbindResource(getConnectionFactory());
236         txObject.getConnectionHolder().clear();
237
238         Connection JavaDoc con = txObject.getConnectionHolder().getConnection();
239         if (logger.isDebugEnabled()) {
240             logger.debug("Releasing CCI Connection [" + con + "] after transaction");
241         }
242         ConnectionFactoryUtils.releaseConnection(con, getConnectionFactory());
243     }
244
245
246     /**
247      * CCI local transaction object, representing a ConnectionHolder.
248      * Used as transaction object by CciLocalTransactionManager.
249      * @see ConnectionHolder
250      */

251     private static class CciLocalTransactionObject {
252
253         private ConnectionHolder connectionHolder;
254
255         public void setConnectionHolder(ConnectionHolder connectionHolder) {
256             this.connectionHolder = connectionHolder;
257         }
258
259         public ConnectionHolder getConnectionHolder() {
260             return connectionHolder;
261         }
262     }
263
264 }
265
Popular Tags