KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > geronimo > transaction > manager > TransactionManagerImpl


1 /**
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements. See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License. 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 JavaDoc;
21 import java.util.Collection JavaDoc;
22 import java.util.HashMap JavaDoc;
23 import java.util.Iterator JavaDoc;
24 import java.util.List JavaDoc;
25 import java.util.Map JavaDoc;
26
27 import javax.transaction.HeuristicMixedException JavaDoc;
28 import javax.transaction.HeuristicRollbackException JavaDoc;
29 import javax.transaction.InvalidTransactionException JavaDoc;
30 import javax.transaction.NotSupportedException JavaDoc;
31 import javax.transaction.RollbackException JavaDoc;
32 import javax.transaction.Status JavaDoc;
33 import javax.transaction.Synchronization JavaDoc;
34 import javax.transaction.SystemException JavaDoc;
35 import javax.transaction.Transaction JavaDoc;
36 import javax.transaction.TransactionManager JavaDoc;
37 import javax.transaction.UserTransaction JavaDoc;
38 import javax.transaction.xa.XAException JavaDoc;
39 import javax.transaction.xa.Xid JavaDoc;
40
41 import edu.emory.mathcs.backport.java.util.concurrent.ConcurrentHashMap;
42 import edu.emory.mathcs.backport.java.util.concurrent.CopyOnWriteArrayList;
43 import org.apache.commons.logging.Log;
44 import org.apache.commons.logging.LogFactory;
45 import org.apache.geronimo.transaction.log.UnrecoverableLog;
46
47 /**
48  * Simple implementation of a transaction manager.
49  *
50  * @version $Rev: 476049 $ $Date: 2006-11-16 23:35:17 -0500 (Thu, 16 Nov 2006) $
51  */

52 public class TransactionManagerImpl implements TransactionManager JavaDoc, UserTransaction JavaDoc, XidImporter, MonitorableTransactionManager {
53     private static final Log log = LogFactory.getLog(TransactionManagerImpl.class);
54     protected static final int DEFAULT_TIMEOUT = 600;
55     protected static final byte[] DEFAULT_TM_ID = new byte[] {71,84,77,73,68};
56
57     final TransactionLog transactionLog;
58     final XidFactory xidFactory;
59     private final int defaultTransactionTimeoutMilliseconds;
60     private final ThreadLocal JavaDoc transactionTimeoutMilliseconds = new ThreadLocal JavaDoc();
61     private final ThreadLocal JavaDoc threadTx = new ThreadLocal JavaDoc();
62     private final ConcurrentHashMap associatedTransactions = new ConcurrentHashMap();
63     private static final Log recoveryLog = LogFactory.getLog("RecoveryController");
64     final Recovery recovery;
65     final Collection JavaDoc resourceManagers;
66     private final CopyOnWriteArrayList transactionAssociationListeners = new CopyOnWriteArrayList();
67     private List JavaDoc recoveryErrors = new ArrayList JavaDoc();
68
69     public TransactionManagerImpl() throws XAException JavaDoc {
70         this(DEFAULT_TIMEOUT,
71                 null,
72                 null,
73                 null);
74     }
75
76     public TransactionManagerImpl(int defaultTransactionTimeoutSeconds) throws XAException JavaDoc {
77         this(defaultTransactionTimeoutSeconds,
78                 null,
79                 null,
80                 null);
81     }
82
83     public TransactionManagerImpl(int defaultTransactionTimeoutSeconds, TransactionLog transactionLog) throws XAException JavaDoc {
84         this(defaultTransactionTimeoutSeconds,
85                 null,
86                 transactionLog,
87                 null);
88     }
89
90     public TransactionManagerImpl(int defaultTransactionTimeoutSeconds, XidFactory xidFactory, TransactionLog transactionLog, Collection JavaDoc resourceManagers) throws XAException JavaDoc {
91         if (defaultTransactionTimeoutSeconds <= 0) {
92             throw new IllegalArgumentException JavaDoc("defaultTransactionTimeoutSeconds must be positive: attempted value: " + defaultTransactionTimeoutSeconds);
93         }
94
95         this.defaultTransactionTimeoutMilliseconds = defaultTransactionTimeoutSeconds * 1000;
96
97         if (transactionLog == null) {
98             this.transactionLog = new UnrecoverableLog();
99         } else {
100             this.transactionLog = transactionLog;
101         }
102
103         if (xidFactory != null) {
104             this.xidFactory = xidFactory;
105         } else {
106             this.xidFactory = new XidFactoryImpl(DEFAULT_TM_ID);
107         }
108
109         this.resourceManagers = resourceManagers;
110         recovery = new RecoveryImpl(this.transactionLog, this.xidFactory);
111
112         if (resourceManagers != null) {
113             recovery.recoverLog();
114             List JavaDoc copy = watchResourceManagers(resourceManagers);
115             for (Iterator JavaDoc iterator = copy.iterator(); iterator.hasNext();) {
116                 ResourceManager resourceManager = (ResourceManager) iterator.next();
117                 recoverResourceManager(resourceManager);
118             }
119         }
120     }
121
122     protected List JavaDoc watchResourceManagers(Collection JavaDoc resourceManagers) {
123         return new ArrayList JavaDoc(resourceManagers);
124     }
125
126     public Transaction JavaDoc getTransaction() {
127         return (Transaction JavaDoc) threadTx.get();
128     }
129
130     private void associate(TransactionImpl tx) throws InvalidTransactionException JavaDoc {
131         if (tx == null) throw new NullPointerException JavaDoc("tx is null");
132
133         Object JavaDoc existingAssociation = associatedTransactions.putIfAbsent(tx, Thread.currentThread());
134         if (existingAssociation != null) {
135             throw new InvalidTransactionException JavaDoc("Specified transaction is already associated with another thread");
136         }
137         threadTx.set(tx);
138         fireThreadAssociated(tx);
139     }
140
141     private void unassociate() {
142         Transaction JavaDoc tx = getTransaction();
143         if (tx != null) {
144             associatedTransactions.remove(tx);
145             threadTx.set(null);
146             fireThreadUnassociated(tx);
147         }
148     }
149
150     public void setTransactionTimeout(int seconds) throws SystemException JavaDoc {
151         if (seconds < 0) {
152             throw new SystemException JavaDoc("transaction timeout must be positive or 0 to reset to default");
153         }
154         if (seconds == 0) {
155             transactionTimeoutMilliseconds.set(null);
156         } else {
157             transactionTimeoutMilliseconds.set(new Long JavaDoc(seconds * 1000));
158         }
159     }
160
161     public int getStatus() throws SystemException JavaDoc {
162         Transaction JavaDoc tx = getTransaction();
163         return (tx != null) ? tx.getStatus() : Status.STATUS_NO_TRANSACTION;
164     }
165
166     public void begin() throws NotSupportedException JavaDoc, SystemException JavaDoc {
167         begin(getTransactionTimeoutMilliseconds(0L));
168     }
169
170     public Transaction JavaDoc begin(long transactionTimeoutMilliseconds) throws NotSupportedException JavaDoc, SystemException JavaDoc {
171         if (getStatus() != Status.STATUS_NO_TRANSACTION) {
172             throw new NotSupportedException JavaDoc("Nested Transactions are not supported");
173         }
174         TransactionImpl tx = new TransactionImpl(xidFactory, transactionLog, getTransactionTimeoutMilliseconds(transactionTimeoutMilliseconds));
175 // timeoutTimer.schedule(tx, getTransactionTimeoutMilliseconds(transactionTimeoutMilliseconds));
176
try {
177             associate(tx);
178         } catch (InvalidTransactionException JavaDoc e) {
179             // should not be possible since we just created that transaction and no one has a reference yet
180
throw new SystemException JavaDoc("Internal error: associate threw an InvalidTransactionException for a newly created transaction");
181         }
182         // Todo: Verify if this is correct thing to do. Use default timeout for next transaction.
183
this.transactionTimeoutMilliseconds.set(null);
184         return tx;
185     }
186
187     public Transaction JavaDoc suspend() throws SystemException JavaDoc {
188         Transaction JavaDoc tx = getTransaction();
189         if (tx != null) {
190             unassociate();
191         }
192         return tx;
193     }
194
195     public void resume(Transaction JavaDoc tx) throws IllegalStateException JavaDoc, InvalidTransactionException JavaDoc, SystemException JavaDoc {
196         if (getTransaction() != null) {
197             throw new IllegalStateException JavaDoc("Thread already associated with another transaction");
198         }
199         if (!(tx instanceof TransactionImpl)) {
200             throw new InvalidTransactionException JavaDoc("Cannot resume foreign transaction: " + tx);
201         }
202         associate((TransactionImpl) tx);
203     }
204
205     public Object JavaDoc getResource(Object JavaDoc key) {
206         TransactionImpl tx = getActiveTransactionImpl();
207         return tx.getResource(key);
208     }
209
210     private TransactionImpl getActiveTransactionImpl() {
211         TransactionImpl tx = (TransactionImpl)threadTx.get();
212         if (tx == null) {
213             throw new IllegalStateException JavaDoc("No tx on thread");
214         }
215         if (tx.getStatus() != Status.STATUS_ACTIVE) {
216             throw new IllegalStateException JavaDoc("Transaction " + tx + " is not active");
217         }
218         return tx;
219     }
220
221     public boolean getRollbackOnly() {
222         TransactionImpl tx = getActiveTransactionImpl();
223         return tx.getRollbackOnly();
224     }
225
226     public Object JavaDoc getTransactionKey() {
227         TransactionImpl tx = getActiveTransactionImpl();
228         return tx.getTransactionKey();
229     }
230
231     public int getTransactionStatus() {
232         TransactionImpl tx = getActiveTransactionImpl();
233         return tx.getTransactionStatus();
234     }
235
236     public void putResource(Object JavaDoc key, Object JavaDoc value) {
237         TransactionImpl tx = getActiveTransactionImpl();
238         tx.putResource(key, value);
239     }
240
241     /**
242      * jta 1.1 method so the jpa implementations can be told to flush their caches.
243      * @param synchronization
244      */

245     public void registerInterposedSynchronization(Synchronization JavaDoc synchronization) {
246         TransactionImpl tx = getActiveTransactionImpl();
247         tx.registerInterposedSynchronization(synchronization);
248     }
249
250     public void setRollbackOnly() throws IllegalStateException JavaDoc {
251         TransactionImpl tx = (TransactionImpl) threadTx.get();
252         if (tx == null) {
253             throw new IllegalStateException JavaDoc("No transaction associated with current thread");
254         }
255         tx.setRollbackOnly();
256     }
257
258     public void commit() throws HeuristicMixedException JavaDoc, HeuristicRollbackException JavaDoc, IllegalStateException JavaDoc, RollbackException JavaDoc, SecurityException JavaDoc, SystemException JavaDoc {
259         Transaction JavaDoc tx = getTransaction();
260         if (tx == null) {
261             throw new IllegalStateException JavaDoc("No transaction associated with current thread");
262         }
263         try {
264             tx.commit();
265         } finally {
266             unassociate();
267         }
268     }
269
270     public void rollback() throws IllegalStateException JavaDoc, SecurityException JavaDoc, SystemException JavaDoc {
271         Transaction JavaDoc tx = getTransaction();
272         if (tx == null) {
273             throw new IllegalStateException JavaDoc("No transaction associated with current thread");
274         }
275         try {
276             tx.rollback();
277         } finally {
278             unassociate();
279         }
280     }
281
282     //XidImporter implementation
283
public Transaction JavaDoc importXid(Xid JavaDoc xid, long transactionTimeoutMilliseconds) throws XAException JavaDoc, SystemException JavaDoc {
284         if (transactionTimeoutMilliseconds < 0) {
285             throw new SystemException JavaDoc("transaction timeout must be positive or 0 to reset to default");
286         }
287         TransactionImpl tx = new TransactionImpl(xid, xidFactory, transactionLog, getTransactionTimeoutMilliseconds(transactionTimeoutMilliseconds));
288         return tx;
289     }
290
291     public void commit(Transaction JavaDoc tx, boolean onePhase) throws XAException JavaDoc {
292         if (onePhase) {
293             try {
294                 tx.commit();
295             } catch (HeuristicMixedException JavaDoc e) {
296                 throw (XAException JavaDoc) new XAException JavaDoc().initCause(e);
297             } catch (HeuristicRollbackException JavaDoc e) {
298                 throw (XAException JavaDoc) new XAException JavaDoc().initCause(e);
299             } catch (RollbackException JavaDoc e) {
300                 throw (XAException JavaDoc) new XAException JavaDoc().initCause(e);
301             } catch (SecurityException JavaDoc e) {
302                 throw (XAException JavaDoc) new XAException JavaDoc().initCause(e);
303             } catch (SystemException JavaDoc e) {
304                 throw (XAException JavaDoc) new XAException JavaDoc().initCause(e);
305             }
306         } else {
307             try {
308                 ((TransactionImpl) tx).preparedCommit();
309             } catch (SystemException JavaDoc e) {
310                 throw (XAException JavaDoc) new XAException JavaDoc().initCause(e);
311             }
312         }
313     }
314
315     public void forget(Transaction JavaDoc tx) throws XAException JavaDoc {
316         //TODO implement this!
317
}
318
319     public int prepare(Transaction JavaDoc tx) throws XAException JavaDoc {
320         try {
321             return ((TransactionImpl) tx).prepare();
322         } catch (SystemException JavaDoc e) {
323             throw (XAException JavaDoc) new XAException JavaDoc().initCause(e);
324         } catch (RollbackException JavaDoc e) {
325             throw (XAException JavaDoc) new XAException JavaDoc().initCause(e);
326         }
327     }
328
329     public void rollback(Transaction JavaDoc tx) throws XAException JavaDoc {
330         try {
331             tx.rollback();
332         } catch (IllegalStateException JavaDoc e) {
333             throw (XAException JavaDoc) new XAException JavaDoc().initCause(e);
334         } catch (SystemException JavaDoc e) {
335             throw (XAException JavaDoc) new XAException JavaDoc().initCause(e);
336         }
337     }
338
339     long getTransactionTimeoutMilliseconds(long transactionTimeoutMilliseconds) {
340         if (transactionTimeoutMilliseconds != 0) {
341             return transactionTimeoutMilliseconds;
342         }
343         Long JavaDoc timeout = (Long JavaDoc) this.transactionTimeoutMilliseconds.get();
344         if (timeout != null) {
345             return timeout.longValue();
346         }
347         return defaultTransactionTimeoutMilliseconds;
348     }
349
350     protected void recoverResourceManager(ResourceManager resourceManager) {
351         NamedXAResource namedXAResource;
352         try {
353             namedXAResource = resourceManager.getRecoveryXAResources();
354         } catch (SystemException JavaDoc e) {
355             recoveryLog.error(e);
356             recoveryErrors.add(e);
357             return;
358         }
359         if (namedXAResource != null) {
360             try {
361                 recovery.recoverResourceManager(namedXAResource);
362             } catch (XAException JavaDoc e) {
363                 recoveryLog.error(e);
364                 recoveryErrors.add(e);
365             } finally {
366                 resourceManager.returnResource(namedXAResource);
367             }
368         }
369     }
370
371
372     public Map JavaDoc getExternalXids() {
373         return new HashMap JavaDoc(recovery.getExternalXids());
374     }
375
376     public void addTransactionAssociationListener(TransactionManagerMonitor listener) {
377         transactionAssociationListeners.addIfAbsent(listener);
378     }
379
380     public void removeTransactionAssociationListener(TransactionManagerMonitor listener) {
381         transactionAssociationListeners.remove(listener);
382     }
383
384     protected void fireThreadAssociated(Transaction JavaDoc tx) {
385         for (Iterator JavaDoc iterator = transactionAssociationListeners.iterator(); iterator.hasNext();) {
386             TransactionManagerMonitor listener = (TransactionManagerMonitor) iterator.next();
387             try {
388                 listener.threadAssociated(tx);
389             } catch (Exception JavaDoc e) {
390                 log.warn("Error calling transaction association listener", e);
391             }
392         }
393     }
394
395     protected void fireThreadUnassociated(Transaction JavaDoc tx) {
396         for (Iterator JavaDoc iterator = transactionAssociationListeners.iterator(); iterator.hasNext();) {
397             TransactionManagerMonitor listener = (TransactionManagerMonitor) iterator.next();
398             try {
399                 listener.threadUnassociated(tx);
400             } catch (Exception JavaDoc e) {
401                 log.warn("Error calling transaction association listener", e);
402             }
403         }
404     }
405 }
406
Popular Tags