KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > caucho > ejb > xa > TransactionContext


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  * Free SoftwareFoundation, Inc.
23  * 59 Temple Place, Suite 330
24  * Boston, MA 02111-1307 USA
25  *
26  * @author Scott Ferguson
27  */

28
29 package com.caucho.ejb.xa;
30
31 import com.caucho.amber.manager.AmberConnection;
32 import com.caucho.ejb.EJBExceptionWrapper;
33 import com.caucho.ejb.entity.EntityServer;
34 import com.caucho.ejb.entity.QEntity;
35 import com.caucho.log.Log;
36 import com.caucho.transaction.TransactionImpl;
37 import com.caucho.util.Alarm;
38 import com.caucho.util.L10N;
39
40 import javax.ejb.EJBException JavaDoc;
41 import javax.ejb.SessionSynchronization JavaDoc;
42 import javax.transaction.Status JavaDoc;
43 import javax.transaction.Synchronization JavaDoc;
44 import javax.transaction.Transaction JavaDoc;
45 import javax.transaction.UserTransaction JavaDoc;
46 import java.rmi.RemoteException JavaDoc;
47 import java.util.logging.Level JavaDoc;
48 import java.util.logging.Logger JavaDoc;
49
50 /**
51  * Handles entity beans for a single transaction.
52  */

53 public class TransactionContext implements Synchronization JavaDoc {
54   static final L10N L = new L10N(TransactionContext.class);
55   protected static final Logger JavaDoc log = Log.open(TransactionContext.class);
56
57   public static final TransactionContext NULL_TRANSACTION =
58     new TransactionContext(null);
59
60   private EjbTransactionManager _container;
61   private AmberConnection _amberConn;
62
63   private UserTransaction JavaDoc _userTransaction;
64   private Transaction JavaDoc _transaction;
65
66   // the previous TransactionContext when this one completes
67
TransactionContext _old;
68   // the previous Transaction when this one completes
69
Transaction JavaDoc _oldTrans;
70
71   private long _startTime;
72
73   private TransactionObject []_objects = new TransactionObject[16];
74   private int _objectTop;
75
76   private SessionSynchronization JavaDoc []_sessions = new SessionSynchronization JavaDoc[16];
77   private int _sessionTop;
78
79   private boolean _isRowLocking;
80   private boolean _rollbackOnly;
81
82   private boolean _isUserTransaction;
83   private int _depth;
84   private boolean _isAlive;
85   private boolean _isCommitting;
86
87   TransactionContext(EjbTransactionManager container)
88   {
89     _container = container;
90
91     if (container != null)
92       _userTransaction = container.getUserTransaction();
93   }
94
95   void init(boolean pushDepth)
96   {
97     if (_isAlive) {
98       log.warning(L.l("Transaction {0} nested start. This is an internal Resin error, please report it as a bug at bugs@caucho.com.", this));
99
100       throw new IllegalStateException JavaDoc(L.l("nested transaction start"));
101     }
102
103     _transaction = null;
104     _old = null;
105     _oldTrans = null;
106     _objectTop = 0;
107     _sessionTop = 0;
108     _rollbackOnly = false;
109     _depth = pushDepth ? 1 : 0;
110     _isUserTransaction = false;
111     _isAlive = true;
112     _isRowLocking = false;
113     _startTime = Alarm.getCurrentTime();
114   }
115
116   public void setTransaction(Transaction JavaDoc transaction)
117   {
118     if (_transaction != null && _transaction != transaction)
119       throw new IllegalStateException JavaDoc("can't set transaction twice.");
120     _transaction = transaction;
121
122     if (transaction != null) {
123       try {
124         transaction.registerSynchronization(this);
125       } catch (Exception JavaDoc e) {
126         throw new EJBExceptionWrapper(e);
127       }
128     }
129   }
130
131   public Transaction JavaDoc getTransaction()
132   {
133     return _transaction;
134   }
135
136   /**
137    * Returns true for a read-only transaction.
138    */

139   public boolean isReadOnly()
140   {
141     return _transaction == null;
142   }
143
144   /**
145    * Returns true for a row-locking transaction.
146    */

147   public boolean isRowLocking()
148   {
149     return _transaction != null && _isRowLocking;
150   }
151
152   /**
153    * Set true for a row-locking transaction.
154    */

155   public void setRowLocking(boolean isRowLocking)
156   {
157     _isRowLocking = isRowLocking;
158   }
159
160   TransactionContext getOld()
161   {
162     return _old;
163   }
164
165   void setOld(TransactionContext old)
166   {
167     _old = old;
168   }
169
170   Transaction JavaDoc getOldTrans()
171   {
172     return _oldTrans;
173   }
174
175   void setOldTrans(Transaction JavaDoc old)
176   {
177     if (old == _transaction && old != null)
178       throw new IllegalStateException JavaDoc();
179
180     _oldTrans = old;
181   }
182
183   public void pushDepth()
184   {
185     if (_depth == 0) {
186       _isAlive = true;
187     }
188
189     _depth++;
190   }
191
192   public void setUserTransaction(boolean isUserTransaction)
193   {
194     if (_depth == 0)
195       _isAlive = true;
196
197     _isUserTransaction = isUserTransaction;
198   }
199
200   /**
201    * Returns true if the transaction must rollback.
202    */

203   public boolean getRollbackOnly()
204   {
205     return _rollbackOnly;
206   }
207
208   /**
209    * Forces the transaction to rollback.
210    */

211   public void setRollbackOnly()
212   {
213     _rollbackOnly = true;
214
215     if (_transaction != null) {
216       try {
217         _transaction.setRollbackOnly();
218       } catch (Exception JavaDoc e) {
219         throw new EJBExceptionWrapper(e);
220       }
221     }
222   }
223
224   /**
225    * Forces the transaction to rollback.
226    */

227   public RuntimeException JavaDoc setRollbackOnly(Throwable JavaDoc exn)
228   {
229     _rollbackOnly = true;
230
231     if (log.isLoggable(Level.FINER))
232       log.log(Level.FINER, "rollback only: " + exn, exn);
233
234     if (_transaction != null) {
235       try {
236         if (_transaction instanceof TransactionImpl)
237           ((TransactionImpl) _transaction).setRollbackOnly(exn);
238         else
239           _transaction.setRollbackOnly();
240       } catch (Exception JavaDoc e) {
241         return EJBExceptionWrapper.createRuntime(exn);
242       }
243     }
244
245     return EJBExceptionWrapper.createRuntime(exn);
246   }
247
248   /**
249    * Add a new persistent object to the transaction context.
250    *
251    * @param object the new persistent object to be managed
252    */

253   public void addObject(TransactionObject object)
254   {
255     if (_objectTop + 1 >= _objects.length) {
256       TransactionObject []newObjects;
257       newObjects = new TransactionObject[_objects.length * 2];
258       for (int i = 0; i < _objectTop; i++)
259         newObjects[i] = _objects[i];
260       _objects = newObjects;
261     }
262
263     _objects[_objectTop++] = object;
264   }
265
266   /**
267    * Remove a transaction object from the transaction context.
268    *
269    * @param object the transaction object to be removed
270    */

271   public void removeObject(TransactionObject object)
272   {
273     for (int i = 0; i < _objectTop; i++) {
274       if (_objects[i] == object) {
275         for (int j = i; j + 1 < _objectTop; j++)
276           _objects[j] = _objects[j + 1];
277         i--;
278         _objectTop--;
279       }
280     }
281   }
282
283   /**
284    * Returns the matching object.
285    */

286   public QEntity getEntity(EntityServer server, Object JavaDoc primaryKey)
287   {
288     for (int i = _objectTop - 1; i >= 0; i--) {
289       TransactionObject obj = _objects[i];
290
291       if (obj instanceof QEntity) {
292         QEntity entity = (QEntity) obj;
293
294         if (entity._caucho_isMatch(server, primaryKey)) {
295           return entity;
296         }
297       }
298     }
299
300     return null;
301   }
302
303   /**
304    * Returns the amber connection.
305    */

306   public AmberConnection getAmberConnection()
307   {
308     if (_amberConn == null) {
309       _amberConn = _container.getEJBManager().getAmberManager().getThreadConnection();
310     }
311
312     try {
313       _amberConn.setXA(_transaction != null);
314     } catch (Exception JavaDoc e) {
315       log.log(Level.WARNING, e.toString(), e);
316     }
317
318     return _amberConn;
319   }
320
321   /**
322    * Add a session to the transaction context.
323    *
324    * @param session the new session to be managed
325    */

326   public void addSession(SessionSynchronization JavaDoc session)
327     throws EJBException JavaDoc
328   {
329     for (int i = _sessionTop - 1; i >= 0; i--)
330       if (_sessions[i] == session)
331         return;
332
333     if (_sessionTop + 1 >= _sessions.length) {
334       SessionSynchronization JavaDoc []newSessions;
335       newSessions = new SessionSynchronization JavaDoc[_sessions.length * 2];
336
337       for (int i = 0; i < _sessionTop; i++)
338         newSessions[i] = _sessions[i];
339       _sessions = newSessions;
340     }
341
342     _sessions[_sessionTop++] = session;
343     try {
344       session.afterBegin();
345     } catch (RemoteException JavaDoc e) {
346       EJBException JavaDoc exn = new EJBException JavaDoc(e.toString());
347       exn.initCause(e);
348       throw exn;
349     }
350   }
351
352   /**
353    * Synchronizes the objects in the context.
354    */

355   public void sync()
356     throws EJBException JavaDoc
357   {
358     try {
359       for (int i = _objectTop - 1; i >= 0; i--) {
360         _objects[i]._caucho_sync();
361       }
362     } catch (Exception JavaDoc e) {
363       throw setRollbackOnly(e);
364     }
365   }
366
367   /**
368    * Returns true if the transaction isn't used.
369    */

370   public boolean isEmpty()
371   {
372     if (! _isAlive)
373       return true;
374     else if (_transaction == null)
375       return true;
376     else if (! (_transaction instanceof TransactionImpl))
377       return false;
378     else
379       return ((TransactionImpl) _transaction).isEmpty();
380   }
381
382   /**
383    * Commit the transaction
384    */

385   public void commit()
386     throws EJBException JavaDoc
387   {
388     if (_isCommitting || --_depth > 0)
389       return;
390
391     boolean hasCompletion = false;
392     try {
393       _isCommitting = true;
394
395       if (! _isAlive) {
396         log.warning(L.l("Transaction has died"));
397       }
398       else if (_transaction == null) {
399         hasCompletion = true;
400         try {
401           beforeCompletion();
402         } finally {
403           afterCompletion(_rollbackOnly ?
404                           Status.STATUS_ROLLEDBACK :
405                           Status.STATUS_COMMITTED);
406         }
407       }
408       else if (_rollbackOnly ||
409                _transaction.getStatus() == Status.STATUS_MARKED_ROLLBACK) {
410         hasCompletion = true;
411         _userTransaction.rollback();
412       }
413       else if (_transaction.getStatus() != Status.STATUS_NO_TRANSACTION) {
414         hasCompletion = true;
415         _userTransaction.commit();
416       }
417     } catch (Exception JavaDoc e) {
418       throw EJBExceptionWrapper.createRuntime(e);
419     } finally {
420       _isCommitting = false;
421
422       if (! hasCompletion)
423         afterCompletion(Status.STATUS_ROLLEDBACK);
424     }
425   }
426
427   /**
428    * Rollback the transaction (help?)
429    */

430   public void rollback()
431     throws EJBException JavaDoc
432   {
433     if (_isCommitting || --_depth > 0)
434       return;
435
436     try {
437       _isCommitting = true;
438
439       if (! _rollbackOnly)
440         setRollbackOnly();
441
442       if (_transaction == null && _isAlive) {
443         try {
444           beforeCompletion();
445         } finally {
446           afterCompletion(Status.STATUS_ROLLEDBACK);
447         }
448       }
449       else
450         _userTransaction.rollback();
451     } catch (EJBException JavaDoc e) {
452       throw e;
453     } catch (Exception JavaDoc e) {
454       throw new EJBExceptionWrapper(e);
455     } finally {
456       _isCommitting = false;
457
458       if (_depth <= 0 && _transaction != null)
459         afterCompletion(Status.STATUS_ROLLEDBACK);
460     }
461   }
462
463   /**
464    * Called by the transaction before the transaction completes.
465    */

466   public void beforeCompletion()
467   {
468     try {
469       if (_transaction != null &&
470           _transaction.getStatus() == Status.STATUS_MARKED_ROLLBACK)
471         _rollbackOnly = true;
472
473       for (int i = _sessionTop - 1; i >= 0; i--)
474         _sessions[i].beforeCompletion();
475
476       for (int i = _objectTop - 1; i >= 0; i--) {
477         _objects[i]._caucho_beforeCompletion(! _rollbackOnly);
478       }
479
480       // ejb/0600: com.caucho.transaction.TransactionImpl
481
// will call _amberConn.beforeCompletion() which
482
// already calls beforeCommit().
483
//
484
// if (_amberConn != null)
485
// _amberConn.beforeCommit();
486
} catch (Throwable JavaDoc e) {
487       throw setRollbackOnly(e);
488     }
489   }
490
491   public boolean isDead()
492   {
493     return ! _isAlive;
494   }
495
496   /**
497    * After the transaction completes, do any extra work.
498    */

499   public void afterCompletion(int status)
500   {
501     /*
502       if (! _isUserTransaction && _depth > 0) {
503       return;
504       }
505     */

506
507     if (! _isAlive) {
508       IllegalStateException JavaDoc e = new IllegalStateException JavaDoc("after completion called for dead transaction.");
509       log.log(Level.WARNING, e.toString(), e);
510       return;
511     }
512
513     boolean wasCommitted = status == Status.STATUS_COMMITTED;
514     int sessionTop = _sessionTop;
515     int objectTop = _objectTop;
516     TransactionContext old = _old;
517     Transaction JavaDoc transaction = _transaction;
518     Transaction JavaDoc oldTrans = _oldTrans;
519
520     _sessionTop = 0;
521     _objectTop = 0;
522     _old = null;
523     if (oldTrans == transaction)
524       oldTrans = null;
525     _oldTrans = null;
526     _rollbackOnly = false;
527
528     Throwable JavaDoc exn = null;
529
530     try {
531       AmberConnection amberConn = _amberConn;
532       _amberConn = null;
533       if (amberConn != null) {
534         amberConn.afterCommit(wasCommitted);
535         amberConn.freeConnection();
536       }
537     } catch (Throwable JavaDoc e) {
538       log.log(Level.WARNING, e.toString(), e);
539     }
540
541     for (int i = sessionTop - 1; i >= 0; i--) {
542       try {
543         _sessions[i].afterCompletion(wasCommitted);
544         _sessions[i] = null;
545       } catch (Throwable JavaDoc e) {
546         exn = e;
547         log.log(Level.WARNING, e.toString(), e);
548       }
549     }
550
551     for (int i = objectTop - 1; i >= 0; i--) {
552       try {
553         _objects[i]._caucho_afterCompletion(wasCommitted);
554         _objects[i] = null;
555       } catch (Throwable JavaDoc e) {
556         exn = e;
557         log.log(Level.WARNING, e.toString(), e);
558       }
559     }
560
561     _transaction = null;
562     _isAlive = false;
563
564     if (_depth == 0 || _isUserTransaction && _depth == 1) {
565       _container.resume(old, oldTrans, transaction);
566       _container.freeTransaction(this);
567     }
568
569     if (exn != null)
570       throw EJBExceptionWrapper.createRuntime(exn);
571   }
572 }
573
Popular Tags