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