Source Code Cross Referenced for DataSourceUtils.java in  » J2EE » spring-framework-2.5 » org » springframework » jdbc » datasource » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » J2EE » spring framework 2.5 » org.springframework.jdbc.datasource 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


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.jdbc.datasource;
018:
019:        import java.sql.Connection;
020:        import java.sql.SQLException;
021:        import java.sql.Statement;
022:
023:        import javax.sql.DataSource;
024:
025:        import org.apache.commons.logging.Log;
026:        import org.apache.commons.logging.LogFactory;
027:
028:        import org.springframework.jdbc.CannotGetJdbcConnectionException;
029:        import org.springframework.transaction.TransactionDefinition;
030:        import org.springframework.transaction.support.TransactionSynchronizationAdapter;
031:        import org.springframework.transaction.support.TransactionSynchronizationManager;
032:        import org.springframework.util.Assert;
033:
034:        /**
035:         * Helper class that provides static methods for obtaining JDBC Connections from
036:         * a {@link javax.sql.DataSource}. Includes special support for Spring-managed
037:         * transactional Connections, e.g. managed by {@link DataSourceTransactionManager}
038:         * or {@link org.springframework.transaction.jta.JtaTransactionManager}.
039:         *
040:         * <p>Used internally by Spring's {@link org.springframework.jdbc.core.JdbcTemplate},
041:         * Spring's JDBC operation objects and the JDBC {@link DataSourceTransactionManager}.
042:         * Can also be used directly in application code.
043:         *
044:         * @author Rod Johnson
045:         * @author Juergen Hoeller
046:         * @see #getConnection
047:         * @see #releaseConnection
048:         * @see DataSourceTransactionManager
049:         * @see org.springframework.transaction.jta.JtaTransactionManager
050:         * @see org.springframework.transaction.support.TransactionSynchronizationManager
051:         */
052:        public abstract class DataSourceUtils {
053:
054:            /**
055:             * Order value for TransactionSynchronization objects that clean up
056:             * JDBC Connections.
057:             */
058:            public static final int CONNECTION_SYNCHRONIZATION_ORDER = 1000;
059:
060:            private static final Log logger = LogFactory
061:                    .getLog(DataSourceUtils.class);
062:
063:            /**
064:             * Obtain a Connection from the given DataSource. Translates SQLExceptions into
065:             * the Spring hierarchy of unchecked generic data access exceptions, simplifying
066:             * calling code and making any exception that is thrown more meaningful.
067:             * <p>Is aware of a corresponding Connection bound to the current thread, for example
068:             * when using {@link DataSourceTransactionManager}. Will bind a Connection to the
069:             * thread if transaction synchronization is active, e.g. when running within a
070:             * {@link org.springframework.transaction.jta.JtaTransactionManager JTA} transaction).
071:             * @param dataSource the DataSource to obtain Connections from
072:             * @return a JDBC Connection from the given DataSource
073:             * @throws org.springframework.jdbc.CannotGetJdbcConnectionException
074:             * if the attempt to get a Connection failed
075:             * @see #releaseConnection
076:             */
077:            public static Connection getConnection(DataSource dataSource)
078:                    throws CannotGetJdbcConnectionException {
079:                try {
080:                    return doGetConnection(dataSource);
081:                } catch (SQLException ex) {
082:                    throw new CannotGetJdbcConnectionException(
083:                            "Could not get JDBC Connection", ex);
084:                }
085:            }
086:
087:            /**
088:             * Actually obtain a JDBC Connection from the given DataSource.
089:             * Same as {@link #getConnection}, but throwing the original SQLException.
090:             * <p>Is aware of a corresponding Connection bound to the current thread, for example
091:             * when using {@link DataSourceTransactionManager}. Will bind a Connection to the thread
092:             * if transaction synchronization is active (e.g. if in a JTA transaction).
093:             * <p>Directly accessed by {@link TransactionAwareDataSourceProxy}.
094:             * @param dataSource the DataSource to obtain Connections from
095:             * @return a JDBC Connection from the given DataSource
096:             * @throws SQLException if thrown by JDBC methods
097:             * @see #doReleaseConnection
098:             */
099:            public static Connection doGetConnection(DataSource dataSource)
100:                    throws SQLException {
101:                Assert.notNull(dataSource, "No DataSource specified");
102:
103:                ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager
104:                        .getResource(dataSource);
105:                if (conHolder != null
106:                        && (conHolder.hasConnection() || conHolder
107:                                .isSynchronizedWithTransaction())) {
108:                    conHolder.requested();
109:                    if (!conHolder.hasConnection()) {
110:                        logger
111:                                .debug("Fetching resumed JDBC Connection from DataSource");
112:                        conHolder.setConnection(dataSource.getConnection());
113:                    }
114:                    return conHolder.getConnection();
115:                }
116:                // Else we either got no holder or an empty thread-bound holder here.
117:
118:                logger.debug("Fetching JDBC Connection from DataSource");
119:                Connection con = dataSource.getConnection();
120:
121:                if (TransactionSynchronizationManager.isSynchronizationActive()) {
122:                    logger
123:                            .debug("Registering transaction synchronization for JDBC Connection");
124:                    // Use same Connection for further JDBC actions within the transaction.
125:                    // Thread-bound object will get removed by synchronization at transaction completion.
126:                    ConnectionHolder holderToUse = conHolder;
127:                    if (holderToUse == null) {
128:                        holderToUse = new ConnectionHolder(con);
129:                    } else {
130:                        holderToUse.setConnection(con);
131:                    }
132:                    holderToUse.requested();
133:                    TransactionSynchronizationManager
134:                            .registerSynchronization(new ConnectionSynchronization(
135:                                    holderToUse, dataSource));
136:                    holderToUse.setSynchronizedWithTransaction(true);
137:                    if (holderToUse != conHolder) {
138:                        TransactionSynchronizationManager.bindResource(
139:                                dataSource, holderToUse);
140:                    }
141:                }
142:
143:                return con;
144:            }
145:
146:            /**
147:             * Prepare the given Connection with the given transaction semantics.
148:             * @param con the Connection to prepare
149:             * @param definition the transaction definition to apply
150:             * @return the previous isolation level, if any
151:             * @throws SQLException if thrown by JDBC methods
152:             * @see #resetConnectionAfterTransaction
153:             */
154:            public static Integer prepareConnectionForTransaction(
155:                    Connection con, TransactionDefinition definition)
156:                    throws SQLException {
157:
158:                Assert.notNull(con, "No Connection specified");
159:
160:                // Set read-only flag.
161:                if (definition != null && definition.isReadOnly()) {
162:                    try {
163:                        if (logger.isDebugEnabled()) {
164:                            logger.debug("Setting JDBC Connection [" + con
165:                                    + "] read-only");
166:                        }
167:                        con.setReadOnly(true);
168:                    } catch (Throwable ex) {
169:                        // SQLException or UnsupportedOperationException
170:                        // -> ignore, it's just a hint anyway.
171:                        logger.debug("Could not set JDBC Connection read-only",
172:                                ex);
173:                    }
174:                }
175:
176:                // Apply specific isolation level, if any.
177:                Integer previousIsolationLevel = null;
178:                if (definition != null
179:                        && definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT) {
180:                    if (logger.isDebugEnabled()) {
181:                        logger
182:                                .debug("Changing isolation level of JDBC Connection ["
183:                                        + con
184:                                        + "] to "
185:                                        + definition.getIsolationLevel());
186:                    }
187:                    previousIsolationLevel = new Integer(con
188:                            .getTransactionIsolation());
189:                    con.setTransactionIsolation(definition.getIsolationLevel());
190:                }
191:
192:                return previousIsolationLevel;
193:            }
194:
195:            /**
196:             * Reset the given Connection after a transaction,
197:             * regarding read-only flag and isolation level.
198:             * @param con the Connection to reset
199:             * @param previousIsolationLevel the isolation level to restore, if any
200:             * @see #prepareConnectionForTransaction
201:             */
202:            public static void resetConnectionAfterTransaction(Connection con,
203:                    Integer previousIsolationLevel) {
204:                Assert.notNull(con, "No Connection specified");
205:                try {
206:                    // Reset transaction isolation to previous value, if changed for the transaction.
207:                    if (previousIsolationLevel != null) {
208:                        if (logger.isDebugEnabled()) {
209:                            logger
210:                                    .debug("Resetting isolation level of JDBC Connection ["
211:                                            + con
212:                                            + "] to "
213:                                            + previousIsolationLevel);
214:                        }
215:                        con.setTransactionIsolation(previousIsolationLevel
216:                                .intValue());
217:                    }
218:
219:                    // Reset read-only flag.
220:                    if (con.isReadOnly()) {
221:                        if (logger.isDebugEnabled()) {
222:                            logger
223:                                    .debug("Resetting read-only flag of JDBC Connection ["
224:                                            + con + "]");
225:                        }
226:                        con.setReadOnly(false);
227:                    }
228:                } catch (Throwable ex) {
229:                    logger
230:                            .debug(
231:                                    "Could not reset JDBC Connection after transaction",
232:                                    ex);
233:                }
234:            }
235:
236:            /**
237:             * Determine whether the given JDBC Connection is transactional, that is,
238:             * bound to the current thread by Spring's transaction facilities.
239:             * @param con the Connection to check
240:             * @param dataSource the DataSource that the Connection was obtained from
241:             * (may be <code>null</code>)
242:             * @return whether the Connection is transactional
243:             */
244:            public static boolean isConnectionTransactional(Connection con,
245:                    DataSource dataSource) {
246:                if (dataSource == null) {
247:                    return false;
248:                }
249:                ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager
250:                        .getResource(dataSource);
251:                return (conHolder != null && connectionEquals(conHolder, con));
252:            }
253:
254:            /**
255:             * Apply the current transaction timeout, if any,
256:             * to the given JDBC Statement object.
257:             * @param stmt the JDBC Statement object
258:             * @param dataSource the DataSource that the Connection was obtained from
259:             * @throws SQLException if thrown by JDBC methods
260:             * @see java.sql.Statement#setQueryTimeout
261:             */
262:            public static void applyTransactionTimeout(Statement stmt,
263:                    DataSource dataSource) throws SQLException {
264:                applyTimeout(stmt, dataSource, 0);
265:            }
266:
267:            /**
268:             * Apply the specified timeout - overridden by the current transaction timeout,
269:             * if any - to the given JDBC Statement object.
270:             * @param stmt the JDBC Statement object
271:             * @param dataSource the DataSource that the Connection was obtained from
272:             * @param timeout the timeout to apply (or 0 for no timeout outside of a transaction)
273:             * @throws SQLException if thrown by JDBC methods
274:             * @see java.sql.Statement#setQueryTimeout
275:             */
276:            public static void applyTimeout(Statement stmt,
277:                    DataSource dataSource, int timeout) throws SQLException {
278:                Assert.notNull(stmt, "No Statement specified");
279:                Assert.notNull(dataSource, "No DataSource specified");
280:                ConnectionHolder holder = (ConnectionHolder) TransactionSynchronizationManager
281:                        .getResource(dataSource);
282:                if (holder != null && holder.hasTimeout()) {
283:                    // Remaining transaction timeout overrides specified value.
284:                    stmt.setQueryTimeout(holder.getTimeToLiveInSeconds());
285:                } else if (timeout > 0) {
286:                    // No current transaction timeout -> apply specified value.
287:                    stmt.setQueryTimeout(timeout);
288:                }
289:            }
290:
291:            /**
292:             * Close the given Connection, obtained from the given DataSource,
293:             * if it is not managed externally (that is, not bound to the thread).
294:             * @param con the Connection to close if necessary
295:             * (if this is <code>null</code>, the call will be ignored)
296:             * @param dataSource the DataSource that the Connection was obtained from
297:             * (may be <code>null</code>)
298:             * @see #getConnection
299:             */
300:            public static void releaseConnection(Connection con,
301:                    DataSource dataSource) {
302:                try {
303:                    doReleaseConnection(con, dataSource);
304:                } catch (SQLException ex) {
305:                    logger.debug("Could not close JDBC Connection", ex);
306:                } catch (Throwable ex) {
307:                    logger.debug(
308:                            "Unexpected exception on closing JDBC Connection",
309:                            ex);
310:                }
311:            }
312:
313:            /**
314:             * Actually close the given Connection, obtained from the given DataSource.
315:             * Same as {@link #releaseConnection}, but throwing the original SQLException.
316:             * <p>Directly accessed by {@link TransactionAwareDataSourceProxy}.
317:             * @param con the Connection to close if necessary
318:             * (if this is <code>null</code>, the call will be ignored)
319:             * @param dataSource the DataSource that the Connection was obtained from
320:             * (may be <code>null</code>)
321:             * @throws SQLException if thrown by JDBC methods
322:             * @see #doGetConnection
323:             */
324:            public static void doReleaseConnection(Connection con,
325:                    DataSource dataSource) throws SQLException {
326:                if (con == null) {
327:                    return;
328:                }
329:
330:                if (dataSource != null) {
331:                    ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager
332:                            .getResource(dataSource);
333:                    if (conHolder != null && connectionEquals(conHolder, con)) {
334:                        // It's the transactional Connection: Don't close it.
335:                        conHolder.released();
336:                        return;
337:                    }
338:                }
339:
340:                // Leave the Connection open only if the DataSource is our
341:                // special SmartDataSoruce and it wants the Connection left open.
342:                if (!(dataSource instanceof  SmartDataSource)
343:                        || ((SmartDataSource) dataSource).shouldClose(con)) {
344:                    logger.debug("Returning JDBC Connection to DataSource");
345:                    con.close();
346:                }
347:            }
348:
349:            /**
350:             * Determine whether the given two Connections are equal, asking the target
351:             * Connection in case of a proxy. Used to detect equality even if the
352:             * user passed in a raw target Connection while the held one is a proxy.
353:             * @param conHolder the ConnectionHolder for the held Connection (potentially a proxy)
354:             * @param passedInCon the Connection passed-in by the user
355:             * (potentially a target Connection without proxy)
356:             * @return whether the given Connections are equal
357:             * @see #getTargetConnection
358:             */
359:            private static boolean connectionEquals(ConnectionHolder conHolder,
360:                    Connection passedInCon) {
361:                if (!conHolder.hasConnection()) {
362:                    return false;
363:                }
364:                Connection heldCon = conHolder.getConnection();
365:                // Explicitly check for identity too: for Connection handles that do not implement
366:                // "equals" properly, such as the ones Commons DBCP exposes).
367:                return (heldCon == passedInCon || heldCon.equals(passedInCon) || getTargetConnection(
368:                        heldCon).equals(passedInCon));
369:            }
370:
371:            /**
372:             * Return the innermost target Connection of the given Connection. If the given
373:             * Connection is a proxy, it will be unwrapped until a non-proxy Connection is
374:             * found. Else, the passed-in Connection will be returned as-is.
375:             * @param con the Connection proxy to unwrap
376:             * @return the innermost target Connection, or the passed-in one if no proxy
377:             * @see ConnectionProxy#getTargetConnection
378:             */
379:            public static Connection getTargetConnection(Connection con) {
380:                Connection conToUse = con;
381:                while (conToUse instanceof  ConnectionProxy) {
382:                    conToUse = ((ConnectionProxy) conToUse)
383:                            .getTargetConnection();
384:                }
385:                return conToUse;
386:            }
387:
388:            /**
389:             * Determine the connection synchronization order to use for the given
390:             * DataSource. Decreased for every level of nesting that a DataSource
391:             * has, checked through the level of DelegatingDataSource nesting.
392:             * @param dataSource the DataSource to check
393:             * @return the connection synchronization order to use
394:             * @see #CONNECTION_SYNCHRONIZATION_ORDER
395:             */
396:            private static int getConnectionSynchronizationOrder(
397:                    DataSource dataSource) {
398:                int order = CONNECTION_SYNCHRONIZATION_ORDER;
399:                DataSource currDs = dataSource;
400:                while (currDs instanceof  DelegatingDataSource) {
401:                    order--;
402:                    currDs = ((DelegatingDataSource) currDs)
403:                            .getTargetDataSource();
404:                }
405:                return order;
406:            }
407:
408:            /**
409:             * Callback for resource cleanup at the end of a non-native JDBC transaction
410:             * (e.g. when participating in a JtaTransactionManager transaction).
411:             * @see org.springframework.transaction.jta.JtaTransactionManager
412:             */
413:            private static class ConnectionSynchronization extends
414:                    TransactionSynchronizationAdapter {
415:
416:                private final ConnectionHolder connectionHolder;
417:
418:                private final DataSource dataSource;
419:
420:                private int order;
421:
422:                private boolean holderActive = true;
423:
424:                public ConnectionSynchronization(
425:                        ConnectionHolder connectionHolder, DataSource dataSource) {
426:                    this .connectionHolder = connectionHolder;
427:                    this .dataSource = dataSource;
428:                    this .order = getConnectionSynchronizationOrder(dataSource);
429:                }
430:
431:                public int getOrder() {
432:                    return this .order;
433:                }
434:
435:                public void suspend() {
436:                    if (this .holderActive) {
437:                        TransactionSynchronizationManager
438:                                .unbindResource(this .dataSource);
439:                        if (this .connectionHolder.hasConnection()
440:                                && !this .connectionHolder.isOpen()) {
441:                            // Release Connection on suspend if the application doesn't keep
442:                            // a handle to it anymore. We will fetch a fresh Connection if the
443:                            // application accesses the ConnectionHolder again after resume,
444:                            // assuming that it will participate in the same transaction.
445:                            releaseConnection(this .connectionHolder
446:                                    .getConnection(), this .dataSource);
447:                            this .connectionHolder.setConnection(null);
448:                        }
449:                    }
450:                }
451:
452:                public void resume() {
453:                    if (this .holderActive) {
454:                        TransactionSynchronizationManager.bindResource(
455:                                this .dataSource, this .connectionHolder);
456:                    }
457:                }
458:
459:                public void beforeCompletion() {
460:                    // Release Connection early if the holder is not open anymore
461:                    // (that is, not used by another resource like a Hibernate Session
462:                    // that has its own cleanup via transaction synchronization),
463:                    // to avoid issues with strict JTA implementations that expect
464:                    // the close call before transaction completion.
465:                    if (!this .connectionHolder.isOpen()) {
466:                        TransactionSynchronizationManager
467:                                .unbindResource(this .dataSource);
468:                        this .holderActive = false;
469:                        if (this .connectionHolder.hasConnection()) {
470:                            releaseConnection(this .connectionHolder
471:                                    .getConnection(), this .dataSource);
472:                        }
473:                    }
474:                }
475:
476:                public void afterCompletion(int status) {
477:                    // If we haven't closed the Connection in beforeCompletion,
478:                    // close it now. The holder might have been used for other
479:                    // cleanup in the meantime, for example by a Hibernate Session.
480:                    if (this .holderActive) {
481:                        // The thread-bound ConnectionHolder might not be available anymore,
482:                        // since afterCompletion might get called from a different thread.
483:                        if (TransactionSynchronizationManager
484:                                .hasResource(this .dataSource)) {
485:                            TransactionSynchronizationManager
486:                                    .unbindResource(this .dataSource);
487:                        }
488:                        this .holderActive = false;
489:                        if (this .connectionHolder.hasConnection()) {
490:                            releaseConnection(this .connectionHolder
491:                                    .getConnection(), this .dataSource);
492:                            // Reset the ConnectionHolder: It might remain bound to the thread.
493:                            this.connectionHolder.setConnection(null);
494:                        }
495:                        this.connectionHolder.reset();
496:                    }
497:                }
498:            }
499:
500:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.