KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > derby > client > net > NetXAResource


1 /*
2
3    Derby - Class org.apache.derby.client.net.NetXAResource
4
5    Licensed to the Apache Software Foundation (ASF) under one or more
6    contributor license agreements. See the NOTICE file distributed with
7    this work for additional information regarding copyright ownership.
8    The ASF licenses this file to You under the Apache License, Version 2.0
9    (the "License"); you may not use this file except in compliance with
10    the License. You may obtain a copy of the License at
11
12       http://www.apache.org/licenses/LICENSE-2.0
13
14    Unless required by applicable law or agreed to in writing, software
15    distributed under the License is distributed on an "AS IS" BASIS,
16    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17    See the License for the specific language governing permissions and
18    limitations under the License.
19
20 */

21 /**********************************************************************
22  *
23  *
24  * Component Name =
25  *
26  * Package Name = org.apache.derby.client.net
27  *
28  * Descriptive Name = class implements XAResource
29  *
30  * Status = New code
31  *
32  * Function = Handle XA methods
33  *
34  * List of Classes
35  * - NetXAResource
36  *
37  * Restrictions : None
38  *
39  **********************************************************************/

40 package org.apache.derby.client.net;
41
42 import java.net.InetAddress JavaDoc;
43 import java.net.UnknownHostException JavaDoc;
44 import java.util.Collections JavaDoc;
45 import java.util.Enumeration JavaDoc;
46 import java.util.LinkedList JavaDoc;
47 import java.util.List JavaDoc;
48 import java.util.Vector JavaDoc;
49 import javax.sql.XAConnection JavaDoc;
50 import javax.transaction.xa.XAException JavaDoc;
51 import javax.transaction.xa.XAResource JavaDoc;
52 import javax.transaction.xa.Xid JavaDoc;
53
54 import org.apache.derby.client.ClientXid;
55 import org.apache.derby.client.am.Connection;
56 import org.apache.derby.client.am.SqlException;
57 import org.apache.derby.client.am.ClientMessageId;
58 import org.apache.derby.shared.common.reference.SQLState;
59
60 public class NetXAResource implements XAResource JavaDoc {
61     public static final int TMTIMEOUT = 0x00000100;
62     public static final int ACTIVE_ONLY = -1;
63     public static final int XA_NULL_XID = -1; // null Xid has Format Id of -1
64
public static final int INITIAL_CALLINFO_ELEMENTS = 1;
65     public static final int RECOVER_XID_ARRAY_LENGTH = 10;
66     public static final ClientXid nullXid = new ClientXid();
67
68     // xaFunction defines, shows which queued XA function is being performed
69
public static final int XAFUNC_NONE = 0;
70     public static final int XAFUNC_COMMIT = 1;
71     public static final int XAFUNC_END = 2;
72     public static final int XAFUNC_FORGET = 3;
73     public static final int XAFUNC_PREPARE = 4;
74     public static final int XAFUNC_RECOVER = 5;
75     public static final int XAFUNC_ROLLBACK = 6;
76     public static final int XAFUNC_START = 7;
77     public static final String JavaDoc XAFUNCSTR_NONE = "No XA Function";
78     public static final String JavaDoc XAFUNCSTR_COMMIT = "XAResource.commit()";
79     public static final String JavaDoc XAFUNCSTR_END = "XAResource.end()";
80     public static final String JavaDoc XAFUNCSTR_FORGET = "XAResource.forget()";
81     public static final String JavaDoc XAFUNCSTR_PREPARE = "XAResource.prepare()";
82     public static final String JavaDoc XAFUNCSTR_RECOVER = "XAResource.recover()";
83     public static final String JavaDoc XAFUNCSTR_ROLLBACK = "XAResource.rollback()";
84     public static final String JavaDoc XAFUNCSTR_START = "XAResource.start()";
85
86     public int nextElement = 0;
87
88     // XAResources with same RM group list
89
protected static Vector JavaDoc xaResourceSameRMGroup_ = new Vector JavaDoc();
90     protected int sameRMGroupIndex_ = 0;
91     protected NetXAResource nextSameRM_ = null;
92     protected boolean ignoreMe_ = false;
93
94
95
96     public org.apache.derby.client.am.SqlException exceptionsOnXA = null;
97
98     XAConnection JavaDoc xaconn_;
99     org.apache.derby.client.net.NetXAConnection netXAConn_;
100     org.apache.derby.client.net.NetConnection conn_;
101     int rmId_; // unique RmId generated by XAConnection
102
// TODO: change to a single callInfo field (not an array)
103
NetXACallInfo callInfoArray_[] =
104             new NetXACallInfo[INITIAL_CALLINFO_ELEMENTS];
105     int numXACallInfo_ = INITIAL_CALLINFO_ELEMENTS;
106     int connectionCount_ = 1;
107     int activeXATransCount_ = 0;
108     String JavaDoc rmIdx_; // userid in case we need to create a secondary connection
109
String JavaDoc rmIdy_; // password in case we need to create a secondary connection
110
// TODO: remove port and ipaddr_
111
int port_; // port needed to make secondary connection for recover in DS mode.
112
String JavaDoc ipaddr_; // ip address needed to make secondary connection for recover in DS mode.
113

114     private List JavaDoc specialRegisters_ = Collections.synchronizedList(new LinkedList JavaDoc());
115
116     public NetXAResource(XAConnection JavaDoc xaconn, int rmId,
117                          String JavaDoc userId, String JavaDoc password,
118                          org.apache.derby.client.net.NetXAConnection conn) {
119         xaconn_ = xaconn;
120         rmId_ = rmId;
121         conn_ = conn.getNetConnection();
122         netXAConn_ = conn;
123         rmIdx_ = userId;
124         rmIdy_ = password;
125         port_ = conn_.netAgent_.getPort();
126         ipaddr_ = conn_.netAgent_.socket_.getLocalAddress().getHostAddress();
127         conn.setNetXAResource(this);
128
129         // link the primary connection to the first XACallInfo element
130
conn_.currXACallInfoOffset_ = 0;
131
132         // construct the NetXACallInfo object for the array.
133
for (int i = 0; i < INITIAL_CALLINFO_ELEMENTS; ++i) {
134             callInfoArray_[i] = new NetXACallInfo(null, XAResource.TMNOFLAGS, this,
135                     null);
136         }
137
138         // initialize the first XACallInfo element with the information from the
139
// primary connection
140
callInfoArray_[0].actualConn_ = conn;
141         callInfoArray_[0].currConnection_ = true;
142         callInfoArray_[0].freeEntry_ = false;
143         // ~~~ save conn_ connection variables in callInfoArray_[0]
144
callInfoArray_[0].saveConnectionVariables();
145
146         // add this new XAResource to the list of other XAResources for the Same RM
147
initForReuse();
148     }
149
150     public void commit(Xid JavaDoc xid, boolean onePhase) throws XAException JavaDoc {
151         NetAgent netAgent = conn_.netAgent_;
152         int rc = XAResource.XA_OK;
153         
154         exceptionsOnXA = null;
155         if (conn_.agent_.loggingEnabled()) {
156             conn_.agent_.logWriter_.traceEntry(this, "commit", xid, onePhase);
157         }
158         if (conn_.isPhysicalConnClosed()) {
159             connectionClosedFailure();
160         }
161
162         // update the XACallInfo
163
NetXACallInfo callInfo = callInfoArray_[conn_.currXACallInfoOffset_];
164         callInfo.xaFlags_ = (onePhase ? XAResource.TMONEPHASE :
165                 XAResource.TMNOFLAGS);
166         callInfo.xid_ = xid;
167         callInfo.xaResource_ = this;
168         callInfo.xaRetVal_ = XAResource.XA_OK; // initialize XARETVAL
169
try {
170             netAgent.beginWriteChainOutsideUOW();
171             netAgent.netConnectionRequest_.writeXaCommit(conn_, xid);
172             netAgent.flowOutsideUOW();
173             netAgent.netConnectionReply_.readXaCommit(conn_);
174             if (callInfo.xaRetVal_ != XAResource.XA_OK) { // xaRetVal has possible error, format it
175
callInfo.xaFunction_ = XAFUNC_COMMIT;
176                 rc = xaRetValErrorAccumSQL(callInfo, rc);
177                 callInfo.xaRetVal_ = XAResource.XA_OK; // re-initialize XARETVAL
178
}
179             netAgent.endReadChain();
180         } catch (SqlException sqle) {
181             rc = XAException.XAER_RMERR;
182             exceptionsOnXA = org.apache.derby.client.am.Utils.accumulateSQLException
183                     (sqle, exceptionsOnXA);
184         } finally {
185             conn_.pendingEndXACallinfoOffset_ = -1; // indicate no pending callinfo
186
}
187         if (rc != XAResource.XA_OK) {
188             throwXAException(rc, false);
189         }
190     }
191
192     /**
193      * Ends the work performed on behalf of a transaction branch. The resource manager dissociates the XA resource from
194      * the transaction branch specified and let the transaction be completed.
195      * <p/>
196      * If TMSUSPEND is specified in flags, the transaction branch is temporarily suspended in incomplete state. The
197      * transaction context is in suspened state and must be resumed via start with TMRESUME specified.
198      * <p/>
199      * If TMFAIL is specified, the portion of work has failed. The resource manager may mark the transaction as
200      * rollback-only
201      * <p/>
202      * If TMSUCCESS is specified, the portion of work has completed successfully.
203      *
204      * @param xid A global transaction identifier that is the same as what was used previously in the start method.
205      * @param flags One of TMSUCCESS, TMFAIL, or TMSUSPEND
206      *
207      * @throws XAException An error has occurred. Possible XAException values are XAER_RMERR, XAER_RMFAILED, XAER_NOTA,
208      * XAER_INVAL, XAER_PROTO, or XA_RB*.
209      */

210
211     public void end(Xid JavaDoc xid, int flags) throws XAException JavaDoc {
212
213         NetAgent netAgent = conn_.netAgent_;
214         int rc = XAResource.XA_OK;
215         exceptionsOnXA = null;
216         if (conn_.agent_.loggingEnabled()) {
217             conn_.agent_.logWriter_.traceEntry(this, "end", xid, flags);
218         }
219         if (conn_.isPhysicalConnClosed()) {
220             connectionClosedFailure();
221         }
222
223         NetXACallInfo callInfo = callInfoArray_[conn_.currXACallInfoOffset_];
224         callInfo.setReadOnlyTransactionFlag(conn_.readOnlyTransaction_);
225         callInfo.xaFlags_ = flags;
226         callInfo.xid_ = xid;
227         callInfo.xaResource_ = this;
228         callInfo.xaRetVal_ = XAResource.XA_OK; // initialize XARETVAL
229
try {
230             netAgent.beginWriteChainOutsideUOW();
231             netAgent.netConnectionRequest_.writeXaEndUnitOfWork(conn_);
232             netAgent.flowOutsideUOW();
233             rc = netAgent.netConnectionReply_.readXaEndUnitOfWork(conn_);
234             conn_.pendingEndXACallinfoOffset_ = -1; // indicate no pending end
235
if (callInfo.xaRetVal_ != XAResource.XA_OK) { // xaRetVal has possible error, format it
236
callInfo.xaFunction_ = XAFUNC_END;
237                 rc = xaRetValErrorAccumSQL(callInfo, rc);
238                 callInfo.xaRetVal_ = XAResource.XA_OK; // re-initialize XARETVAL
239
}
240             netAgent.endReadChain();
241         } catch (SqlException sqle) {
242             rc = XAException.XAER_RMERR;
243             exceptionsOnXA = org.apache.derby.client.am.Utils.accumulateSQLException
244                     (sqle, exceptionsOnXA);
245         } finally {
246             conn_.pendingEndXACallinfoOffset_ = -1; // indicate no pending callinfo
247
}
248         if (rc != XAResource.XA_OK) {
249             throwXAException(rc, false);
250         }else {
251             conn_.setXAState(Connection.XA_T0_NOT_ASSOCIATED);
252         }
253     }
254
255     /**
256      * Tell the resource manager to forget about a heuristically (MANUALLY) completed transaction branch.
257      *
258      * @param xid A global transaction identifier
259      *
260      * @throws XAException An error has occurred. Possible exception values are XAER_RMERR, XAER_RMFAIL, XAER_NOTA,
261      * XAER_INVAL, or XAER_PROTO.
262      */

263
264     public void forget(Xid JavaDoc xid) throws XAException JavaDoc {
265         NetAgent netAgent = conn_.netAgent_;
266         int rc = XAResource.XA_OK;
267         exceptionsOnXA = null;
268
269         if (conn_.agent_.loggingEnabled()) {
270             conn_.agent_.logWriter_.traceEntry(this, "forget", xid);
271         }
272         if (conn_.isPhysicalConnClosed()) {
273             connectionClosedFailure();
274         }
275         NetXACallInfo callInfo = callInfoArray_[conn_.currXACallInfoOffset_];
276         callInfo.xid_ = xid;
277         callInfo.xaResource_ = this;
278         callInfo.xaRetVal_ = XAResource.XA_OK; // initialize XARETVAL
279
try {
280             // flow the required PROTOCOL to the server
281
netAgent.beginWriteChainOutsideUOW();
282
283             // sent the commit PROTOCOL
284
netAgent.netConnectionRequest_.writeXaForget(netAgent.netConnection_, xid);
285
286             netAgent.flowOutsideUOW();
287
288             // read the reply to the commit
289
netAgent.netConnectionReply_.readXaForget(netAgent.netConnection_);
290
291             netAgent.endReadChain();
292             if (callInfo.xaRetVal_ != XAResource.XA_OK) { // xaRetVal has possible error, format it
293
callInfo.xaFunction_ = XAFUNC_FORGET;
294                 rc = xaRetValErrorAccumSQL(callInfo, rc);
295                 callInfo.xaRetVal_ = XAResource.XA_OK; // re-initialize XARETVAL
296
}
297         } catch (SqlException sqle) {
298             exceptionsOnXA = org.apache.derby.client.am.Utils.accumulateSQLException
299                     (sqle, exceptionsOnXA);
300             throwXAException(XAException.XAER_RMERR);
301         } finally {
302             conn_.pendingEndXACallinfoOffset_ = -1; // indicate no pending callinfo
303
}
304         if (rc != XAResource.XA_OK) {
305             throwXAException(rc, false);
306         }
307
308     }
309
310     /**
311      * Obtain the current transaction timeout value set for this XAResource instance. If
312      * <CODE>XAResource.setTransactionTimeout</CODE> was not use prior to invoking this method, the return value is the
313      * default timeout set for the resource manager; otherwise, the value used in the previous
314      * <CODE>setTransactionTimeout</CODE> call is returned.
315      *
316      * @return the transaction timeout value in seconds.
317      *
318      * @throws XAException An error has occurred. Possible exception values are XAER_RMERR, XAER_RMFAIL.
319      */

320     public int getTransactionTimeout() throws XAException JavaDoc {
321         if (conn_.agent_.loggingEnabled()) {
322             conn_.agent_.logWriter_.traceEntry(this, "getTransactionTimeout");
323         }
324         exceptionsOnXA = null;
325         if (conn_.isPhysicalConnClosed()) {
326             connectionClosedFailure();
327         }
328
329         if (conn_.agent_.loggingEnabled()) {
330             conn_.agent_.logWriter_.traceExit(this, "getTransactionTimeout", 0);
331         }
332         return 0; // we don't support transaction timeout
333
}
334
335     /**
336      * Ask the resource manager to prepare for a transaction commit of the transaction specified in xid.
337      *
338      * @param xid A global transaction identifier
339      *
340      * @return A value indicating the resource manager's vote on the outcome of the transaction. The possible values
341      * are: XA_RDONLY or XA_OK. If the resource manager wants to roll back the transaction, it should do so by
342      * raising an appropriate XAException in the prepare method.
343      *
344      * @throws XAException An error has occurred. Possible exception values are: XA_RB*, XAER_RMERR, XAER_RMFAIL,
345      * XAER_NOTA, XAER_INVAL, or XAER_PROTO.
346      */

347     public int prepare(Xid JavaDoc xid) throws XAException JavaDoc { // public interface for prepare
348
// just call prepareX with the recursion flag set to true
349
exceptionsOnXA = null;
350
351         if (conn_.agent_.loggingEnabled()) {
352             conn_.agent_.logWriter_.traceEntry(this, "prepare", xid);
353         }
354         if (conn_.isPhysicalConnClosed()) {
355             connectionClosedFailure();
356         }
357
358         /// update the XACallInfo
359
NetAgent netAgent = conn_.netAgent_;
360         int rc = XAResource.XA_OK;
361         NetXACallInfo callInfo = callInfoArray_[conn_.currXACallInfoOffset_];
362         callInfo.xid_ = xid;
363         callInfo.xaResource_ = this;
364         callInfo.xaRetVal_ = XAResource.XA_OK; // initialize XARETVAL
365
try {
366             netAgent.beginWriteChainOutsideUOW();
367             // sent the prepare PROTOCOL
368
netAgent.netConnectionRequest_.writeXaPrepare(conn_);
369             netAgent.flowOutsideUOW();
370
371             // read the reply to the prepare
372
rc = netAgent.netConnectionReply_.readXaPrepare(conn_);
373             if ((callInfo.xaRetVal_ != XAResource.XA_OK) &&
374                     (callInfo.xaRetVal_ != XAException.XA_RDONLY)) { // xaRetVal has possible error, format it
375
callInfo.xaFunction_ = XAFUNC_PREPARE;
376                 rc = xaRetValErrorAccumSQL(callInfo, rc);
377                 callInfo.xaRetVal_ = XAResource.XA_OK; // re-initialize XARETVAL
378
}
379
380             netAgent.endReadChain();
381         } catch (SqlException sqle) {
382             rc = XAException.XAER_RMERR;
383             exceptionsOnXA = org.apache.derby.client.am.Utils.accumulateSQLException
384                     (sqle, exceptionsOnXA);
385         } finally {
386             conn_.pendingEndXACallinfoOffset_ = -1; // indicate no pending callinfo
387
}
388         if ((rc != XAResource.XA_OK ) && (rc != XAResource.XA_RDONLY)) {
389             throwXAException(rc, false);
390         }
391         if (conn_.agent_.loggingEnabled()) {
392             conn_.agent_.logWriter_.traceExit(this, "prepare", rc);
393         }
394         return rc;
395     }
396
397     /**
398      * Obtain a list of prepared transaction branches from a resource manager. The transaction manager calls this method
399      * during recovery to obtain the list of transaction branches that are currently in prepared or heuristically
400      * completed states.
401      *
402      * @param flag One of TMSTARTRSCAN, TMENDRSCAN, TMNOFLAGS. TMNOFLAGS must be used when no other flags are set in
403      * flags.
404      *
405      * @return The resource manager returns zero or more XIDs for the transaction branches that are currently in a
406      * prepared or heuristically completed state. If an error occurs during the operation, the resource manager
407      * should raise the appropriate XAException.
408      *
409      * @throws XAException An error has occurred. Possible values are XAER_RMERR, XAER_RMFAIL, XAER_INVAL, and
410      * XAER_PROTO.
411      */

412     public Xid JavaDoc[] recover(int flag) throws XAException JavaDoc {
413         int rc = XAResource.XA_OK;
414         NetAgent netAgent = conn_.netAgent_;
415
416         if (conn_.agent_.loggingEnabled()) {
417             conn_.agent_.logWriter_.traceEntry(this, "recover", flag);
418         }
419         exceptionsOnXA = null;
420         if (conn_.isPhysicalConnClosed()) {
421             connectionClosedFailure();
422         }
423
424         Xid JavaDoc[] xidList = null;
425         int numXid = 0;
426
427         NetXACallInfo callInfo = callInfoArray_[conn_.currXACallInfoOffset_];
428         callInfo.xaFlags_ = flag;
429         callInfo.xaResource_ = this;
430         callInfo.xaRetVal_ = XAResource.XA_OK; // initialize XARETVAL
431
try {
432             netAgent.beginWriteChainOutsideUOW();
433             // sent the recover PROTOCOL
434
netAgent.netConnectionRequest_.writeXaRecover(conn_, flag);
435             netAgent.flowOutsideUOW();
436             netAgent.netConnectionReply_.readXaRecover(conn_);
437             if (callInfo.xaRetVal_ != XAResource.XA_OK) { // xaRetVal has possible error, format it
438
callInfo.xaFunction_ = XAFUNC_RECOVER;
439                 rc = xaRetValErrorAccumSQL(callInfo, rc);
440                 callInfo.xaRetVal_ = XAResource.XA_OK; // re-initialize XARETVAL
441
}
442             netAgent.endReadChain();
443             if (conn_.indoubtTransactions_ != null) {
444                 numXid = conn_.indoubtTransactions_.size();
445                 xidList = new Xid JavaDoc[numXid];
446                 int i = 0;
447                 nextElement = 0;
448                 for (Enumeration JavaDoc e = conn_.indoubtTransactions_.keys();
449                      e.hasMoreElements(); i++) {
450                     xidList[i] = (Xid JavaDoc) e.nextElement();
451                 }
452             }
453         } catch (SqlException sqle) {
454             rc = XAException.XAER_RMERR;
455             exceptionsOnXA = org.apache.derby.client.am.Utils.accumulateSQLException
456                     (sqle, exceptionsOnXA);
457         } finally {
458             conn_.pendingEndXACallinfoOffset_ = -1; // indicate no pending callinfo
459
}
460         if (rc != XAResource.XA_OK) {
461             throwXAException(rc, false);
462         }
463
464         if (conn_.agent_.loggingEnabled()) {
465             conn_.agent_.logWriter_.traceExit(this, "recover", xidList);
466         }
467         return xidList;
468     }
469
470     /**
471      * Inform the resource manager to roll back work done on behalf of a transaction branch
472      *
473      * @param xid A global transaction identifier
474      *
475      * @throws XAException An error has occurred
476      */

477     public void rollback(Xid JavaDoc xid) throws XAException JavaDoc {
478         NetAgent netAgent = conn_.netAgent_;
479         int rc = XAResource.XA_OK;
480         exceptionsOnXA = null;
481
482         if (conn_.agent_.loggingEnabled()) {
483             conn_.agent_.logWriter_.traceEntry(this, "rollback", xid);
484         }
485         if (conn_.isPhysicalConnClosed()) {
486             connectionClosedFailure();
487         }
488
489         // update the XACallInfo
490
NetXACallInfo callInfo = callInfoArray_[conn_.currXACallInfoOffset_];
491         callInfo.xid_ = xid;
492         callInfo.xaResource_ = this;
493         callInfo.xaRetVal_ = XAResource.XA_OK; // initialize XARETVAL
494
try {
495             netAgent.beginWriteChainOutsideUOW();
496             netAgent.netConnectionRequest_.writeXaRollback(conn_, xid);
497             netAgent.flowOutsideUOW();
498             // read the reply to the rollback
499
rc = netAgent.netConnectionReply_.readXaRollback(conn_);
500             netAgent.endReadChain();
501             if (callInfo.xaRetVal_ != XAResource.XA_OK) { // xaRetVal has possible error, format it
502
callInfo.xaFunction_ = XAFUNC_END;
503                 rc = xaRetValErrorAccumSQL(callInfo, rc);
504                 callInfo.xaRetVal_ = XAResource.XA_OK; // re-initialize XARETVAL
505
}
506         } catch (SqlException sqle) {
507             rc = XAException.XAER_RMERR;
508             exceptionsOnXA = org.apache.derby.client.am.Utils.accumulateSQLException
509                     (sqle, exceptionsOnXA);
510         } finally {
511             conn_.pendingEndXACallinfoOffset_ = -1; // indicate no pending callinfo
512
}
513         if (rc != XAResource.XA_OK) {
514             throwXAException(rc, false);
515         }
516  
517     }
518
519     /**
520      * <P>Set the current transaction timeout value for this <CODE>XAResource</CODE> instance. This value overwrites the
521      * default transaction timeout value in the resource manager. The newly assigned timeout value is effective for the
522      * life of this <CODE>XAResource</CODE> instance unless a new value is set.<P>
523      *
524      * @param seconds the transaction timeout value in seconds.
525      *
526      * @throws XAException An error has occurred. Possible exception values are XAER_RMERR, XAER_RMFAIL, or XAER_INVAL.
527      */

528     public boolean setTransactionTimeout(int seconds) throws XAException JavaDoc {
529         if (conn_.agent_.loggingEnabled()) {
530             conn_.agent_.logWriter_.traceExit(this, "setTransactionTimeout", false);
531         }
532         exceptionsOnXA = null;
533         return false; // we don't support transaction timeout in our layer.
534
/* int rc = xaSetTransTimeOut(seconds);
535            if (rc != XAResource.XA_OK)
536              throwXAException(rc); */

537     }
538
539     /**
540      * Start work on behalf of a transaction branch specified in xid
541      *
542      * @param xid A global transaction identifier to be associated with the resource
543      * @param flags One of TMNOFLAGS, TMJOIN, or TMRESUME
544      *
545      * @throws XAException An error has occurred. Possible exceptions * are XA_RB*, XAER_RMERR, XAER_RMFAIL,
546      * XAER_DUPID, XAER_OUTSIDE, XAER_NOTA, XAER_INVAL, or XAER_PROTO.
547      */

548     public synchronized void start(Xid JavaDoc xid, int flags) throws XAException JavaDoc {
549
550         NetAgent netAgent = conn_.netAgent_;
551         int rc = XAResource.XA_OK;
552         exceptionsOnXA = null;
553         if (conn_.agent_.loggingEnabled()) {
554             conn_.agent_.logWriter_.traceEntry(this, "start", xid, flags);
555         }
556         if (conn_.isPhysicalConnClosed()) {
557             connectionClosedFailure();
558         }
559         
560         // DERBY-1025 - Flow an auto-commit if in auto-commit mode before
561
// entering a global transaction
562
try {
563             if(conn_.autoCommit_)
564                 conn_.flowAutoCommit();
565         } catch (SqlException sqle) {
566             rc = XAException.XAER_RMERR;
567             exceptionsOnXA = org.apache.derby.client.am.Utils.accumulateSQLException
568                     (sqle, exceptionsOnXA);
569         }
570
571         // update the XACallInfo
572
NetXACallInfo callInfo = callInfoArray_[conn_.currXACallInfoOffset_];
573         callInfo.xaFlags_ = flags;
574         callInfo.xaInProgress_ = true;
575         callInfo.xid_ = xid;
576         callInfo.xaResource_ = this;
577         callInfo.xaRetVal_ = XAResource.XA_OK; // initialize XARETVAL
578
try {
579             netAgent.beginWriteChainOutsideUOW();
580             netAgent.netConnectionRequest_.writeXaStartUnitOfWork(conn_);
581             netAgent.flowOutsideUOW();
582             netAgent.netConnectionReply_.readXaStartUnitOfWork(conn_);
583             if (callInfo.xaRetVal_ != XAResource.XA_OK) { // xaRetVal has possible error, format it
584
callInfo.xaFunction_ = XAFUNC_START;
585                 rc = xaRetValErrorAccumSQL(callInfo, rc);
586                 callInfo.xaRetVal_ = XAResource.XA_OK; // re-initialize XARETVAL
587
}
588             // Setting this is currently required to avoid client from sending
589
// commit for autocommit.
590
if (rc == XAResource.XA_OK) {
591                 conn_.setXAState(Connection.XA_T1_ASSOCIATED);
592             }
593
594         } catch (SqlException sqle) {
595             rc = XAException.XAER_RMERR;
596             exceptionsOnXA = org.apache.derby.client.am.Utils.accumulateSQLException
597                     (sqle, exceptionsOnXA);
598         } finally {
599             conn_.pendingEndXACallinfoOffset_ = -1; // indicate no pending callinfo
600
}
601         if (rc != XAResource.XA_OK) {
602             throwXAException(rc, false);
603         }
604     }
605
606
607     protected void throwXAException(int rc) throws XAException JavaDoc {
608         throwXAException(rc, rc != XAException.XAER_NOTA);
609     }
610
611     private String JavaDoc getXAExceptionText(int rc) {
612         String JavaDoc xaExceptionText;
613         switch (rc) {
614         case javax.transaction.xa.XAException.XA_RBROLLBACK:
615             xaExceptionText = "XA_RBROLLBACK";
616             break;
617         case javax.transaction.xa.XAException.XA_RBCOMMFAIL:
618             xaExceptionText = "XA_RBCOMMFAIL";
619             break;
620         case javax.transaction.xa.XAException.XA_RBDEADLOCK:
621             xaExceptionText = "XA_RBDEADLOCK";
622             break;
623         case javax.transaction.xa.XAException.XA_RBINTEGRITY:
624             xaExceptionText = "XA_RBINTEGRITY";
625             break;
626         case javax.transaction.xa.XAException.XA_RBOTHER:
627             xaExceptionText = "XA_RBOTHER";
628             break;
629         case javax.transaction.xa.XAException.XA_RBPROTO:
630             xaExceptionText = "XA_RBPROTO";
631             break;
632         case javax.transaction.xa.XAException.XA_RBTIMEOUT:
633             xaExceptionText = "XA_RBTIMEOUT";
634             break;
635         case javax.transaction.xa.XAException.XA_RBTRANSIENT:
636             xaExceptionText = "XA_RBTRANSIENT";
637             break;
638         case javax.transaction.xa.XAException.XA_NOMIGRATE:
639             xaExceptionText = "XA_NOMIGRATE";
640             break;
641         case javax.transaction.xa.XAException.XA_HEURHAZ:
642             xaExceptionText = "XA_HEURHAZ";
643             break;
644         case javax.transaction.xa.XAException.XA_HEURCOM:
645             xaExceptionText = "XA_HEURCOM";
646             break;
647         case javax.transaction.xa.XAException.XA_HEURRB:
648             xaExceptionText = "XA_HEURRB";
649             break;
650         case javax.transaction.xa.XAException.XA_HEURMIX:
651             xaExceptionText = "XA_HEURMIX";
652             break;
653         case javax.transaction.xa.XAException.XA_RETRY:
654             xaExceptionText = "XA_RETRY";
655             break;
656         case javax.transaction.xa.XAException.XA_RDONLY:
657             xaExceptionText = "XA_RDONLY";
658             break;
659         case javax.transaction.xa.XAException.XAER_ASYNC:
660             xaExceptionText = "XAER_ASYNC";
661             break;
662         case javax.transaction.xa.XAException.XAER_RMERR:
663             xaExceptionText = "XAER_RMERR";
664             break;
665         case javax.transaction.xa.XAException.XAER_NOTA:
666             xaExceptionText = "XAER_NOTA";
667             break;
668         case javax.transaction.xa.XAException.XAER_INVAL:
669             xaExceptionText = "XAER_INVAL";
670             break;
671         case javax.transaction.xa.XAException.XAER_PROTO:
672             xaExceptionText = "XAER_PROTO";
673             break;
674         case javax.transaction.xa.XAException.XAER_RMFAIL:
675             xaExceptionText = "XAER_RMFAIL";
676             break;
677         case javax.transaction.xa.XAException.XAER_DUPID:
678             xaExceptionText = "XAER_DUPID";
679             break;
680         case javax.transaction.xa.XAException.XAER_OUTSIDE:
681             xaExceptionText = "XAER_OUTSIDE";
682             break;
683         case XAResource.XA_OK:
684             xaExceptionText = "XA_OK";
685             break;
686         default:
687             xaExceptionText = "Unknown Error";
688             break;
689         }
690         return xaExceptionText;
691     }
692
693     protected void throwXAException(int rc, boolean resetFlag) throws XAException JavaDoc { // ~~~
694
String JavaDoc xaExceptionText;
695         if (resetFlag) {
696             // reset the state of the failed connection
697
NetXACallInfo callInfo = callInfoArray_[conn_.currXACallInfoOffset_];
698             callInfo.xaInProgress_ = false;
699             callInfo.xaWasSuspended = false;
700         }
701
702         xaExceptionText = getXAExceptionText(rc);
703         // save the SqlException chain to add it to the XAException
704
org.apache.derby.client.am.SqlException sqlExceptions = exceptionsOnXA;
705
706         while (exceptionsOnXA != null) { // one or more SqlExceptions received, format them
707
xaExceptionText = xaExceptionText + " : " + exceptionsOnXA.getMessage();
708             exceptionsOnXA = (org.apache.derby.client.am.SqlException)
709                     exceptionsOnXA.getNextException();
710         }
711         org.apache.derby.client.am.XaException xaException =
712                 new org.apache.derby.client.am.XaException(conn_.agent_.logWriter_,
713                         sqlExceptions,
714                         xaExceptionText);
715         xaException.errorCode = rc;
716         setXaStateForXAException(rc);
717         throw xaException;
718     }
719
720
721     /**
722      * Reset the transaction branch association state to XA_T0_NOT_ASSOCIATED
723      * for XAER_RM* and XA_RB* Exceptions. All other exeptions leave the state
724      * unchanged
725      *
726      * @param rc // return code from XAException
727      * @throws XAException
728      */

729     private void setXaStateForXAException(int rc) {
730         switch (rc)
731         {
732             // Reset to T0, not associated for XA_RB*, RM*
733
// XAER_RMFAIL and XAER_RMERR will be fatal to the connection
734
// but that is not dealt with here
735
case javax.transaction.xa.XAException.XAER_RMFAIL:
736            case javax.transaction.xa.XAException.XAER_RMERR:
737            case javax.transaction.xa.XAException.XA_RBROLLBACK:
738            case javax.transaction.xa.XAException.XA_RBCOMMFAIL:
739            case javax.transaction.xa.XAException.XA_RBDEADLOCK:
740            case javax.transaction.xa.XAException.XA_RBINTEGRITY:
741            case javax.transaction.xa.XAException.XA_RBOTHER:
742            case javax.transaction.xa.XAException.XA_RBPROTO:
743            case javax.transaction.xa.XAException.XA_RBTIMEOUT:
744            case javax.transaction.xa.XAException.XA_RBTRANSIENT:
745             conn_.setXAState(Connection.XA_T0_NOT_ASSOCIATED);
746            break;
747             // No change for other XAExceptions
748
// javax.transaction.xa.XAException.XA_NOMIGRATE
749
//javax.transaction.xa.XAException.XA_HEURHAZ
750
// javax.transaction.xa.XAException.XA_HEURCOM
751
// javax.transaction.xa.XAException.XA_HEURRB
752
// javax.transaction.xa.XAException.XA_HEURMIX
753
// javax.transaction.xa.XAException.XA_RETRY
754
// javax.transaction.xa.XAException.XA_RDONLY
755
// javax.transaction.xa.XAException.XAER_ASYNC
756
// javax.transaction.xa.XAException.XAER_NOTA
757
// javax.transaction.xa.XAException.XAER_INVAL
758
// javax.transaction.xa.XAException.XAER_PROTO
759
// javax.transaction.xa.XAException.XAER_DUPID
760
// javax.transaction.xa.XAException.XAER_OUTSIDE
761
default:
762               return;
763         }
764     }
765
766     public boolean isSameRM(XAResource JavaDoc xares) throws XAException JavaDoc {
767         boolean isSame = false; // preset that the RMs are NOT the same
768
exceptionsOnXA = null;
769
770         if (conn_.agent_.loggingEnabled()) {
771             conn_.agent_.logWriter_.traceEntry(this, "isSameRM", xares);
772         }
773         if (conn_.isPhysicalConnClosed()) {
774             connectionClosedFailure();
775         }
776
777         if (xares instanceof org.apache.derby.client.net.NetXAResource) { // both are NetXAResource so check to see if this is the same RM
778
// remember, isSame is initialized to false
779
NetXAResource derbyxares = (NetXAResource) xares;
780             while (true) {
781                 if (!conn_.databaseName_.equalsIgnoreCase(derbyxares.conn_.databaseName_)) {
782                     break; // database names are not equal, not same RM
783
}
784                 if (!conn_.netAgent_.server_.equalsIgnoreCase
785                         (derbyxares.conn_.netAgent_.server_)) { // server name strings not equal, compare IP addresses
786
try {
787                         // 1st convert "localhost" to actual server name
788
String JavaDoc server1 = this.processLocalHost(conn_.netAgent_.server_);
789                         String JavaDoc server2 =
790                                 this.processLocalHost(derbyxares.conn_.netAgent_.server_);
791                         // now convert the server name to ip address
792
InetAddress JavaDoc serverIP1 = InetAddress.getByName(server1);
793                         InetAddress JavaDoc serverIP2 = InetAddress.getByName(server2);
794                         if (!serverIP1.equals(serverIP2)) {
795                             break; // server IPs are not equal, not same RM
796
}
797                     } catch (UnknownHostException JavaDoc ue) {
798                         break;
799                     }
800                 }
801                 if (conn_.netAgent_.port_ != derbyxares.conn_.netAgent_.port_) {
802                     break; // ports are not equal, not same RM
803
}
804                 isSame = true; // everything the same, set RMs are the same
805
break;
806             }
807         }
808
809         if (conn_.agent_.loggingEnabled()) {
810             conn_.agent_.logWriter_.traceExit
811                     (this, "isSameRM", isSame);
812         }
813         return isSame;
814     }
815     
816     public static boolean xidsEqual(Xid JavaDoc xid1, Xid JavaDoc xid2) { // determine if the 2 xids contain the same values even if not same object
817
// comapre the format ids
818
if (xid1.getFormatId() != xid2.getFormatId()) {
819             return false; // format ids are not the same
820
}
821
822         // compare the global transaction ids
823
int xid1Length = xid1.getGlobalTransactionId().length;
824         if (xid1Length != xid2.getGlobalTransactionId().length) {
825             return false; // length of the global trans ids are not the same
826
}
827         byte[] xid1Bytes = xid1.getGlobalTransactionId();
828         byte[] xid2Bytes = xid2.getGlobalTransactionId();
829         int i;
830         for (i = 0; i < xid1Length; ++i) { // check all bytes are the same
831
if (xid1Bytes[i] != xid2Bytes[i]) {
832                 return false; // bytes in the global trans ids are not the same
833
}
834         }
835
836         // compare the branch qualifiers
837
xid1Length = xid1.getBranchQualifier().length;
838         if (xid1Length != xid2.getBranchQualifier().length) {
839             return false; // length of the global trans ids are not the same
840
}
841         xid1Bytes = xid1.getBranchQualifier();
842         xid2Bytes = xid2.getBranchQualifier();
843         for (i = 0; i < xid1Length; ++i) { // check all bytes are the same
844
if (xid1Bytes[i] != xid2Bytes[i]) {
845                 return false; // bytes in the global trans ids are not the same
846
}
847         }
848
849         return true; // all of the fields are the same, xid1 == xid2
850
}
851
852
853     public List JavaDoc getSpecialRegisters() {
854         return specialRegisters_;
855     }
856
857     public void addSpecialRegisters(String JavaDoc s) {
858         if (s.substring(0, 1).equals("@")) {
859             // SET statement is coming from Client
860
if (specialRegisters_.remove(s.substring(1))) {
861                 specialRegisters_.remove(s);
862                 specialRegisters_.add(s.substring(1));
863             } else {
864                 specialRegisters_.remove(s);
865                 specialRegisters_.add(s);
866             }
867         } else { // SET statement is coming from Server
868
specialRegisters_.remove(s);
869             specialRegisters_.add(s);
870         }
871     }
872
873     private void connectionClosedFailure() throws XAException JavaDoc { // throw an XAException XAER_RMFAIL, with a chained SqlException - closed
874
exceptionsOnXA = org.apache.derby.client.am.Utils.accumulateSQLException
875                 (new SqlException(null,
876                         new ClientMessageId(SQLState.NO_CURRENT_CONNECTION)),
877                         exceptionsOnXA);
878         throwXAException(javax.transaction.xa.XAException.XAER_RMFAIL);
879     }
880
881     private String JavaDoc getXAFuncStr(int xaFunc) {
882         switch (xaFunc) {
883         case XAFUNC_COMMIT:
884             return XAFUNCSTR_COMMIT;
885         case XAFUNC_END:
886             return XAFUNCSTR_END;
887         case XAFUNC_FORGET:
888             return XAFUNCSTR_FORGET;
889         case XAFUNC_PREPARE:
890             return XAFUNCSTR_PREPARE;
891         case XAFUNC_RECOVER:
892             return XAFUNCSTR_RECOVER;
893         case XAFUNC_ROLLBACK:
894             return XAFUNCSTR_ROLLBACK;
895         case XAFUNC_START:
896             return XAFUNCSTR_START;
897         }
898         return XAFUNCSTR_NONE;
899     }
900
901     protected int xaRetValErrorAccumSQL(NetXACallInfo callInfo, int currentRC) {
902
903         // xaRetVal_ is set by the server to be one of the
904
// standard constants from XAException.
905
int rc = callInfo.xaRetVal_;
906
907         if (rc != XAResource.XA_OK) { // error was detected
908
// create an SqlException to report this error within
909
SqlException accumSql = new SqlException(conn_.netAgent_.logWriter_,
910                 new ClientMessageId(SQLState.NET_XARETVAL_ERROR),
911                 getXAFuncStr(callInfo.xaFunction_),
912                 getXAExceptionText(rc),
913                 org.apache.derby.client.am.SqlCode.queuedXAError);
914             exceptionsOnXA = org.apache.derby.client.am.Utils.accumulateSQLException
915                     (accumSql, exceptionsOnXA);
916
917             if (currentRC != XAResource.XA_OK) { // the rc passed into this function had an error also, prioritize error
918
if (currentRC < 0) { // rc passed in was a major error use it instead of current error
919
return currentRC;
920                 }
921             }
922         }
923         return rc;
924     }
925
926     private String JavaDoc processLocalHost(String JavaDoc serverName) {
927         if (serverName.equalsIgnoreCase("localhost")) { // this is a localhost, find hostname
928
try {
929                 InetAddress JavaDoc localhostNameIA = InetAddress.getLocalHost();
930                 String JavaDoc localhostName = localhostNameIA.getHostName();
931                 return localhostName;
932             } catch (SecurityException JavaDoc se) {
933                 return serverName;
934             } catch (UnknownHostException JavaDoc ue) {
935                 return serverName;
936             }
937         }
938         // not "localhost", return original server name
939
return serverName;
940     }
941
942     protected void removeXaresFromSameRMchain() {
943         // check all NetXAResources on the same RM for the NetXAResource to remove
944
try {
945             this.ignoreMe_ = true; // use the ignoreMe_ flag to indicate the
946
// XAResource to remove
947
NetXAResource prevXAResource = null;
948             NetXAResource currXAResource;
949             synchronized (xaResourceSameRMGroup_) { // make sure no one changes this vector list
950
currXAResource = (NetXAResource) xaResourceSameRMGroup_.elementAt(sameRMGroupIndex_);
951                 while (currXAResource != null) { // is this the XAResource to remove?
952
if (currXAResource.ignoreMe_) { // this NetXAResource is the one to remove
953
if (prevXAResource != null) { // this XAResource is not first in chain, just move next to prev
954
prevXAResource.nextSameRM_ = currXAResource.nextSameRM_;
955                         } else { // this XAResource is first in chain, just move next to root
956
xaResourceSameRMGroup_.set(sameRMGroupIndex_,
957                                     currXAResource.nextSameRM_);
958                         }
959                         return;
960                     }
961                     // this is not the NetXAResource to remove, try the next one
962
prevXAResource = currXAResource;
963                     currXAResource = currXAResource.nextSameRM_;
964                 }
965             }
966         } finally {
967             this.ignoreMe_ = false;
968         }
969     }
970
971
972     public void initForReuse() {
973         // add this new XAResource to the list of other XAResources for the Same RM
974
// first find out if there are any other XAResources for the same RM
975
// then check to make sure it is not already in the chain
976
synchronized (xaResourceSameRMGroup_) { // make sure no one changes this vector list
977
int groupCount = xaResourceSameRMGroup_.size();
978             int index = 0;
979             int firstFreeElement = -1;
980             NetXAResource xaResourceGroup = null;
981
982             for (; index < groupCount; ++index) { // check if this group is the same RM
983
xaResourceGroup = (NetXAResource) xaResourceSameRMGroup_.elementAt(index);
984                 if (xaResourceGroup == null) { // this is a free element, save its index if first found
985
if (firstFreeElement == -1) { // first free element, save index
986
firstFreeElement = index;
987                     }
988                     continue; // go to next element
989
}
990                 try {
991                     if (xaResourceGroup.isSameRM(this)) { // it is the same RM add this XAResource to the chain if not there
992
NetXAResource nextXares = (NetXAResource)
993                                 xaResourceSameRMGroup_.elementAt(sameRMGroupIndex_);
994                         while (nextXares != null) { // is this NetXAResource the one we are trying to add?
995
if (nextXares.equals(this)) { // the XAResource to be added already is in chain, don't add
996
break;
997                             }
998                             // Xid was not on that NetXAResource, try the next one
999
nextXares = nextXares.nextSameRM_;
1000                        }
1001
1002                        if (nextXares == null) { // XAResource to be added is not in the chain already, add it
1003
// add it at the head of the chain
1004
sameRMGroupIndex_ = index;
1005                            this.nextSameRM_ = xaResourceGroup.nextSameRM_;
1006                            xaResourceGroup.nextSameRM_ = this;
1007                        }
1008                        return; // done
1009
}
1010                } catch (XAException JavaDoc xae) {
1011                }
1012            }
1013
1014            // no other same RM was found, add this as first of new group
1015
if (firstFreeElement == -1) { // no free element found, add new element to end
1016
xaResourceSameRMGroup_.add(this);
1017                sameRMGroupIndex_ = groupCount;
1018            } else { // use first free element found
1019
xaResourceSameRMGroup_.setElementAt(this, firstFreeElement);
1020                sameRMGroupIndex_ = firstFreeElement;
1021            }
1022        }
1023    }
1024}
1025
Popular Tags