KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jboss > tm > usertx > client > ClientUserTransaction


1 /*
2 * JBoss, Home of Professional Open Source
3 * Copyright 2005, JBoss Inc., and individual contributors as indicated
4 * by the @authors tag. See the copyright.txt in the distribution for a
5 * full listing of individual contributors.
6 *
7 * This is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License as
9 * published by the Free Software Foundation; either version 2.1 of
10 * the License, or (at your option) any later version.
11 *
12 * This software is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this software; if not, write to the Free
19 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
20 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
21 */

22 package org.jboss.tm.usertx.client;
23
24 import java.io.Serializable JavaDoc;
25
26 import java.rmi.RemoteException JavaDoc;
27
28 import java.util.LinkedList JavaDoc;
29 import java.util.Hashtable JavaDoc;
30
31 import javax.naming.InitialContext JavaDoc;
32 import javax.naming.Reference JavaDoc;
33 import javax.naming.Referenceable JavaDoc;
34 import javax.naming.NamingException JavaDoc;
35
36 import javax.transaction.UserTransaction JavaDoc;
37 import javax.transaction.Transaction JavaDoc;
38 import javax.transaction.Status JavaDoc;
39 import javax.transaction.NotSupportedException JavaDoc;
40 import javax.transaction.SystemException JavaDoc;
41 import javax.transaction.RollbackException JavaDoc;
42 import javax.transaction.HeuristicMixedException JavaDoc;
43 import javax.transaction.HeuristicRollbackException JavaDoc;
44
45 import org.jboss.tm.TransactionPropagationContextFactory;
46
47 import org.jboss.tm.usertx.interfaces.UserTransactionSession;
48 import org.jboss.tm.usertx.interfaces.UserTransactionSessionFactory;
49 import org.jboss.naming.NamingContextFactory;
50
51 /**
52  * The client-side UserTransaction implementation. This will delegate all
53  * UserTransaction calls to the server.
54  *
55  * <em>Warning:</em> This is only for stand-alone clients that do not have their
56  * own transaction service. No local work is done in the context of transactions
57  * started here, only work done in beans at the server. Instantiating objects of
58  * this class outside the server will change the JRMP GenericProxy so that
59  * outgoing calls use the propagation contexts of the transactions started
60  * here.
61  * @author <a HREF="mailto:osh@sparre.dk">Ole Husgaard</a>
62  * @author Scott.Stark@jboss.org
63  * @version $Revision: 37459 $
64  */

65 public class ClientUserTransaction
66    implements UserTransaction JavaDoc,
67    TransactionPropagationContextFactory,
68    Referenceable JavaDoc,
69    Serializable JavaDoc
70 {
71    // Static --------------------------------------------------------
72
/** @since at least jboss-3.2.0 */
73    private static final long serialVersionUID = 1747989355209242872L;
74
75    /**
76     * Our singleton instance.
77     */

78    private static ClientUserTransaction singleton = null;
79
80    /**
81     * Return a reference to the singleton instance.
82     */

83    public static ClientUserTransaction getSingleton()
84    {
85       if (singleton == null)
86          singleton = new ClientUserTransaction();
87       return singleton;
88    }
89
90
91    // Constructors --------------------------------------------------
92

93    /**
94     * Create a new instance.
95     */

96    private ClientUserTransaction()
97    {
98    }
99
100    // Public --------------------------------------------------------
101

102    //
103
// implements interface UserTransaction
104
//
105

106    public void begin()
107       throws NotSupportedException JavaDoc, SystemException JavaDoc
108    {
109       ThreadInfo info = getThreadInfo();
110
111       try
112       {
113          Object JavaDoc tpc = getSession().begin(info.getTimeout());
114          info.push(tpc);
115       }
116       catch (SystemException JavaDoc e)
117       {
118          throw e;
119       }
120       catch (RemoteException JavaDoc e)
121       {
122          // destroy session gone bad.
123
destroySession();
124          throw new SystemException JavaDoc(e.toString());
125       }
126       catch (Exception JavaDoc e)
127       {
128          throw new SystemException JavaDoc(e.toString());
129       }
130    }
131
132    public void commit()
133       throws RollbackException JavaDoc,
134       HeuristicMixedException JavaDoc,
135       HeuristicRollbackException JavaDoc,
136       SecurityException JavaDoc,
137       IllegalStateException JavaDoc,
138       SystemException JavaDoc
139    {
140       ThreadInfo info = getThreadInfo();
141
142       try
143       {
144          getSession().commit(info.getTpc());
145          info.pop();
146       }
147       catch (RollbackException JavaDoc e)
148       {
149          info.pop();
150          throw e;
151       }
152       catch (HeuristicMixedException JavaDoc e)
153       {
154          throw e;
155       }
156       catch (HeuristicRollbackException JavaDoc e)
157       {
158          throw e;
159       }
160       catch (SecurityException JavaDoc e)
161       {
162          throw e;
163       }
164       catch (SystemException JavaDoc e)
165       {
166          throw e;
167       }
168       catch (IllegalStateException JavaDoc e)
169       {
170          throw e;
171       }
172       catch (RemoteException JavaDoc e)
173       {
174          // destroy session gone bad.
175
destroySession();
176          throw new SystemException JavaDoc(e.toString());
177       }
178       catch (Exception JavaDoc e)
179       {
180          throw new SystemException JavaDoc(e.toString());
181       }
182    }
183
184    public void rollback()
185       throws SecurityException JavaDoc,
186       IllegalStateException JavaDoc,
187       SystemException JavaDoc
188    {
189       ThreadInfo info = getThreadInfo();
190
191       try
192       {
193          getSession().rollback(info.getTpc());
194          info.pop();
195       }
196       catch (SecurityException JavaDoc e)
197       {
198          throw e;
199       }
200       catch (SystemException JavaDoc e)
201       {
202          throw e;
203       }
204       catch (IllegalStateException JavaDoc e)
205       {
206          throw e;
207       }
208       catch (RemoteException JavaDoc e)
209       {
210          // destroy session gone bad.
211
destroySession();
212          throw new SystemException JavaDoc(e.toString());
213       }
214       catch (Exception JavaDoc e)
215       {
216          throw new SystemException JavaDoc(e.toString());
217       }
218    }
219
220    public void setRollbackOnly()
221       throws IllegalStateException JavaDoc,
222       SystemException JavaDoc
223    {
224       ThreadInfo info = getThreadInfo();
225
226       try
227       {
228          getSession().setRollbackOnly(info.getTpc());
229       }
230       catch (SystemException JavaDoc e)
231       {
232          throw e;
233       }
234       catch (IllegalStateException JavaDoc e)
235       {
236          throw e;
237       }
238       catch (RemoteException JavaDoc e)
239       {
240          // destroy session gone bad.
241
destroySession();
242          throw new SystemException JavaDoc(e.toString());
243       }
244       catch (Exception JavaDoc e)
245       {
246          throw new SystemException JavaDoc(e.toString());
247       }
248    }
249
250    public int getStatus()
251       throws SystemException JavaDoc
252    {
253       ThreadInfo info = getThreadInfo();
254       Object JavaDoc tpc = info.getTpc();
255
256       if (tpc == null)
257       {
258          return Status.STATUS_NO_TRANSACTION;
259       }
260
261       try
262       {
263          return getSession().getStatus(tpc);
264       }
265       catch (SystemException JavaDoc e)
266       {
267          throw e;
268       }
269       catch (RemoteException JavaDoc e)
270       {
271          // destroy session gone bad.
272
destroySession();
273          throw new SystemException JavaDoc(e.toString());
274       }
275       catch (Exception JavaDoc e)
276       {
277          throw new SystemException JavaDoc(e.toString());
278       }
279    }
280
281    public void setTransactionTimeout(int seconds)
282       throws SystemException JavaDoc
283    {
284       getThreadInfo().setTimeout(seconds);
285    }
286
287
288    //
289
// implements interface TransactionPropagationContextFactory
290
//
291

292    public Object JavaDoc getTransactionPropagationContext()
293    {
294       return getThreadInfo().getTpc();
295    }
296
297    public Object JavaDoc getTransactionPropagationContext(Transaction JavaDoc tx)
298    {
299       // No need to implement in a stand-alone client.
300
throw new InternalError JavaDoc("Should not have been used.");
301    }
302  
303
304    //
305
// implements interface Referenceable
306
//
307

308    public Reference JavaDoc getReference()
309       throws NamingException JavaDoc
310    {
311       Reference JavaDoc ref = new Reference JavaDoc("org.jboss.tm.usertx.client.ClientUserTransaction",
312          "org.jboss.tm.usertx.client.ClientUserTransactionObjectFactory",
313          null);
314
315       return ref;
316    }
317
318
319    // Private -------------------------------------------------------
320

321    /**
322     * The RMI remote interface to the real tx service session at the server.
323     */

324    private UserTransactionSession session = null;
325
326    /**
327     * Storage of per-thread information used here.
328     */

329    private transient ThreadLocal JavaDoc threadInfo = new ThreadLocal JavaDoc();
330
331
332    /**
333     * Create a new session.
334     */

335    private synchronized void createSession()
336    {
337       // Destroy any old session.
338
if (session != null)
339          destroySession();
340
341       try
342       {
343          // Get a reference to the UT session factory.
344
UserTransactionSessionFactory factory;
345          Hashtable JavaDoc env = (Hashtable JavaDoc) NamingContextFactory.lastInitialContextEnv.get();
346          InitialContext JavaDoc ctx = new InitialContext JavaDoc(env);
347          factory = (UserTransactionSessionFactory) ctx.lookup("UserTransactionSessionFactory");
348          // Call factory to get a UT session.
349
session = factory.newInstance();
350       }
351       catch (Exception JavaDoc ex)
352       {
353          throw new RuntimeException JavaDoc("UT factory lookup failed", ex);
354       }
355    }
356
357    /**
358     * Destroy the current session.
359     */

360    private synchronized void destroySession()
361    {
362       if (session != null)
363       {
364          try
365          {
366             session.destroy();
367          }
368          catch (RemoteException JavaDoc ex)
369          {
370             // Ignore.
371
}
372          session = null;
373       }
374    }
375
376    /**
377     * Get the session. This will create a session, if one does not already
378     * exist.
379     */

380    private synchronized UserTransactionSession getSession()
381    {
382       if (session == null)
383          createSession();
384       return session;
385    }
386
387
388    /**
389     * Return the per-thread information, possibly creating it if needed.
390     */

391    private ThreadInfo getThreadInfo()
392    {
393       ThreadInfo ret = (ThreadInfo) threadInfo.get();
394
395       if (ret == null)
396       {
397          ret = new ThreadInfo();
398          threadInfo.set(ret);
399       }
400
401       return ret;
402    }
403
404
405    // Inner classes -------------------------------------------------
406

407    /**
408     * Per-thread data holder class. This stores the stack of TPCs for the
409     * transactions started by this thread.
410     */

411    private class ThreadInfo
412    {
413       /**
414        * A stack of TPCs for transactions started by this thread. If the
415        * underlying service does not support nested transactions, its size is
416        * never greater than 1. Last element of the list denotes the stack top.
417        */

418       private LinkedList JavaDoc tpcStack = new LinkedList JavaDoc();
419
420       /**
421        * The timeout value (in seconds) for new transactions started by this
422        * thread.
423        */

424       private int timeout = 0;
425
426       /**
427        * Override to terminate any transactions that the thread may have
428        * forgotten.
429        */

430       protected void finalize()
431          throws Throwable JavaDoc
432       {
433          try
434          {
435             while (!tpcStack.isEmpty())
436             {
437                Object JavaDoc tpc = getTpc();
438                pop();
439
440                try
441                {
442                   getSession().rollback(tpc);
443                }
444                catch (Exception JavaDoc ex)
445                {
446                   // ignore
447
}
448             }
449          }
450          catch (Throwable JavaDoc t)
451          {
452             // ignore
453
}
454          super.finalize();
455       }
456
457       /**
458        * Push the TPC of a newly started transaction on the stack.
459        */

460       void push(Object JavaDoc tpc)
461       {
462          tpcStack.addLast(tpc);
463       }
464
465       /**
466        * Pop the TPC of a newly terminated transaction from the stack.
467        */

468       void pop()
469       {
470          tpcStack.removeLast();
471       }
472
473       /**
474        * Get the TPC at the top of the stack.
475        */

476       Object JavaDoc getTpc()
477       {
478          return (tpcStack.isEmpty()) ? null : tpcStack.getLast();
479       }
480
481       /**
482        * Return the default transaction timeout in seconds to use for new
483        * transactions started by this thread. A value of <code>0</code> means
484        * that a default timeout value should be used.
485        */

486       int getTimeout()
487       {
488          return timeout;
489       }
490
491       /**
492        * Set the default transaction timeout in seconds to use for new
493        * transactions started by this thread.
494        */

495       void setTimeout(int seconds)
496       {
497          timeout = seconds;
498       }
499    }
500
501 }
502
Popular Tags