1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.springframework.transaction.jta;
18
19 import java.util.List;
20 import javax.naming.NamingException;
21
22 import com.ibm.websphere.uow.UOWSynchronizationRegistry;
23 import com.ibm.wsspi.uow.UOWAction;
24 import com.ibm.wsspi.uow.UOWActionException;
25 import com.ibm.wsspi.uow.UOWException;
26 import com.ibm.wsspi.uow.UOWManager;
27 import com.ibm.wsspi.uow.UOWManagerFactory;
28
29 import org.springframework.transaction.IllegalTransactionStateException;
30 import org.springframework.transaction.InvalidTimeoutException;
31 import org.springframework.transaction.NestedTransactionNotSupportedException;
32 import org.springframework.transaction.TransactionDefinition;
33 import org.springframework.transaction.TransactionException;
34 import org.springframework.transaction.TransactionSystemException;
35 import org.springframework.transaction.support.CallbackPreferringPlatformTransactionManager;
36 import org.springframework.transaction.support.DefaultTransactionDefinition;
37 import org.springframework.transaction.support.DefaultTransactionStatus;
38 import org.springframework.transaction.support.SmartTransactionObject;
39 import org.springframework.transaction.support.TransactionCallback;
40 import org.springframework.transaction.support.TransactionSynchronization;
41 import org.springframework.transaction.support.TransactionSynchronizationManager;
42 import org.springframework.transaction.support.TransactionSynchronizationUtils;
43 import org.springframework.util.ReflectionUtils;
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87 @SuppressWarnings("serial")
88 public class WebSphereUowTransactionManager extends JtaTransactionManager
89 implements CallbackPreferringPlatformTransactionManager {
90
91
92
93
94
95 public static final String DEFAULT_UOW_MANAGER_NAME = "java:comp/websphere/UOWManager";
96
97
98 private UOWManager uowManager;
99
100 private String uowManagerName;
101
102
103
104
105
106 public WebSphereUowTransactionManager() {
107 setAutodetectTransactionManager(false);
108 }
109
110
111
112
113
114 public WebSphereUowTransactionManager(UOWManager uowManager) {
115 this();
116 this.uowManager = uowManager;
117 }
118
119
120
121
122
123
124
125
126 public void setUowManager(UOWManager uowManager) {
127 this.uowManager = uowManager;
128 }
129
130
131
132
133
134
135
136 public void setUowManagerName(String uowManagerName) {
137 this.uowManagerName = uowManagerName;
138 }
139
140
141 @Override
142 public void afterPropertiesSet() throws TransactionSystemException {
143 initUserTransactionAndTransactionManager();
144
145
146 if (this.uowManager == null) {
147 if (this.uowManagerName != null) {
148 this.uowManager = lookupUowManager(this.uowManagerName);
149 }
150 else {
151 this.uowManager = lookupDefaultUowManager();
152 }
153 }
154 }
155
156
157
158
159
160
161
162
163
164 protected UOWManager lookupUowManager(String uowManagerName) throws TransactionSystemException {
165 try {
166 if (logger.isDebugEnabled()) {
167 logger.debug("Retrieving WebSphere UOWManager from JNDI location [" + uowManagerName + "]");
168 }
169 return getJndiTemplate().lookup(uowManagerName, UOWManager.class);
170 }
171 catch (NamingException ex) {
172 throw new TransactionSystemException(
173 "WebSphere UOWManager is not available at JNDI location [" + uowManagerName + "]", ex);
174 }
175 }
176
177
178
179
180
181
182
183
184 protected UOWManager lookupDefaultUowManager() throws TransactionSystemException {
185 try {
186 logger.debug("Retrieving WebSphere UOWManager from default JNDI location [" + DEFAULT_UOW_MANAGER_NAME + "]");
187 return getJndiTemplate().lookup(DEFAULT_UOW_MANAGER_NAME, UOWManager.class);
188 }
189 catch (NamingException ex) {
190 logger.debug("WebSphere UOWManager is not available at default JNDI location [" +
191 DEFAULT_UOW_MANAGER_NAME + "] - falling back to UOWManagerFactory lookup");
192 return UOWManagerFactory.getUOWManager();
193 }
194 }
195
196
197
198
199 @Override
200 protected void doRegisterAfterCompletionWithJtaTransaction(
201 JtaTransactionObject txObject, List<TransactionSynchronization> synchronizations) {
202
203 this.uowManager.registerInterposedSynchronization(new JtaAfterCompletionSynchronization(synchronizations));
204 }
205
206
207
208
209
210
211
212
213
214
215 @Override
216 public boolean supportsResourceAdapterManagedTransactions() {
217 return true;
218 }
219
220
221 @Override
222 public <T> T execute(TransactionDefinition definition, TransactionCallback<T> callback) throws TransactionException {
223 if (definition == null) {
224
225 definition = new DefaultTransactionDefinition();
226 }
227
228 if (definition.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
229 throw new InvalidTimeoutException("Invalid transaction timeout", definition.getTimeout());
230 }
231 int pb = definition.getPropagationBehavior();
232 boolean existingTx = (this.uowManager.getUOWStatus() != UOWSynchronizationRegistry.UOW_STATUS_NONE &&
233 this.uowManager.getUOWType() != UOWSynchronizationRegistry.UOW_TYPE_LOCAL_TRANSACTION);
234
235 int uowType = UOWSynchronizationRegistry.UOW_TYPE_GLOBAL_TRANSACTION;
236 boolean joinTx = false;
237 boolean newSynch = false;
238
239 if (existingTx) {
240 if (pb == TransactionDefinition.PROPAGATION_NEVER) {
241 throw new IllegalTransactionStateException(
242 "Transaction propagation 'never' but existing transaction found");
243 }
244 if (pb == TransactionDefinition.PROPAGATION_NESTED) {
245 throw new NestedTransactionNotSupportedException(
246 "Transaction propagation 'nested' not supported for WebSphere UOW transactions");
247 }
248 if (pb == TransactionDefinition.PROPAGATION_SUPPORTS ||
249 pb == TransactionDefinition.PROPAGATION_REQUIRED || pb == TransactionDefinition.PROPAGATION_MANDATORY) {
250 joinTx = true;
251 newSynch = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
252 }
253 else if (pb == TransactionDefinition.PROPAGATION_NOT_SUPPORTED) {
254 uowType = UOWSynchronizationRegistry.UOW_TYPE_LOCAL_TRANSACTION;
255 newSynch = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
256 }
257 else {
258 newSynch = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
259 }
260 }
261 else {
262 if (pb == TransactionDefinition.PROPAGATION_MANDATORY) {
263 throw new IllegalTransactionStateException(
264 "Transaction propagation 'mandatory' but no existing transaction found");
265 }
266 if (pb == TransactionDefinition.PROPAGATION_SUPPORTS ||
267 pb == TransactionDefinition.PROPAGATION_NOT_SUPPORTED || pb == TransactionDefinition.PROPAGATION_NEVER) {
268 uowType = UOWSynchronizationRegistry.UOW_TYPE_LOCAL_TRANSACTION;
269 newSynch = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
270 }
271 else {
272 newSynch = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
273 }
274 }
275
276 boolean debug = logger.isDebugEnabled();
277 if (debug) {
278 logger.debug("Creating new transaction with name [" + definition.getName() + "]: " + definition);
279 }
280 SuspendedResourcesHolder suspendedResources = (!joinTx ? suspend(null) : null);
281 try {
282 if (definition.getTimeout() > TransactionDefinition.TIMEOUT_DEFAULT) {
283 this.uowManager.setUOWTimeout(uowType, definition.getTimeout());
284 }
285 if (debug) {
286 logger.debug("Invoking WebSphere UOW action: type=" + uowType + ", join=" + joinTx);
287 }
288 UOWActionAdapter<T> action = new UOWActionAdapter<T>(
289 definition, callback, (uowType == UOWManager.UOW_TYPE_GLOBAL_TRANSACTION), !joinTx, newSynch, debug);
290 this.uowManager.runUnderUOW(uowType, joinTx, action);
291 if (debug) {
292 logger.debug("Returned from WebSphere UOW action: type=" + uowType + ", join=" + joinTx);
293 }
294 return action.getResult();
295 }
296 catch (UOWException ex) {
297 throw new TransactionSystemException("UOWManager transaction processing failed", ex);
298 }
299 catch (UOWActionException ex) {
300 throw new TransactionSystemException("UOWManager threw unexpected UOWActionException", ex);
301 }
302 finally {
303 if (suspendedResources != null) {
304 resume(null, suspendedResources);
305 }
306 }
307 }
308
309
310
311
312
313 private class UOWActionAdapter<T> implements UOWAction, SmartTransactionObject {
314
315 private final TransactionDefinition definition;
316
317 private final TransactionCallback<T> callback;
318
319 private final boolean actualTransaction;
320
321 private final boolean newTransaction;
322
323 private final boolean newSynchronization;
324
325 private boolean debug;
326
327 private T result;
328
329 private Throwable exception;
330
331 public UOWActionAdapter(TransactionDefinition definition, TransactionCallback<T> callback,
332 boolean actualTransaction, boolean newTransaction, boolean newSynchronization, boolean debug) {
333 this.definition = definition;
334 this.callback = callback;
335 this.actualTransaction = actualTransaction;
336 this.newTransaction = newTransaction;
337 this.newSynchronization = newSynchronization;
338 this.debug = debug;
339 }
340
341 @Override
342 public void run() {
343 DefaultTransactionStatus status = prepareTransactionStatus(
344 this.definition, (this.actualTransaction ? this : null),
345 this.newTransaction, this.newSynchronization, this.debug, null);
346 try {
347 this.result = this.callback.doInTransaction(status);
348 triggerBeforeCommit(status);
349 }
350 catch (Throwable ex) {
351 this.exception = ex;
352 uowManager.setRollbackOnly();
353 }
354 finally {
355 if (status.isLocalRollbackOnly()) {
356 if (status.isDebug()) {
357 logger.debug("Transactional code has requested rollback");
358 }
359 uowManager.setRollbackOnly();
360 }
361 triggerBeforeCompletion(status);
362 if (status.isNewSynchronization()) {
363 List<TransactionSynchronization> synchronizations = TransactionSynchronizationManager.getSynchronizations();
364 TransactionSynchronizationManager.clear();
365 if (!synchronizations.isEmpty()) {
366 uowManager.registerInterposedSynchronization(new JtaAfterCompletionSynchronization(synchronizations));
367 }
368 }
369 }
370 }
371
372 public T getResult() {
373 if (this.exception != null) {
374 ReflectionUtils.rethrowRuntimeException(this.exception);
375 }
376 return this.result;
377 }
378
379 @Override
380 public boolean isRollbackOnly() {
381 return uowManager.getRollbackOnly();
382 }
383
384 @Override
385 public void flush() {
386 TransactionSynchronizationUtils.triggerFlush();
387 }
388 }
389
390 }