KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > ofbiz > minerva > pool > jdbc > xa > wrapper > XAResourceImpl


1 /*
2  * Licensed under the X license (see http://www.x.org/terms.htm)
3  */

4 package org.ofbiz.minerva.pool.jdbc.xa.wrapper;
5
6 import javax.transaction.xa.XAException JavaDoc;
7 import javax.transaction.xa.XAResource JavaDoc;
8 import javax.transaction.xa.Xid JavaDoc;
9 import java.sql.Connection JavaDoc;
10 import java.sql.SQLException JavaDoc;
11
12 import org.apache.log4j.Logger;
13
14 /**
15  * JTA resource implementation for JDBC 1.0 connections. This is somewhat
16  * limited in two respects. First, it does not support two-phase commits since
17  * JDBC 1.0 does not. It will operate in the presence of two-phase commits, but
18  * will throw heuristic exceptions if there is a failure during a commit or
19  * rollback. Second, it can only be associated with one transaction
20  * at a time, and will throw exceptions if a second transaction tries to
21  * attach before the first has called commit, rollback, or forget.
22  * <P><FONT COLOR="RED"><B>Warning:</B></FONT></P> This implementation assumes
23  * that forget will be called after a failed commit or rollback. Otherwise,
24  * the database connection will never be closed.</P>
25  *
26  * @author Aaron Mulder (ammulder@alumni.princeton.edu)
27  */

28 public class XAResourceImpl implements XAResource JavaDoc {
29
30     private Connection JavaDoc con;
31     private XAConnectionImpl xaCon;
32     private Xid JavaDoc current;
33     private boolean active = false;
34     private int timeout_ignored = 0;
35     private Logger log = Logger.getLogger(XAResourceImpl.class);
36
37     /**
38      * Creates a new instance as the transactional resource for the specified
39      * underlying connection.
40      */

41     public XAResourceImpl(Connection JavaDoc con) {
42         this.con = con;
43     }
44
45     /**
46      * Sets the XAConnection associated with this XAResource. This is required,
47      * but both classes cannot include an instance of the other in their
48      * constructor!
49      * @throws java.lang.IllegalStateException
50      * Occurs when this is called more than once.
51      */

52     void setXAConnection(XAConnectionImpl xaCon) {
53         if (this.xaCon != null)
54             throw new IllegalStateException JavaDoc();
55         this.xaCon = xaCon;
56     }
57
58     public XAConnectionImpl getXAConnection() {
59         return xaCon;
60     }
61
62     /**
63      * Gets whether there is outstanding work on behalf of a Transaction. If
64      * there is not, then a connection that is closed will cause the
65      * XAConnection to be closed or returned to a pool. If there is, then the
66      * XAConnection must be kept open until commit or rollback is called.
67      */

68     public boolean isTransaction() {
69         return current != null;
70     }
71
72     /**
73      * Closes this instance permanently.
74      */

75     public void close() {
76         con = null;
77         current = null;
78         xaCon = null;
79     }
80
81     /**
82      * Commits a transaction.
83      * @throws XAException
84      * Occurs when the state was not correct (end never called), the
85      * transaction ID is wrong, the connection was set to Auto-Commit,
86      * or the commit on the underlying connection fails. The error code
87      * differs depending on the exact situation.
88      */

89     public void commit(Xid JavaDoc id, boolean twoPhase) throws XAException JavaDoc {
90         // System.out.println("commit: " + xaCon + ", current: " + current + ", xid: " + id + ", active: " + active);
91
if (active && !twoPhase) // End was not called!
92
System.err.println("WARNING: Connection not closed before transaction commit.\nConnection will not participate in any future transactions.\nAre you sure you want to be doing this?");
93         if (current == null || !id.equals(current)) // wrong Xid
94
{
95             throwXAException(XAException.XAER_NOTA);
96         }
97
98         try {
99             if (con.getAutoCommit()) {
100                 throwXAException(XAException.XA_HEURCOM);
101             }
102         } catch (SQLException JavaDoc e) {
103             log.error(e);
104         }
105
106         try {
107             con.commit();
108         } catch (SQLException JavaDoc e) {
109             log.error(e);
110             try {
111                 con.rollback();
112                 if (!twoPhase) {
113                     throwXAException(XAException.XA_RBROLLBACK);
114                 }
115             } catch (SQLException JavaDoc e2) {
116             }
117             if (twoPhase) {
118                 throwXAException(XAException.XA_HEURRB); // no 2PC!
119
} else {
120                 throwXAException(XAException.XA_RBOTHER); // no 2PC!
121
}
122             // Truly, neither committed nor rolled back. Ouch!
123
}
124         current = null;
125         if (active) {
126             active = false; // No longer associated with the original transaction
127
} else {
128             xaCon.transactionFinished(); // No longer in use at all
129
}
130     }
131
132     /**
133      * Dissociates a resource from a global transaction.
134      * @throws XAException
135      * Occurs when the state was not correct (end called twice), or the
136      * transaction ID is wrong.
137      */

138     public void end(Xid JavaDoc id, int flags) throws XAException JavaDoc {
139         //System.out.println("end: " + xaCon + ", current: " + current + ", xid: " + id + ", active: " + active);
140
if (!active) // End was called twice!
141
{
142             throwXAException(XAException.XAER_PROTO);
143         }
144         if (current == null || !id.equals(current)) {
145             throwXAException(XAException.XAER_NOTA);
146         }
147         active = false;
148     }
149
150     /**
151      * Indicates that no further action will be taken on behalf of this
152      * transaction (after a heuristic failure). It is assumed this will be
153      * called after a failed commit or rollback.
154      * @throws XAException
155      * Occurs when the state was not correct (end never called), or the
156      * transaction ID is wrong.
157      */

158     public void forget(Xid JavaDoc id) throws XAException JavaDoc {
159         if (current == null || !id.equals(current)) {
160             throwXAException(XAException.XAER_NOTA);
161         }
162         current = null;
163         xaCon.transactionFailed();
164         if (active) // End was not called!
165
System.err.println("WARNING: Connection not closed before transaction forget.\nConnection will not participate in any future transactions.\nAre you sure you want to be doing this?");
166     }
167
168     /**
169      * Gets the transaction timeout.
170      */

171     public int getTransactionTimeout() throws XAException JavaDoc {
172         return timeout_ignored;
173     }
174
175     /**
176      * Since the concept of resource managers does not really apply here (all
177      * JDBC connections must be managed individually), indicates whether the
178      * specified resource is the same as this one.
179      */

180     public boolean isSameRM(XAResource JavaDoc res) throws XAException JavaDoc {
181         return res == this;
182     }
183
184     /**
185      * Prepares a transaction to commit. Since JDBC 1.0 does not support
186      * 2-phase commits, this claims the commit is OK (so long as some work was
187      * done on behalf of the specified transaction).
188      * @throws XAException
189      * Occurs when the state was not correct (end never called), the
190      * transaction ID is wrong, or the connection was set to Auto-Commit.
191      */

192     public int prepare(Xid JavaDoc id) throws XAException JavaDoc {
193         //System.out.println("prepare: " + xaCon + ", current: " + current + ", xid: " + id + ", active: " + active);
194
if (active) // End was not called!
195
System.err.println("WARNING: Connection not closed before transaction commit.\nConnection will not participate in any future transactions.\nAre you sure you want to be doing this?");
196         if (current == null || !id.equals(current)) // wrong Xid
197
{
198             throwXAException(XAException.XAER_NOTA);
199         }
200
201         try {
202             if (con.getAutoCommit()) {
203                 throwXAException(XAException.XA_HEURCOM);
204             }
205         } catch (SQLException JavaDoc e) {
206             log.error(e);
207         }
208
209         return XA_OK;
210     }
211
212     /**
213      * Returns all transaction IDs where work was done with no corresponding
214      * commit, rollback, or forget. Not really sure why this is useful in the
215      * context of JDBC drivers.
216      */

217     public Xid JavaDoc[] recover(int flag) throws javax.transaction.xa.XAException JavaDoc {
218         if (current == null)
219             return new Xid JavaDoc[0];
220         else
221             return new Xid JavaDoc[]{current};
222     }
223
224     /**
225      * Rolls back the work, assuming it was done on behalf of the specified
226      * transaction.
227      * @throws XAException
228      * Occurs when the state was not correct (end never called), the
229      * transaction ID is wrong, the connection was set to Auto-Commit,
230      * or the rollback on the underlying connection fails. The error code
231      * differs depending on the exact situation.
232      */

233     public void rollback(Xid JavaDoc id) throws XAException JavaDoc {
234         //System.out.println("rollback: " + xaCon + ", current: " + current + ", xid: " + id + ", active: " + active);
235
if (active) // End was not called!
236
log.error("WARNING: Connection not closed before transaction rollback. Connection will not participate in any future transactions. Are you sure you want to be doing this?");
237         if (current == null || !id.equals(current)) { // wrong Xid
238
throwXAException(XAException.XAER_NOTA);
239         }
240         try {
241             if (con.getAutoCommit()) {
242                 throwXAException(XAException.XA_HEURCOM);
243             }
244         } catch (SQLException JavaDoc e) {
245             log.error(e);
246         }
247
248         try {
249             con.rollback();
250         } catch (SQLException JavaDoc e) {
251             log.error(e);
252             throwXAException("Rollback failed: " + e.getMessage());
253         }
254         current = null;
255         if (active) {
256             active = false; // No longer associated with the original transaction
257
} else {
258             xaCon.transactionFinished(); // No longer in use at all
259
}
260     }
261
262     /**
263      * Sets the transaction timeout. This is saved, but the value is not used
264      * by the current implementation.
265      */

266     public boolean setTransactionTimeout(int timeout) throws XAException JavaDoc {
267         timeout_ignored = timeout;
268         return true;
269     }
270
271     /**
272      * Associates a JDBC connection with a global transaction. We assume that
273      * end will be called followed by prepare, commit, or rollback.
274      * If start is called after end but before commit or rollback, there is no
275      * way to distinguish work done by different transactions on the same
276      * connection). If start is called more than once before
277      * end, either it's a duplicate transaction ID or illegal transaction ID
278      * (since you can't have two transactions associated with one DB
279      * connection).
280      * @throws XAException
281      * Occurs when the state was not correct (start called twice), the
282      * transaction ID is wrong, or the instance has already been closed.
283      */

284     public void start(Xid JavaDoc id, int flags) throws XAException JavaDoc {
285         //System.out.println("start: " + xaCon + ", current: " + current + ", xid: " + id + ", active: " + active);
286
if (active) {// Start was called twice!
287
if (current != null && id.equals(current)) {
288                 throwXAException(XAException.XAER_DUPID);
289             } else {
290                 throwXAException(XAException.XAER_PROTO);
291             }
292         }
293         if (current != null && !id.equals(current)) {
294             //System.out.println("current xid: " + current + ", new xid: " + id);
295
throwXAException(XAException.XAER_NOTA);
296         }
297         if (con == null) {
298             throwXAException(XAException.XA_RBOTHER);
299         }
300         current = id;
301         active = true;
302     }
303
304     protected void throwXAException(int code) throws XAException JavaDoc {
305         xaCon.setConnectionError(new SQLException JavaDoc("XAException occured with code: " + code));
306         throw new XAException JavaDoc(code);
307     }
308
309     protected void throwXAException(String JavaDoc msg) throws XAException JavaDoc {
310         xaCon.setConnectionError(new SQLException JavaDoc("XAException occured: " + msg));
311         throw new XAException JavaDoc(msg);
312     }
313 }
314
Popular Tags