Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: org/apache/geronimo/transaction/manager/TransactionManagerImpl.java


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.manager;
19  
20  import java.util.ArrayList;
21  import java.util.Collection;
22  import java.util.HashMap;
23  import java.util.Iterator;
24  import java.util.List;
25  import java.util.Map;
26  import javax.transaction.HeuristicMixedException;
27  import javax.transaction.HeuristicRollbackException;
28  import javax.transaction.InvalidTransactionException;
29  import javax.transaction.NotSupportedException;
30  import javax.transaction.RollbackException;
31  import javax.transaction.Status;
32  import javax.transaction.SystemException;
33  import javax.transaction.Transaction;
34  import javax.transaction.xa.XAException;
35  import javax.transaction.xa.Xid;
36  
37  import org.apache.commons.logging.Log;
38  import org.apache.commons.logging.LogFactory;
39  import org.apache.geronimo.gbean.GBeanInfo;
40  import org.apache.geronimo.gbean.GBeanInfoBuilder;
41  import org.apache.geronimo.gbean.ReferenceCollection;
42  import org.apache.geronimo.gbean.ReferenceCollectionEvent;
43  import org.apache.geronimo.gbean.ReferenceCollectionListener;
44  import org.apache.geronimo.j2ee.j2eeobjectnames.NameFactory;
45  import org.apache.geronimo.transaction.ExtendedTransactionManager;
46  import org.apache.geronimo.transaction.log.UnrecoverableLog;
47  
48  /**
49   * Simple implementation of a transaction manager.
50   *
51   * @version $Rev: 156292 $ $Date: 2005-03-05 18:48:02 -0800 (Sat, 05 Mar 2005) $
52   */
53  public class TransactionManagerImpl implements ExtendedTransactionManager, XidImporter {
54      final TransactionLog transactionLog;
55      final XidFactory xidFactory;
56      private final int defaultTransactionTimeoutMilliseconds;
57      private final ThreadLocal transactionTimeoutMilliseconds = new ThreadLocal();
58      private final ThreadLocal threadTx = new ThreadLocal();
59      private static final Log recoveryLog = LogFactory.getLog("RecoveryController");
60      final Recovery recovery;
61      final ReferenceCollection resourceManagers;
62      private List recoveryErrors = new ArrayList();
63  
64      /**
65       * TODO NOTE!!! this should be called in an unspecified transaction context, but we cannot enforce this restriction!
66       */
67      public TransactionManagerImpl(int defaultTransactionTimeoutSeconds, TransactionLog transactionLog, Collection resourceManagers) throws XAException {
68          if (defaultTransactionTimeoutSeconds <= 0) {
69              throw new IllegalArgumentException("defaultTransactionTimeoutSeconds must be positive: attempted value: " + defaultTransactionTimeoutSeconds);
70          }
71  
72          this.defaultTransactionTimeoutMilliseconds = defaultTransactionTimeoutSeconds * 1000;
73          this.transactionLog = transactionLog == null ? new UnrecoverableLog() : transactionLog;
74          this.xidFactory = new XidFactoryImpl("WHAT DO WE CALL IT?".getBytes());
75          this.resourceManagers = (ReferenceCollection) resourceManagers;
76          recovery = new RecoveryImpl(this.transactionLog, this.xidFactory);
77  
78          if (resourceManagers != null) {
79              recovery.recoverLog();
80              List copy = null;
81              synchronized (resourceManagers) {
82                  copy = new ArrayList(resourceManagers);
83                  this.resourceManagers.addReferenceCollectionListener(new ReferenceCollectionListener() {
84                      public void memberAdded(ReferenceCollectionEvent event) {
85                          ResourceManager resourceManager = (ResourceManager) event.getMember();
86                          recoverResourceManager(resourceManager);
87                      }
88  
89                      public void memberRemoved(ReferenceCollectionEvent event) {
90                      }
91  
92                  });
93              }
94              for (Iterator iterator = copy.iterator(); iterator.hasNext();) {
95                  ResourceManager resourceManager = (ResourceManager) iterator.next();
96                  recoverResourceManager(resourceManager);
97              }
98              //what to do if there are recovery errors? or not all resource managers are online?
99          }
100     }
101 
102     public Transaction getTransaction() throws SystemException {
103         return (Transaction) threadTx.get();
104     }
105 
106     public void setTransactionTimeout(int seconds) throws SystemException {
107         if (seconds < 0) {
108             throw new SystemException("transaction timeout must be positive or 0 to reset to default");
109         }
110         if (seconds == 0) {
111             transactionTimeoutMilliseconds.set(null);
112         } else {
113             transactionTimeoutMilliseconds.set(new Long(seconds * 1000));
114         }
115     }
116 
117     public int getStatus() throws SystemException {
118         Transaction tx = getTransaction();
119         return (tx != null) ? tx.getStatus() : Status.STATUS_NO_TRANSACTION;
120     }
121 
122     public void begin() throws NotSupportedException, SystemException {
123         begin(getTransactionTimeoutMilliseconds(0L));
124     }
125 
126     public Transaction begin(long transactionTimeoutMilliseconds) throws NotSupportedException, SystemException {
127         if (getStatus() != Status.STATUS_NO_TRANSACTION) {
128             throw new NotSupportedException("Nested Transactions are not supported");
129         }
130         TransactionImpl tx = new TransactionImpl(xidFactory, transactionLog, getTransactionTimeoutMilliseconds(transactionTimeoutMilliseconds));
131 //        timeoutTimer.schedule(tx, getTransactionTimeoutMilliseconds(transactionTimeoutMilliseconds));
132         threadTx.set(tx);
133                 // Todo: Verify if this is correct thing to do. Use default timeout for next transaction.
134         this.transactionTimeoutMilliseconds.set(null);
135         return tx;
136     }
137 
138     public Transaction suspend() throws SystemException {
139         Transaction tx = getTransaction();
140         if (tx != null) {
141         }
142         threadTx.set(null);
143         return tx;
144     }
145 
146     public void resume(Transaction tx) throws IllegalStateException, InvalidTransactionException, SystemException {
147         if (threadTx.get() != null) {
148             throw new IllegalStateException("Transaction already associated with current thread");
149         }
150         if (tx instanceof TransactionImpl == false) {
151             throw new InvalidTransactionException("Cannot resume foreign transaction: " + tx);
152         }
153         threadTx.set(tx);
154     }
155 
156     public void setRollbackOnly() throws IllegalStateException, SystemException {
157         Transaction tx = getTransaction();
158         if (tx == null) {
159             throw new IllegalStateException("No transaction associated with current thread");
160         }
161         tx.setRollbackOnly();
162     }
163 
164     public void commit() throws HeuristicMixedException, HeuristicRollbackException, IllegalStateException, RollbackException, SecurityException, SystemException {
165         Transaction tx = getTransaction();
166         if (tx == null) {
167             throw new IllegalStateException("No transaction associated with current thread");
168         }
169         try {
170             tx.commit();
171         } finally {
172             threadTx.set(null);
173         }
174     }
175 
176     public void rollback() throws IllegalStateException, SecurityException, SystemException {
177         Transaction tx = getTransaction();
178         if (tx == null) {
179             throw new IllegalStateException("No transaction associated with current thread");
180         }
181         try {
182             tx.rollback();
183         } finally {
184             threadTx.set(null);
185         }
186     }
187 
188     //XidImporter implementation
189     public Transaction importXid(Xid xid, long transactionTimeoutMilliseconds) throws XAException, SystemException {
190         if (transactionTimeoutMilliseconds < 0) {
191             throw new SystemException("transaction timeout must be positive or 0 to reset to default");
192         }
193         TransactionImpl tx = new TransactionImpl(xid, xidFactory, transactionLog, getTransactionTimeoutMilliseconds(transactionTimeoutMilliseconds));
194         return tx;
195     }
196 
197     public void commit(Transaction tx, boolean onePhase) throws XAException {
198         if (onePhase) {
199             try {
200                 tx.commit();
201             } catch (HeuristicMixedException e) {
202                 throw (XAException) new XAException().initCause(e);
203             } catch (HeuristicRollbackException e) {
204                 throw (XAException) new XAException().initCause(e);
205             } catch (RollbackException e) {
206                 throw (XAException) new XAException().initCause(e);
207             } catch (SecurityException e) {
208                 throw (XAException) new XAException().initCause(e);
209             } catch (SystemException e) {
210                 throw (XAException) new XAException().initCause(e);
211             }
212         } else {
213             try {
214                 ((TransactionImpl) tx).preparedCommit();
215             } catch (SystemException e) {
216                 throw (XAException) new XAException().initCause(e);
217             }
218         }
219     }
220 
221     public void forget(Transaction tx) throws XAException {
222         //TODO implement this!
223     }
224 
225     public int prepare(Transaction tx) throws XAException {
226         try {
227             return ((TransactionImpl) tx).prepare();
228         } catch (SystemException e) {
229             throw (XAException) new XAException().initCause(e);
230         } catch (RollbackException e) {
231             throw (XAException) new XAException().initCause(e);
232         }
233     }
234 
235     public void rollback(Transaction tx) throws XAException {
236         try {
237             tx.rollback();
238         } catch (IllegalStateException e) {
239             throw (XAException) new XAException().initCause(e);
240         } catch (SystemException e) {
241             throw (XAException) new XAException().initCause(e);
242         }
243     }
244 
245     long getTransactionTimeoutMilliseconds(long transactionTimeoutMilliseconds) {
246         if (transactionTimeoutMilliseconds != 0) {
247             return transactionTimeoutMilliseconds;
248         }
249         Long timeout = (Long) this.transactionTimeoutMilliseconds.get();
250         if (timeout != null) {
251             return timeout.longValue();
252         }
253         return defaultTransactionTimeoutMilliseconds;
254     }
255 
256     protected void recoverResourceManager(ResourceManager resourceManager) {
257         NamedXAResource namedXAResource = null;
258         try {
259             namedXAResource = resourceManager.getRecoveryXAResources();
260         } catch (SystemException e) {
261             recoveryLog.error(e);
262             recoveryErrors.add(e);
263             return;
264         }
265         if (namedXAResource != null) {
266             try {
267                 recovery.recoverResourceManager(namedXAResource);
268             } catch (XAException e) {
269                 recoveryLog.error(e);
270                 recoveryErrors.add(e);
271             } finally {
272                 resourceManager.returnResource(namedXAResource);
273             }
274         }
275     }
276 
277 
278     public Map getExternalXids() {
279         return new HashMap(recovery.getExternalXids());
280     }
281 
282     public static final GBeanInfo GBEAN_INFO;
283 
284     static {
285         GBeanInfoBuilder infoBuilder = new GBeanInfoBuilder(TransactionManagerImpl.class, NameFactory.JTA_RESOURCE);
286 
287         infoBuilder.addAttribute("defaultTransactionTimeoutSeconds", int.class, true);
288         infoBuilder.addReference("TransactionLog", TransactionLog.class, NameFactory.JTA_RESOURCE);
289         infoBuilder.addReference("ResourceManagers", ResourceManager.class);//two kinds of things, so specify the type in each pattern.
290 
291         infoBuilder.addInterface(ExtendedTransactionManager.class);
292         infoBuilder.addInterface(XidImporter.class);
293 
294         infoBuilder.setConstructor(new String[]{"defaultTransactionTimeoutSeconds", "TransactionLog", "ResourceManagers"});
295 
296         GBEAN_INFO = infoBuilder.getBeanInfo();
297     }
298 
299 
300     public static GBeanInfo getGBeanInfo() {
301         return GBEAN_INFO;
302     }
303 }