KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > portal > common > transaction > Transactions


1 /*****************************************
2  * *
3  * JBoss Portal: The OpenSource Portal *
4  * *
5  * Distributable under LGPL license. *
6  * See terms of license at gnu.org. *
7  * *
8  *****************************************/

9 package org.jboss.portal.common.transaction;
10
11 import javax.transaction.Status JavaDoc;
12 import javax.transaction.SystemException JavaDoc;
13 import javax.transaction.Transaction JavaDoc;
14 import javax.transaction.TransactionManager JavaDoc;
15 import javax.transaction.NotSupportedException JavaDoc;
16 import javax.transaction.HeuristicMixedException JavaDoc;
17 import javax.transaction.HeuristicRollbackException JavaDoc;
18 import javax.transaction.RollbackException JavaDoc;
19
20 import org.apache.log4j.Logger;
21
22 /**
23  * Utility class for managing transactions.
24  *
25  * @author <a HREF="mailto:julien@jboss.org">Julien Viet</a>
26  * @version $Revision: 1.8 $
27  */

28 public class Transactions
29 {
30
31    private static Logger log = Logger.getLogger(Transactions.class);
32
33    private static final String JavaDoc[] STATUS_NAMES = {
34       "CANNOT_GET_STATUS",
35       "STATUS_ACTIVE",
36       "STATUS_MARKED_ROLLBACK",
37       "STATUS_PREPARED",
38       "STATUS_COMMITTED",
39       "STATUS_ROLLEDBACK",
40       "STATUS_UNKNOWN",
41       "STATUS_NO_TRANSACTION",
42       "STATUS_PREPARING",
43       "STATUS_COMMITTING",
44       "STATUS_ROLLING_BACK"};
45
46    /**
47     * Apply the transaction type before the unit of work.
48     *
49     * @param type the transaction type
50     * @param tm the transaction manager
51     * @return the new transaction if one has been started.
52     * @throws TransactionException
53     * @throws IllegalArgumentException if the type or the transaction manager is null
54     */

55    public static Transaction JavaDoc applyBefore(Type type, TransactionManager JavaDoc tm) throws TransactionException, IllegalArgumentException JavaDoc
56    {
57       if (tm == null)
58       {
59          throw new IllegalArgumentException JavaDoc("No transaction manager provided");
60       }
61       if (type == null)
62       {
63          throw new IllegalArgumentException JavaDoc("No type");
64       }
65
66       // Suspend the incoming transaction
67
Transaction JavaDoc oldTx = suspend(tm);
68
69       if (oldTx != null)
70       {
71          type.txBefore(tm, oldTx);
72       }
73       else
74       {
75          type.noTxBefore(tm);
76       }
77
78       return oldTx;
79    }
80
81    /**
82     * Apply the transaction type after the unit of work has been done.
83     *
84     * @param type the transaction type
85     * @param tm the transaction manager
86     * @param oldTx the old transaction if it is not null
87     * @throws TransactionException
88     * @throws IllegalArgumentException if the type of the transaction manager is null
89     */

90    public static void applyAfter(Type type, TransactionManager JavaDoc tm, Transaction JavaDoc oldTx) throws TransactionException, IllegalArgumentException JavaDoc
91    {
92       if (tm == null)
93       {
94          throw new IllegalArgumentException JavaDoc("No transaction manager provided");
95       }
96       if (type == null)
97       {
98          throw new IllegalArgumentException JavaDoc("No type");
99       }
100
101       try
102       {
103          if (oldTx != null)
104          {
105             type.txAfter(tm, oldTx);
106          }
107          else
108          {
109             type.noTxAfter(tm);
110          }
111       }
112       finally
113       {
114          if (oldTx != null)
115          {
116             try
117             {
118                resume(tm, oldTx);
119             }
120             catch (TransactionException ignore)
121             {
122                log.error("Was not capable to resume the incoming transaction", ignore);
123             }
124          }
125       }
126    }
127
128    /**
129     * Apply the transaction type around the unit of work.
130     *
131     * @param type the transaction type
132     * @param tm the transaction manager
133     * @param runnable the unit of work
134     * @return the object returned by the runnable object
135     * @throws NestedException wraps any exception throws by the runnable object
136     * @throws TransactionException
137     * @throws IllegalArgumentException if any method argument is null
138     */

139    public static Object JavaDoc apply(Type type, TransactionManager JavaDoc tm, final Runnable JavaDoc runnable) throws NestedException, TransactionException, IllegalArgumentException JavaDoc
140    {
141       if (tm == null)
142       {
143          throw new IllegalArgumentException JavaDoc("No transaction manager provided");
144       }
145       if (runnable == null)
146       {
147          throw new IllegalArgumentException JavaDoc("No code to execute");
148       }
149       if (type == null)
150       {
151          throw new IllegalArgumentException JavaDoc("No type");
152       }
153
154       // Any throwable thrown by the wrapped code
155
Throwable JavaDoc throwable = null;
156
157       // Any object returned by the wrapped code
158
Object JavaDoc ret = null;
159
160       // Suspend the incoming transaction
161
Transaction JavaDoc oldTx = suspend(tm);
162
163       try
164       {
165          if (oldTx != null)
166          {
167             type.txBefore(tm, oldTx);
168             try
169             {
170                ret = runnable.run();
171             }
172             catch (Throwable JavaDoc t)
173             {
174                throwable = t;
175             }
176             finally
177             {
178                type.txAfter(tm, oldTx);
179             }
180          }
181          else
182          {
183             type.noTxBefore(tm);
184             try
185             {
186                ret = runnable.run();
187             }
188             catch (Throwable JavaDoc t)
189             {
190                throwable = t;
191             }
192             finally
193             {
194                type.noTxAfter(tm);
195             }
196          }
197       }
198       finally
199       {
200          if (oldTx != null)
201          {
202             try
203             {
204                resume(tm, oldTx);
205             }
206             catch (TransactionException ignore)
207             {
208                log.error("Was not capable to resume the incoming transaction", ignore);
209             }
210          }
211       }
212       if (throwable != null)
213       {
214          if (throwable instanceof Error JavaDoc)
215          {
216             throw (Error JavaDoc)throwable;
217          }
218          else
219          {
220             throw new NestedException(throwable);
221          }
222       }
223       else
224       {
225          return ret;
226       }
227    }
228
229    public static Object JavaDoc notSupported(TransactionManager JavaDoc tm, Runnable JavaDoc runnable)
230       throws NestedException, TransactionException
231    {
232       return apply(TYPE_NOT_SUPPORTED, tm, runnable);
233    }
234
235    public static Object JavaDoc never(TransactionManager JavaDoc tm, Runnable JavaDoc runnable)
236       throws NestedException, TransactionException
237    {
238       return apply(TYPE_NEVER, tm, runnable);
239    }
240
241    public static Object JavaDoc mandatory(TransactionManager JavaDoc tm, Runnable JavaDoc runnable)
242       throws NestedException, TransactionException
243    {
244       return apply(TYPE_MANDATORY, tm, runnable);
245    }
246
247    public static Object JavaDoc supports(TransactionManager JavaDoc tm, Runnable JavaDoc runnable)
248       throws NestedException, TransactionException
249    {
250       return apply(TYPE_SUPPORTS, tm, runnable);
251    }
252
253    public static Object JavaDoc required(TransactionManager JavaDoc tm, Runnable JavaDoc runnable)
254       throws NestedException, TransactionException
255    {
256       return apply(TYPE_REQUIRED, tm, runnable);
257    }
258
259    public static Object JavaDoc requiresNew(TransactionManager JavaDoc tm, Runnable JavaDoc runnable)
260       throws NestedException, TransactionException
261    {
262       return apply(TYPE_REQUIRES_NEW, tm, runnable);
263    }
264
265    /**
266     * Begin a new transaction.
267     *
268     * @param tm the transaction manager
269     * @throws IllegalArgumentException if the tm is null
270     */

271    public static void begin(TransactionManager JavaDoc tm) throws IllegalArgumentException JavaDoc, TransactionException
272    {
273       try
274       {
275          if (tm == null)
276          {
277             throw new IllegalArgumentException JavaDoc("No transaction manager");
278          }
279          tm.begin();
280       }
281       catch (SystemException JavaDoc e)
282       {
283          log.error("Problem when beginning transaction", e);
284          throw new TransactionException(e);
285       }
286       catch (NotSupportedException JavaDoc e)
287       {
288          log.error("Problem when beginning transaction", e);
289          throw new TransactionException(e);
290       }
291    }
292
293    /**
294     * Mark the transaction as rollback only.
295     *
296     * @param tx the transaction to mark as rollback only
297     * @throws IllegalArgumentException if the transaction is null
298     * @throws TransactionException
299     */

300    private static void setRollbackOnly(Transaction JavaDoc tx) throws IllegalArgumentException JavaDoc, TransactionException
301    {
302       try
303       {
304          if (tx == null)
305          {
306             throw new IllegalArgumentException JavaDoc("No transaction to set rollback only");
307          }
308          tx.setRollbackOnly();
309       }
310       catch (SystemException JavaDoc e)
311       {
312          log.error("Problem when setting transaction as rollback only", e);
313          throw new TransactionException(e);
314       }
315    }
316
317    /**
318     * Mark the active transaction for this thread as rollback only
319     *
320     * @see #setRollbackOnly(javax.transaction.Transaction)
321     * @param tm the transaction manager
322     * @throws IllegalArgumentException if the tm is null
323     */

324    public static void setRollbackOnly(TransactionManager JavaDoc tm) throws IllegalArgumentException JavaDoc, TransactionException
325    {
326       try
327       {
328          if (tm == null)
329          {
330             throw new IllegalArgumentException JavaDoc("No transaction manager");
331          }
332          Transaction JavaDoc tx = tm.getTransaction();
333          if (tx == null)
334          {
335             throw new TransactionException("No active transaction to set rollback only");
336          }
337          setRollbackOnly(tx);
338       }
339       catch (SystemException JavaDoc e)
340       {
341          log.error("Problem when setting transaction as rollback only", e);
342          throw new TransactionException(e);
343       }
344    }
345
346    public void safeSetRollbackOnly(TransactionManager JavaDoc tm)
347    {
348       try
349       {
350          setRollbackOnly(tm);
351       }
352       catch (IllegalArgumentException JavaDoc e)
353       {
354          log.error("", e);
355       }
356       catch (TransactionException e)
357       {
358          log.error("", e);
359       }
360    }
361
362    public static void safeEnd(TransactionManager JavaDoc tm)
363    {
364       try
365       {
366          end(tm);
367       }
368       catch (IllegalArgumentException JavaDoc e)
369       {
370          log.error("", e);
371       }
372       catch (TransactionException e)
373       {
374          log.error("", e);
375       }
376    }
377
378    /**
379     * Terminate the active transaction for this thread. If the transaction is marked for rollback
380     * then it is rollbacked otherwise it is commited.
381     *
382     * @param tm the transaction manager
383     * @return true if commit happened, false otherwise
384     * @throws IllegalArgumentException if the tm is null
385     */

386    public static boolean end(TransactionManager JavaDoc tm) throws IllegalArgumentException JavaDoc, TransactionException
387    {
388       try
389       {
390          if (tm == null)
391          {
392             throw new IllegalArgumentException JavaDoc("No transaction manager");
393          }
394          int status = tm.getStatus();
395          switch (status)
396          {
397          case Status.STATUS_MARKED_ROLLBACK:
398             tm.rollback();
399             return false;
400          case Status.STATUS_ACTIVE:
401             tm.commit();
402             return true;
403          default:
404             throw new TransactionException("Abnormal status for ending a tx " + STATUS_NAMES[status]);
405          }
406       }
407       catch (SystemException JavaDoc e)
408       {
409          log.error("Problem when ending transaction", e);
410          throw new TransactionException(e);
411       }
412       catch (HeuristicMixedException JavaDoc e)
413       {
414          log.error("Problem when ending transaction", e);
415          throw new TransactionException(e);
416       }
417       catch (HeuristicRollbackException JavaDoc e)
418       {
419          log.error("Problem when ending transaction", e);
420          throw new TransactionException(e);
421       }
422       catch (RollbackException JavaDoc e)
423       {
424          log.error("Problem when ending transaction", e);
425          throw new TransactionException(e);
426       }
427    }
428
429    /**
430     * Associate the thread with a transaction
431     *
432     * @param tm the transaction manager
433     * @param tx the transaction to associate with the this thread
434     * @throws IllegalArgumentException if any argument is null
435     * @throws TransactionException
436     */

437    public static void resume(TransactionManager JavaDoc tm, Transaction JavaDoc tx) throws IllegalArgumentException JavaDoc, TransactionException
438    {
439       try
440       {
441          if (tm == null)
442          {
443             throw new IllegalArgumentException JavaDoc("No transaction manager");
444          }
445          if (tx == null)
446          {
447             throw new IllegalArgumentException JavaDoc("No transaction to resume");
448          }
449          tm.resume(tx);
450       }
451       catch (Exception JavaDoc e)
452       {
453          log.error("Problem when resuming transaction", e);
454          throw new TransactionException(e);
455       }
456    }
457
458    /**
459     * Disassociate the current thread with the active transaction.
460     *
461     * @param tm the transaction manager
462     * @return the transaction previously associated with this thread
463     * @throws IllegalArgumentException if the transaction manager is null
464     * @throws TransactionException
465     */

466    public static Transaction JavaDoc suspend(TransactionManager JavaDoc tm) throws IllegalArgumentException JavaDoc, TransactionException
467    {
468       try
469       {
470          if (tm == null)
471          {
472             throw new IllegalArgumentException JavaDoc("No transaction manager");
473          }
474          return tm.suspend();
475       }
476       catch (SystemException JavaDoc e)
477       {
478          log.error("Problem when suspending transaction", e);
479          throw new TransactionException(e);
480       }
481    }
482
483    public interface Runnable
484    {
485       Object JavaDoc run() throws Exception JavaDoc;
486    }
487
488    public abstract static class Type
489    {
490       private final String JavaDoc name;
491
492       private Type(String JavaDoc name)
493       {
494          this.name = name;
495       }
496
497       abstract void txBefore(TransactionManager JavaDoc tm, Transaction JavaDoc oldTx) throws TransactionException;
498
499       abstract void txAfter(TransactionManager JavaDoc tm, Transaction JavaDoc oldTx);
500
501       abstract void noTxBefore(TransactionManager JavaDoc tm) throws TransactionException;
502
503       abstract void noTxAfter(TransactionManager JavaDoc tm);
504
505       public String JavaDoc getName()
506       {
507          return name;
508       }
509
510       public String JavaDoc toString()
511       {
512          return name;
513       }
514    }
515
516    public static final Type TYPE_NOT_SUPPORTED = new Type("NOT_SUPPORTED")
517    {
518       void txBefore(TransactionManager JavaDoc tm, Transaction JavaDoc oldTx)
519       {
520       }
521       void txAfter(TransactionManager JavaDoc tm, Transaction JavaDoc oldTx)
522       {
523       }
524       void noTxBefore(TransactionManager JavaDoc tm)
525       {
526       }
527       void noTxAfter(TransactionManager JavaDoc tm)
528       {
529       }
530    };
531
532    public static final Type TYPE_SUPPORTS = new Type("SUPPORTS")
533    {
534       void txBefore(TransactionManager JavaDoc tm, Transaction JavaDoc oldTx) throws TransactionException
535       {
536          resume(tm, oldTx);
537       }
538       void txAfter(TransactionManager JavaDoc tm, Transaction JavaDoc oldTx)
539       {
540          try
541          {
542             suspend(tm);
543          }
544          catch (IllegalStateException JavaDoc ignore)
545          {
546             log.error("Problem when suspending transaction", ignore);
547          }
548       }
549       void noTxBefore(TransactionManager JavaDoc tm)
550       {
551       }
552       void noTxAfter(TransactionManager JavaDoc tm)
553       {
554       }
555    };
556
557    public static final Type TYPE_REQUIRED = new Type("REQUIRED")
558    {
559       void txBefore(TransactionManager JavaDoc tm, Transaction JavaDoc oldTx)
560       {
561          resume(tm, oldTx);
562       }
563       void txAfter(TransactionManager JavaDoc tm, Transaction JavaDoc oldTx)
564       {
565          try
566          {
567             suspend(tm);
568          }
569          catch (TransactionException ignore)
570          {
571             log.error("Problem when suspending transaction", ignore);
572          }
573       }
574       void noTxBefore(TransactionManager JavaDoc tm) throws TransactionException
575       {
576          begin(tm);
577       }
578       void noTxAfter(TransactionManager JavaDoc tm)
579       {
580          try
581          {
582             end(tm);
583          }
584          catch (IllegalStateException JavaDoc ignore)
585          {
586             log.error("Problem when ending transaction", ignore);
587          }
588       }
589    };
590
591    public static final Type TYPE_REQUIRES_NEW = new Type("REQUIRES_NEW")
592    {
593       void txBefore(TransactionManager JavaDoc tm, Transaction JavaDoc oldTx) throws TransactionException
594       {
595          begin(tm);
596       }
597       void txAfter(TransactionManager JavaDoc tm, Transaction JavaDoc oldTx)
598       {
599          try
600          {
601             end(tm);
602          }
603          catch (IllegalStateException JavaDoc ignore)
604          {
605             log.error("Problem when ending transaction", ignore);
606          }
607       }
608       void noTxBefore(TransactionManager JavaDoc tm) throws TransactionException
609       {
610          begin(tm);
611       }
612       void noTxAfter(TransactionManager JavaDoc tm)
613       {
614          try
615          {
616             end(tm);
617          }
618          catch (IllegalStateException JavaDoc ignore)
619          {
620             log.error("Problem when ending transaction", ignore);
621          }
622       }
623    };
624
625    public static final Type TYPE_MANDATORY = new Type("MANDATORY")
626    {
627       void txBefore(TransactionManager JavaDoc tm, Transaction JavaDoc oldTx) throws TransactionException
628       {
629          resume(tm, oldTx);
630       }
631       void txAfter(TransactionManager JavaDoc tm, Transaction JavaDoc oldTx)
632       {
633       }
634       void noTxBefore(TransactionManager JavaDoc tm) throws TransactionException
635       {
636          throw new TransactionException("No incoming transaction");
637       }
638       void noTxAfter(TransactionManager JavaDoc tm)
639       {
640          throw new UnsupportedOperationException JavaDoc("Should never ne called");
641       }
642    };
643
644    public static final Type TYPE_NEVER = new Type("NEVER")
645    {
646       void txBefore(TransactionManager JavaDoc tm, Transaction JavaDoc oldTx) throws TransactionException
647       {
648          throw new TransactionException("Need no incoming transaction");
649       }
650       void txAfter(TransactionManager JavaDoc tm, Transaction JavaDoc oldTx)
651       {
652          throw new UnsupportedOperationException JavaDoc("Should never ne called");
653       }
654       void noTxBefore(TransactionManager JavaDoc tm)
655       {
656       }
657       void noTxAfter(TransactionManager JavaDoc tm)
658       {
659       }
660    };
661 }
662
Popular Tags