KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > geronimo > transaction > context > InheritableTransactionContext


1 /**
2  *
3  * Copyright 2003-2004 The Apache Software Foundation
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */

17
18 package org.apache.geronimo.transaction.context;
19
20 import java.util.Iterator JavaDoc;
21 import java.util.Map JavaDoc;
22 import java.util.ArrayList JavaDoc;
23 import javax.transaction.SystemException JavaDoc;
24 import javax.transaction.Status JavaDoc;
25 import javax.transaction.Transaction JavaDoc;
26 import javax.transaction.InvalidTransactionException JavaDoc;
27 import javax.transaction.NotSupportedException JavaDoc;
28 import javax.transaction.HeuristicMixedException JavaDoc;
29 import javax.transaction.HeuristicRollbackException JavaDoc;
30 import javax.transaction.RollbackException JavaDoc;
31 import javax.transaction.Synchronization JavaDoc;
32 import javax.transaction.xa.XAResource JavaDoc;
33
34 import org.apache.geronimo.transaction.ExtendedTransactionManager;
35 import org.apache.geronimo.transaction.ConnectionReleaser;
36 import org.apache.geronimo.transaction.InstanceContext;
37
38 /**
39  * @version $Rev: 155839 $ $Date: 2005-03-01 15:30:08 -0800 (Tue, 01 Mar 2005) $
40  */

41 abstract class InheritableTransactionContext extends AbstractTransactionContext {
42     private final ExtendedTransactionManager txnManager;
43     private Transaction JavaDoc transaction;
44     private boolean threadAssociated = false;
45
46     protected InheritableTransactionContext(ExtendedTransactionManager txnManager) {
47         this.txnManager = txnManager;
48     }
49
50     protected InheritableTransactionContext(ExtendedTransactionManager txnManager, Transaction JavaDoc transaction) {
51         this.txnManager = txnManager;
52         this.transaction = transaction;
53     }
54
55     void begin(long transactionTimeoutMilliseconds) throws SystemException JavaDoc, NotSupportedException JavaDoc {
56         if (transaction != null) {
57             throw new SystemException JavaDoc("Context is already associated with a transaction");
58         }
59         transaction = txnManager.begin(transactionTimeoutMilliseconds);
60         threadAssociated = true;
61     }
62
63     boolean isThreadAssociated() {
64         return threadAssociated;
65     }
66
67     public Transaction JavaDoc getTransaction() {
68         return transaction;
69     }
70
71     public boolean isInheritable() {
72         return true;
73     }
74
75     public boolean isActive() {
76         if (transaction == null) {
77             return false;
78         }
79         try {
80             int status = transaction.getStatus();
81             return status == Status.STATUS_ACTIVE || status == Status.STATUS_MARKED_ROLLBACK;
82         } catch (SystemException JavaDoc e) {
83             return false;
84         }
85     }
86
87     public boolean enlistResource(XAResource JavaDoc xaResource) throws RollbackException JavaDoc, SystemException JavaDoc {
88         if (transaction == null) {
89             throw new IllegalStateException JavaDoc("There is no transaction in progress.");
90         }
91
92         return transaction.enlistResource(xaResource);
93     }
94
95     public boolean delistResource(XAResource JavaDoc xaResource, int flag) throws SystemException JavaDoc {
96         if (transaction == null) {
97             throw new IllegalStateException JavaDoc("There is no transaction in progress.");
98         }
99
100         return transaction.delistResource(xaResource, flag);
101     }
102
103     public void registerSynchronization(Synchronization JavaDoc synchronization) throws RollbackException JavaDoc, SystemException JavaDoc {
104         if (transaction == null) {
105             throw new IllegalStateException JavaDoc("There is no transaction in progress.");
106         }
107
108         transaction.registerSynchronization(synchronization);
109     }
110
111     public boolean getRollbackOnly() throws SystemException JavaDoc {
112         if (transaction == null) {
113             throw new IllegalStateException JavaDoc("There is no transaction in progress.");
114         }
115
116         int status = transaction.getStatus();
117         return (status == Status.STATUS_MARKED_ROLLBACK ||
118                 status == Status.STATUS_ROLLEDBACK ||
119                 status == Status.STATUS_ROLLING_BACK);
120     }
121
122     public void setRollbackOnly() throws IllegalStateException JavaDoc, SystemException JavaDoc {
123         if (transaction == null) {
124             throw new IllegalStateException JavaDoc("There is no transaction in progress.");
125         }
126         transaction.setRollbackOnly();
127     }
128
129     public void suspend() throws SystemException JavaDoc {
130         Transaction JavaDoc suspendedTransaction = txnManager.suspend();
131         if (transaction != suspendedTransaction) {
132             throw new SystemException JavaDoc("Suspend did not return our transaction: expectedTx=" + transaction + ", suspendedTx=" + suspendedTransaction);
133         }
134         threadAssociated = false;
135     }
136
137     public void resume() throws SystemException JavaDoc, InvalidTransactionException JavaDoc {
138         txnManager.resume(transaction);
139         threadAssociated = true;
140     }
141
142     public boolean commit() throws HeuristicMixedException JavaDoc, HeuristicRollbackException JavaDoc, SystemException JavaDoc, RollbackException JavaDoc {
143         return complete();
144     }
145
146     public void rollback() throws SystemException JavaDoc {
147         setRollbackOnly();
148         try {
149             complete();
150         } catch (SystemException JavaDoc e) {
151             throw e;
152         } catch (RuntimeException JavaDoc e) {
153             throw e;
154         } catch (Error JavaDoc e) {
155             throw e;
156         } catch (Exception JavaDoc e) {
157             throw (SystemException JavaDoc) new SystemException JavaDoc("After commit of container transaction failed").initCause(e);
158         }
159     }
160
161     private boolean complete() throws HeuristicMixedException JavaDoc, HeuristicRollbackException JavaDoc, SystemException JavaDoc, RollbackException JavaDoc {
162         if (transaction == null) {
163             throw new IllegalStateException JavaDoc("There is no transaction in progress.");
164         }
165
166         boolean wasCommitted = false;
167         try {
168             if (isRolledback()) {
169                 return false;
170             }
171
172             flushState();
173
174             if (isRolledback()) {
175                 return false;
176             }
177
178             // todo we need to flush anyone enrolled during before and then call before on any flushed...
179
beforeCommit();
180
181             if (isRolledback()) {
182                 return false;
183             }
184
185             // verify our tx is the current tx associated with the thread
186
// this is really only an error case and should never happen, but just to be sure double check
187
// immedately before committing using the transaction manager
188
Transaction JavaDoc currentTransaction = txnManager.getTransaction();
189             if (currentTransaction != transaction) {
190                 throw new SystemException JavaDoc("An unknown transaction is currently associated with the thread: expectedTx=" + transaction + ", currentTx=" + currentTransaction);
191             }
192
193             txnManager.commit();
194             wasCommitted = true;
195         } catch (Throwable JavaDoc t) {
196             rollbackAndThrow("Unable to commit container transaction", t);
197         } finally {
198             transaction = null;
199             try {
200                 afterCommit(wasCommitted);
201             } catch (Throwable JavaDoc e) {
202                 rollbackAndThrow("After commit of container transaction failed", e);
203             } finally {
204                 unassociateAll();
205                 connectorAfterCommit();
206                 threadAssociated = false;
207             }
208         }
209         return wasCommitted;
210     }
211
212     private void beforeCommit() throws Throwable JavaDoc {
213         // @todo allow for enrollment during pre-commit
214
ArrayList JavaDoc toFlush = getAssociatedContexts();
215         for (Iterator JavaDoc i = toFlush.iterator(); i.hasNext();) {
216             InstanceContext context = (InstanceContext) i.next();
217             if (!context.isDead()) {
218                 context.beforeCommit();
219             }
220         }
221     }
222
223     private void afterCommit(boolean status) throws Throwable JavaDoc {
224         Throwable JavaDoc firstThrowable = null;
225         ArrayList JavaDoc toFlush = getAssociatedContexts();
226         for (Iterator JavaDoc i = toFlush.iterator(); i.hasNext();) {
227             InstanceContext context = (InstanceContext) i.next();
228             if (!context.isDead()) {
229                 try {
230                     context.afterCommit(status);
231                 } catch (Throwable JavaDoc e) {
232                     if (firstThrowable == null) {
233                         firstThrowable = e;
234                     }
235                 }
236             }
237         }
238
239         if (firstThrowable instanceof Error JavaDoc) {
240             throw (Error JavaDoc) firstThrowable;
241         } else if (firstThrowable instanceof Exception JavaDoc) {
242             throw (Exception JavaDoc) firstThrowable;
243         } else if (firstThrowable != null) {
244             throw (SystemException JavaDoc) new SystemException JavaDoc().initCause(firstThrowable);
245         }
246     }
247
248     private void connectorAfterCommit() {
249         if (managedConnections != null) {
250             for (Iterator JavaDoc entries = managedConnections.entrySet().iterator(); entries.hasNext();) {
251                 Map.Entry JavaDoc entry = (Map.Entry JavaDoc) entries.next();
252                 ConnectionReleaser key = (ConnectionReleaser) entry.getKey();
253                 key.afterCompletion(entry.getValue());
254             }
255             //If BeanTransactionContext never reuses the same instance for sequential BMT, this
256
//clearing is unnecessary.
257
managedConnections.clear();
258         }
259     }
260
261     private boolean isRolledback() throws SystemException JavaDoc {
262         int status;
263         try {
264             status = transaction.getStatus();
265         } catch (SystemException JavaDoc e) {
266             transaction.rollback();
267             throw e;
268         }
269
270         if (status == Status.STATUS_MARKED_ROLLBACK) {
271             // verify our tx is the current tx associated with the thread
272
// this is really only an error case and should never happen, but just to be sure double check
273
// immedately before committing using the transaction manager
274
Transaction JavaDoc currentTransaction = txnManager.getTransaction();
275             if (currentTransaction != transaction) {
276                 throw new SystemException JavaDoc("An unknown transaction is currently associated with the thread: expectedTx=" + transaction + ", currentTx=" + currentTransaction);
277             }
278
279             // we need to rollback
280
txnManager.rollback();
281             return true;
282         } else if (status == Status.STATUS_ROLLEDBACK ||
283                 status == Status.STATUS_ROLLING_BACK) {
284             // already rolled back
285
return true;
286         }
287         return false;
288     }
289
290     private void rollbackAndThrow(String JavaDoc message, Throwable JavaDoc throwable) throws HeuristicMixedException JavaDoc, HeuristicRollbackException JavaDoc, SystemException JavaDoc, RollbackException JavaDoc {
291         try {
292             if (txnManager.getStatus() != Status.STATUS_NO_TRANSACTION) {
293                 txnManager.rollback();
294             }
295         } catch (Throwable JavaDoc t) {
296             log.error("Unable to roll back transaction", t);
297         }
298
299         try {
300             // make doubly sure our transaction was rolled back
301
// this can happen when there was a junk transaction on the thread
302
int status = transaction.getStatus();
303             if (status != Status.STATUS_ROLLEDBACK &&
304                     status != Status.STATUS_ROLLING_BACK) {
305                 transaction.rollback();
306             }
307         } catch (Throwable JavaDoc t) {
308             log.error("Unable to roll back transaction", t);
309         }
310
311         if (throwable instanceof HeuristicMixedException JavaDoc) {
312             throw (HeuristicMixedException JavaDoc) throwable;
313         } else if (throwable instanceof HeuristicRollbackException JavaDoc) {
314             throw (HeuristicRollbackException JavaDoc) throwable;
315         } else if (throwable instanceof RollbackException JavaDoc) {
316             throw (RollbackException JavaDoc) throwable;
317         } else if (throwable instanceof SystemException JavaDoc) {
318             throw (SystemException JavaDoc) throwable;
319         } else if (throwable instanceof Error JavaDoc) {
320             throw (Error JavaDoc) throwable;
321         } else if (throwable instanceof RuntimeException JavaDoc) {
322             throw (RuntimeException JavaDoc) throwable;
323         } else {
324             throw (SystemException JavaDoc) new SystemException JavaDoc(message).initCause(throwable);
325         }
326     }
327 }
328
Popular Tags