001: /*
002: * Copyright 2002-2007 the original author or authors.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.springframework.jca.cci.connection;
018:
019: import javax.resource.ResourceException;
020: import javax.resource.cci.Connection;
021: import javax.resource.cci.ConnectionFactory;
022: import javax.resource.cci.ConnectionSpec;
023:
024: import org.apache.commons.logging.Log;
025: import org.apache.commons.logging.LogFactory;
026:
027: import org.springframework.jca.cci.CannotGetCciConnectionException;
028: import org.springframework.transaction.support.TransactionSynchronizationAdapter;
029: import org.springframework.transaction.support.TransactionSynchronizationManager;
030: import org.springframework.util.Assert;
031:
032: /**
033: * Helper class that provides static methods for obtaining CCI Connections
034: * from a {@link javax.resource.cci.ConnectionFactory}. Includes special
035: * support for Spring-managed transactional Connections, e.g. managed
036: * by {@link CciLocalTransactionManager} or
037: * {@link org.springframework.transaction.jta.JtaTransactionManager}.
038: *
039: * <p>Used internally by {@link org.springframework.jca.cci.core.CciTemplate},
040: * Spring's CCI operation objects and the {@link CciLocalTransactionManager}.
041: * Can also be used directly in application code.
042: *
043: * @author Thierry Templier
044: * @author Juergen Hoeller
045: * @since 1.2
046: * @see #getConnection
047: * @see #releaseConnection
048: * @see CciLocalTransactionManager
049: * @see org.springframework.transaction.jta.JtaTransactionManager
050: * @see org.springframework.transaction.support.TransactionSynchronizationManager
051: */
052: public abstract class ConnectionFactoryUtils {
053:
054: private static final Log logger = LogFactory
055: .getLog(ConnectionFactoryUtils.class);
056:
057: /**
058: * Obtain a Connection from the given ConnectionFactory. Translates ResourceExceptions
059: * into the Spring hierarchy of unchecked generic data access exceptions, simplifying
060: * calling code and making any exception that is thrown more meaningful.
061: * <p>Is aware of a corresponding Connection bound to the current thread, for example
062: * when using {@link CciLocalTransactionManager}. Will bind a Connection to the thread
063: * if transaction synchronization is active (e.g. if in a JTA transaction).
064: * @param cf the ConnectionFactory to obtain Connection from
065: * @return a CCI Connection from the given ConnectionFactory
066: * @throws org.springframework.jca.cci.CannotGetCciConnectionException
067: * if the attempt to get a Connection failed
068: * @see #releaseConnection
069: */
070: public static Connection getConnection(ConnectionFactory cf)
071: throws CannotGetCciConnectionException {
072: return getConnection(cf, null);
073: }
074:
075: /**
076: * Obtain a Connection from the given ConnectionFactory. Translates ResourceExceptions
077: * into the Spring hierarchy of unchecked generic data access exceptions, simplifying
078: * calling code and making any exception that is thrown more meaningful.
079: * <p>Is aware of a corresponding Connection bound to the current thread, for example
080: * when using {@link CciLocalTransactionManager}. Will bind a Connection to the thread
081: * if transaction synchronization is active (e.g. if in a JTA transaction).
082: * @param cf the ConnectionFactory to obtain Connection from
083: * @param spec the ConnectionSpec for the desired Connection (may be <code>null</code>).
084: * Note: If this is specified, a new Connection will be obtained for every call,
085: * without participating in a shared transactional Connection.
086: * @return a CCI Connection from the given ConnectionFactory
087: * @throws org.springframework.jca.cci.CannotGetCciConnectionException
088: * if the attempt to get a Connection failed
089: * @see #releaseConnection
090: */
091: public static Connection getConnection(ConnectionFactory cf,
092: ConnectionSpec spec) throws CannotGetCciConnectionException {
093: try {
094: if (spec != null) {
095: Assert.notNull(cf, "No ConnectionFactory specified");
096: return cf.getConnection(spec);
097: } else {
098: return doGetConnection(cf);
099: }
100: } catch (ResourceException ex) {
101: throw new CannotGetCciConnectionException(
102: "Could not get CCI Connection", ex);
103: }
104: }
105:
106: /**
107: * Actually obtain a CCI Connection from the given ConnectionFactory.
108: * Same as {@link #getConnection}, but throwing the original ResourceException.
109: * <p>Is aware of a corresponding Connection bound to the current thread, for example
110: * when using {@link CciLocalTransactionManager}. Will bind a Connection to the thread
111: * if transaction synchronization is active (e.g. if in a JTA transaction).
112: * <p>Directly accessed by {@link TransactionAwareConnectionFactoryProxy}.
113: * @param cf the ConnectionFactory to obtain Connection from
114: * @return a CCI Connection from the given ConnectionFactory
115: * @throws ResourceException if thrown by CCI API methods
116: * @see #doReleaseConnection
117: */
118: public static Connection doGetConnection(ConnectionFactory cf)
119: throws ResourceException {
120: Assert.notNull(cf, "No ConnectionFactory specified");
121:
122: ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager
123: .getResource(cf);
124: if (conHolder != null) {
125: return conHolder.getConnection();
126: }
127:
128: logger.debug("Opening CCI Connection");
129: Connection con = cf.getConnection();
130:
131: if (TransactionSynchronizationManager.isSynchronizationActive()) {
132: logger
133: .debug("Registering transaction synchronization for CCI Connection");
134: conHolder = new ConnectionHolder(con);
135: conHolder.setSynchronizedWithTransaction(true);
136: TransactionSynchronizationManager
137: .registerSynchronization(new ConnectionSynchronization(
138: conHolder, cf));
139: TransactionSynchronizationManager.bindResource(cf,
140: conHolder);
141: }
142:
143: return con;
144: }
145:
146: /**
147: * Determine whether the given JCA CCI Connection is transactional, that is,
148: * bound to the current thread by Spring's transaction facilities.
149: * @param con the Connection to check
150: * @param cf the ConnectionFactory that the Connection was obtained from
151: * (may be <code>null</code>)
152: * @return whether the Connection is transactional
153: */
154: public static boolean isConnectionTransactional(Connection con,
155: ConnectionFactory cf) {
156: if (cf == null) {
157: return false;
158: }
159: ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager
160: .getResource(cf);
161: return (conHolder != null && conHolder.getConnection() == con);
162: }
163:
164: /**
165: * Close the given Connection, obtained from the given ConnectionFactory,
166: * if it is not managed externally (that is, not bound to the thread).
167: * @param con the Connection to close if necessary
168: * (if this is <code>null</code>, the call will be ignored)
169: * @param cf the ConnectionFactory that the Connection was obtained from
170: * (can be <code>null</code>)
171: * @see #getConnection
172: */
173: public static void releaseConnection(Connection con,
174: ConnectionFactory cf) {
175: try {
176: doReleaseConnection(con, cf);
177: } catch (ResourceException ex) {
178: logger.debug("Could not close CCI Connection", ex);
179: } catch (Throwable ex) {
180: // We don't trust the CCI driver: It might throw RuntimeException or Error.
181: logger.debug(
182: "Unexpected exception on closing CCI Connection",
183: ex);
184: }
185: }
186:
187: /**
188: * Actually close the given Connection, obtained from the given ConnectionFactory.
189: * Same as {@link #releaseConnection}, but throwing the original ResourceException.
190: * <p>Directly accessed by {@link TransactionAwareConnectionFactoryProxy}.
191: * @param con the Connection to close if necessary
192: * (if this is <code>null</code>, the call will be ignored)
193: * @param cf the ConnectionFactory that the Connection was obtained from
194: * (can be <code>null</code>)
195: * @throws ResourceException if thrown by JCA CCI methods
196: * @see #doGetConnection
197: */
198: public static void doReleaseConnection(Connection con,
199: ConnectionFactory cf) throws ResourceException {
200: if (con == null || isConnectionTransactional(con, cf)) {
201: return;
202: }
203: con.close();
204: }
205:
206: /**
207: * Callback for resource cleanup at the end of a non-native CCI transaction
208: * (e.g. when participating in a JTA transaction).
209: */
210: private static class ConnectionSynchronization extends
211: TransactionSynchronizationAdapter {
212:
213: private final ConnectionHolder connectionHolder;
214:
215: private final ConnectionFactory connectionFactory;
216:
217: private boolean holderActive = true;
218:
219: public ConnectionSynchronization(
220: ConnectionHolder connectionHolder,
221: ConnectionFactory connectionFactory) {
222: this .connectionHolder = connectionHolder;
223: this .connectionFactory = connectionFactory;
224: }
225:
226: public void suspend() {
227: if (this .holderActive) {
228: TransactionSynchronizationManager
229: .unbindResource(this .connectionFactory);
230: }
231: }
232:
233: public void resume() {
234: if (this .holderActive) {
235: TransactionSynchronizationManager.bindResource(
236: this .connectionFactory, this .connectionHolder);
237: }
238: }
239:
240: public void beforeCompletion() {
241: TransactionSynchronizationManager
242: .unbindResource(this .connectionFactory);
243: this .holderActive = false;
244: releaseConnection(this.connectionHolder.getConnection(),
245: this.connectionFactory);
246: }
247: }
248:
249: }
|