KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > hibernate > transaction > JTATransaction


1 //$Id: JTATransaction.java,v 1.13 2005/04/29 20:29:51 oneovthafew Exp $
2
package org.hibernate.transaction;
3
4 import javax.naming.InitialContext JavaDoc;
5 import javax.naming.NamingException JavaDoc;
6 import javax.transaction.Status JavaDoc;
7 import javax.transaction.Synchronization JavaDoc;
8 import javax.transaction.SystemException JavaDoc;
9 import javax.transaction.UserTransaction JavaDoc;
10
11 import org.apache.commons.logging.Log;
12 import org.apache.commons.logging.LogFactory;
13 import org.hibernate.AssertionFailure;
14 import org.hibernate.HibernateException;
15 import org.hibernate.Transaction;
16 import org.hibernate.TransactionException;
17 import org.hibernate.jdbc.JDBCContext;
18 import org.hibernate.util.JTAHelper;
19
20 /**
21  * Implements a basic transaction strategy for JTA transactions. Instances check to
22  * see if there is an existing JTA transaction. If none exists, a new transaction
23  * is started. If one exists, all work is done in the existing context. The
24  * following properties are used to locate the underlying <tt>UserTransaction</tt>:
25  * <br><br>
26  * <table>
27  * <tr><td><tt>hibernate.jndi.url</tt></td><td>JNDI initial context URL</td></tr>
28  * <tr><td><tt>hibernate.jndi.class</tt></td><td>JNDI provider class</td></tr>
29  * <tr><td><tt>jta.UserTransaction</tt></td><td>JNDI name</td></tr>
30  * </table>
31  * @author Gavin King
32  */

33 public class JTATransaction implements Transaction JavaDoc {
34
35     private static final Log log = LogFactory.getLog(JTATransaction.class);
36
37     private final JDBCContext jdbcContext;
38     private final TransactionFactory.Context transactionContext;
39
40     private UserTransaction JavaDoc ut;
41     private boolean newTransaction;
42     //private boolean synchronization;
43
private boolean begun;
44     private boolean commitFailed;
45     private boolean callback;
46     private javax.transaction.Transaction JavaDoc transaction;
47
48     public JTATransaction(JDBCContext jdbcContext, TransactionFactory.Context transactionContext) {
49         this.jdbcContext = jdbcContext;
50         this.transactionContext = transactionContext;
51     }
52
53     public void begin(InitialContext JavaDoc context, String JavaDoc utName) throws HibernateException {
54         log.debug("begin");
55
56         log.debug("Looking for UserTransaction under: " + utName);
57         try {
58             ut = (UserTransaction JavaDoc) context.lookup(utName);
59         }
60         catch (NamingException JavaDoc ne) {
61             log.error("Could not find UserTransaction in JNDI", ne);
62             throw new TransactionException("Could not find UserTransaction in JNDI: ", ne);
63         }
64         if (ut==null) {
65             throw new AssertionFailure("A naming service lookup returned null");
66         }
67
68         log.debug("Obtained UserTransaction");
69
70         try {
71             newTransaction = ut.getStatus() == Status.STATUS_NO_TRANSACTION;
72             if (newTransaction) {
73                 ut.begin();
74                 log.debug("Began a new JTA transaction");
75             }
76         }
77         catch (Exception JavaDoc e) {
78             log.error("JTA transaction begin failed", e);
79             throw new TransactionException("JTA transaction begin failed", e);
80         }
81
82         /*if (newTransaction) {
83             // don't need a synchronization since we are committing
84             // or rolling back the transaction ourselves - assuming
85             // that we do no work in beforeTransactionCompletion()
86             synchronization = false;
87         }*/

88
89         boolean synchronization = jdbcContext.registerSynchronizationIfPossible();
90
91         if ( !newTransaction && !synchronization ) {
92             log.warn("You should set hibernate.transaction.manager_lookup_class if cache is enabled");
93         }
94
95         if (!synchronization) {
96             //if we could not register a synchronization,
97
//do the before/after completion callbacks
98
//ourself (but we need to let jdbcContext
99
//know that this is what we are going to
100
//do, so it doesn't keep trying to register
101
//synchronizations)
102
callback = jdbcContext.registerCallbackIfNecessary();
103         }
104
105         begun = true;
106     }
107
108     public void commit() throws HibernateException {
109         if (!begun) {
110             throw new TransactionException("Transaction not successfully started");
111         }
112
113         log.debug("commit");
114
115         boolean flush = !transactionContext.isFlushModeNever()
116                 && ( callback || !transactionContext.isFlushBeforeCompletionEnabled() );
117
118         if (flush) {
119             transactionContext.managedFlush(); //if an exception occurs during flush, user must call rollback()
120
}
121
122         if (callback && newTransaction) {
123             jdbcContext.beforeTransactionCompletion(this);
124         }
125
126         closeIfRequired();
127
128         if (newTransaction) {
129             try {
130                 ut.commit();
131                 log.debug("Committed JTA UserTransaction");
132             }
133             catch (Exception JavaDoc e) {
134                 commitFailed = true; // so the transaction is already rolled back, by JTA spec
135
log.error("JTA commit failed", e);
136                 throw new TransactionException("JTA commit failed: ", e);
137             }
138             finally {
139                 afterCommitRollback();
140             }
141         }
142         else {
143             // this one only really needed for badly-behaved applications!
144
// (if the TransactionManager has a Sychronization registered,
145
// its a noop)
146
// (actually we do need it for downgrading locks)
147
afterCommitRollback();
148         }
149
150     }
151
152     public void rollback() throws HibernateException {
153         if (!begun) {
154             throw new TransactionException("Transaction not successfully started");
155         }
156
157         log.debug("rollback");
158
159         /*if (!synchronization && newTransaction && !commitFailed) {
160             jdbcContext.beforeTransactionCompletion(this);
161         }*/

162
163         try {
164             closeIfRequired();
165         }
166         catch (Exception JavaDoc e) {
167             log.error("could not close session during rollback", e);
168             //swallow it, and continue to roll back JTA transaction
169
}
170
171         try {
172             if (newTransaction) {
173                 if (!commitFailed) {
174                     ut.rollback();
175                     log.debug("Rolled back JTA UserTransaction");
176                 }
177             }
178             else {
179                 ut.setRollbackOnly();
180                 log.debug("set JTA UserTransaction to rollback only");
181             }
182         }
183         catch (Exception JavaDoc e) {
184             log.error("JTA rollback failed", e);
185             throw new TransactionException("JTA rollback failed", e);
186         }
187         finally {
188             afterCommitRollback();
189         }
190     }
191
192     private static final int NULL = Integer.MIN_VALUE;
193
194     private void afterCommitRollback() throws TransactionException {
195
196         if (callback) { // this method is a noop if there is a Synchronization!
197

198             if (!newTransaction) log.warn("You should set hibernate.transaction.manager_lookup_class if cache is enabled");
199             int status=NULL;
200             try {
201                 status = ut.getStatus();
202             }
203             catch (Exception JavaDoc e) {
204                 log.error("Could not determine transaction status after commit", e);
205                 throw new TransactionException("Could not determine transaction status after commit", e);
206             }
207             finally {
208                 /*if (status!=Status.STATUS_COMMITTED && status!=Status.STATUS_ROLLEDBACK) {
209                     log.warn("Transaction not complete - you should set hibernate.transaction.manager_lookup_class if cache is enabled");
210                     //throw exception??
211                 }*/

212                 jdbcContext.afterTransactionCompletion(status==Status.STATUS_COMMITTED, this);
213             }
214
215         }
216     }
217
218     public boolean wasRolledBack() throws TransactionException {
219
220         if (!begun) return false;
221         if (commitFailed) return true;
222
223         final int status;
224         try {
225             status = ut.getStatus();
226         }
227         catch (SystemException JavaDoc se) {
228             log.error("Could not determine transaction status", se);
229             throw new TransactionException("Could not determine transaction status", se);
230         }
231         if (status==Status.STATUS_UNKNOWN) {
232             throw new TransactionException("Could not determine transaction status");
233         }
234         else {
235             return JTAHelper.isRollback(status);
236         }
237     }
238
239     public boolean wasCommitted() throws TransactionException {
240
241         if (!begun || commitFailed) return false;
242
243         final int status;
244         try {
245             status = ut.getStatus();
246         }
247         catch (SystemException JavaDoc se) {
248             log.error("Could not determine transaction status", se);
249             throw new TransactionException("Could not determine transaction status: ", se);
250         }
251         if (status==Status.STATUS_UNKNOWN) {
252             throw new TransactionException("Could not determine transaction status");
253         }
254         else {
255             return status==Status.STATUS_COMMITTED;
256         }
257     }
258     
259     public boolean isActive() throws TransactionException {
260
261         if (!begun || commitFailed) return false;
262
263         final int status;
264         try {
265             status = ut.getStatus();
266         }
267         catch (SystemException JavaDoc se) {
268             log.error("Could not determine transaction status", se);
269             throw new TransactionException("Could not determine transaction status: ", se);
270         }
271         if (status==Status.STATUS_UNKNOWN) {
272             throw new TransactionException("Could not determine transaction status");
273         }
274         else {
275             return status==Status.STATUS_ACTIVE;
276         }
277     }
278
279     public void registerSynchronization(Synchronization JavaDoc sync) throws HibernateException {
280         if (transaction!=null) {
281             try {
282                 transaction.registerSynchronization(sync);
283             }
284             catch (Exception JavaDoc e) {
285                 throw new TransactionException("could not register