KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > caucho > jca > UserTransactionImpl


1 /*
2  * Copyright (c) 1998-2006 Caucho Technology -- all rights reserved
3  *
4  * This file is part of Resin(R) Open Source
5  *
6  * Each copy or derived work must preserve the copyright notice and this
7  * notice unmodified.
8  *
9  * Resin Open Source is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * Resin Open Source is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
17  * of NON-INFRINGEMENT. See the GNU General Public License for more
18  * details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with Resin Open Source; if not, write to the
22  *
23  * Free Software Foundation, Inc.
24  * 59 Temple Place, Suite 330
25  * Boston, MA 02111-1307 USA
26  *
27  * @author Scott Ferguson
28  */

29
30 package com.caucho.jca;
31
32 import com.caucho.log.Log;
33 import com.caucho.transaction.TransactionImpl;
34 import com.caucho.transaction.TransactionManagerImpl;
35 import com.caucho.util.L10N;
36
37 import javax.resource.spi.ConnectionRequestInfo JavaDoc;
38 import javax.resource.spi.ManagedConnectionFactory JavaDoc;
39 import javax.security.auth.Subject JavaDoc;
40 import javax.transaction.*;
41 import javax.transaction.xa.Xid JavaDoc;
42 import java.util.ArrayList JavaDoc;
43 import java.util.logging.Level JavaDoc;
44 import java.util.logging.Logger JavaDoc;
45
46 /**
47  * Implementation of the UserTransactionImpl for a thread instance.
48  */

49 public class UserTransactionImpl implements UserTransaction {
50   private static final Logger JavaDoc log = Log.open(UserTransactionImpl.class);
51   private static final L10N L = new L10N(UserTransactionImpl.class);
52
53   private TransactionManagerImpl _transactionManager;
54
55   private ArrayList JavaDoc<UserPoolItem> _resources = new ArrayList JavaDoc<UserPoolItem>();
56   private ArrayList JavaDoc<PoolItem> _poolItems = new ArrayList JavaDoc<PoolItem>();
57   private ArrayList JavaDoc<BeginResource> _beginResources
58     = new ArrayList JavaDoc<BeginResource>();
59   private ArrayList JavaDoc<CloseResource> _closeResources
60     = new ArrayList JavaDoc<CloseResource>();
61
62   private int _xaDepth;
63   
64   /**
65    * Creates the proxy.
66   */

67   public UserTransactionImpl(TransactionManagerImpl tm)
68   {
69     _transactionManager = tm;
70   }
71   
72   /**
73    * Sets the transaction's timeout.
74    */

75   public void setTransactionTimeout(int seconds)
76     throws SystemException
77   {
78     _transactionManager.setTransactionTimeout(seconds);
79   }
80   
81   /**
82    * Gets the transaction's status
83    */

84   public int getStatus()
85     throws SystemException
86   {
87     return _transactionManager.getStatus();
88   }
89
90   /**
91    * Enlist a resource.
92    */

93   void enlistResource(UserPoolItem resource)
94     throws SystemException, RollbackException
95   {
96     if (_resources.contains(resource))
97       return;
98     
99     Transaction xa = _transactionManager.getTransaction();
100     if (xa != null) {
101       PoolItem poolItem = resource.getXAPoolItem();
102
103       enlistPoolItem(xa, poolItem);
104     }
105     
106     _resources.add(resource);
107   }
108
109   private void enlistPoolItem(Transaction xa, PoolItem poolItem)
110     throws SystemException, RollbackException
111   {
112     if (poolItem == null)
113       return;
114     else if (! poolItem.supportsTransaction()) {
115       // server/164j
116
return;
117     }
118     
119     // XXX: new
120
if (_poolItems.contains(poolItem))
121       return;
122     
123     poolItem.setTransaction(this);
124
125     if (xa instanceof TransactionImpl) {
126       TransactionImpl xaImpl = (TransactionImpl) xa;
127       
128       // server/164l
129
if (xaImpl.allowLocalTransactionOptimization())
130     poolItem.enableLocalTransactionOptimization(true);
131     }
132
133     if (poolItem.getXid() == null)
134       xa.enlistResource(poolItem);
135     
136     _poolItems.add(poolItem);
137   }
138
139   /**
140    * Delist a pool item
141    */

142   void delistPoolItem(PoolItem poolItem, int flags)
143     throws SystemException, RollbackException
144   {
145     Transaction xa = _transactionManager.getTransaction();
146
147     try {
148       if (xa != null)
149     xa.delistResource(poolItem, flags);
150     } finally {
151       _poolItems.remove(poolItem);
152     }
153   }
154
155   /**
156    * Delist a resource.
157    */

158   void delistResource(UserPoolItem resource)
159   {
160     _resources.remove(resource);
161   }
162
163   /**
164    * Enlist a resource automatically called when a transaction begins
165    */

166   public void enlistBeginResource(BeginResource resource)
167   {
168     _beginResources.add(resource);
169
170     try {
171       Transaction xa = _transactionManager.getTransaction();
172       if (xa != null)
173     resource.begin(xa);
174     } catch (Exception JavaDoc e) {
175       throw new RuntimeException JavaDoc(e);
176     }
177   }
178
179   /**
180    * Enlist a resource automatically closed when the context ends.
181    */

182   public void enlistCloseResource(CloseResource resource)
183   {
184     _closeResources.add(resource);
185   }
186
187   /**
188    * Allocates a resource matching the parameters. If none matches,
189    * return null.
190    */

191   UserPoolItem allocate(ManagedConnectionFactory JavaDoc mcf,
192             Subject JavaDoc subject,
193             ConnectionRequestInfo JavaDoc info)
194   {
195     if (_xaDepth == 0)
196       return null;
197     
198     ArrayList JavaDoc<PoolItem> poolItems = _poolItems;
199     int length = poolItems.size();
200     
201     for (int i = 0; i < length; i++) {
202       PoolItem poolItem = poolItems.get(i);
203
204       UserPoolItem item = poolItem.allocateXA(mcf, subject, info);
205
206       if (item != null)
207     return item;
208     }
209
210     return null;
211   }
212
213   /**
214    * Finds the pool item joined to this one.
215    * return null.
216    */

217   PoolItem findJoin(PoolItem item)
218   {
219     if (_xaDepth == 0)
220       return null;
221     
222     ArrayList JavaDoc<PoolItem> poolItems = _poolItems;
223     int length = poolItems.size();
224     
225     for (int i = 0; i < length; i++) {
226       PoolItem poolItem = poolItems.get(i);
227
228       if (poolItem.isJoin(item))
229     return poolItem;
230     }
231
232     return null;
233   }
234
235   /**
236    * Returns the XID.
237    */

238   public Xid JavaDoc getXid()
239     throws SystemException, RollbackException
240   {
241     TransactionImpl xa = (TransactionImpl) _transactionManager.getTransaction();
242
243     if (xa != null)
244       return xa.getXid();
245     else
246       return null;
247   }
248
249   /**
250    * Returns the XID.
251    */

252   public int getEnlistedResourceCount()
253     throws SystemException, RollbackException
254   {
255     TransactionImpl xa = (TransactionImpl) _transactionManager.getTransaction();
256
257     if (xa != null)
258       return xa.getEnlistedResourceCount();
259     else
260       return 0;
261   }
262   
263   /**
264    * Start the transaction.
265    */

266   public void begin()
267     throws NotSupportedException, SystemException
268   {
269     _transactionManager.begin();
270     _xaDepth++;
271     boolean isOkay = false;
272
273     try {
274       TransactionImpl xa = (TransactionImpl) _transactionManager.getTransaction();
275       xa.setUserTransaction(this);
276     
277       _poolItems.clear();
278     
279       // enlist "cached" connections
280
int length = _resources.size();
281
282       for (int i = 0; i < length; i++) {
283     UserPoolItem userPoolItem = _resources.get(i);
284
285     for (int j = _poolItems.size() - 1; j >= 0; j--) {
286       PoolItem poolItem = _poolItems.get(j);
287
288       if (poolItem.share(userPoolItem)) {
289         break;
290       }
291     }
292
293     PoolItem xaPoolItem = userPoolItem.getXAPoolItem();
294     if (! _poolItems.contains(xaPoolItem))
295       _poolItems.add(xaPoolItem);
296       }
297
298       for (int i = 0; i < _poolItems.size(); i++) {
299     PoolItem poolItem = _poolItems.get(i);
300
301     poolItem.enableLocalTransactionOptimization(_poolItems.size() == 1);
302
303     try {
304       xa.enlistResource(poolItem);
305     } catch (Exception JavaDoc e) {
306       throw new SystemException(e);
307     }
308       }
309
310       // enlist begin resources
311
for (int i = 0; i < _beginResources.size(); i++) {
312     try {
313       BeginResource resource = _beginResources.get(i);
314
315       resource.begin(xa);
316     } catch (Throwable JavaDoc e) {
317       log.log(Level.WARNING, e.toString(), e);
318     }
319       }
320
321       isOkay = true;
322     } finally {
323       if (! isOkay) {
324     log.warning("Rolling back transaction from failed begin()");
325     
326     // something has gone very wrong
327
_xaDepth--;
328
329     ArrayList JavaDoc<PoolItem> recoveryList = new ArrayList JavaDoc<PoolItem>(_poolItems);
330     _poolItems.clear();
331     _resources.clear();
332
333     for (int i = 0; i < recoveryList.size(); i++) {
334       try {
335         PoolItem item = recoveryList.get(i);
336
337         item.abortConnection();
338         
339         item.destroy();
340       } catch (Throwable JavaDoc e) {
341         log.log(Level.FINE, e.toString(), e);
342       }
343     }
344     
345     _transactionManager.rollback();
346       }
347     }
348   }
349
350   /**
351    * Suspends the transaction.
352    */

353   public UserTransactionSuspendState suspend()
354   {
355     if (_xaDepth == 0)
356       throw new IllegalStateException JavaDoc(L.l("suspend may only be called in a transaction."));
357
358     _xaDepth--;
359     
360     UserTransactionSuspendState state;
361     state = new UserTransactionSuspendState(_poolItems);
362     _poolItems.clear();
363
364     return state;
365   }
366
367   /**
368    * Resumes the transaction.
369    */

370   public void resume(UserTransactionSuspendState state)
371   {
372     /*
373     if (_inTransaction)
374       throw new IllegalStateException(L.l("resume may only be called outside of a transaction."));
375     */

376
377     _xaDepth++;
378
379     _poolItems.addAll(state.getPoolItems());
380   }
381   
382   /**
383    * Marks the transaction as rollback only.
384    */

385   public void setRollbackOnly()
386     throws IllegalStateException JavaDoc, SystemException
387   {
388     _transactionManager.setRollbackOnly();
389   }
390   
391   /**
392    * Commits the transaction
393    */

394   public void commit()
395     throws IllegalStateException JavaDoc, RollbackException, HeuristicMixedException,
396        HeuristicRollbackException, SecurityException JavaDoc, SystemException
397   {
398     try {
399       /* XXX: interaction with hessian XA
400       if (_xaDepth == 0)
401     throw new IllegalStateException("Can't commit outside of a transaction. Either the UserTransaction.begin() is missing or the transaction has already been committed or rolled back.");
402       */

403       
404       _transactionManager.commit();
405     } finally {
406       _poolItems.clear();
407       if (_xaDepth > 0)
408     _xaDepth--;
409     }
410   }
411   
412   /**
413    * Rolls the transaction back
414    */

415   public void rollback()
416     throws IllegalStateException JavaDoc, SecurityException JavaDoc, SystemException
417   {
418     try {
419       _transactionManager.rollback();
420     } finally {
421       _poolItems.clear();
422       if (_xaDepth > 0)
423     _xaDepth--;
424     }
425   }
426
427   /**
428    * Aborts the transaction.
429    */

430   public void abortTransaction()
431     throws IllegalStateException JavaDoc
432   {
433     IllegalStateException JavaDoc exn = null;
434
435     boolean inTransaction = _xaDepth > 0;
436     _xaDepth = 0;
437
438     if (! inTransaction && _poolItems.size() > 0) {
439       Exception JavaDoc e = new IllegalStateException JavaDoc("user transaction pool broken");
440       log.log(Level.WARNING, e.toString(), e);
441     }
442     
443     _poolItems.clear();
444
445     if (inTransaction) {
446       try {
447     TransactionImpl xa = (TransactionImpl) _transactionManager.getTransaction();
448
449     exn = new IllegalStateException JavaDoc(L.l("Transactions must have a commit() or rollback() in a finally block."));
450       
451     log.warning("Rolling back dangling transaction. All transactions must have a commit() or rollback() in a finally block.");
452       
453     _transactionManager.rollback();
454       } catch (Throwable JavaDoc e) {
455     log.log(Level.WARNING, e.toString());
456       }
457
458     }
459
460     _beginResources.clear();
461     
462     while (_closeResources.size() > 0) {
463       try {
464     CloseResource resource;
465
466     resource = _closeResources.remove(_closeResources.size() - 1);
467     resource.close();
468       } catch (Throwable JavaDoc e) {
469     log.log(Level.WARNING, e.toString(), e);
470       }
471     }
472
473     if (_resources.size() > 0) {
474       log.warning("Closing dangling connections. All connections must have a close() in a finally block.");
475     }
476     while (_resources.size() > 0) {
477       UserPoolItem userPoolItem = _resources.remove(_resources.size() - 1);
478       
479       try {
480     IllegalStateException JavaDoc stackTrace = userPoolItem.getAllocationStackTrace();
481
482     if (stackTrace != null)
483       log.log(Level.WARNING, stackTrace.getMessage(), stackTrace);
484     else {
485       // start saving the allocation stack trace.
486
userPoolItem.setSaveAllocationStackTrace(true);
487     }
488       
489     if (exn == null)
490       exn = new IllegalStateException JavaDoc(L.l("Connection {0} was not closed. Connections must have a close() in a finally block.",
491                           userPoolItem.getUserConnection()));
492
493     userPoolItem.abortConnection();
494       } catch (Throwable JavaDoc e) {
495     log.log(Level.WARNING, e.toString(), e);
496       }
497     }
498
499     _poolItems.clear();
500
501     try {
502       _transactionManager.setTransactionTimeout(0);
503     } catch (Throwable JavaDoc e) {
504       log.log(Level.WARNING, e.toString(), e);
505     }
506
507     if (exn != null)
508       throw exn;
509   }
510 }
511
512
Popular Tags