KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > ofbiz > entity > transaction > TransactionUtil


1 /*
2  * $Id: TransactionUtil.java 6778 2006-02-20 05:13:55Z jonesde $
3  *
4  * Copyright 2001-2006 The Apache Software Foundation
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
7  * use this file except in compliance with the License. You may obtain a copy of
8  * the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15  * License for the specific language governing permissions and limitations
16  * under the License.
17  */

18 package org.ofbiz.entity.transaction;
19
20 import java.sql.Connection JavaDoc;
21 import java.sql.SQLException JavaDoc;
22 import java.sql.Timestamp JavaDoc;
23 import java.util.HashMap JavaDoc;
24 import java.util.Iterator JavaDoc;
25 import java.util.LinkedList JavaDoc;
26 import java.util.List JavaDoc;
27 import java.util.Map JavaDoc;
28 import javax.sql.XAConnection JavaDoc;
29 import javax.transaction.*;
30 import javax.transaction.xa.XAException JavaDoc;
31 import javax.transaction.xa.XAResource JavaDoc;
32
33 import org.ofbiz.base.util.Debug;
34 import org.ofbiz.base.util.UtilDateTime;
35 import org.ofbiz.base.util.UtilValidate;
36
37 /**
38  * <p>Transaction Utility to help with some common transaction tasks
39  * <p>Provides a wrapper around the transaction objects to allow for changes in underlying implementations in the future.
40  *
41  * @author <a HREF="mailto:jonesde@ofbiz.org">David E. Jones</a>
42  * @version $Rev: 6778 $
43  * @since 2.0
44  */

45 public class TransactionUtil implements Status {
46     // Debug module name
47
public static final String JavaDoc module = TransactionUtil.class.getName();
48     public static Map JavaDoc debugResMap = new HashMap JavaDoc();
49     public static boolean debugResources = true;
50
51     /** Begins a transaction in the current thread IF transactions are available; only
52      * tries if the current transaction status is ACTIVE, if not active it returns false.
53      * If and on only if it begins a transaction it will return true. In other words, if
54      * a transaction is already in place it will return false and do nothing.
55      */

56     public static boolean begin() throws GenericTransactionException {
57         return begin(0);
58     }
59
60     /** Begins a transaction in the current thread IF transactions are available; only
61      * tries if the current transaction status is ACTIVE, if not active it returns false.
62      * If and on only if it begins a transaction it will return true. In other words, if
63      * a transaction is already in place it will return false and do nothing.
64      */

65     public static synchronized boolean begin(int timeout) throws GenericTransactionException {
66         UserTransaction ut = TransactionFactory.getUserTransaction();
67         if (ut != null) {
68             try {
69                 int currentStatus = ut.getStatus();
70                 Debug.logVerbose("[TransactionUtil.begin] current status : " + getTransactionStateString(currentStatus), module);
71                 if (currentStatus == Status.STATUS_ACTIVE) {
72                     Debug.logVerbose("[TransactionUtil.begin] active transaction in place, so no transaction begun", module);
73                     return false;
74                 } else if (currentStatus == Status.STATUS_MARKED_ROLLBACK) {
75                     Exception JavaDoc e = getTransactionBeginStack();
76                     if (e != null) {
77                         Debug.logWarning(e, "[TransactionUtil.begin] active transaction marked for rollback in place, so no transaction begun; this stack trace shows when the exception began: ", module);
78                     } else {
79                         Debug.logWarning("[TransactionUtil.begin] active transaction marked for rollback in place, so no transaction begun", module);
80                     }
81
82                     RollbackOnlyCause roc = getSetRollbackOnlyCause();
83                     // do we have a cause? if so, throw special exception
84
if (roc != null && !roc.isEmpty()) {
85                         throw new GenericTransactionException("The current transaction is marked for rollback, not beginning a new transaction and aborting current operation; the rollbackOnly was caused by: " + roc.getCauseMessage(), roc.getCauseThrowable());
86                     } else {
87                         return false;
88                     }
89                 }
90
91                 // set the timeout for THIS transaction
92
if (timeout > 0) {
93                     ut.setTransactionTimeout(timeout);
94                     Debug.logVerbose("[TransactionUtil.begin] set transaction timeout to : " + timeout + " seconds", module);
95                 }
96
97                 // begin the transaction
98
ut.begin();
99                 Debug.logVerbose("[TransactionUtil.begin] transaction begun", module);
100
101                 // reset the timeout to the default
102
if (timeout > 0) {
103                     ut.setTransactionTimeout(0);
104                 }
105
106                 // reset the transaction stamps, just in case...
107
clearTransactionStamps();
108                 // initialize the start stamp
109
getTransactionStartStamp();
110                 // set the tx begin stack placeholder
111
setTransactionBeginStack();
112
113                 // initialize the debug resource
114
if (debugResources) {
115                     DebugXaResource dxa = new DebugXaResource();
116                     try {
117                         dxa.enlist();
118                     } catch (XAException JavaDoc e) {
119                         Debug.logError(e, module);
120                     }
121                 }
122
123                 return true;
124             } catch (NotSupportedException e) {
125                 //This is Java 1.4 only, but useful for certain debuggins: Throwable t = e.getCause() == null ? e : e.getCause();
126
throw new GenericTransactionException("Not Supported error, could not begin transaction (probably a nesting problem)", e);
127             } catch (SystemException e) {
128                 //This is Java 1.4 only, but useful for certain debuggins: Throwable t = e.getCause() == null ? e : e.getCause();
129
throw new GenericTransactionException("System error, could not begin transaction", e);
130             }
131         } else {
132             Debug.logInfo("[TransactionUtil.begin] no user transaction, so no transaction begun", module);
133             return false;
134         }
135     }
136
137     /** Gets the status of the transaction in the current thread IF
138      * transactions are available, otherwise returns STATUS_NO_TRANSACTION */

139     public static int getStatus() throws GenericTransactionException {
140         UserTransaction ut = TransactionFactory.getUserTransaction();
141         if (ut != null) {
142             try {
143                 return ut.getStatus();
144             } catch (SystemException e) {
145                 throw new GenericTransactionException("System error, could not get status", e);
146             }
147         } else {
148             return STATUS_NO_TRANSACTION;
149         }
150     }
151
152     public static boolean isTransactionInPlace() throws GenericTransactionException {
153         int status = getStatus();
154         if (status == STATUS_NO_TRANSACTION) {
155             return false;
156         } else {
157             return true;
158         }
159     }
160
161
162     /** Commits the transaction in the current thread IF transactions are available
163      * AND if beganTransaction is true
164      */

165     public static void commit(boolean beganTransaction) throws GenericTransactionException {
166         if (beganTransaction) {
167             TransactionUtil.commit();
168         }
169     }
170
171     /** Commits the transaction in the current thread IF transactions are available */
172     public static void commit() throws GenericTransactionException {
173         UserTransaction ut = TransactionFactory.getUserTransaction();
174
175         if (ut != null) {
176             try {
177                 int status = ut.getStatus();
178                 Debug.logVerbose("[TransactionUtil.commit] current status : " + getTransactionStateString(status), module);
179
180                 if (status != STATUS_NO_TRANSACTION) {
181                     ut.commit();
182
183                     // clear out the stamps to keep it clean
184
clearTransactionStamps();
185                     // clear out the stack too
186
clearTransactionBeginStack();
187                     clearSetRollbackOnlyCause();
188
189                     Debug.logVerbose("[TransactionUtil.commit] transaction committed", module);
190                 } else {
191                     Debug.logInfo("[TransactionUtil.commit] Not committing transaction, status is STATUS_NO_TRANSACTION", module);
192                 }
193             } catch (RollbackException e) {
194                 RollbackOnlyCause rollbackOnlyCause = getSetRollbackOnlyCause();
195
196                 if (rollbackOnlyCause != null) {
197                     // the transaction is now definitely over, so clear stuff as normal now that we have the info from it that we want
198
clearTransactionStamps();
199                     clearTransactionBeginStack();
200                     clearSetRollbackOnlyCause();
201                     
202                     Debug.logError(e, "Rollback Only was set when trying to commit transaction here; throwing rollbackOnly cause exception", module);
203                     throw new GenericTransactionException("Roll back error, could not commit transaction, was rolled back instead because of: " + rollbackOnlyCause.getCauseMessage(), rollbackOnlyCause.getCauseThrowable());
204                 } else {
205                     Throwable JavaDoc t = e.getCause() == null ? e : e.getCause();
206                     throw new GenericTransactionException("Roll back error (with no rollbackOnly cause found), could not commit transaction, was rolled back instead: " + t.toString(), t);
207                 }
208             } catch (HeuristicMixedException e) {
209                 Throwable JavaDoc t = e.getCause() == null ? e : e.getCause();
210                 throw new GenericTransactionException("Could not commit transaction, HeuristicMixed exception: " + t.toString(), t);
211             } catch (HeuristicRollbackException e) {
212                 Throwable JavaDoc t = e.getCause() == null ? e : e.getCause();
213                 throw new GenericTransactionException("Could not commit transaction, HeuristicRollback exception: " + t.toString(), t);
214             } catch (SystemException e) {
215                 Throwable JavaDoc t = e.getCause() == null ? e : e.getCause();
216                 throw new GenericTransactionException("System error, could not commit transaction: " + t.toString(), t);
217             }
218         } else {
219             Debug.logInfo("[TransactionUtil.commit] UserTransaction is null, not commiting", module);
220         }
221     }
222
223     /** @deprecated */
224     public static void rollback(boolean beganTransaction) throws GenericTransactionException {
225         Debug.logWarning("WARNING: called rollback without debug/error info; it is recommended to always pass this to make otherwise tricky bugs much easier to track down.", module);
226         rollback(beganTransaction, null, null);
227     }
228     
229     /** Rolls back transaction in the current thread IF transactions are available
230      * AND if beganTransaction is true; if beganTransaction is not true,
231      * setRollbackOnly is called to insure that the transaction will be rolled back
232      */

233     public static void rollback(boolean beganTransaction, String JavaDoc causeMessage, Throwable JavaDoc causeThrowable) throws GenericTransactionException {
234         if (beganTransaction) {
235             TransactionUtil.rollback();
236         } else {
237             TransactionUtil.setRollbackOnly(causeMessage, causeThrowable);
238         }
239     }
240
241     /** Rolls back transaction in the current thread IF transactions are available */
242     public static void rollback() throws GenericTransactionException {
243         UserTransaction ut = TransactionFactory.getUserTransaction();
244
245         if (ut != null) {
246             try {
247                 int status = ut.getStatus();
248                 Debug.logVerbose("[TransactionUtil.rollback] current status : " + getTransactionStateString(status), module);
249
250                 if (status != STATUS_NO_TRANSACTION) {
251                     //if (Debug.infoOn()) Thread.dumpStack();
252
if (Debug.infoOn()) {
253                         Exception JavaDoc newE = new Exception JavaDoc("Stack Trace");
254                         Debug.logError(newE, "[TransactionUtil.rollback]", module);
255                     }
256
257                     // clear out the stamps to keep it clean
258
clearTransactionStamps();
259                     // clear out the stack too
260
clearTransactionBeginStack();
261                     clearSetRollbackOnlyCause();
262
263                     ut.rollback();
264                     Debug.logInfo("[TransactionUtil.rollback] transaction rolled back", module);
265                 } else {
266                     Debug.logInfo("[TransactionUtil.rollback] transaction not rolled back, status is STATUS_NO_TRANSACTION", module);
267                 }
268             } catch (SystemException e) {
269                 //This is Java 1.4 only, but useful for certain debuggins: Throwable t = e.getCause() == null ? e : e.getCause();
270
throw new GenericTransactionException("System error, could not rollback transaction", e);
271             }
272         } else {
273             Debug.logInfo("[TransactionUtil.rollback] No UserTransaction, transaction not rolled back", module);
274         }
275     }
276
277     /** Makes a rollback the only possible outcome of the transaction in the current thread IF transactions are available */
278     public static void setRollbackOnly(String JavaDoc causeMessage, Throwable JavaDoc causeThrowable) throws GenericTransactionException {
279         UserTransaction ut = TransactionFactory.getUserTransaction();
280         if (ut != null) {
281             try {
282                 int status = ut.getStatus();
283                 Debug.logVerbose("[TransactionUtil.setRollbackOnly] current code : " + getTransactionStateString(status), module);
284
285                 if (status != STATUS_NO_TRANSACTION) {
286                     if (status != STATUS_MARKED_ROLLBACK) {
287                         if (Debug.warningOn()) Debug.logWarning(new Exception JavaDoc(causeMessage), "[TransactionUtil.setRollbackOnly] Calling transaction setRollbackOnly; this stack trace shows where this is happening:", module);
288                         ut.setRollbackOnly();
289                         setSetRollbackOnlyCause(causeMessage, causeThrowable);
290                     } else {
291                         Debug.logInfo("[TransactionUtil.setRollbackOnly] transaction rollback only not set, rollback only is already set.", module);
292                     }
293                 } else {
294                     Debug.logInfo("[TransactionUtil.setRollbackOnly] transaction rollback only not set, status is STATUS_NO_TRANSACTION", module);
295                 }
296             } catch (SystemException e) {
297                 //This is Java 1.4 only, but useful for certain debuggins: Throwable t = e.getCause() == null ? e : e.getCause();
298
throw new GenericTransactionException("System error, could not set rollback only on transaction", e);
299             }
300         } else {
301             Debug.logInfo("[TransactionUtil.setRollbackOnly] No UserTransaction, transaction rollback only not set", module);
302         }
303     }
304
305     public static Transaction suspend() throws GenericTransactionException {
306         try {
307             if (TransactionUtil.getStatus() == TransactionUtil.STATUS_ACTIVE) {
308                 TransactionManager txMgr = TransactionFactory.getTransactionManager();
309                 if (txMgr != null ) {
310                     pushTransactionBeginStackSave(clearTransactionBeginStack());
311                     pushSetRollbackOnlyCauseSave(clearSetRollbackOnlyCause());
312                     Transaction trans = txMgr.suspend();
313                     pushSuspendedTransaction(trans);
314                     return trans;
315                 } else {
316                     return null;
317                 }
318             } else {
319                 Debug.logWarning("No transaction active, so not suspending.", module);
320                 return null;
321             }
322         } catch (SystemException e) {
323             throw new GenericTransactionException("System error, could not suspend transaction", e);
324         }
325     }
326
327     public static void resume(Transaction parentTx) throws GenericTransactionException {
328         if (parentTx == null) return;
329         try {
330             TransactionManager txMgr = TransactionFactory.getTransactionManager();
331             if (txMgr != null ) {
332                 setTransactionBeginStack(popTransactionBeginStackSave());
333                 setSetRollbackOnlyCause(popSetRollbackOnlyCauseSave());
334                 txMgr.resume(parentTx);
335                 removeSuspendedTransaction(parentTx);
336             }
337         } catch (InvalidTransactionException e) {
338             /* NOTE: uncomment this for Weblogic Application Server
339             // this is a work-around for non-standard Weblogic functionality; for more information see: http://www.onjava.com/pub/a/onjava/2005/07/20/transactions.html?page=3
340             if (parentTx instanceof weblogic.transaction.ClientTransactionManager) {
341                 // WebLogic 8 and above
342                 ((weblogic.transaction.ClientTransactionManager) parentTx).forceResume(transaction);
343             } else if (parentTx instanceof weblogic.transaction.TransactionManager) {
344                 // WebLogic 7
345                 ((weblogic.transaction.TransactionManager) parentTx).forceResume(transaction);
346             } else {
347                 throw new GenericTransactionException("System error, could not resume transaction", e);
348             }
349             */

350             throw new GenericTransactionException("System error, could not resume transaction", e);
351         } catch (SystemException e) {
352             throw new GenericTransactionException("System error, could not resume transaction", e);
353         }
354     }
355
356     /** Sets the timeout of the transaction in the current thread IF transactions are available */
357     public static void setTransactionTimeout(int seconds) throws GenericTransactionException {
358         UserTransaction ut = TransactionFactory.getUserTransaction();
359         if (ut != null) {
360             try {
361                 ut.setTransactionTimeout(seconds);
362             } catch (SystemException e) {
363                 throw new GenericTransactionException("System error, could not set transaction timeout", e);
364             }
365         }
366     }
367
368     /** Enlists the given XAConnection and if a transaction is active in the current thread, returns a plain JDBC Connection */
369     public static Connection JavaDoc enlistConnection(XAConnection JavaDoc xacon) throws GenericTransactionException {
370         if (xacon == null) {
371             return null;
372         }
373         try {
374             XAResource JavaDoc resource = xacon.getXAResource();
375             TransactionUtil.enlistResource(resource);
376             return xacon.getConnection();
377         } catch (SQLException JavaDoc e) {
378             throw new GenericTransactionException("SQL error, could not enlist connection in transaction even though transactions are available", e);
379         }
380     }
381
382     public static void enlistResource(XAResource JavaDoc resource) throws GenericTransactionException {
383         if (resource == null) {
384             return;
385         }
386
387         try {
388             TransactionManager tm = TransactionFactory.getTransactionManager();
389             if (tm != null && tm.getStatus() == STATUS_ACTIVE) {
390                 Transaction tx = tm.getTransaction();
391                 if (tx != null) {
392                      tx.enlistResource(resource);
393                 }
394             }
395         } catch (RollbackException e) {
396             //This is Java 1.4 only, but useful for certain debuggins: Throwable t = e.getCause() == null ? e : e.getCause();
397
throw new GenericTransactionException("Roll Back error, could not enlist resource in transaction even though transactions are available, current transaction rolled back", e);
398         } catch (SystemException e) {
399             //This is Java 1.4 only, but useful for certain debuggins: Throwable t = e.getCause() == null ? e : e.getCause();
400
throw new GenericTransactionException("System error, could not enlist resource in transaction even though transactions are available", e);
401         }
402     }
403
404     public static String JavaDoc getTransactionStateString(int state) {
405         switch (state) {
406             case Status.STATUS_ACTIVE:
407                 return "Transaction Active (" + state + ")";
408             case Status.STATUS_COMMITTED:
409                 return "Transaction Committed (" + state + ")";
410             case Status.STATUS_COMMITTING:
411                 return "Transaction Committing (" + state + ")";
412             case Status.STATUS_MARKED_ROLLBACK:
413                 return "Transaction Marked Rollback (" + state + ")";
414             case Status.STATUS_NO_TRANSACTION:
415                 return "No Transaction (" + state + ")";
416             case Status.STATUS_PREPARED:
417                 return "Transaction Prepared (" + state + ")";
418             case Status.STATUS_PREPARING:
419                 return "Transaction Preparing (" + state + ")";
420             case Status.STATUS_ROLLEDBACK:
421                 return "Transaction Rolledback (" + state + ")";
422             case Status.STATUS_ROLLING_BACK:
423                 return "Transaction Rolling Back (" + state + ")";
424             case Status.STATUS_UNKNOWN:
425                 return "Transaction Status Unknown (" + state + ")";
426             default:
427                 return "Not a valid state code (" + state + ")";
428         }
429     }
430
431     public static void logRunningTx() {
432         if (debugResources) {
433             if (debugResMap != null && debugResMap.size() > 0) {
434                 Iterator JavaDoc i = debugResMap.keySet().iterator();
435                 while (i.hasNext()) {
436                     Object JavaDoc o = i.next();
437                     DebugXaResource dxa = (DebugXaResource) debugResMap.get(o);
438                     dxa.log();
439                 }
440             }
441         }
442     }
443
444     public static void registerSynchronization(Synchronization sync) throws GenericTransactionException {
445         if (sync == null) {
446             return;
447         }
448
449         try {
450             TransactionManager tm = TransactionFactory.getTransactionManager();
451             if (tm != null && tm.getStatus() == STATUS_ACTIVE) {
452                 Transaction tx = tm.getTransaction();
453                 if (tx != null) {
454                     tx.registerSynchronization(sync);
455                 }
456             }
457         } catch (RollbackException e) {
458             //This is Java 1.4 only, but useful for certain debuggins: Throwable t = e.getCause() == null ? e : e.getCause();
459
throw new GenericTransactionException("Roll Back error, could not register synchronization in transaction even though transactions are available, current transaction rolled back", e);
460         } catch (SystemException e) {
461             //This is Java 1.4 only, but useful for certain debuggins: Throwable t = e.getCause() == null ? e : e.getCause();
462
throw new GenericTransactionException("System error, could not register synchronization in transaction even though transactions are available", e);
463         }
464     }
465
466     // =======================================
467
// =======================================
468
private static ThreadLocal JavaDoc suspendedTxStack = new ThreadLocal JavaDoc();
469
470     /** BE VERY CARFUL WHERE YOU CALL THIS!! */
471     public static int cleanSuspendedTransactions() throws GenericTransactionException {
472         Transaction trans = null;
473         int num = 0;
474         while ((trans = popSuspendedTransaction()) != null) {
475             resume(trans);
476             rollback();
477             num++;
478         }
479         return num;
480     }
481     public static boolean suspendedTransactionsHeld() {
482         List JavaDoc tl = (List JavaDoc) suspendedTxStack.get();
483         if (tl != null && tl.size() > 0) {
484             return true;
485         } else {
486             return false;
487         }
488     }
489     protected static void pushSuspendedTransaction(Transaction t) {
490         List JavaDoc tl = (List JavaDoc) suspendedTxStack.get();
491         if (tl == null) {
492             tl = new LinkedList JavaDoc();
493             suspendedTxStack.set(tl);
494         }
495         tl.add(0, t);
496     }
497     protected static Transaction popSuspendedTransaction() {
498         List JavaDoc tl = (List JavaDoc) suspendedTxStack.get();
499         if (tl != null && tl.size() > 0) {
500             return (Transaction) tl.remove(0);
501         } else {
502             return null;
503         }
504     }
505     protected static void removeSuspendedTransaction(Transaction t) {
506         List JavaDoc tl = (List JavaDoc) suspendedTxStack.get();
507         if (tl != null && tl.size() > 0) {
508             tl.remove(t);
509         }
510     }
511
512     // =======================================
513
// =======================================
514
private static ThreadLocal JavaDoc transactionBeginStack = new ThreadLocal JavaDoc();
515     private static ThreadLocal JavaDoc transactionBeginStackSave = new ThreadLocal JavaDoc();
516
517     private static void pushTransactionBeginStackSave(Exception JavaDoc e) {
518         List JavaDoc el = (List JavaDoc) transactionBeginStackSave.get();
519         if (el == null) {
520             el = new LinkedList JavaDoc();
521             transactionBeginStackSave.set(el);
522         }
523         el.add(0, e);
524     }
525     private static Exception JavaDoc popTransactionBeginStackSave() {
526         List JavaDoc el = (List JavaDoc) transactionBeginStackSave.get();
527         if (el != null && el.size() > 0) {
528             return (Exception JavaDoc) el.remove(0);
529         } else {
530             return null;
531         }
532     }
533
534     private static void setTransactionBeginStack() {
535         Exception JavaDoc e = new Exception JavaDoc("Tx Stack Placeholder");
536         setTransactionBeginStack(e);
537     }
538     private static void setTransactionBeginStack(Exception JavaDoc newExc) {
539         if (transactionBeginStack.get() != null) {
540             Exception JavaDoc e = (Exception JavaDoc) transactionBeginStack.get();
541             Debug.logWarning(e, "WARNING: In setTransactionBeginStack a stack placeholder was already in place, here is where the transaction began: ", module);
542             Exception JavaDoc e2 = new Exception JavaDoc("Current Stack Trace");
543             Debug.logWarning(e2, "WARNING: In setTransactionBeginStack a stack placeholder was already in place, here is the current location: ", module);
544         }
545         transactionBeginStack.set(newExc);
546     }
547     private static Exception JavaDoc clearTransactionBeginStack() {
548         Exception JavaDoc e = (Exception JavaDoc) transactionBeginStack.get();
549         if (e == null) {
550             Exception JavaDoc e2 = new Exception JavaDoc("Current Stack Trace");
551             Debug.logWarning(e2, "WARNING: In clearTransactionBeginStack no stack placeholder was in place, here is the current location: ", module);
552             return null;
553         } else {
554             transactionBeginStack.set(null);
555             return e;
556         }
557     }
558     public static Exception JavaDoc getTransactionBeginStack() {
559         Exception JavaDoc e = (Exception JavaDoc) transactionBeginStack.get();
560         if (e == null) {
561             Exception JavaDoc e2 = new Exception JavaDoc("Current Stack Trace");
562             Debug.logWarning(e2, "WARNING: In getTransactionBeginStack no stack placeholder was in place, here is the current location: ", module);
563         }
564         return e;
565     }
566
567     // =======================================
568
// =======================================
569
private static class RollbackOnlyCause {
570         protected String JavaDoc causeMessage;
571         protected Throwable JavaDoc causeThrowable;
572         public RollbackOnlyCause(String JavaDoc causeMessage, Throwable JavaDoc causeThrowable) {
573             this.causeMessage = causeMessage;
574             this.causeThrowable = causeThrowable;
575         }
576         public String JavaDoc getCauseMessage() { return this.causeMessage + (this.causeThrowable == null ? "" : this.causeThrowable.toString()); }
577         public Throwable JavaDoc getCauseThrowable() { return this.causeThrowable; }
578         public void logError(String JavaDoc message) { Debug.logError(this.getCauseThrowable(), (message == null ? "" : message) + this.getCauseMessage(), module); }
579         public boolean isEmpty() { return (UtilValidate.isEmpty(this.getCauseMessage()) && this.getCauseThrowable() == null); }
580     }
581     
582     private static ThreadLocal JavaDoc setRollbackOnlyCause = new ThreadLocal JavaDoc();
583     private static ThreadLocal JavaDoc setRollbackOnlyCauseSave = new ThreadLocal JavaDoc();
584
585     private static void pushSetRollbackOnlyCauseSave(RollbackOnlyCause e) {
586         List JavaDoc el = (List JavaDoc) setRollbackOnlyCauseSave.get();
587         if (el == null) {
588             el = new LinkedList JavaDoc();
589             setRollbackOnlyCauseSave.set(el);
590         }
591         el.add(0, e);
592     }
593     private static RollbackOnlyCause popSetRollbackOnlyCauseSave() {
594         List JavaDoc el = (List JavaDoc) setRollbackOnlyCauseSave.get();
595         if (el != null && el.size() > 0) {
596             return (RollbackOnlyCause) el.remove(0);
597         } else {
598             return null;
599         }
600     }
601
602     private static void setSetRollbackOnlyCause(String JavaDoc causeMessage, Throwable JavaDoc causeThrowable) {
603         RollbackOnlyCause roc = new RollbackOnlyCause(causeMessage, causeThrowable);
604         setSetRollbackOnlyCause(roc);
605     }
606     private static void setSetRollbackOnlyCause(RollbackOnlyCause newRoc) {
607         if (setRollbackOnlyCause.get() != null) {
608             RollbackOnlyCause roc = (RollbackOnlyCause) setRollbackOnlyCause.get();
609             roc.logError("WARNING: In setSetRollbackOnlyCause a stack placeholder was already in place, here is the original rollbackOnly cause: ");
610             Exception JavaDoc e2 = new Exception JavaDoc("Current Stack Trace");
611             Debug.logWarning(e2, "WARNING: In setSetRollbackOnlyCause a stack placeholder was already in place, here is the current location: ", module);
612         }
613         setRollbackOnlyCause.set(newRoc);
614     }
615     private static RollbackOnlyCause clearSetRollbackOnlyCause() {
616         RollbackOnlyCause roc = (RollbackOnlyCause) setRollbackOnlyCause.get();
617         if (roc == null) {
618             /* this is an obnoxious message, leaving out for now; could be added manually if a problem with this is suspected
619             if (Debug.verboseOn()) {
620                 // for this in particular, unlike the begin location, normally there will not be a setRollbackOnlyCause, so don't complain about it except in verbose
621                 Debug.logVerbose(new Exception("Current Stack Trace"), "In clearSetRollbackOnlyCause no stack placeholder was in place, here is the current location: ", module);
622             }
623             */

624             return null;
625         } else {
626             setRollbackOnlyCause.set(null);
627             return roc;
628         }
629     }
630     public static RollbackOnlyCause getSetRollbackOnlyCause() {
631         if (setRollbackOnlyCause.get() == null) {
632             Exception JavaDoc e = new Exception JavaDoc("Current Stack Trace");
633             Debug.logWarning(e, "WARNING: In getSetRollbackOnlyCause no stack placeholder was in place, here is the current location: ", module);
634         }
635         return (RollbackOnlyCause) setRollbackOnlyCause.get();
636     }
637
638     // =======================================
639
// =======================================
640
private static ThreadLocal JavaDoc transactionStartStamp = new ThreadLocal JavaDoc();
641     private static ThreadLocal JavaDoc transactionLastNowStamp = new ThreadLocal JavaDoc();
642
643     public static Timestamp JavaDoc getTransactionStartStamp() {
644         Timestamp JavaDoc curStamp = (Timestamp JavaDoc) transactionStartStamp.get();
645         if (curStamp == null) {
646             curStamp = UtilDateTime.nowTimestamp();
647             transactionStartStamp.set(curStamp);
648
649             // we know this is the first time set for this transaction, so make sure the StampClearSync is registered
650
try {
651                 registerSynchronization(new StampClearSync());
652             } catch (GenericTransactionException e) {
653                 Debug.logError(e, "Error registering StampClearSync synchronization, stamps will still be reset if begin/commit/rollback are call through TransactionUtil, but not if otherwise", module);
654             }
655         }
656         return curStamp;
657     }
658
659     public static Timestamp JavaDoc getTransactionUniqueNowStamp() {
660         Timestamp JavaDoc lastNowStamp = (Timestamp JavaDoc) transactionLastNowStamp.get();
661         Timestamp JavaDoc nowTimestamp = UtilDateTime.nowTimestamp();
662
663         // check for an overlap with the lastNowStamp, or if the lastNowStamp is in the future because of incrementing to make each stamp unique
664
if (lastNowStamp != null && (lastNowStamp.equals(nowTimestamp) || lastNowStamp.after(nowTimestamp))) {
665             nowTimestamp = new Timestamp JavaDoc(lastNowStamp.getTime() + 1);
666         }
667
668         transactionLastNowStamp.set(nowTimestamp);
669         return nowTimestamp;
670     }
671
672     protected static void clearTransactionStamps() {
673         transactionStartStamp.set(null);
674         transactionLastNowStamp.set(null);
675     }
676
677     public static class StampClearSync implements Synchronization {
678         public void afterCompletion(int status) {
679             TransactionUtil.clearTransactionStamps();
680         }
681
682         public void beforeCompletion() {
683         }
684     }
685 }
686
Popular Tags