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.Savepoint;
020:
021: import org.apache.commons.logging.Log;
022: import org.apache.commons.logging.LogFactory;
023:
024: import org.springframework.transaction.CannotCreateTransactionException;
025: import org.springframework.transaction.NestedTransactionNotSupportedException;
026: import org.springframework.transaction.SavepointManager;
027: import org.springframework.transaction.TransactionException;
028: import org.springframework.transaction.TransactionSystemException;
029: import org.springframework.transaction.TransactionUsageException;
030: import org.springframework.transaction.support.SmartTransactionObject;
031: import org.springframework.util.ClassUtils;
032:
033: /**
034: * Convenient base class for JDBC-aware transaction objects.
035: * Can contain a {@link ConnectionHolder}, and implements the
036: * {@link org.springframework.transaction.SavepointManager}
037: * interface based on that ConnectionHolder.
038: *
039: * <p>Allows for programmatic management of JDBC 3.0
040: * {@link java.sql.Savepoint Savepoints}. Spring's
041: * {@link org.springframework.transaction.support.DefaultTransactionStatus}
042: * will automatically delegate to this, as it autodetects transaction
043: * objects that implement the SavepointManager interface.
044: *
045: * <p>Note that savepoints are only supported for drivers which
046: * support JDBC 3.0 or higher.
047: *
048: * @author Juergen Hoeller
049: * @since 1.1
050: */
051: public abstract class JdbcTransactionObjectSupport implements
052: SavepointManager, SmartTransactionObject {
053:
054: private static final Log logger = LogFactory
055: .getLog(JdbcTransactionObjectSupport.class);
056:
057: // Determine whether JDK 1.4's Savepoint interface is available,
058: // indicating that Spring's transaction savepoints are supported.
059: private static boolean savepointClassAvailable = ClassUtils
060: .isPresent("java.sql.Savepoint",
061: JdbcTransactionObjectSupport.class.getClassLoader());
062:
063: private ConnectionHolder connectionHolder;
064:
065: private Integer previousIsolationLevel;
066:
067: private boolean savepointAllowed;
068:
069: public void setConnectionHolder(ConnectionHolder connectionHolder) {
070: this .connectionHolder = connectionHolder;
071: }
072:
073: public ConnectionHolder getConnectionHolder() {
074: return this .connectionHolder;
075: }
076:
077: public boolean hasConnectionHolder() {
078: return (this .connectionHolder != null);
079: }
080:
081: public void setPreviousIsolationLevel(Integer previousIsolationLevel) {
082: this .previousIsolationLevel = previousIsolationLevel;
083: }
084:
085: public Integer getPreviousIsolationLevel() {
086: return this .previousIsolationLevel;
087: }
088:
089: public void setSavepointAllowed(boolean savepointAllowed) {
090: this .savepointAllowed = savepointAllowed;
091: }
092:
093: public boolean isSavepointAllowed() {
094: return this .savepointAllowed;
095: }
096:
097: //---------------------------------------------------------------------
098: // Implementation of SavepointManager
099: //---------------------------------------------------------------------
100:
101: /**
102: * This implementation creates a JDBC 3.0 Savepoint and returns it.
103: * @see java.sql.Connection#setSavepoint
104: */
105: public Object createSavepoint() throws TransactionException {
106: if (!savepointClassAvailable) {
107: throw new NestedTransactionNotSupportedException(
108: "Cannot create a nested JDBC transaction because you are not running on JDK 1.4 or higher");
109: }
110: ConnectionHolder conHolder = getConnectionHolderForSavepoint();
111: try {
112: if (!conHolder.supportsSavepoints()) {
113: throw new NestedTransactionNotSupportedException(
114: "Cannot create a nested transaction because savepoints are not supported by your JDBC driver");
115: }
116: } catch (Throwable ex) {
117: throw new NestedTransactionNotSupportedException(
118: "Cannot create a nested transaction because your JDBC driver is not a JDBC 3.0 driver",
119: ex);
120: }
121: try {
122: return conHolder.createSavepoint();
123: } catch (Throwable ex) {
124: throw new CannotCreateTransactionException(
125: "Could not create JDBC savepoint", ex);
126: }
127: }
128:
129: /**
130: * This implementation rolls back to the given JDBC 3.0 Savepoint.
131: * @see java.sql.Connection#rollback(java.sql.Savepoint)
132: */
133: public void rollbackToSavepoint(Object savepoint)
134: throws TransactionException {
135: try {
136: getConnectionHolderForSavepoint().getConnection().rollback(
137: (Savepoint) savepoint);
138: } catch (Throwable ex) {
139: throw new TransactionSystemException(
140: "Could not roll back to JDBC savepoint", ex);
141: }
142: }
143:
144: /**
145: * This implementation releases the given JDBC 3.0 Savepoint.
146: * @see java.sql.Connection#releaseSavepoint
147: */
148: public void releaseSavepoint(Object savepoint)
149: throws TransactionException {
150: try {
151: getConnectionHolderForSavepoint().getConnection()
152: .releaseSavepoint((Savepoint) savepoint);
153: } catch (Throwable ex) {
154: logger.debug("Could not explicitly release JDBC savepoint",
155: ex);
156: }
157: }
158:
159: protected ConnectionHolder getConnectionHolderForSavepoint()
160: throws TransactionException {
161: if (!isSavepointAllowed()) {
162: throw new NestedTransactionNotSupportedException(
163: "Transaction manager does not allow nested transactions");
164: }
165: if (!hasConnectionHolder()) {
166: throw new TransactionUsageException(
167: "Cannot create nested transaction if not exposing a JDBC transaction");
168: }
169: return getConnectionHolder();
170: }
171:
172: }
|