001: /* ====================================================================
002: * The LateralNZ Software License, Version 1.0
003: *
004: * Copyright (c) 2003 LateralNZ. All rights reserved.
005: *
006: * Redistribution and use in source and binary forms, with or without
007: * modification, are permitted provided that the following conditions
008: * are met:
009: *
010: * 1. Redistributions of source code must retain the above copyright
011: * notice, this list of conditions and the following disclaimer.
012: *
013: * 2. Redistributions in binary form must reproduce the above copyright
014: * notice, this list of conditions and the following disclaimer in
015: * the documentation and/or other materials provided with the
016: * distribution.
017: *
018: * 3. The end-user documentation included with the redistribution,
019: * if any, must include the following acknowledgment:
020: * "This product includes software developed by
021: * LateralNZ (http://www.lateralnz.org/) and other third parties."
022: * Alternately, this acknowledgment may appear in the software itself,
023: * if and wherever such third-party acknowledgments normally appear.
024: *
025: * 4. The names "LateralNZ" must not be used to endorse or promote
026: * products derived from this software without prior written
027: * permission. For written permission, please
028: * contact oss@lateralnz.org.
029: *
030: * 5. Products derived from this software may not be called "Panther",
031: * or "Lateral" or "LateralNZ", nor may "PANTHER" or "LATERAL" or
032: * "LATERALNZ" appear in their name, without prior written
033: * permission of LateralNZ.
034: *
035: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
036: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
037: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
038: * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
039: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
040: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
041: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
042: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
043: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
044: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
045: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
046: * SUCH DAMAGE.
047: * ====================================================================
048: *
049: * This software consists of voluntary contributions made by many
050: * individuals on behalf of LateralNZ. For more
051: * information on Lateral, please see http://www.lateralnz.com/ or
052: * http://www.lateralnz.org
053: *
054: */
055: package org.lateralnz.simpletrans;
056:
057: import java.io.Serializable;
058: import javax.naming.Reference;
059: import javax.naming.Referenceable;
060: import javax.transaction.HeuristicMixedException;
061: import javax.transaction.HeuristicRollbackException;
062: import javax.transaction.RollbackException;
063: import javax.transaction.Status;
064: import javax.transaction.SystemException;
065: import javax.transaction.Transaction;
066: import javax.transaction.TransactionManager;
067: import javax.transaction.UserTransaction;
068:
069: import org.apache.log4j.Logger;
070:
071: /**
072: * a singleton implementation of a transaction manager, using thread-local variables to store
073: * the current transaction.
074: *
075: * @author J R Briggs
076: */
077: public class SimpleTransactionManager implements TransactionManager,
078: UserTransaction, Serializable, Referenceable {
079: private static final Logger log = Logger
080: .getLogger(SimpleTransactionManager.class.getName());
081: private static Reference REF = new Reference(
082: SimpleTransactionManager.class.getName());
083: private static final SimpleTransactionManager stm = new SimpleTransactionManager();
084:
085: private static final Boolean FALSE = new Boolean(false);
086: private static final Boolean TRUE = new Boolean(true);
087:
088: private static ThreadLocal IN_TRANS = new ThreadLocal() {
089: protected Object initialValue() {
090: return FALSE;
091: }
092: };
093:
094: private static ThreadLocal TRANS = new ThreadLocal() {
095: protected Object initialValue() {
096: return new SimpleTransaction();
097: }
098: };
099:
100: public static final SimpleTransactionManager getTransactionManager() {
101: return stm;
102: }
103:
104: public Reference getReference() {
105: return REF;
106: }
107:
108: /**
109: * begin a transaction. This method differs from that specified by the TransactionManager
110: * interface, in that it doesn't throw an exception if the current thread is already in
111: * a transaction -- and it doesn't create a nested transaction. This basically
112: * assumes that everything will run in the current transaction.
113: */
114: public void begin() {
115: if (!isInTransaction()) {
116: IN_TRANS.set(TRUE);
117: Transaction t = new SimpleTransaction();
118: TRANS.set(t);
119: if (log.isDebugEnabled()) {
120: log.debug("started new transaction " + t);
121: }
122: } else if (log.isDebugEnabled()) {
123: log.debug("new transaction not started, already in trans");
124: }
125: }
126:
127: /**
128: * commit the current transaction (note: this doesn't throw an error if the
129: * current thread is not in a transaction)
130: */
131: public void commit() throws RollbackException,
132: HeuristicMixedException, HeuristicRollbackException,
133: SystemException {
134: if (isInTransaction()) {
135: Transaction trans = (Transaction) TRANS.get();
136: trans.commit();
137: TRANS.set(null);
138: IN_TRANS.set(FALSE);
139: if (log.isDebugEnabled()) {
140: log.debug("committed transaction " + trans);
141: }
142: } else if (log.isDebugEnabled()) {
143: log.debug("not in transaction, no commit");
144: }
145: }
146:
147: /**
148: * get the status of the current transaction
149: */
150: public int getStatus() throws SystemException {
151: if (isInTransaction()) {
152: Transaction trans = (Transaction) TRANS.get();
153: return trans.getStatus();
154: } else {
155: return Status.STATUS_NO_TRANSACTION;
156: }
157: }
158:
159: /**
160: * get the transaction for the current (calling) thread
161: */
162: public Transaction getTransaction() {
163: if (isInTransaction()) {
164: return (Transaction) TRANS.get();
165: } else {
166: return null;
167: }
168: }
169:
170: /**
171: * not supported
172: */
173: public void resume(Transaction transaction) {
174: throw new UnsupportedOperationException();
175: }
176:
177: /**
178: * rollback the current transaction (note: this doesn't throw an error if the
179: * current thread is not in a transaction)
180: */
181: public void rollback() throws SystemException {
182: if (isInTransaction()) {
183: Transaction trans = (Transaction) TRANS.get();
184: trans.rollback();
185: TRANS.set(null);
186: IN_TRANS.set(FALSE);
187: if (log.isDebugEnabled()) {
188: log.debug("rolled back transaction");
189: }
190: } else if (log.isDebugEnabled()) {
191: log.debug("not in transaction, no commit");
192: }
193: }
194:
195: /**
196: * flag the current transaction for rollback (note: this doesn't throw an error
197: * if the current thread is not in a transaction)
198: */
199: public void setRollbackOnly() throws SystemException {
200: if (isInTransaction()) {
201: Transaction trans = (Transaction) TRANS.get();
202: trans.setRollbackOnly();
203: }
204: }
205:
206: /**
207: * not supported
208: */
209: public void setTransactionTimeout(int param) {
210: throw new UnsupportedOperationException();
211: }
212:
213: /**
214: * not supported
215: */
216: public Transaction suspend() {
217: throw new UnsupportedOperationException();
218: }
219:
220: /**
221: * a helper function to indicate if the calling thread is in a transaction
222: */
223: protected boolean isInTransaction() {
224: Boolean b = (Boolean) IN_TRANS.get();
225: if (b.booleanValue()) {
226: Transaction trans = (Transaction) TRANS.get();
227: try {
228: if (trans != null
229: && trans.getStatus() != Status.STATUS_NO_TRANSACTION
230: && trans.getStatus() != Status.STATUS_UNKNOWN) {
231: return true;
232: }
233: } catch (Exception e) {
234: e.printStackTrace();
235: }
236: }
237: return false;
238: }
239:
240: }
|