1
2
3
4
5
6
7 package org.mule.transaction;
8
9 import org.apache.commons.logging.Log;
10 import org.apache.commons.logging.LogFactory;
11 import org.mule.api.MuleContext;
12 import org.mule.api.transaction.*;
13 import org.mule.config.i18n.CoreMessages;
14
15 public class TransactionTemplate<T>
16 {
17
18 private static final Log logger = LogFactory.getLog(TransactionTemplate.class);
19
20 private final TransactionConfig config;
21 private final MuleContext context;
22
23 public TransactionTemplate(TransactionConfig config, MuleContext context)
24 {
25 this.config = config;
26 this.context = context;
27 }
28
29 public T execute(TransactionCallback<T> callback) throws Exception
30 {
31
32 if (config == null)
33 {
34 return callback.doInTransaction();
35 }
36
37 Transaction joinedExternal = null;
38 byte action = (config != null) ? config.getAction() : TransactionConfig.ACTION_DEFAULT;
39 Transaction tx = TransactionCoordination.getInstance().getTransaction();
40 if (tx == null && context != null && config != null && config.isInteractWithExternal())
41 {
42
43 TransactionFactory tmFactory = config.getFactory();
44 if (tmFactory instanceof ExternalTransactionAwareTransactionFactory)
45 {
46 ExternalTransactionAwareTransactionFactory extmFactory =
47 (ExternalTransactionAwareTransactionFactory) tmFactory;
48 joinedExternal = tx = extmFactory.joinExternalTransaction(context);
49 }
50 }
51
52 Transaction suspendedXATx = null;
53
54 if (action == TransactionConfig.ACTION_NEVER && tx != null)
55 {
56 throw new IllegalTransactionStateException(
57 CoreMessages.transactionAvailableButActionIs("Never"));
58 }
59 else if ((action == TransactionConfig.ACTION_NONE || action == TransactionConfig.ACTION_ALWAYS_BEGIN)
60 && tx != null)
61 {
62 if (logger.isDebugEnabled())
63 {
64 logger.debug(action + ", " + "current TX: " + tx);
65 }
66
67 if (tx.isXA())
68 {
69
70 suspendedXATx = tx;
71 suspendXATransaction(suspendedXATx);
72 }
73 else
74 {
75
76 resolveTransaction(tx);
77 }
78
79 tx = null;
80 }
81 else if (action == TransactionConfig.ACTION_ALWAYS_JOIN && tx == null)
82 {
83 throw new IllegalTransactionStateException(
84 CoreMessages.transactionNotAvailableButActionIs("Always Join"));
85 }
86
87 if (action == TransactionConfig.ACTION_ALWAYS_BEGIN
88 || (action == TransactionConfig.ACTION_BEGIN_OR_JOIN && tx == null))
89 {
90 logger.debug("Beginning transaction");
91 tx = config.getFactory().beginTransaction(context);
92 logger.debug("Transaction successfully started: " + tx);
93 }
94 else
95 {
96 tx = null;
97 }
98
99 T result = callback.doInTransaction();
100 if (tx != null)
101 {
102
103 tx = TransactionCoordination.getInstance().getTransaction();
104 }
105 if (tx != null)
106 {
107 resolveTransaction(tx);
108 }
109 if (suspendedXATx != null)
110 {
111 resumeXATransaction(suspendedXATx);
112 tx = suspendedXATx;
113 }
114 if (joinedExternal != null)
115 {
116 TransactionCoordination.getInstance().unbindTransaction(joinedExternal);
117 }
118 return result;
119 }
120
121 protected void resolveTransaction(Transaction tx) throws TransactionException
122 {
123 if (tx.isRollbackOnly())
124 {
125 if (logger.isDebugEnabled())
126 {
127 logger.debug("Transaction has been marked rollbackOnly, rolling it back: " + tx);
128 }
129 tx.rollback();
130 } else
131 {
132 if (logger.isDebugEnabled())
133 {
134 logger.debug("Committing transaction " + tx);
135 }
136 tx.commit();
137 }
138 }
139
140 protected void suspendXATransaction(Transaction tx) throws TransactionException
141 {
142 if (logger.isDebugEnabled())
143 {
144 logger.debug("Suspending " + tx);
145 }
146
147 tx.suspend();
148
149 if (logger.isDebugEnabled())
150 {
151 logger.debug("Successfully suspended " + tx);
152 logger.debug("Unbinding the following TX from the current context: " + tx);
153 }
154
155 TransactionCoordination.getInstance().unbindTransaction(tx);
156 }
157
158 protected void resumeXATransaction(Transaction tx) throws TransactionException
159 {
160 if (logger.isDebugEnabled())
161 {
162 logger.debug("Re-binding and Resuming " + tx);
163 }
164
165 TransactionCoordination.getInstance().bindTransaction(tx);
166 tx.resume();
167 }
168
169 }
170