KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectweb > jonas > jdbc_xa > XAResourceImpl


1 /*
2  * JOnAS: Java(TM) Open Application Server
3  * Copyright (C) 1999 Bull S.A.
4  * Contact: jonas-team@objectweb.org
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19  * USA
20  *
21  * --------------------------------------------------------------------------
22  * $Id: XAResourceImpl.java,v 1.14 2005/04/28 08:43:25 benoitf Exp $
23  * --------------------------------------------------------------------------
24  */

25
26
27 package org.objectweb.jonas.jdbc_xa;
28
29 import java.sql.Connection JavaDoc;
30 import java.sql.SQLException JavaDoc;
31 import javax.transaction.xa.*;
32 import org.objectweb.jonas.common.Log;
33 import org.objectweb.util.monolog.api.Logger;
34 import org.objectweb.util.monolog.api.BasicLevel;
35
36 /**
37  * This is the implementation of the XAResource interface for our pseudo
38  * JDBC-XA driver. This object is used to demarcate the transactions and
39  * associate an XID to the SQL requests (start-end).
40  * Actually, no real 2PC is done here because the std JDBC driver do not support
41  * a java XA interface for it (only commit/rollback but no prepare!)
42  * So we choose to return always OK at prepare. The goal is more to offer a
43  * standard JDBC-XA interface to the EJB Container than to achieve a real
44  * distributed 2PC. Anyway, when database vendors will offer real JDBC-XA
45  * drivers, the JOnAS Server will be OK without any change.
46  * @author Philippe Durieux
47  * Contributor(s):
48  */

49 public class XAResourceImpl implements XAResource {
50
51     private static Logger logger = null;
52
53     private Connection JavaDoc actConn = null;
54     private XAConnectionImpl xac = null;
55     private int timeout;
56     private Xid currXid = null;
57     private boolean xaStarted = false;
58     private String JavaDoc rmid = null;
59
60     // -----------------------------------------------------------------
61
// Constructors
62
// -----------------------------------------------------------------
63

64     /**
65      * Build an instance.
66      * @param xac associated XAConnection
67      * @param actual underlying database connection
68      * @param ds the XADataSource
69      */

70     public XAResourceImpl(XAConnectionImpl xac, Connection JavaDoc actual, XADataSourceImpl ds) {
71         this.xac = xac;
72         this.actConn = actual;
73         this.rmid = ds.getDataSourceName();
74         logger = Log.getLogger(Log.JONAS_JDBCXA_PREFIX);
75         if (logger.isLoggable(BasicLevel.DEBUG)) {
76             logger.log(BasicLevel.DEBUG, "new object for " + this);
77         }
78     }
79
80     // -----------------------------------------------------------------
81
// XAResource implementation
82
// -----------------------------------------------------------------
83

84     /**
85      * Commit the global transaction specified by xid.
86      * @param xid transaction xid
87      * @param onePhase true if one phase commit
88      * @throws XAException XA protocol error
89      */

90     public synchronized void commit(Xid xid, boolean onePhase) throws XAException {
91         if (logger.isLoggable(BasicLevel.DEBUG)) {
92             logger.log(BasicLevel.DEBUG, "XA-COMMIT for " + this);
93             logger.log(BasicLevel.DEBUG, "Xid = " + xid);
94         }
95
96         // Make sure that we do not mix transactions
97
// Since start and end are not sent to database, we must check here
98
// the xids.
99
if (currXid != null && !currXid.equals(xid)) {
100             if (logger.isLoggable(BasicLevel.DEBUG)) {
101                 logger.log(BasicLevel.DEBUG, "mixed xids: " + xid + " != " + currXid);
102             }
103             XAException ex = new XAException("cannot mix transactions");
104             throw(ex);
105         }
106         currXid = null; // just for cleaning
107
if (xaStarted) {
108             // Unbalance start/end. Probably a close is missing.
109
// We decide to unset xa_start here to avoid a further error, but
110
// I'm not sure it's a good idea.
111
logger.log(BasicLevel.WARN, "XA START without XA END");
112
113             xaStarted = false;
114         }
115
116         // Commit the transaction
117
try {
118             actConn.commit();
119         } catch (SQLException JavaDoc e) {
120             logger.log(BasicLevel.ERROR, "Cannot commit transaction:" + e);
121             xac.notifyError(e);
122             throw(new XAException("Error on commit"));
123         }
124     }
125
126     /**
127      * Ends the work performed on behalf of a transaction branch.
128      * @param xid transaction xid
129      * @param flags currently unused
130      * @throws XAException XA protocol error
131      */

132     public synchronized void end(Xid xid, int flags) throws XAException {
133         if (logger.isLoggable(BasicLevel.DEBUG)) {
134             logger.log(BasicLevel.DEBUG, "XA-END for " + this);
135             logger.log(BasicLevel.DEBUG, "Xid = " + xid);
136         }
137
138         // Check that we got a start on this Xid first.
139
if (currXid == null || !currXid.equals(xid)) {
140             logger.log(BasicLevel.WARN, "END without START or mixed xids: " + xid + " != " + currXid);
141             XAException ex = new XAException(XAException.XA_RBPROTO);
142             throw(ex);
143         }
144         xaStarted = false;
145     }
146
147     /**
148      * Tell the resource manager to forget about a heuristically
149      * completed transaction branch.
150      * @param xid transaction xid
151      * @throws XAException XA protocol error
152      */

153     public synchronized void forget(Xid xid) throws XAException {
154
155         // not implemented. XXX
156
if (logger.isLoggable(BasicLevel.DEBUG)) {
157             logger.log(BasicLevel.DEBUG, "XA-FORGET for " + this);
158             logger.log(BasicLevel.DEBUG, "Xid = " + xid);
159         }
160         currXid = null;
161     }
162
163     /**
164      * Obtain the current transaction timeout value set for this
165      * XAResource instance.
166      * @return the current transaction timeout in seconds
167      * @throws XAException XA protocol error
168      */

169     public synchronized int getTransactionTimeout() throws XAException {
170         if (logger.isLoggable(BasicLevel.DEBUG)) {
171             logger.log(BasicLevel.DEBUG, "getTransactionTimeout for " + this);
172         }
173         return timeout;
174     }
175
176     /** Determine if the resource manager instance represented by the
177      * target object is the same as the resource manager instance
178      * represented by the parameter xares
179      * @param xares An XAResource object
180      * @return True if same RM instance, otherwise false.
181      * @throws XAException XA protocol error
182      */

183     public boolean isSameRM(XAResource xares) throws XAException {
184
185
186         // In this pseudo-driver, we must return true only if
187
// both objects refer to the same XAResource, and not
188
// the same Resource Manager, because actually, we must
189
// send commit/rollback on each XAResource involved in
190
// the transaction.
191
if (xares.equals(this)) {
192             if (logger.isLoggable(BasicLevel.DEBUG)) {
193                 logger.log(BasicLevel.DEBUG, "isSameRM = true " + this);
194             }
195             return true;
196         }
197         if (logger.isLoggable(BasicLevel.DEBUG)) {
198             logger.log(BasicLevel.DEBUG, "isSameRM = false " + this);
199         }
200         return false;
201     }
202
203
204     /**
205      * Ask the resource manager to prepare for a transaction commit
206      * of the transaction specified in xid.
207      * @param xid transaction xid
208      * @throws XAException XA protocol error
209      */

210     public synchronized int prepare(Xid xid) throws XAException {
211
212         if (logger.isLoggable(BasicLevel.DEBUG)) {
213             logger.log(BasicLevel.DEBUG, "XA-PREPARE for " + this);
214             logger.log(BasicLevel.DEBUG, "Xid = " + xid);
215         }
216         // No 2PC on standard JDBC drivers
217
return XA_OK;
218     }
219
220     /**
221      * Obtain a list of prepared transaction branches from a resource
222      * manager.
223      * @return an array of transaction Xids
224      * @throws XAException XA protocol error
225      */

226     public synchronized Xid[] recover(int flag) throws XAException {
227
228         if (logger.isLoggable(BasicLevel.DEBUG)) {
229             logger.log(BasicLevel.DEBUG, "XA-RECOVER for " + this);
230         }
231         // Not implemented
232
return null;
233     }
234
235     /**
236      * Inform the resource manager to roll back work done on behalf
237      * of a transaction branch
238      * @param xid transaction xid
239      * @throws XAException XA protocol error
240      */

241     public synchronized void rollback(Xid xid) throws XAException {
242
243         if (logger.isLoggable(BasicLevel.DEBUG)) {
244             logger.log(BasicLevel.DEBUG, "XA-ROLLBACK for " + this);
245             logger.log(BasicLevel.DEBUG, "Xid = " + xid);
246         }
247
248         // Make sure that we do not mix transactions
249
// Since start and end are not sent to database, we must check here
250
// the xids.
251
if (currXid != null && !currXid.equals(xid)) {
252             if (logger.isLoggable(BasicLevel.DEBUG)) {
253                 logger.log(BasicLevel.DEBUG, "mixed xids: " + xid + " != " + currXid);
254             }
255             XAException ex = new XAException("Cannot mix transactions");
256             throw(ex);
257         }
258         currXid = null; // just for cleaning
259
if (xaStarted) {
260             // Unbalance start/end. Probably a close is missing.
261
// We decide to unset xa_start here to avoid a further error, but
262
// I'm not sure it's a good idea.
263
logger.log(BasicLevel.WARN, "XA START without XA END");
264             xaStarted = false;
265         }
266
267         // Make sure that we are not in AutoCommit mode
268
try {
269             if (actConn.getAutoCommit() == true) {
270                 logger.log(BasicLevel.ERROR, "Rollback called on XAResource with AutoCommit set");
271                 throw (new XAException(XAException.XA_HEURCOM));
272             }
273         } catch (SQLException JavaDoc e) {
274             logger.log(BasicLevel.ERROR, "Cannot getAutoCommit:" + e);
275             xac.notifyError(e);
276             throw(new XAException("Error on getAutoCommit"));
277         }
278
279         // Rollback the transaction
280
try {
281             actConn.rollback();
282         } catch (SQLException JavaDoc e) {
283             logger.log(BasicLevel.ERROR, "Cannot rollback transaction:" + e);
284             xac.notifyError(e);
285             throw(new XAException("Error on rollback"));
286         }
287     }
288
289     /**
290      * Set the current transaction timeout value for this XAResource
291      * instance.
292      * @param seconds timeout value, in seconds.
293      * @return always true
294      * @throws XAException XA protocol error
295      */

296     public synchronized boolean setTransactionTimeout(int seconds) throws XAException {
297
298         if (logger.isLoggable(BasicLevel.DEBUG)) {
299             logger.log(BasicLevel.DEBUG, "setTransactionTimeout " + this);
300         }
301         timeout = seconds;
302         return true;
303     }
304
305     /**
306      * Start work on behalf of a transaction branch specified in xid
307      * @param xid transaction xid
308      * @throws XAException XA protocol error
309      */

310     public synchronized void start(Xid xid, int flags) throws XAException {
311
312         if (logger.isLoggable(BasicLevel.DEBUG)) {
313             logger.log(BasicLevel.DEBUG, "XA-START for " + this);
314             logger.log(BasicLevel.DEBUG, "Xid = " + xid);
315         }
316         if (xaStarted) {
317             if (logger.isLoggable(BasicLevel.DEBUG)) {
318                 logger.log(BasicLevel.DEBUG, "mixed xids: " + xid + " != " + currXid);
319             }
320             XAException ex = new XAException("XA START: mixed transactions");
321             throw ex;
322         }
323         currXid = xid;
324         xaStarted = true;
325     }
326
327     // ---------------------------------------------------------------------
328
// Other methods
329
// ---------------------------------------------------------------------
330

331     /*
332      * get the RMID
333      * @return the rmid.
334      */

335     public String JavaDoc getRMID() {
336         return rmid;
337     }
338 }
339
Popular Tags