KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > openejb > core > TransactionManagerWrapper


1 /**
2  * Redistribution and use of this software and associated documentation
3  * ("Software"), with or without modification, are permitted provided
4  * that the following conditions are met:
5  *
6  * 1. Redistributions of source code must retain copyright
7  * statements and notices. Redistributions must also contain a
8  * copy of this document.
9  *
10  * 2. Redistributions in binary form must reproduce the
11  * above copyright notice, this list of conditions and the
12  * following disclaimer in the documentation and/or other
13  * materials provided with the distribution.
14  *
15  * 3. The name "Exolab" must not be used to endorse or promote
16  * products derived from this Software without prior written
17  * permission of Exoffice Technologies. For written permission,
18  * please contact info@exolab.org.
19  *
20  * 4. Products derived from this Software may not be called "Exolab"
21  * nor may "Exolab" appear in their names without prior written
22  * permission of Exoffice Technologies. Exolab is a registered
23  * trademark of Exoffice Technologies.
24  *
25  * 5. Due credit should be given to the Exolab Project
26  * (http://www.exolab.org/).
27  *
28  * THIS SOFTWARE IS PROVIDED BY EXOFFICE TECHNOLOGIES AND CONTRIBUTORS
29  * ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
30  * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
31  * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
32  * EXOFFICE TECHNOLOGIES OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
33  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
34  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
35  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
37  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
38  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
39  * OF THE POSSIBILITY OF SUCH DAMAGE.
40  *
41  * Copyright 1999 (C) Exoffice Technologies Inc. All Rights Reserved.
42  *
43  * $Id: TransactionManagerWrapper.java 1921 2005-06-19 22:40:34Z jlaskowski $
44  */

45 package org.openejb.core;
46
47 import java.util.Hashtable JavaDoc;
48 import java.util.Vector JavaDoc;
49
50 import javax.transaction.Status JavaDoc;
51 import javax.transaction.Synchronization JavaDoc;
52 import javax.transaction.Transaction JavaDoc;
53 import javax.transaction.TransactionManager JavaDoc;
54 import javax.transaction.xa.XAResource JavaDoc;
55
56 /**
57  * This class intercepts requests to the TransactonManager so that it
58  * can provide wrappers for javax.transaction.Transaction objects.
59  * The Transaction wrappers allow Synchronization objects can be more
60  * finely managed. This allows, for example, enterprise beans to have
61  * their synchronization callback methods executed before
62  * synchronization objects registered by the Persistence Manager
63  * instances or Connectors.
64  * <p>
65  * Synchronized objects can be registered in groups organized by
66  * priority. The Synchronization group with the highest priority,
67  * priority = 1, is handled first, so that all of 1st (priority=1)
68  * synchronization group beforeCompletion() and afterCompletion( )
69  * methods are executed first. The synchronization group with the
70  * second highest priority (priority = 2) is handled second and so on.
71  * <p>
72  * Their are 3 priorities (1, 2, and 3). Synchronization objects may
73  * be added with any one of these priorities. If a Synchronization
74  * object is added with a priority higher then 3, its added to the
75  * third priority group. If a Synchronization object is added with a
76  * priority lower then 1, its added to the first priority group.
77  * <p>
78  * Within a synchronization group, Synchronization objects are
79  * handled in the order they were registered. The first
80  * Synchronization object added to the group is handled first.
81  * <p>
82  * All the beforeCompletion() methods on all the Synchronization
83  * objects will be executed before any of the afterCompletion()
84  * methods are executed. Both are executed according to priority and
85  * order registered.
86  */

87 public class TransactionManagerWrapper implements TransactionManager JavaDoc {
88     /**
89      * Transaction Manager Instance
90      *
91      * @see org.openejb.spi.TransactionService
92      */

93     final private TransactionManager JavaDoc transactionManager;
94     /**
95      */

96     final private Hashtable JavaDoc wrapperMap = new Hashtable JavaDoc();
97
98     final static protected org.apache.log4j.Category logger = org.apache.log4j.Category.getInstance("Transaction");
99
100     /**
101      * Constructor
102      *
103      * @param txMngr The Transaction Manager plugged into OpenEJB
104      */

105     public TransactionManagerWrapper(TransactionManager JavaDoc txMngr) {
106         transactionManager = txMngr;
107     }
108     
109     public javax.transaction.TransactionManager JavaDoc getTxManager() {
110         return transactionManager;
111     }
112
113     /**
114      * Delegates the call to the Transaction Manager
115      * passed into the constructor.
116      *
117      * @exception javax.transaction.SystemException
118      * @exception javax.transaction.NotSupportedException
119      */

120     public void begin( )throws javax.transaction.SystemException JavaDoc, javax.transaction.NotSupportedException JavaDoc{
121         int status=transactionManager.getStatus();
122         if(status== Status.STATUS_NO_TRANSACTION ||
123            status== Status.STATUS_ROLLEDBACK ||
124            status== Status.STATUS_COMMITTED ) {
125         transactionManager.begin();
126             createTxWrapper();
127         }else {
128             throw new javax.transaction.NotSupportedException JavaDoc("Can't start new transaction."+getStatus(status));
129         }
130     }
131     /**
132      * Delegates the call to the Transaction Manager
133      * passed into the constructor.
134      *
135      * @exception javax.transaction.SystemException
136      * @exception javax.transaction.RollbackException
137      * @exception javax.transaction.HeuristicRollbackException
138      * @exception javax.transaction.HeuristicMixedException
139      */

140     public void commit()throws javax.transaction.SystemException JavaDoc, javax.transaction.RollbackException JavaDoc, javax.transaction.HeuristicRollbackException JavaDoc, javax.transaction.HeuristicMixedException JavaDoc {
141         transactionManager.commit();
142     }
143     /**
144      * Delegates the call to the Transaction Manager
145      * passed into the constructor.
146      *
147      * @return int
148      * @exception javax.transaction.SystemException
149      */

150     public int getStatus()throws javax.transaction.SystemException JavaDoc{
151         return transactionManager.getStatus();
152     }
153     /**
154      * Delegates the call to the Transaction Manager
155      * passed into the constructor.
156      *
157      * @return Transaction
158      * @exception javax.transaction.SystemException
159      */

160     public Transaction JavaDoc getTransaction( )throws javax.transaction.SystemException JavaDoc{
161         return getTxWrapper(transactionManager.getTransaction());
162     }
163     /**
164      * Delegates the call to the Transaction Manager
165      * passed into the constructor.
166      *
167      * @param tx
168      * @exception javax.transaction.SystemException
169      * @exception javax.transaction.InvalidTransactionException
170      */

171     public void resume(Transaction JavaDoc tx)
172     throws javax.transaction.SystemException JavaDoc, javax.transaction.InvalidTransactionException JavaDoc{
173         if ( tx instanceof TransactionWrapper ) {
174             tx = ((TransactionWrapper)tx).transaction;
175         }
176         transactionManager.resume(tx);
177     }
178     /**
179      * Delegates the call to the Transaction Manager
180      * passed into the constructor.
181      *
182      * @return Transaction
183      * @exception javax.transaction.SystemException
184      */

185     public Transaction JavaDoc suspend( )throws javax.transaction.SystemException JavaDoc{
186         return getTxWrapper(transactionManager.suspend());
187     }
188     /**
189      * Delegates the call to the Transaction Manager
190      * passed into the constructor.
191      *
192      * @exception javax.transaction.SystemException
193      */

194     public void rollback()throws javax.transaction.SystemException JavaDoc{
195         transactionManager.rollback();
196     }
197     /**
198      * Delegates the call to the Transaction Manager
199      * passed into the constructor.
200      *
201      * @exception javax.transaction.SystemException
202      */

203     public void setRollbackOnly( )throws javax.transaction.SystemException JavaDoc{
204         transactionManager.setRollbackOnly();
205     }
206     /**
207      * Delegates the call to the Transaction Manager
208      * passed into the constructor.
209      *
210      * @param x
211      * @exception javax.transaction.SystemException
212      */

213     public void setTransactionTimeout(int x)throws javax.transaction.SystemException JavaDoc{
214         transactionManager.setTransactionTimeout(x);
215     }
216
217     /**
218      * Returns the wrapper for a given transaction
219      *
220      * @param tx
221      * @return Transaction
222      * @exception javax.transaction.SystemException
223      */

224     private Transaction JavaDoc getTxWrapper(Transaction JavaDoc tx)throws javax.transaction.SystemException JavaDoc{
225         if ( tx == null ) {
226           return null;
227         }
228         return (TransactionWrapper)wrapperMap.get(tx);
229     }
230
231     /**
232      * to be called ONLY from beginTransaction, to register a synchronization
233      * object while we can (e.g. before a rollback)
234      */

235     private void createTxWrapper() {
236                 try {
237             Transaction JavaDoc tx = transactionManager.getTransaction();
238             TransactionWrapper txW = new TransactionWrapper(tx);
239                     tx.registerSynchronization(txW);
240             wrapperMap.put(tx,txW);
241         } catch ( Exception JavaDoc re ) {
242             // this should never happen since we register right after
243
// the transaction started.
244
logger.info("", re);
245         }
246     }
247     
248     /**
249      * Wraps the Transaction Manager's transaction implementation to intercept calls
250      * to the Transaction object, most notably to registerSynchronization
251      */

252     private class TransactionWrapper
253     implements Transaction JavaDoc, javax.transaction.Synchronization JavaDoc {
254
255         /**
256          * The Transaction Manager's transaction instance.
257          */

258         private final Transaction JavaDoc transaction;
259
260         private final Vector JavaDoc registeredSynchronizations;
261
262         final public static int MAX_PRIORITY_LEVEL = 3;
263
264         private TransactionWrapper(Transaction JavaDoc tx) {
265             transaction = tx;
266             registeredSynchronizations = new Vector JavaDoc();
267         }
268
269
270         ///////////////////////////////////////////////
271
/// Transaction Methods ///
272
///////////////////////////////////////////////
273

274         public Transaction JavaDoc getTransaction() {
275
276             return transaction;
277         }
278
279         public boolean equals(java.lang.Object JavaDoc obj) {
280             if(obj != null && obj instanceof TransactionWrapper) {
281                 return transaction.equals( ((TransactionWrapper)obj).getTransaction() );
282             }
283
284             return false;
285         }
286         // equals and hashCode always have to be implemented together!
287
public int hashCode() {
288             return transaction.hashCode();
289         }
290
291         public String JavaDoc toString(){
292             return transaction.toString();
293         }
294
295         public void commit()
296         throws javax.transaction.SystemException JavaDoc, javax.transaction.RollbackException JavaDoc, javax.transaction.HeuristicRollbackException JavaDoc, javax.transaction.HeuristicMixedException JavaDoc {
297             transaction.commit();
298         }
299
300         public boolean delistResource(XAResource JavaDoc xaRes, int flag)throws javax.transaction.SystemException JavaDoc {
301             return transaction.delistResource(xaRes,flag);
302         }
303
304         public boolean enlistResource(XAResource JavaDoc xaRes)throws javax.transaction.SystemException JavaDoc, javax.transaction.RollbackException JavaDoc {
305             return transaction.enlistResource(xaRes);
306         }
307
308         public int getStatus()throws javax.transaction.SystemException JavaDoc{
309             return transaction.getStatus();
310         }
311         /*
312         * Automatically add the Synchronization object to the lowest priority register.
313         * Synchronization objects are executed in groups according to their priority
314         * and within each group according to the order they were registered.
315         */

316         public void registerSynchronization(Synchronization JavaDoc sync)
317         throws javax.transaction.SystemException JavaDoc, javax.transaction.RollbackException JavaDoc{
318
319             registerSynchronization(sync,MAX_PRIORITY_LEVEL);
320         }
321
322         /**
323          * This method allows for notification when the transaction ends.
324          * As opposed to the documented behavior of the same method on the
325          * Transaction interface the registration will succeed even after
326          * the transaction has been marked for rollback. Multiple registrations
327          * for the same object will be ignored.
328          * @param sync
329          * @param priority
330          */

331         private void registerSynchronization(Synchronization JavaDoc sync, int priority) {
332             if (!registeredSynchronizations.contains(sync)) {
333                 registeredSynchronizations.addElement(sync);
334             }
335         }
336
337         public void rollback()throws javax.transaction.SystemException JavaDoc{
338             transaction.rollback();
339         }
340
341         public void setRollbackOnly() throws javax.transaction.SystemException JavaDoc{
342             transaction.setRollbackOnly();
343         }
344         ///////////////////////////////////////////////
345
/// Synchronization Methods ///
346
///////////////////////////////////////////////
347

348         public void beforeCompletion() {
349             int count = registeredSynchronizations.size();
350             for ( int i=0; i<count; ++i ) {
351                 try {
352                     Synchronization JavaDoc sync = (Synchronization JavaDoc)registeredSynchronizations.elementAt(i);
353                         sync.beforeCompletion();
354                     } catch ( RuntimeException JavaDoc re ) {
355                     logger.error("", re);
356                 }
357             }
358         }
359
360         public void afterCompletion(int status) {
361             int count = registeredSynchronizations.size();
362             for ( int i=0; i<count; ++i ) {
363                 try {
364                     Synchronization JavaDoc sync = (Synchronization JavaDoc)registeredSynchronizations.elementAt(i);
365                         sync.afterCompletion(status);
366                     } catch ( RuntimeException JavaDoc re ) {
367                     logger.error("", re);
368                 }
369             }
370             wrapperMap.remove(transaction);
371         }
372
373     }// End Innerclass: TransctionWrapper
374

375     /**
376      * Returns the readable name for the specified status.
377      *
378      * @param status The status
379      * @return The status
380      */

381     public static String JavaDoc getStatus( int status )
382     {
383         StringBuffer JavaDoc buffer;
384
385         buffer = new StringBuffer JavaDoc(100);
386         switch ( status ) {
387         case Status.STATUS_ACTIVE:
388             buffer.append( "STATUS_ACTIVE: " );
389             buffer.append( "A transaction is associated with the target object and it is in the active state." );
390             break;
391         case Status.STATUS_COMMITTED:
392             buffer.append( "STATUS_COMMITTED: " );
393             buffer.append( "A transaction is associated with the target object and it has been committed." );
394             break;
395         case Status.STATUS_COMMITTING:
396             buffer.append( "STATUS_COMMITTING: " );
397             buffer.append( "A transaction is associated with the target object and it is in the process of committing." );
398             break;
399         case Status.STATUS_MARKED_ROLLBACK:
400             buffer.append( "STATUS_MARKED_ROLLBACK: " );
401             buffer.append( "A transaction is associated with the target object and it has been marked for rollback, perhaps as a result of a setRollbackOnly operation." );
402             break;
403         case Status.STATUS_NO_TRANSACTION:
404             buffer.append( "STATUS_NO_TRANSACTION: " );
405             buffer.append( "No transaction is currently associated with the target object." );
406             break;
407         case Status.STATUS_PREPARED:
408             buffer.append( "STATUS_PREPARED: " );
409             buffer.append( "A transaction is associated with the target object and it has been prepared, i.e." );
410             break;
411         case Status.STATUS_PREPARING:
412             buffer.append( "STATUS_PREPARING: " );
413             buffer.append( "A transaction is associated with the target object and it is in the process of preparing." );
414             break;
415         case Status.STATUS_ROLLEDBACK:
416             buffer.append( "STATUS_ROLLEDBACK: " );
417             buffer.append( "A transaction is associated with the target object and the outcome has been determined as rollback." );
418             break;
419         case Status.STATUS_ROLLING_BACK:
420             buffer.append( "STATUS_ROLLING_BACK: " );
421             buffer.append( "A transaction is associated with the target object and it is in the process of rolling back." );
422             break;
423         default:
424             buffer.append( "Unknown status " + status );
425             break;
426         }
427         return buffer.toString();
428     }
429 }
430
Popular Tags