001: /*
002: * CoadunationLib: The coaduntion library.
003: * Copyright (C) 2007 Rift IT Contracting
004: *
005: * This library is free software; you can redistribute it and/or
006: * modify it under the terms of the GNU Lesser General Public
007: * License as published by the Free Software Foundation; either
008: * version 2.1 of the License, or (at your option) any later version.
009: *
010: * This library is distributed in the hope that it will be useful,
011: * but WITHOUT ANY WARRANTY; without even the implied warranty of
012: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
013: * Lesser General Public License for more details.
014: *
015: * You should have received a copy of the GNU Lesser General Public
016: * License along with this library; if not, write to the Free Software
017: * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
018: *
019: * UserTransactionWrapper.java
020: */
021:
022: // the package path
023: package com.rift.coad.util.transaction;
024:
025: // java imports
026: import javax.naming.Context;
027: import javax.naming.InitialContext;
028: import javax.transaction.UserTransaction;
029: import javax.transaction.TransactionManager;
030: import javax.transaction.Status;
031:
032: // logging import
033: import org.apache.log4j.Logger;
034:
035: /**
036: * This object is responsible for wrapping the user transaction.
037: *
038: * @author Brett Chaldecott
039: */
040: public class UserTransactionWrapper {
041:
042: /**
043: * This object contains the information about a single transaction.
044: */
045: public class TransactionInfo {
046:
047: // private member variable
048: private boolean ownLock = false;
049: private int lockCount = 0;
050: private boolean committed = false;
051:
052: /**
053: * The constructor of the transaction information object.
054: */
055: public TransactionInfo(boolean ownLock) {
056: this .ownLock = ownLock;
057: }
058:
059: /**
060: * This method returns true if this object owns the lock.
061: *
062: * @return This method returns TRUE if this lock is owned buy this
063: * object.
064: */
065: public boolean getOwnLock() {
066: return ownLock;
067: }
068:
069: /**
070: * This method returns the lock count for this transaction.
071: *
072: * @return The lock value.
073: */
074: public int lock() {
075: return ++lockCount;
076: }
077:
078: /**
079: * This method returns the lock count.
080: *
081: * @return The lock value.
082: */
083: public int unlock() {
084: if (lockCount == 0) {
085: return lockCount;
086: }
087: return --lockCount;
088: }
089:
090: /**
091: * This method returns the lock count for the current transaction.
092: *
093: * @return The current value of the lock count.
094: */
095: public int getLockCount() {
096: return lockCount;
097: }
098:
099: /**
100: * This method returns true if this object is committed.
101: *
102: * @return TRUE if committed, FALSE if not.
103: */
104: public boolean getCommited() {
105: return committed;
106: }
107:
108: /**
109: * This method sets the committed flag to true.
110: *
111: * @exception TransactionException
112: */
113: public void commit() throws TransactionException {
114: try {
115: ut.commit();
116: } catch (java.lang.NullPointerException ex) {
117: log
118: .error(
119: "Failed to commit the changes because of null "
120: + "pointer exception. Assuming cleanup was successfull : "
121: + ex.getMessage(), ex);
122: } catch (Exception ex) {
123:
124: log.error("Failed to commit the changes : "
125: + ex.getMessage(), ex);
126: throw new TransactionException(
127: "Failed to commit the changes : "
128: + ex.getMessage(), ex);
129: } finally {
130: lockCount--;
131: committed = true;
132: }
133:
134: }
135: }
136:
137: // private member variables
138: protected static Logger log = Logger
139: .getLogger(UserTransactionWrapper.class.getName());
140:
141: // private member variables
142: private Context context = null;
143: private UserTransaction ut = null;
144: private TransactionManager transactionManager = null;
145: private ThreadLocal currentTransaction = new ThreadLocal();
146:
147: /**
148: * Creates a new instance of UserTransactionWrapper
149: */
150: public UserTransactionWrapper() throws TransactionException {
151: try {
152: context = new InitialContext();
153: ut = (UserTransaction) context
154: .lookup("java:comp/UserTransaction");
155: } catch (Exception ex) {
156: throw new TransactionException("Failed to instanciate the "
157: + "UserTransactionWrapper because : "
158: + ex.getMessage(), ex);
159: }
160:
161: }
162:
163: /**
164: * This method begins a transaction for a thread, if one is not already
165: * running.
166: *
167: * @exception TransactionException
168: */
169: public void begin() throws TransactionException {
170: try {
171: TransactionInfo trans = (TransactionInfo) currentTransaction
172: .get();
173: if (trans == null) {
174: if (ut.getStatus() == Status.STATUS_NO_TRANSACTION) {
175: ut.begin();
176: trans = new TransactionInfo(true);
177: currentTransaction.set(trans);
178: } else {
179: trans = new TransactionInfo(false);
180: currentTransaction.set(trans);
181: }
182: }
183: trans.lock();
184: } catch (Exception ex) {
185: throw new TransactionException(
186: "Failed to start the transaction : "
187: + ex.getMessage(), ex);
188: }
189: }
190:
191: /**
192: * This method commits the transaction
193: *
194: * @exception TransactionException
195: */
196: public void commit() throws TransactionException {
197: try {
198: TransactionInfo trans = (TransactionInfo) currentTransaction
199: .get();
200: if (trans == null) {
201: throw new TransactionException(
202: "There is no transaction for this thread");
203: } else if (trans.getOwnLock() == false) {
204: log
205: .info("Commit called on transaction not owned by this object");
206: return;
207: } else if (trans.getLockCount() != 1) {
208: throw new TransactionException(
209: "This transaction cannot be commit at this point as "
210: + "there are two many recursions. "
211: + "Must be commit at the top.");
212: }
213: trans.commit();
214: } catch (TransactionException ex) {
215: throw ex;
216: } catch (Exception ex) {
217: throw new TransactionException(
218: "Failed to start the transaction : "
219: + ex.getMessage(), ex);
220: }
221: }
222:
223: /**
224: * This method is called to release a lock on a transaction and will result
225: * in rollback if the transaction is not commited
226: *
227: * @exception TransactionException;
228: */
229: public void release() {
230: try {
231: TransactionInfo trans = (TransactionInfo) currentTransaction
232: .get();
233: if (trans == null) {
234: return;
235: }
236: if ((0 == trans.unlock()) && trans.getOwnLock()
237: && !trans.getCommited()
238: && (ut.getStatus() == Status.STATUS_ACTIVE)) {
239: ut.rollback();
240: }
241: if (trans.getLockCount() == 0) {
242: currentTransaction.set(null);
243: }
244: } catch (Exception ex) {
245: log.error("Failed to release the transaction : "
246: + ex.getMessage(), ex);
247: }
248: }
249:
250: }
|