KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > caucho > transaction > TransactionManagerImpl


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.transaction;
30
31 import com.caucho.config.types.Period;
32 import com.caucho.loader.ClassLoaderListener;
33 import com.caucho.loader.DynamicClassLoader;
34 import com.caucho.loader.Environment;
35 import com.caucho.log.Log;
36 import com.caucho.transaction.xalog.AbstractXALogManager;
37 import com.caucho.transaction.xalog.AbstractXALogStream;
38 import com.caucho.util.Crc64;
39 import com.caucho.util.L10N;
40 import com.caucho.util.RandomUtil;
41
42 import javax.transaction.*;
43 import javax.transaction.xa.XAException JavaDoc;
44 import javax.transaction.xa.XAResource JavaDoc;
45 import javax.transaction.xa.Xid JavaDoc;
46 import java.io.Serializable JavaDoc;
47 import java.lang.ref.WeakReference JavaDoc;
48 import java.util.ArrayList JavaDoc;
49 import java.util.logging.Level JavaDoc;
50 import java.util.logging.Logger JavaDoc;
51
52 /**
53  * Implementation of the transaction manager.
54  */

55 public class TransactionManagerImpl
56   implements TransactionManager, Serializable JavaDoc,
57          ClassLoaderListener {
58   private static L10N L = new L10N(TransactionManagerImpl.class);
59   private static Logger JavaDoc log = Log.open(TransactionManagerImpl.class);
60   
61   private static TransactionManagerImpl _tm = new TransactionManagerImpl();
62
63   private int _serverId;
64
65   private AbstractXALogManager _xaLogManager;
66
67   // thread local is dependent on the transaction manager
68
private ThreadLocal JavaDoc<TransactionImpl> _threadTransaction
69     = new ThreadLocal JavaDoc<TransactionImpl>();
70
71   private ArrayList JavaDoc<WeakReference JavaDoc<TransactionImpl>> _transactionList
72     = new ArrayList JavaDoc<WeakReference JavaDoc<TransactionImpl>>();
73
74   // listeners for transaction begin
75
private ArrayList JavaDoc<TransactionListener> _transactionListeners
76     = new ArrayList JavaDoc<TransactionListener>();
77
78   private long _timeout = -1;
79
80   public TransactionManagerImpl()
81   {
82   }
83
84   /**
85    * Returns the local transaction manager.
86    */

87   public static TransactionManagerImpl getInstance()
88   {
89     return _tm;
90   }
91
92   /**
93    * Returns the local transaction manager.
94    */

95   public static TransactionManagerImpl getLocal()
96   {
97     return _tm;
98   }
99
100   /**
101    * Sets the timeout.
102    */

103   public void setTimeout(Period timeout)
104   {
105     _timeout = timeout.getPeriod();
106   }
107
108   /**
109    * Gets the timeout.
110    */

111   public long getTimeout()
112   {
113     return _timeout;
114   }
115
116   /**
117    * Sets the XA log manager.
118    */

119   public void setXALogManager(AbstractXALogManager xaLogManager)
120   {
121     _xaLogManager = xaLogManager;
122   }
123
124   /**
125    * Create a new transaction and associate it with the thread.
126    */

127   public void begin()
128     throws NotSupportedException, SystemException
129   {
130     getCurrent().begin();
131   }
132
133   /**
134    * Creates a new transaction id.
135    */

136   XidImpl createXID()
137   {
138     return new XidImpl(getServerId(),
139                RandomUtil.getRandomLong());
140   }
141   /**
142    * Creates a new transaction id.
143    */

144   AbstractXALogStream getXALogStream()
145   {
146     if (_xaLogManager != null)
147       return _xaLogManager.getStream();
148     else
149       return null;
150   }
151
152   /**
153    * Returns the server id.
154    */

155   private int getServerId()
156   {
157     if (_serverId == 0) {
158       String JavaDoc server = (String JavaDoc) Environment.getAttribute("caucho.server-id");
159
160       if (server == null)
161     _serverId = 1;
162       else
163     _serverId = (int) Crc64.generate(server);
164     }
165     
166     return _serverId;
167   }
168
169   /**
170    * Returns the transaction for the current thread.
171    */

172   public Transaction getTransaction()
173     throws SystemException
174   {
175     TransactionImpl trans = _threadTransaction.get();
176
177     if (trans == null ||
178         trans.getStatus() == Status.STATUS_NO_TRANSACTION ||
179         trans.getStatus() == Status.STATUS_UNKNOWN ||
180         trans.isSuspended())
181       return null;
182     else {
183       return trans;
184     }
185   }
186
187   /**
188    * Suspend the transaction.
189    */

190   public Transaction suspend()
191     throws SystemException
192   {
193     TransactionImpl trans = _threadTransaction.get();
194
195     if (trans == null ||
196         (! trans.hasResources() &&
197          (trans.getStatus() == Status.STATUS_NO_TRANSACTION ||
198           trans.getStatus() == Status.STATUS_UNKNOWN)))
199       return null;
200     
201     _threadTransaction.set(null);
202     trans.suspend();
203
204     return trans;
205   }
206
207   /**
208    * Resume the transaction.
209    */

210   public void resume(Transaction tobj)
211     throws InvalidTransactionException, SystemException
212   {
213     Transaction old = _threadTransaction.get();
214     
215     if (old != null && old.getStatus() != Status.STATUS_NO_TRANSACTION)
216       throw new SystemException(L.l("can't resume transaction with active transaction {0}", String.valueOf(old)));
217
218     TransactionImpl impl = (TransactionImpl) tobj;
219
220     impl.resume();
221
222     _threadTransaction.set(impl);
223   }
224   
225   /**
226    * Force any completion to be a rollback.
227    */

228   public void setRollbackOnly()
229     throws SystemException
230   {
231     getCurrent().setRollbackOnly();
232   }
233
234   /**
235    * Returns the transaction's status
236    */

237   public int getStatus()
238     throws SystemException
239   {
240     return getCurrent().getStatus();
241   }
242
243   /**
244    * sets the timeout for the transaction
245    */

246   public void setTransactionTimeout(int seconds)
247     throws SystemException
248   {
249     getCurrent().setTransactionTimeout(seconds);
250   }
251
252   /**
253    * Commit the transaction.
254    */

255   public void commit()
256     throws RollbackException, HeuristicMixedException,
257     HeuristicRollbackException, SystemException
258   {
259     getCurrent().commit();
260   }
261
262   /**
263    * Rollback the transaction.
264    */

265   public void rollback()
266   {
267     getCurrent().rollback();
268   }
269
270   /**
271    * Returns the corresponding user transaction.
272    */

273   /*
274   public UserTransaction getUserTransaction()
275   {
276     return this;
277   }
278   */

279   
280   /**
281    * Returns the current TransactionImpl, creating if necessary.
282    *
283    * <p/>The TransactionImpl is not an official externally
284    * visible Transaction if the status == NO_TRANSACTION.
285    */

286   public TransactionImpl getCurrent()
287   {
288     TransactionImpl trans = _threadTransaction.get();
289     
290     if (trans == null || trans.isDead()) {
291       trans = new TransactionImpl(this);
292       _threadTransaction.set(trans);
293
294       addTransaction(trans);
295     }
296
297     return trans;
298   }
299
300   private void addTransaction(TransactionImpl trans)
301   {
302     synchronized (_transactionList) {
303       for (int i = _transactionList.size() - 1; i >= 0; i--) {
304     WeakReference JavaDoc<TransactionImpl> ref = _transactionList.get(i);
305
306     if (ref.get() == null)
307       _transactionList.remove(i);
308       }
309
310       _transactionList.add(new WeakReference JavaDoc<TransactionImpl>(trans));
311     }
312   }
313
314   /**
315    * Returns the corresponding user transaction.
316    */

317   public void recover(XAResource JavaDoc xaRes)
318     throws XAException JavaDoc
319   {
320     Xid JavaDoc []xids;
321
322     xids = xaRes.recover(XAResource.TMSTARTRSCAN|XAResource.TMENDRSCAN);
323
324     if (xids == null)
325       return;
326
327     for (int i = 0; i < xids.length; i++) {
328       byte []global = xids[i].getGlobalTransactionId();
329
330       if (global.length != XidImpl.GLOBAL_LENGTH)
331     continue;
332       
333       XidImpl xidImpl = new XidImpl(xids[i].getGlobalTransactionId());
334
335       if (_xaLogManager != null &&
336       _xaLogManager.hasCommittedXid(xidImpl)) {
337     log.fine(L.l("XAResource {0} commit xid {1}", xaRes, xidImpl));
338
339     try {
340       xaRes.commit(xidImpl, false);
341     } catch (Throwable JavaDoc e) {
342       log.log(Level.WARNING, e.toString(), e);
343     }
344       }
345       else {
346     // XXX: need to check if the transaction belongs to this TM
347
// the ownership is encoded in the xid
348

349     log.fine(L.l("XAResource {0} forget xid {1}", xaRes, xidImpl));
350     
351     try {
352       xaRes.forget(xidImpl);
353     } catch (Throwable JavaDoc e) {
354       log.log(Level.WARNING, e.toString(), e);
355     }
356       }
357     }
358   }
359
360   /**
361    * Flushes the log stream (primarily for QA).
362    */

363   public void flush()
364   {
365     if (_xaLogManager != null)
366       _xaLogManager.flush();
367   }
368   
369   /**
370    * Handles the case where a class loader has completed initialization
371    */

372   public void classLoaderInit(DynamicClassLoader loader)
373   {
374   }
375   
376   /**
377    * Handles the case where a class loader is dropped.
378    */

379   public void classLoaderDestroy(DynamicClassLoader loader)
380   {
381     AbstractXALogManager xaLogManager = _xaLogManager;
382     _xaLogManager = null;
383     
384     if (xaLogManager != null)
385       xaLogManager.close();
386
387     _serverId = 0;
388
389     synchronized (_transactionList) {
390       for (int i = _transactionList.size() - 1; i >= 0; i--) {
391     WeakReference JavaDoc<TransactionImpl> ref = _transactionList.get(i);
392     TransactionImpl xa = ref.get();
393
394     try {
395       if (xa != null) {
396         xa.rollback();
397       }
398     } catch (Throwable JavaDoc e) {
399       log.log(Level.WARNING, e.toString(), e);
400     }
401       }
402     }
403   }
404
405   /**
406    * Clearing for test purposes.
407    */

408   public void testClear()
409   {
410     _serverId = 0;
411     _timeout = -1;
412     AbstractXALogManager logManager = _xaLogManager;
413     _xaLogManager = null;
414
415     if (logManager != null)
416       logManager.close();
417   }
418
419   public String JavaDoc toString()
420   {
421     return "TransactionManagerImpl[]";
422   }
423 }
424
Popular Tags