KickJava   Java API By Example, From Geeks To Geeks.

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


1 /**
2  *
3  * Copyright 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.HashMap JavaDoc;
21 import java.util.Iterator JavaDoc;
22 import java.util.Map JavaDoc;
23 import javax.resource.spi.XATerminator JavaDoc;
24 import javax.transaction.InvalidTransactionException JavaDoc;
25 import javax.transaction.NotSupportedException JavaDoc;
26 import javax.transaction.Status JavaDoc;
27 import javax.transaction.SystemException JavaDoc;
28 import javax.transaction.Transaction JavaDoc;
29 import javax.transaction.TransactionManager JavaDoc;
30 import javax.transaction.xa.XAException JavaDoc;
31 import javax.transaction.xa.XAResource JavaDoc;
32 import javax.transaction.xa.Xid JavaDoc;
33
34 import org.apache.geronimo.gbean.GBeanInfo;
35 import org.apache.geronimo.gbean.GBeanInfoBuilder;
36 import org.apache.geronimo.j2ee.j2eeobjectnames.NameFactory;
37 import org.apache.geronimo.transaction.ExtendedTransactionManager;
38 import org.apache.geronimo.transaction.ImportedTransactionActiveException;
39 import org.apache.geronimo.transaction.XAWork;
40 import org.apache.geronimo.transaction.manager.XidImporter;
41 import org.apache.commons.logging.Log;
42 import org.apache.commons.logging.LogFactory;
43
44 /**
45  * @version $Rev: 156292 $ $Date: 2005-03-05 18:48:02 -0800 (Sat, 05 Mar 2005) $
46  */

47 public class TransactionContextManager implements XATerminator JavaDoc, XAWork {
48     private static final Log log = LogFactory.getLog(TransactionContextManager.class);
49     private static final boolean NOT_IN_RECOVERY = false;
50     private static final boolean IN_RECOVERY = true;
51
52     private ThreadLocal JavaDoc CONTEXT = new ThreadLocal JavaDoc();
53     private final ExtendedTransactionManager transactionManager;
54     private final XidImporter importer;
55     private final Map JavaDoc importedTransactions = new HashMap JavaDoc();
56
57     private boolean recoveryState = NOT_IN_RECOVERY;
58
59     //use as reference endpoint.
60
public TransactionContextManager() {
61         this(null, null);
62     }
63
64     public TransactionContextManager(ExtendedTransactionManager transactionManager, XidImporter importer) {
65         this.transactionManager = transactionManager;
66         this.importer = importer;
67     }
68
69     public TransactionManager JavaDoc getTransactionManager() {
70         return transactionManager;
71     }
72
73     public void setTransactionTimeout(int timeoutSeconds) throws SystemException JavaDoc {
74         transactionManager.setTransactionTimeout(timeoutSeconds);
75     }
76
77     public TransactionContext getContext() {
78         return (TransactionContext) CONTEXT.get();
79     }
80
81     public void setContext(TransactionContext transactionContext) {
82         CONTEXT.set(transactionContext);
83     }
84
85     public TransactionContext newContainerTransactionContext() throws NotSupportedException JavaDoc, SystemException JavaDoc {
86         ContainerTransactionContext transactionContext = new ContainerTransactionContext(transactionManager);
87         setContext(transactionContext);
88         return transactionContext;
89     }
90
91     public TransactionContext newBeanTransactionContext(long transactionTimeoutMilliseconds) throws NotSupportedException JavaDoc, SystemException JavaDoc {
92         TransactionContext ctx = getContext();
93         if (ctx instanceof UnspecifiedTransactionContext == false) {
94             throw new NotSupportedException JavaDoc("Previous Transaction has not been committed");
95         }
96         UnspecifiedTransactionContext oldContext = (UnspecifiedTransactionContext) ctx;
97         BeanTransactionContext transactionContext = new BeanTransactionContext(transactionManager, oldContext);
98         oldContext.suspend();
99         try {
100             transactionContext.begin(transactionTimeoutMilliseconds);
101         } catch (SystemException JavaDoc e) {
102             oldContext.resume();
103             throw e;
104         } catch (NotSupportedException JavaDoc e) {
105             oldContext.resume();
106             throw e;
107         }
108         setContext(transactionContext);
109         return transactionContext;
110     }
111
112     public TransactionContext newUnspecifiedTransactionContext() {
113         UnspecifiedTransactionContext transactionContext = new UnspecifiedTransactionContext();
114         setContext(transactionContext);
115         return transactionContext;
116     }
117
118     public TransactionContext suspendBeanTransactionContext() throws SystemException JavaDoc {
119         // suspend the exisiting unspecified transaction context
120
TransactionContext callerContext = getContext();
121         if (!(callerContext instanceof BeanTransactionContext)) {
122             throw new SystemException JavaDoc("Caller context is not a bean managed transaction context");
123         }
124         BeanTransactionContext beanContext = ((BeanTransactionContext) callerContext);
125
126         // update the old context in the bean context
127
UnspecifiedTransactionContext oldContext = beanContext.getOldContext();
128         beanContext.setOldContext(null);
129
130         // suspend the bean context
131
try {
132             beanContext.suspend();
133             return beanContext;
134         } catch (SystemException JavaDoc e) {
135             if (beanContext.isActive()) {
136                 try {
137                     beanContext.rollback();
138                 } catch (SystemException JavaDoc e1) {
139                     log.warn("Unable to rollback transaction", e);
140                 }
141             }
142             throw e;
143         } finally {
144             // always resume the old transaction
145
setContext(oldContext);
146             oldContext.resume();
147             setContext(oldContext);
148         }
149     }
150
151     public void resumeBeanTransactionContext(TransactionContext context) throws SystemException JavaDoc, InvalidTransactionException JavaDoc {
152         if (!(context instanceof BeanTransactionContext)) {
153             throw new InvalidTransactionException JavaDoc("Context is not a bean managed transaction context");
154         }
155         if (!context.isActive()) {
156             throw new InvalidTransactionException JavaDoc("Context is not active");
157         }
158         BeanTransactionContext beanContext = ((BeanTransactionContext) context);
159
160         // suspend the exisiting unspecified transaction context
161
TransactionContext callerContext = getContext();
162         if (!(callerContext instanceof UnspecifiedTransactionContext)) {
163             throw new InvalidTransactionException JavaDoc("Caller context is not an unspecified transaction context");
164         }
165         callerContext.suspend();
166
167         try {
168             beanContext.setOldContext((UnspecifiedTransactionContext) callerContext);
169             context.resume();
170             setContext(context);
171         } catch (SystemException JavaDoc e) {
172             if (beanContext.isActive()) {
173                 try {
174                     beanContext.rollback();
175                 } catch (SystemException JavaDoc e1) {
176                     log.warn("Unable to rollback transaction", e);
177                 }
178             }
179             beanContext.setOldContext(null);
180             callerContext.resume();
181             throw e;
182         } catch (InvalidTransactionException JavaDoc e) {
183             if (beanContext.isActive()) {
184                 try {
185                     beanContext.rollback();
186                 } catch (SystemException JavaDoc e1) {
187                     log.warn("Unable to rollback transaction", e);
188                 }
189             }
190             beanContext.setOldContext(null);
191             callerContext.resume();
192             throw e;
193         }
194     }
195
196     public int getStatus() throws SystemException JavaDoc {
197         return transactionManager.getStatus();
198     }
199
200     public void setRollbackOnly() throws SystemException JavaDoc {
201         transactionManager.setRollbackOnly();
202     }
203
204
205     /**
206      * @see javax.resource.spi.XATerminator#commit(javax.transaction.xa.Xid, boolean)
207      */

208     public void commit(Xid JavaDoc xid, boolean onePhase) throws XAException JavaDoc {
209         ContainerTransactionContext containerTransactionContext;
210         synchronized (importedTransactions) {
211             containerTransactionContext = (ContainerTransactionContext) importedTransactions.remove(xid);
212         }
213         if (containerTransactionContext == null) {
214             throw new XAException JavaDoc("No imported transaction for xid: " + xid);
215         }
216
217         try {
218             int status = containerTransactionContext.getTransaction().getStatus();
219             assert status == Status.STATUS_ACTIVE || status == Status.STATUS_PREPARED: "invalid status: " + status;
220         } catch (SystemException JavaDoc e) {
221             throw new XAException JavaDoc();
222         }
223         importer.commit(containerTransactionContext.getTransaction(), onePhase);
224     }
225
226     /**
227      * @see javax.resource.spi.XATerminator#forget(javax.transaction.xa.Xid)
228      */

229     public void forget(Xid JavaDoc xid) throws XAException JavaDoc {
230         ContainerTransactionContext containerTransactionContext;
231         synchronized (importedTransactions) {
232             containerTransactionContext = (ContainerTransactionContext) importedTransactions.remove(xid);
233         }
234         if (containerTransactionContext == null) {
235             throw new XAException JavaDoc("No imported transaction for xid: " + xid);
236         }
237         //todo is there a correct status test here?
238
// try {
239
// int status = tx.getStatus();
240
// assert status == Status.STATUS_ACTIVE || status == Status.STATUS_PREPARED;
241
// } catch (SystemException e) {
242
// throw new XAException();
243
// }
244
importer.forget(containerTransactionContext.getTransaction());
245     }
246
247     /**
248      * @see javax.resource.spi.XATerminator#prepare(javax.transaction.xa.Xid)
249      */

250     public int prepare(Xid JavaDoc xid) throws XAException JavaDoc {
251         ContainerTransactionContext containerTransactionContext;
252         synchronized (importedTransactions) {
253             containerTransactionContext = (ContainerTransactionContext) importedTransactions.get(xid);
254         }
255         if (containerTransactionContext == null) {
256             throw new XAException JavaDoc("No imported transaction for xid: " + xid);
257         }
258         Transaction JavaDoc tx = containerTransactionContext.getTransaction();
259         try {
260             int status = tx.getStatus();
261             assert status == Status.STATUS_ACTIVE;
262         } catch (SystemException JavaDoc e) {
263             throw new XAException JavaDoc();
264         }
265         return importer.prepare(tx);
266     }
267
268     /**
269      * @see javax.resource.spi.XATerminator#recover(int)
270      */

271     public Xid JavaDoc[] recover(int flag) throws XAException JavaDoc {
272         if (recoveryState == NOT_IN_RECOVERY) {
273             if ((flag & XAResource.TMSTARTRSCAN) == 0) {
274                 throw new XAException JavaDoc(XAException.XAER_PROTO);
275             }
276             recoveryState = IN_RECOVERY;
277         }
278         if ((flag & XAResource.TMENDRSCAN) != 0) {
279             recoveryState = NOT_IN_RECOVERY;
280         }
281         //we always return all xids in first call.
282
//calling "startrscan" repeatedly starts at beginning of list again.
283
if ((flag & XAResource.TMSTARTRSCAN) != 0) {
284             Map JavaDoc recoveredXidMap = transactionManager.getExternalXids();
285             Xid JavaDoc[] recoveredXids = new Xid JavaDoc[recoveredXidMap.size()];
286             int i = 0;
287             synchronized (importedTransactions) {
288                 for (Iterator JavaDoc iterator = recoveredXidMap.entrySet().iterator(); iterator.hasNext();) {
289                     Map.Entry JavaDoc entry = (Map.Entry JavaDoc) iterator.next();
290                     Xid JavaDoc xid = (Xid JavaDoc) entry.getKey();
291                     recoveredXids[i++] = xid;
292                     ContainerTransactionContext containerTransactionContext = new ContainerTransactionContext(transactionManager, (Transaction JavaDoc) entry.getValue());
293                     importedTransactions.put(xid, containerTransactionContext);
294                 }
295             }
296             return recoveredXids;
297         } else {
298             return new Xid JavaDoc[0];
299         }
300     }
301
302     /**
303      * @see javax.resource.spi.XATerminator#rollback(javax.transaction.xa.Xid)
304      */

305     public void rollback(Xid JavaDoc xid) throws XAException JavaDoc {
306         ContainerTransactionContext containerTransactionContext;
307         synchronized (importedTransactions) {
308             containerTransactionContext = (ContainerTransactionContext) importedTransactions.remove(xid);
309         }
310         if (containerTransactionContext == null) {
311             throw new XAException JavaDoc("No imported transaction for xid: " + xid);
312         }
313         Transaction JavaDoc tx = containerTransactionContext.getTransaction();
314
315         try {
316             int status = tx.getStatus();
317             assert status == Status.STATUS_ACTIVE || status == Status.STATUS_PREPARED;
318         } catch (SystemException JavaDoc e) {
319             throw new XAException JavaDoc();
320         }
321         importer.rollback(tx);
322     }
323
324
325     //XAWork implementation
326
public void begin(Xid JavaDoc xid, long txTimeoutMillis) throws XAException JavaDoc, InvalidTransactionException JavaDoc, SystemException JavaDoc, ImportedTransactionActiveException {
327         ContainerTransactionContext containerTransactionContext;
328         synchronized (importedTransactions) {
329             containerTransactionContext = (ContainerTransactionContext) importedTransactions.get(xid);
330             if (containerTransactionContext == null) {
331                 //this does not associate tx with current thread.
332
Transaction JavaDoc transaction = importer.importXid(xid, txTimeoutMillis);
333                 containerTransactionContext = new ContainerTransactionContext(transactionManager, transaction);
334                 importedTransactions.put(xid, containerTransactionContext);
335             } else {
336                 if (containerTransactionContext.isThreadAssociated()) {
337                     throw new ImportedTransactionActiveException(xid);
338                 }
339             }
340             containerTransactionContext.resume();
341         }
342         setContext(containerTransactionContext);
343     }
344
345     public void end(Xid JavaDoc xid) throws XAException JavaDoc, SystemException JavaDoc {
346         setContext(null);
347         synchronized (importedTransactions) {
348             ContainerTransactionContext containerTransactionContext = (ContainerTransactionContext) importedTransactions.get(xid);
349             if (containerTransactionContext == null) {
350                 throw new XAException JavaDoc("No imported transaction for xid: " + xid);
351             }
352             if (!containerTransactionContext.isThreadAssociated()) {
353                 throw new XAException JavaDoc("tx not active for containerTransactionContext: " + containerTransactionContext + ", xid: " + xid);
354             }
355             containerTransactionContext.suspend();
356         }
357     }
358
359
360     public static final GBeanInfo GBEAN_INFO;
361
362     static {
363         GBeanInfoBuilder infoFactory = new GBeanInfoBuilder(TransactionContextManager.class, NameFactory.JTA_RESOURCE);
364
365         infoFactory.addOperation("getTransactionManager");
366         infoFactory.addOperation("getContext");
367         infoFactory.addOperation("setContext", new Class JavaDoc[]{TransactionContext.class});
368         infoFactory.addOperation("newContainerTransactionContext");
369         infoFactory.addOperation("newBeanTransactionContext", new Class JavaDoc[] {long.class});
370         infoFactory.addOperation("newUnspecifiedTransactionContext");
371         infoFactory.addOperation("resumeBeanTransactionContext", new Class JavaDoc[] {TransactionContext.class});
372         infoFactory.addOperation("suspendBeanTransactionContext");
373         infoFactory.addOperation("getStatus");
374         infoFactory.addOperation("setRollbackOnly");
375         infoFactory.addOperation("setTransactionTimeout", new Class JavaDoc[] {int.class});
376
377         infoFactory.addReference("TransactionManager", ExtendedTransactionManager.class, NameFactory.JTA_RESOURCE);
378         infoFactory.addReference("XidImporter", XidImporter.class, NameFactory.JTA_RESOURCE);
379
380         infoFactory.addInterface(XATerminator JavaDoc.class);
381         infoFactory.addInterface(XAWork.class);
382
383         infoFactory.setConstructor(new String JavaDoc[]{"TransactionManager", "XidImporter"});
384         GBEAN_INFO = infoFactory.getBeanInfo();
385     }
386
387     public static GBeanInfo getGBeanInfo() {
388         return GBEAN_INFO;
389     }
390
391 }
392
Popular Tags