001: package org.apache.torque.util;
002:
003: /*
004: * Licensed to the Apache Software Foundation (ASF) under one
005: * or more contributor license agreements. See the NOTICE file
006: * distributed with this work for additional information
007: * regarding copyright ownership. The ASF licenses this file
008: * to you under the Apache License, Version 2.0 (the
009: * "License"); you may not use this file except in compliance
010: * with the License. You may obtain a copy of the License at
011: *
012: * http://www.apache.org/licenses/LICENSE-2.0
013: *
014: * Unless required by applicable law or agreed to in writing,
015: * software distributed under the License is distributed on an
016: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017: * KIND, either express or implied. See the License for the
018: * specific language governing permissions and limitations
019: * under the License.
020: */
021:
022: import java.sql.Connection;
023: import java.sql.SQLException;
024:
025: import org.apache.commons.logging.Log;
026: import org.apache.commons.logging.LogFactory;
027:
028: import org.apache.torque.Torque;
029: import org.apache.torque.TorqueException;
030:
031: /**
032: * Refactored begin/commit/rollback transaction methods away from
033: * the <code>BasePeer</code>.
034: *
035: * <p>
036: * This can be used to handle cases where transaction support is optional.
037: * The second parameter of beginOptionalTransaction will determine with a
038: * transaction is used or not.
039: * If a transaction is not used, the commit and rollback methods
040: * do not have any effect. Instead it simply makes the logic easier to follow
041: * by cutting down on the if statements based solely on whether a transaction
042: * is needed or not.
043: *
044: * @author <a href="mailto:stephenh@chase3000.com">Stephen Haberman</a>
045: * @version $Id: Transaction.java 476550 2006-11-18 16:08:37Z tfischer $
046: */
047: public final class Transaction {
048:
049: /** The log. */
050: private static Log log = LogFactory.getLog(Transaction.class);
051:
052: /**
053: * Private constructor to prevent instantiation.
054: *
055: * Class contains only static method ans should therefore not be
056: * instantiated.
057: */
058: private Transaction() {
059: }
060:
061: /**
062: * Begin a transaction for the default database.
063: * This method will fallback gracefully to
064: * return a normal connection, if the database being accessed does
065: * not support transactions.
066: *
067: * @return The Connection for the transaction.
068: * @throws TorqueException Any exceptions caught during processing will be
069: * rethrown wrapped into a TorqueException.
070: */
071: public static Connection begin() throws TorqueException {
072: return Transaction.begin(Torque.getDefaultDB());
073: }
074:
075: /**
076: * Begin a transaction. This method will fallback gracefully to
077: * return a normal connection, if the database being accessed does
078: * not support transactions.
079: *
080: * @param dbName Name of database.
081: * @return The Connection for the transaction.
082: * @throws TorqueException Any exceptions caught during processing will be
083: * rethrown wrapped into a TorqueException.
084: */
085: public static Connection begin(String dbName)
086: throws TorqueException {
087: return Transaction.beginOptional(dbName, true);
088: }
089:
090: /**
091: * Begin a transaction. This method will fallback gracefully to
092: * return a normal connection, if the database being accessed does
093: * not support transactions.
094: *
095: * @param dbName Name of database.
096: * @param useTransaction If false, a transaction won't be used.
097: * @return The Connection for the transaction.
098: * @throws TorqueException Any exceptions caught during processing will be
099: * rethrown wrapped into a TorqueException.
100: */
101: public static Connection beginOptional(String dbName,
102: boolean useTransaction) throws TorqueException {
103: Connection con = Torque.getConnection(dbName);
104: try {
105: if (con.getMetaData().supportsTransactions()
106: && useTransaction) {
107: con.setAutoCommit(false);
108: }
109: } catch (SQLException e) {
110: throw new TorqueException(e);
111: }
112: return con;
113: }
114:
115: /**
116: * Commit a transaction. This method takes care of releasing the
117: * connection after the commit. In databases that do not support
118: * transactions, it only returns the connection.
119: *
120: * @param con The Connection for the transaction.
121: * @throws TorqueException Any exceptions caught during processing will be
122: * rethrown wrapped into a TorqueException.
123: */
124: public static void commit(Connection con) throws TorqueException {
125: if (con == null) {
126: throw new NullPointerException(
127: "Connection object was null. "
128: + "This could be due to a misconfiguration of the "
129: + "DataSourceFactory. Check the logs and Torque.properties "
130: + "to better determine the cause.");
131: }
132:
133: try {
134: if (con.getMetaData().supportsTransactions()
135: && con.getAutoCommit() == false) {
136: con.commit();
137: con.setAutoCommit(true);
138: }
139: } catch (SQLException e) {
140: throw new TorqueException(e);
141: } finally {
142: Torque.closeConnection(con);
143: }
144: }
145:
146: /**
147: * Roll back a transaction in databases that support transactions.
148: * It also releases the connection. In databases that do not support
149: * transactions, this method will log the attempt and release the
150: * connection.
151: *
152: * @param con The Connection for the transaction.
153: * @throws TorqueException Any exceptions caught during processing will be
154: * rethrown wrapped into a TorqueException.
155: */
156: public static void rollback(Connection con) throws TorqueException {
157: if (con == null) {
158: throw new TorqueException(
159: "Connection object was null. "
160: + "This could be due to a misconfiguration of the "
161: + "DataSourceFactory. Check the logs and Torque.properties "
162: + "to better determine the cause.");
163: } else {
164: try {
165: if (con.getMetaData().supportsTransactions()
166: && con.getAutoCommit() == false) {
167: con.rollback();
168: con.setAutoCommit(true);
169: }
170: } catch (SQLException e) {
171: log
172: .error(
173: "An attempt was made to rollback a transaction "
174: + "but the database did not allow the operation to be "
175: + "rolled back.", e);
176: throw new TorqueException(e);
177: } finally {
178: Torque.closeConnection(con);
179: }
180: }
181: }
182:
183: /**
184: * Roll back a transaction without throwing errors if they occur.
185: * A null Connection argument is logged at the debug level and other
186: * errors are logged at warn level.
187: *
188: * @param con The Connection for the transaction.
189: * @see Transaction#rollback(Connection)
190: */
191: public static void safeRollback(Connection con) {
192: if (con == null) {
193: log.debug("called safeRollback with null argument");
194: } else {
195: try {
196: Transaction.rollback(con);
197: } catch (TorqueException e) {
198: log.warn("An error occured during rollback.", e);
199: }
200: }
201: }
202: }
|