EMMA Coverage Report (generated Wed Jun 28 22:15:27 PDT 2006)
[all classes][org.apache.derby.client.net]

COVERAGE SUMMARY FOR SOURCE FILE [NetXAResource.java]

nameclass, %method, %block, %line, %
NetXAResource.java100% (1/1)72%  (18/25)63%  (1083/1714)63%  (295.6/468)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class NetXAResource100% (1/1)72%  (18/25)63%  (1083/1714)63%  (295.6/468)
<static initializer> 100% (1/1)100% (9/9)100% (2/2)
NetXAResource (XAConnection, int, String, String, NetXAConnection): void 100% (1/1)100% (115/115)100% (28/28)
addSpecialRegisters (String): void 0%   (0/1)0%   (0/49)0%   (0/9)
commit (Xid, boolean): void 100% (1/1)69%  (80/116)74%  (21.6/29)
connectionClosedFailure (): void 0%   (0/1)0%   (0/14)0%   (0/3)
end (Xid, int): void 100% (1/1)71%  (89/126)77%  (24.6/32)
forget (Xid): void 100% (1/1)66%  (72/109)69%  (19.4/28)
getSpecialRegisters (): List 0%   (0/1)0%   (0/3)0%   (0/1)
getTransactionTimeout (): int 0%   (0/1)0%   (0/36)0%   (0/8)
getXAExceptionText (int): String 100% (1/1)28%  (22/78)27%  (14/51)
getXAFuncStr (int): String 100% (1/1)67%  (12/18)67%  (6/9)
initForReuse (): void 100% (1/1)93%  (89/96)91%  (27.4/30)
isSameRM (XAResource): boolean 100% (1/1)55%  (57/104)50%  (13/26)
prepare (Xid): int 100% (1/1)67%  (86/129)72%  (21.6/30)
processLocalHost (String): String 0%   (0/1)0%   (0/19)0%   (0/9)
recover (int): Xid [] 100% (1/1)66%  (105/159)71%  (28.4/40)
removeXaresFromSameRMchain (): void 100% (1/1)83%  (54/65)94%  (15/16)
rollback (Xid): void 100% (1/1)68%  (74/109)73%  (20.4/28)
setTransactionTimeout (int): boolean 0%   (0/1)0%   (0/18)0%   (0/4)
setXaStateForXAException (int): void 100% (1/1)100% (9/9)100% (5/5)
start (Xid, int): void 100% (1/1)67%  (90/135)71%  (26.4/37)
throwXAException (int): void 100% (1/1)70%  (7/10)35%  (0.7/2)
throwXAException (int, boolean): void 100% (1/1)100% (63/63)100% (13/13)
xaRetValErrorAccumSQL (NetXACallInfo, int): int 100% (1/1)100% (50/50)100% (9/9)
xidsEqual (Xid, Xid): boolean 0%   (0/1)0%   (0/75)0%   (0/19)

1/*
2 
3   Derby - Class org.apache.derby.client.net.NetXAResource
4 
5   Copyright (c) 2003, 2005 The Apache Software Foundation or its licensors, where applicable.
6 
7   Licensed under the Apache License, Version 2.0 (the "License");
8   you may not use this file except in compliance with the License.
9   You may obtain a copy of the License at
10 
11      http://www.apache.org/licenses/LICENSE-2.0
12 
13   Unless required by applicable law or agreed to in writing, software
14   distributed under the License is distributed on an "AS IS" BASIS,
15   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   See the License for the specific language governing permissions and
17   limitations under the License.
18 
19*/
20/**********************************************************************
21 *
22 *
23 *  Component Name =
24 *
25 *      Package Name = org.apache.derby.client.net
26 *
27 *  Descriptive Name = class implements XAResource
28 *
29 *  Status = New code
30 *
31 *  Function = Handle XA methods
32 *
33 *  List of Classes
34 *              - NetXAResource
35 *
36 *  Restrictions : None
37 *
38 **********************************************************************/
39package org.apache.derby.client.net;
40 
41import java.net.InetAddress;
42import java.net.UnknownHostException;
43import java.util.Collections;
44import java.util.Enumeration;
45import java.util.LinkedList;
46import java.util.List;
47import java.util.Vector;
48import javax.sql.XAConnection;
49import javax.transaction.xa.XAException;
50import javax.transaction.xa.XAResource;
51import javax.transaction.xa.Xid;
52 
53import org.apache.derby.client.ClientXid;
54import org.apache.derby.client.am.Connection;
55import org.apache.derby.client.am.SqlException;
56import org.apache.derby.client.am.ClientMessageId;
57import org.apache.derby.shared.common.reference.SQLState;
58 
59public class NetXAResource implements XAResource {
60    public static final int TMTIMEOUT = 0x00000100;
61    public static final int ACTIVE_ONLY = -1;
62    public static final int XA_NULL_XID = -1; // null Xid has Format Id of -1
63    public static final int INITIAL_CALLINFO_ELEMENTS = 1;
64    public static final int RECOVER_XID_ARRAY_LENGTH = 10;
65    public static final ClientXid nullXid = new ClientXid();
66 
67    // xaFunction defines, shows which queued XA function is being performed
68    public static final int XAFUNC_NONE = 0;
69    public static final int XAFUNC_COMMIT = 1;
70    public static final int XAFUNC_END = 2;
71    public static final int XAFUNC_FORGET = 3;
72    public static final int XAFUNC_PREPARE = 4;
73    public static final int XAFUNC_RECOVER = 5;
74    public static final int XAFUNC_ROLLBACK = 6;
75    public static final int XAFUNC_START = 7;
76    public static final String XAFUNCSTR_NONE = "No XA Function";
77    public static final String XAFUNCSTR_COMMIT = "XAResource.commit()";
78    public static final String XAFUNCSTR_END = "XAResource.end()";
79    public static final String XAFUNCSTR_FORGET = "XAResource.forget()";
80    public static final String XAFUNCSTR_PREPARE = "XAResource.prepare()";
81    public static final String XAFUNCSTR_RECOVER = "XAResource.recover()";
82    public static final String XAFUNCSTR_ROLLBACK = "XAResource.rollback()";
83    public static final String XAFUNCSTR_START = "XAResource.start()";
84 
85    public int nextElement = 0;
86 
87    // XAResources with same RM group list
88    protected static Vector xaResourceSameRMGroup_ = new Vector();
89    protected int sameRMGroupIndex_ = 0;
90    protected NetXAResource nextSameRM_ = null;
91    protected boolean ignoreMe_ = false;
92 
93 
94 
95    public org.apache.derby.client.am.SqlException exceptionsOnXA = null;
96 
97    XAConnection xaconn_;
98    org.apache.derby.client.net.NetXAConnection netXAConn_;
99    org.apache.derby.client.net.NetConnection conn_;
100    int rmId_; // unique RmId generated by XAConnection
101    // TODO: change to a single callInfo field (not an array)
102    NetXACallInfo callInfoArray_[] =
103            new NetXACallInfo[INITIAL_CALLINFO_ELEMENTS];
104    int numXACallInfo_ = INITIAL_CALLINFO_ELEMENTS;
105    int connectionCount_ = 1;
106    int activeXATransCount_ = 0;
107    String rmIdx_; // userid in case we need to create a secondary connection
108    String rmIdy_; // password in case we need to create a secondary connection
109    // TODO: remove port and ipaddr_
110    int port_;     // port needed to make secondary connection for recover in DS mode.
111    String ipaddr_;  // ip address needed to make secondary connection for recover in DS mode.
112 
113    private List specialRegisters_ = Collections.synchronizedList(new LinkedList());
114 
115    public NetXAResource(XAConnection xaconn, int rmId,
116                         String userId, String password,
117                         org.apache.derby.client.net.NetXAConnection conn) {
118        xaconn_ = xaconn;
119        rmId_ = rmId;
120        conn_ = conn.getNetConnection();
121        netXAConn_ = conn;
122        rmIdx_ = userId;
123        rmIdy_ = password;
124        port_ = conn_.netAgent_.getPort();
125        ipaddr_ = conn_.netAgent_.socket_.getLocalAddress().getHostAddress();
126        conn.setNetXAResource(this);
127 
128        // link the primary connection to the first XACallInfo element
129        conn_.currXACallInfoOffset_ = 0;
130 
131        // construct the NetXACallInfo object for the array.
132        for (int i = 0; i < INITIAL_CALLINFO_ELEMENTS; ++i) {
133            callInfoArray_[i] = new NetXACallInfo(null, XAResource.TMNOFLAGS, this,
134                    null);
135        }
136 
137        // initialize the first XACallInfo element with the information from the
138        //  primary connection
139        callInfoArray_[0].actualConn_ = conn;
140        callInfoArray_[0].currConnection_ = true;
141        callInfoArray_[0].freeEntry_ = false;
142        // ~~~ save conn_ connection variables in callInfoArray_[0]
143        callInfoArray_[0].saveConnectionVariables();
144 
145        // add this new XAResource to the list of other XAResources for the Same RM
146        initForReuse();
147    }
148 
149    public void commit(Xid xid, boolean onePhase) throws XAException {
150        NetAgent netAgent = conn_.netAgent_;
151        int rc = XAResource.XA_OK;
152        
153        exceptionsOnXA = null;
154        if (conn_.agent_.loggingEnabled()) {
155            conn_.agent_.logWriter_.traceEntry(this, "commit", xid, onePhase);
156        }
157        if (conn_.isPhysicalConnClosed()) {
158            connectionClosedFailure();
159        }
160 
161        // update the XACallInfo
162        NetXACallInfo callInfo = callInfoArray_[conn_.currXACallInfoOffset_];
163        callInfo.xaFlags_ = (onePhase ? XAResource.TMONEPHASE :
164                XAResource.TMNOFLAGS);
165        callInfo.xid_ = xid;
166        callInfo.xaResource_ = this;
167        callInfo.xaRetVal_ = XAResource.XA_OK; // initialize XARETVAL
168        try {
169            netAgent.beginWriteChainOutsideUOW();
170            netAgent.netConnectionRequest_.writeXaCommit(conn_, xid);
171            netAgent.flowOutsideUOW();
172            netAgent.netConnectionReply_.readXaCommit(conn_);
173            if (callInfo.xaRetVal_ != XAResource.XA_OK) { // xaRetVal has possible error, format it
174                callInfo.xaFunction_ = XAFUNC_COMMIT;
175                rc = xaRetValErrorAccumSQL(callInfo, rc);
176                callInfo.xaRetVal_ = XAResource.XA_OK; // re-initialize XARETVAL
177            }
178            netAgent.endReadChain();
179        } catch (SqlException sqle) {
180            rc = XAException.XAER_RMERR;
181            exceptionsOnXA = org.apache.derby.client.am.Utils.accumulateSQLException
182                    (sqle, exceptionsOnXA);
183        } finally {
184            conn_.pendingEndXACallinfoOffset_ = -1; // indicate no pending callinfo
185        }
186        if (rc != XAResource.XA_OK) {
187            throwXAException(rc, false);
188        }
189    }
190 
191    /**
192     * Ends the work performed on behalf of a transaction branch. The resource manager dissociates the XA resource from
193     * the transaction branch specified and let the transaction be completed.
194     * <p/>
195     * If TMSUSPEND is specified in flags, the transaction branch is temporarily suspended in incomplete state. The
196     * transaction context is in suspened state and must be resumed via start with TMRESUME specified.
197     * <p/>
198     * If TMFAIL is specified, the portion of work has failed. The resource manager may mark the transaction as
199     * rollback-only
200     * <p/>
201     * If TMSUCCESS is specified, the portion of work has completed successfully.
202     *
203     * @param xid   A global transaction identifier that is the same as what was used previously in the start method.
204     * @param flags One of TMSUCCESS, TMFAIL, or TMSUSPEND
205     *
206     * @throws XAException An error has occurred. Possible XAException values are XAER_RMERR, XAER_RMFAILED, XAER_NOTA,
207     *                     XAER_INVAL, XAER_PROTO, or XA_RB*.
208     */
209 
210    public void end(Xid xid, int flags) throws XAException {
211 
212        NetAgent netAgent = conn_.netAgent_;
213        int rc = XAResource.XA_OK;
214        exceptionsOnXA = null;
215        if (conn_.agent_.loggingEnabled()) {
216            conn_.agent_.logWriter_.traceEntry(this, "end", xid, flags);
217        }
218        if (conn_.isPhysicalConnClosed()) {
219            connectionClosedFailure();
220        }
221 
222        NetXACallInfo callInfo = callInfoArray_[conn_.currXACallInfoOffset_];
223        callInfo.setReadOnlyTransactionFlag(conn_.readOnlyTransaction_);
224        callInfo.xaFlags_ = flags;
225        callInfo.xid_ = xid;
226        callInfo.xaResource_ = this;
227        callInfo.xaRetVal_ = XAResource.XA_OK; // initialize XARETVAL
228        try {
229            netAgent.beginWriteChainOutsideUOW();
230            netAgent.netConnectionRequest_.writeXaEndUnitOfWork(conn_);
231            netAgent.flowOutsideUOW();
232            rc = netAgent.netConnectionReply_.readXaEndUnitOfWork(conn_);
233            conn_.pendingEndXACallinfoOffset_ = -1; // indicate no pending end
234            if (callInfo.xaRetVal_ != XAResource.XA_OK) { // xaRetVal has possible error, format it
235                callInfo.xaFunction_ = XAFUNC_END;
236                rc = xaRetValErrorAccumSQL(callInfo, rc);
237                callInfo.xaRetVal_ = XAResource.XA_OK; // re-initialize XARETVAL
238            }
239            netAgent.endReadChain();
240        } catch (SqlException sqle) {
241            rc = XAException.XAER_RMERR;
242            exceptionsOnXA = org.apache.derby.client.am.Utils.accumulateSQLException
243                    (sqle, exceptionsOnXA);
244        } finally {
245            conn_.pendingEndXACallinfoOffset_ = -1; // indicate no pending callinfo
246        }
247        if (rc != XAResource.XA_OK) {
248            throwXAException(rc, false);
249        }else {
250                conn_.setXAState(Connection.XA_T0_NOT_ASSOCIATED);
251        } 
252    }
253 
254    /**
255     * Tell the resource manager to forget about a heuristically (MANUALLY) completed transaction branch.
256     *
257     * @param xid A global transaction identifier
258     *
259     * @throws XAException An error has occurred. Possible exception values are XAER_RMERR, XAER_RMFAIL, XAER_NOTA,
260     *                     XAER_INVAL, or XAER_PROTO.
261     */
262 
263    public void forget(Xid xid) throws XAException {
264        NetAgent netAgent = conn_.netAgent_;
265        int rc = XAResource.XA_OK;
266        exceptionsOnXA = null;
267 
268        if (conn_.agent_.loggingEnabled()) {
269            conn_.agent_.logWriter_.traceEntry(this, "forget", xid);
270        }
271        if (conn_.isPhysicalConnClosed()) {
272            connectionClosedFailure();
273        }
274        NetXACallInfo callInfo = callInfoArray_[conn_.currXACallInfoOffset_];
275        callInfo.xid_ = xid;
276        callInfo.xaResource_ = this;
277        callInfo.xaRetVal_ = XAResource.XA_OK; // initialize XARETVAL
278        try {
279            // flow the required PROTOCOL to the server
280            netAgent.beginWriteChainOutsideUOW();
281 
282            // sent the commit PROTOCOL
283            netAgent.netConnectionRequest_.writeXaForget(netAgent.netConnection_, xid);
284 
285            netAgent.flowOutsideUOW();
286 
287            // read the reply to the commit
288            netAgent.netConnectionReply_.readXaForget(netAgent.netConnection_);
289 
290            netAgent.endReadChain();
291            if (callInfo.xaRetVal_ != XAResource.XA_OK) { // xaRetVal has possible error, format it
292                callInfo.xaFunction_ = XAFUNC_FORGET;
293                rc = xaRetValErrorAccumSQL(callInfo, rc);
294                callInfo.xaRetVal_ = XAResource.XA_OK; // re-initialize XARETVAL
295            }
296        } catch (SqlException sqle) {
297            exceptionsOnXA = org.apache.derby.client.am.Utils.accumulateSQLException
298                    (sqle, exceptionsOnXA);
299            throwXAException(XAException.XAER_RMERR);
300        } finally {
301            conn_.pendingEndXACallinfoOffset_ = -1; // indicate no pending callinfo
302        }
303        if (rc != XAResource.XA_OK) {
304            throwXAException(rc, false);
305        }
306 
307    }
308 
309    /**
310     * Obtain the current transaction timeout value set for this XAResource instance. If
311     * <CODE>XAResource.setTransactionTimeout</CODE> was not use prior to invoking this method, the return value is the
312     * default timeout set for the resource manager; otherwise, the value used in the previous
313     * <CODE>setTransactionTimeout</CODE> call is returned.
314     *
315     * @return the transaction timeout value in seconds.
316     *
317     * @throws XAException An error has occurred. Possible exception values are XAER_RMERR, XAER_RMFAIL.
318     */
319    public int getTransactionTimeout() throws XAException {
320        if (conn_.agent_.loggingEnabled()) {
321            conn_.agent_.logWriter_.traceEntry(this, "getTransactionTimeout");
322        }
323        exceptionsOnXA = null;
324        if (conn_.isPhysicalConnClosed()) {
325            connectionClosedFailure();
326        }
327 
328        if (conn_.agent_.loggingEnabled()) {
329            conn_.agent_.logWriter_.traceExit(this, "getTransactionTimeout", 0);
330        }
331        return 0; // we don't support transaction timeout
332    }
333 
334    /**
335     * Ask the resource manager to prepare for a transaction commit of the transaction specified in xid.
336     *
337     * @param xid A global transaction identifier
338     *
339     * @return A value indicating the resource manager's vote on the outcome of the transaction. The possible values
340     *         are: XA_RDONLY or XA_OK. If the resource manager wants to roll back the transaction, it should do so by
341     *         raising an appropriate XAException in the prepare method.
342     *
343     * @throws XAException An error has occurred. Possible exception values are: XA_RB*, XAER_RMERR, XAER_RMFAIL,
344     *                     XAER_NOTA, XAER_INVAL, or XAER_PROTO.
345     */
346    public int prepare(Xid xid) throws XAException { // public interface for prepare
347        // just call prepareX with the recursion flag set to true
348        exceptionsOnXA = null;
349 
350        if (conn_.agent_.loggingEnabled()) {
351            conn_.agent_.logWriter_.traceEntry(this, "prepare", xid);
352        }
353        if (conn_.isPhysicalConnClosed()) {
354            connectionClosedFailure();
355        }
356 
357        /// update the XACallInfo
358        NetAgent netAgent = conn_.netAgent_;
359        int rc = XAResource.XA_OK;
360        NetXACallInfo callInfo = callInfoArray_[conn_.currXACallInfoOffset_];
361        callInfo.xid_ = xid;
362        callInfo.xaResource_ = this;
363        callInfo.xaRetVal_ = XAResource.XA_OK; // initialize XARETVAL
364        try {
365            netAgent.beginWriteChainOutsideUOW();
366            // sent the prepare PROTOCOL
367            netAgent.netConnectionRequest_.writeXaPrepare(conn_);
368            netAgent.flowOutsideUOW();
369 
370            // read the reply to the prepare
371            rc = netAgent.netConnectionReply_.readXaPrepare(conn_);
372            if ((callInfo.xaRetVal_ != XAResource.XA_OK) &&
373                    (callInfo.xaRetVal_ != XAException.XA_RDONLY)) { // xaRetVal has possible error, format it
374                callInfo.xaFunction_ = XAFUNC_PREPARE;
375                rc = xaRetValErrorAccumSQL(callInfo, rc);
376                callInfo.xaRetVal_ = XAResource.XA_OK; // re-initialize XARETVAL
377            }
378 
379            netAgent.endReadChain();
380        } catch (SqlException sqle) {
381            rc = XAException.XAER_RMERR;
382            exceptionsOnXA = org.apache.derby.client.am.Utils.accumulateSQLException
383                    (sqle, exceptionsOnXA);
384        } finally {
385            conn_.pendingEndXACallinfoOffset_ = -1; // indicate no pending callinfo
386        }
387        if ((rc != XAResource.XA_OK ) && (rc != XAResource.XA_RDONLY)) {
388            throwXAException(rc, false);
389        }
390        if (conn_.agent_.loggingEnabled()) {
391            conn_.agent_.logWriter_.traceExit(this, "prepare", rc);
392        }
393        return rc;
394    }
395 
396    /**
397     * Obtain a list of prepared transaction branches from a resource manager. The transaction manager calls this method
398     * during recovery to obtain the list of transaction branches that are currently in prepared or heuristically
399     * completed states.
400     *
401     * @param flag One of TMSTARTRSCAN, TMENDRSCAN, TMNOFLAGS. TMNOFLAGS must be used when no other flags are set in
402     *             flags.
403     *
404     * @return The resource manager returns zero or more XIDs for the transaction branches that are currently in a
405     *         prepared or heuristically completed state. If an error occurs during the operation, the resource manager
406     *         should raise the appropriate XAException.
407     *
408     * @throws XAException An error has occurred. Possible values are XAER_RMERR, XAER_RMFAIL, XAER_INVAL, and
409     *                     XAER_PROTO.
410     */
411    public Xid[] recover(int flag) throws XAException {
412        int rc = XAResource.XA_OK;
413        NetAgent netAgent = conn_.netAgent_;
414 
415        if (conn_.agent_.loggingEnabled()) {
416            conn_.agent_.logWriter_.traceEntry(this, "recover", flag);
417        }
418        exceptionsOnXA = null;
419        if (conn_.isPhysicalConnClosed()) {
420            connectionClosedFailure();
421        }
422 
423        Xid[] xidList = null;
424        int numXid = 0;
425 
426        NetXACallInfo callInfo = callInfoArray_[conn_.currXACallInfoOffset_];
427        callInfo.xaFlags_ = flag;
428        callInfo.xaResource_ = this;
429        callInfo.xaRetVal_ = XAResource.XA_OK; // initialize XARETVAL
430        try {
431            netAgent.beginWriteChainOutsideUOW();
432            // sent the recover PROTOCOL
433            netAgent.netConnectionRequest_.writeXaRecover(conn_, flag);
434            netAgent.flowOutsideUOW();
435            netAgent.netConnectionReply_.readXaRecover(conn_);
436            if (callInfo.xaRetVal_ != XAResource.XA_OK) { // xaRetVal has possible error, format it
437                callInfo.xaFunction_ = XAFUNC_RECOVER;
438                rc = xaRetValErrorAccumSQL(callInfo, rc);
439                callInfo.xaRetVal_ = XAResource.XA_OK; // re-initialize XARETVAL
440            }
441            netAgent.endReadChain();
442            if (conn_.indoubtTransactions_ != null) {
443                numXid = conn_.indoubtTransactions_.size();
444                xidList = new Xid[numXid];
445                int i = 0;
446                nextElement = 0;
447                for (Enumeration e = conn_.indoubtTransactions_.keys();
448                     e.hasMoreElements(); i++) {
449                    xidList[i] = (Xid) e.nextElement();
450                }
451            }
452        } catch (SqlException sqle) {
453            rc = XAException.XAER_RMERR;
454            exceptionsOnXA = org.apache.derby.client.am.Utils.accumulateSQLException
455                    (sqle, exceptionsOnXA);
456        } finally {
457            conn_.pendingEndXACallinfoOffset_ = -1; // indicate no pending callinfo
458        }
459        if (rc != XAResource.XA_OK) {
460            throwXAException(rc, false);
461        }
462 
463        if (conn_.agent_.loggingEnabled()) {
464            conn_.agent_.logWriter_.traceExit(this, "recover", xidList);
465        }
466        return xidList;
467    }
468 
469    /**
470     * Inform the resource manager to roll back work done on behalf of a transaction branch
471     *
472     * @param xid A global transaction identifier
473     *
474     * @throws XAException An error has occurred
475     */
476    public void rollback(Xid xid) throws XAException {
477        NetAgent netAgent = conn_.netAgent_;
478        int rc = XAResource.XA_OK;
479        exceptionsOnXA = null;
480 
481        if (conn_.agent_.loggingEnabled()) {
482            conn_.agent_.logWriter_.traceEntry(this, "rollback", xid);
483        }
484        if (conn_.isPhysicalConnClosed()) {
485            connectionClosedFailure();
486        }
487 
488        // update the XACallInfo
489        NetXACallInfo callInfo = callInfoArray_[conn_.currXACallInfoOffset_];
490        callInfo.xid_ = xid;
491        callInfo.xaResource_ = this;
492        callInfo.xaRetVal_ = XAResource.XA_OK; // initialize XARETVAL
493        try {
494            netAgent.beginWriteChainOutsideUOW();
495            netAgent.netConnectionRequest_.writeXaRollback(conn_, xid);
496            netAgent.flowOutsideUOW();
497            // read the reply to the rollback
498            rc = netAgent.netConnectionReply_.readXaRollback(conn_);
499            netAgent.endReadChain();
500            if (callInfo.xaRetVal_ != XAResource.XA_OK) { // xaRetVal has possible error, format it
501                callInfo.xaFunction_ = XAFUNC_END;
502                rc = xaRetValErrorAccumSQL(callInfo, rc);
503                callInfo.xaRetVal_ = XAResource.XA_OK; // re-initialize XARETVAL
504            }
505        } catch (SqlException sqle) {
506            rc = XAException.XAER_RMERR;
507            exceptionsOnXA = org.apache.derby.client.am.Utils.accumulateSQLException
508                    (sqle, exceptionsOnXA);
509        } finally {
510            conn_.pendingEndXACallinfoOffset_ = -1; // indicate no pending callinfo
511        }
512        if (rc != XAResource.XA_OK) {
513            throwXAException(rc, false);
514        }
515 
516    }
517 
518    /**
519     * <P>Set the current transaction timeout value for this <CODE>XAResource</CODE> instance. This value overwrites the
520     * default transaction timeout value in the resource manager. The newly assigned timeout value is effective for the
521     * life of this <CODE>XAResource</CODE> instance unless a new value is set.<P>
522     *
523     * @param seconds the transaction timeout value in seconds.
524     *
525     * @throws XAException An error has occurred. Possible exception values are XAER_RMERR, XAER_RMFAIL, or XAER_INVAL.
526     */
527    public boolean setTransactionTimeout(int seconds) throws XAException {
528        if (conn_.agent_.loggingEnabled()) {
529            conn_.agent_.logWriter_.traceExit(this, "setTransactionTimeout", false);
530        }
531        exceptionsOnXA = null;
532        return false; // we don't support transaction timeout in our layer.
533        /* int rc = xaSetTransTimeOut(seconds);
534           if (rc != XAResource.XA_OK)
535             throwXAException(rc); */
536    }
537 
538    /**
539     * Start work on behalf of a transaction branch specified in xid
540     *
541     * @param xid   A global transaction identifier to be associated with the resource
542     * @param flags One of TMNOFLAGS, TMJOIN, or TMRESUME
543     *
544     * @throws XAException An error has occurred. Possible exceptions   * are XA_RB*, XAER_RMERR, XAER_RMFAIL,
545     *                     XAER_DUPID, XAER_OUTSIDE, XAER_NOTA, XAER_INVAL, or XAER_PROTO.
546     */
547    public synchronized void start(Xid xid, int flags) throws XAException {
548 
549        NetAgent netAgent = conn_.netAgent_;
550        int rc = XAResource.XA_OK;
551        exceptionsOnXA = null;
552        if (conn_.agent_.loggingEnabled()) {
553            conn_.agent_.logWriter_.traceEntry(this, "start", xid, flags);
554        }
555        if (conn_.isPhysicalConnClosed()) {
556            connectionClosedFailure();
557        }
558        
559        // DERBY-1025 - Flow an auto-commit if in auto-commit mode before 
560        // entering a global transaction
561        try {
562                if(conn_.autoCommit_)
563                        conn_.flowAutoCommit();
564        } catch (SqlException sqle) {
565                rc = XAException.XAER_RMERR;
566            exceptionsOnXA = org.apache.derby.client.am.Utils.accumulateSQLException
567                    (sqle, exceptionsOnXA);
568        } 
569 
570        // update the XACallInfo
571        NetXACallInfo callInfo = callInfoArray_[conn_.currXACallInfoOffset_];
572        callInfo.xaFlags_ = flags;
573        callInfo.xaInProgress_ = true;
574        callInfo.xid_ = xid;
575        callInfo.xaResource_ = this;
576        callInfo.xaRetVal_ = XAResource.XA_OK; // initialize XARETVAL
577        try {
578            netAgent.beginWriteChainOutsideUOW();
579            netAgent.netConnectionRequest_.writeXaStartUnitOfWork(conn_);
580            netAgent.flowOutsideUOW();
581            netAgent.netConnectionReply_.readXaStartUnitOfWork(conn_);
582            if (callInfo.xaRetVal_ != XAResource.XA_OK) { // xaRetVal has possible error, format it
583                callInfo.xaFunction_ = XAFUNC_START;
584                rc = xaRetValErrorAccumSQL(callInfo, rc);
585                callInfo.xaRetVal_ = XAResource.XA_OK; // re-initialize XARETVAL
586            }
587            // Setting this is currently required to avoid client from sending
588            // commit for autocommit.
589            if (rc == XAResource.XA_OK) {
590                conn_.setXAState(Connection.XA_T1_ASSOCIATED);
591            }
592 
593        } catch (SqlException sqle) {
594            rc = XAException.XAER_RMERR;
595            exceptionsOnXA = org.apache.derby.client.am.Utils.accumulateSQLException
596                    (sqle, exceptionsOnXA);
597        } finally {
598            conn_.pendingEndXACallinfoOffset_ = -1; // indicate no pending callinfo
599        }
600        if (rc != XAResource.XA_OK) {
601            throwXAException(rc, false);
602        }
603    }
604 
605 
606    protected void throwXAException(int rc) throws XAException {
607        throwXAException(rc, rc != XAException.XAER_NOTA);
608    }
609 
610    private String getXAExceptionText(int rc) {
611        String xaExceptionText;
612        switch (rc) {
613        case javax.transaction.xa.XAException.XA_RBROLLBACK:
614            xaExceptionText = "XA_RBROLLBACK";
615            break;
616        case javax.transaction.xa.XAException.XA_RBCOMMFAIL:
617            xaExceptionText = "XA_RBCOMMFAIL";
618            break;
619        case javax.transaction.xa.XAException.XA_RBDEADLOCK:
620            xaExceptionText = "XA_RBDEADLOCK";
621            break;
622        case javax.transaction.xa.XAException.XA_RBINTEGRITY:
623            xaExceptionText = "XA_RBINTEGRITY";
624            break;
625        case javax.transaction.xa.XAException.XA_RBOTHER:
626            xaExceptionText = "XA_RBOTHER";
627            break;
628        case javax.transaction.xa.XAException.XA_RBPROTO:
629            xaExceptionText = "XA_RBPROTO";
630            break;
631        case javax.transaction.xa.XAException.XA_RBTIMEOUT:
632            xaExceptionText = "XA_RBTIMEOUT";
633            break;
634        case javax.transaction.xa.XAException.XA_RBTRANSIENT:
635            xaExceptionText = "XA_RBTRANSIENT";
636            break;
637        case javax.transaction.xa.XAException.XA_NOMIGRATE:
638            xaExceptionText = "XA_NOMIGRATE";
639            break;
640        case javax.transaction.xa.XAException.XA_HEURHAZ:
641            xaExceptionText = "XA_HEURHAZ";
642            break;
643        case javax.transaction.xa.XAException.XA_HEURCOM:
644            xaExceptionText = "XA_HEURCOM";
645            break;
646        case javax.transaction.xa.XAException.XA_HEURRB:
647            xaExceptionText = "XA_HEURRB";
648            break;
649        case javax.transaction.xa.XAException.XA_HEURMIX:
650            xaExceptionText = "XA_HEURMIX";
651            break;
652        case javax.transaction.xa.XAException.XA_RETRY:
653            xaExceptionText = "XA_RETRY";
654            break;
655        case javax.transaction.xa.XAException.XA_RDONLY:
656            xaExceptionText = "XA_RDONLY";
657            break;
658        case javax.transaction.xa.XAException.XAER_ASYNC:
659            xaExceptionText = "XAER_ASYNC";
660            break;
661        case javax.transaction.xa.XAException.XAER_RMERR:
662            xaExceptionText = "XAER_RMERR";
663            break;
664        case javax.transaction.xa.XAException.XAER_NOTA:
665            xaExceptionText = "XAER_NOTA";
666            break;
667        case javax.transaction.xa.XAException.XAER_INVAL:
668            xaExceptionText = "XAER_INVAL";
669            break;
670        case javax.transaction.xa.XAException.XAER_PROTO:
671            xaExceptionText = "XAER_PROTO";
672            break;
673        case javax.transaction.xa.XAException.XAER_RMFAIL:
674            xaExceptionText = "XAER_RMFAIL";
675            break;
676        case javax.transaction.xa.XAException.XAER_DUPID:
677            xaExceptionText = "XAER_DUPID";
678            break;
679        case javax.transaction.xa.XAException.XAER_OUTSIDE:
680            xaExceptionText = "XAER_OUTSIDE";
681            break;
682        case XAResource.XA_OK:
683            xaExceptionText = "XA_OK";
684            break;
685        default:
686            xaExceptionText = "Unknown Error";
687            break;
688        }
689        return xaExceptionText;
690    }
691 
692    protected void throwXAException(int rc, boolean resetFlag) throws XAException { // ~~~
693        String xaExceptionText;
694        if (resetFlag) {
695            // reset the state of the failed connection
696            NetXACallInfo callInfo = callInfoArray_[conn_.currXACallInfoOffset_];
697            callInfo.xaInProgress_ = false;
698            callInfo.xaWasSuspended = false;
699        }
700 
701        xaExceptionText = getXAExceptionText(rc);
702        // save the SqlException chain to add it to the XAException
703        org.apache.derby.client.am.SqlException sqlExceptions = exceptionsOnXA;
704 
705        while (exceptionsOnXA != null) { // one or more SqlExceptions received, format them
706            xaExceptionText = xaExceptionText + " : " + exceptionsOnXA.getMessage();
707            exceptionsOnXA = (org.apache.derby.client.am.SqlException)
708                    exceptionsOnXA.getNextException();
709        }
710        org.apache.derby.client.am.XaException xaException =
711                new org.apache.derby.client.am.XaException(conn_.agent_.logWriter_,
712                        sqlExceptions,
713                        xaExceptionText);
714        xaException.errorCode = rc;
715        setXaStateForXAException(rc); 
716        throw xaException;
717    }
718 
719 
720    /**
721     * Reset the transaction branch association state  to XA_T0_NOT_ASSOCIATED
722     * for XAER_RM* and XA_RB* Exceptions. All other exeptions leave the state 
723     * unchanged
724     * 
725     * @param rc  // return code from XAException
726     * @throws XAException
727     */
728    private void setXaStateForXAException(int rc) {
729            switch (rc)
730                {
731                // Reset to T0, not  associated for XA_RB*, RM*
732           // XAER_RMFAIL and XAER_RMERR will be fatal to the connection
733           // but that is not dealt with here
734           case javax.transaction.xa.XAException.XAER_RMFAIL:
735           case javax.transaction.xa.XAException.XAER_RMERR:
736           case javax.transaction.xa.XAException.XA_RBROLLBACK:
737           case javax.transaction.xa.XAException.XA_RBCOMMFAIL:
738           case javax.transaction.xa.XAException.XA_RBDEADLOCK:
739           case javax.transaction.xa.XAException.XA_RBINTEGRITY:
740           case javax.transaction.xa.XAException.XA_RBOTHER:
741           case javax.transaction.xa.XAException.XA_RBPROTO:
742           case javax.transaction.xa.XAException.XA_RBTIMEOUT:
743           case javax.transaction.xa.XAException.XA_RBTRANSIENT:
744                   conn_.setXAState(Connection.XA_T0_NOT_ASSOCIATED);
745           break;
746            // No change for other XAExceptions
747            // javax.transaction.xa.XAException.XA_NOMIGRATE
748           //javax.transaction.xa.XAException.XA_HEURHAZ
749           // javax.transaction.xa.XAException.XA_HEURCOM
750           // javax.transaction.xa.XAException.XA_HEURRB
751           // javax.transaction.xa.XAException.XA_HEURMIX
752           // javax.transaction.xa.XAException.XA_RETRY
753           // javax.transaction.xa.XAException.XA_RDONLY
754           // javax.transaction.xa.XAException.XAER_ASYNC
755           // javax.transaction.xa.XAException.XAER_NOTA
756           // javax.transaction.xa.XAException.XAER_INVAL                
757           // javax.transaction.xa.XAException.XAER_PROTO
758           // javax.transaction.xa.XAException.XAER_DUPID
759           // javax.transaction.xa.XAException.XAER_OUTSIDE                    
760            default:
761                            return;
762                }        
763    }
764 
765    public boolean isSameRM(XAResource xares) throws XAException {
766        boolean isSame = false; // preset that the RMs are NOT the same
767        exceptionsOnXA = null;
768 
769        if (conn_.agent_.loggingEnabled()) {
770            conn_.agent_.logWriter_.traceEntry(this, "isSameRM", xares);
771        }
772        if (conn_.isPhysicalConnClosed()) {
773            connectionClosedFailure();
774        }
775 
776        if (xares instanceof org.apache.derby.client.net.NetXAResource) { // both are NetXAResource so check to see if this is the same RM
777            // remember, isSame is initialized to false
778            NetXAResource derbyxares = (NetXAResource) xares;
779            while (true) {
780                if (!conn_.databaseName_.equalsIgnoreCase(derbyxares.conn_.databaseName_)) {
781                    break; // database names are not equal, not same RM
782                }
783                if (!conn_.netAgent_.server_.equalsIgnoreCase
784                        (derbyxares.conn_.netAgent_.server_)) { // server name strings not equal, compare IP addresses
785                    try {
786                        // 1st convert "localhost" to actual server name
787                        String server1 = this.processLocalHost(conn_.netAgent_.server_);
788                        String server2 =
789                                this.processLocalHost(derbyxares.conn_.netAgent_.server_);
790                        // now convert the server name to ip address
791                        InetAddress serverIP1 = InetAddress.getByName(server1);
792                        InetAddress serverIP2 = InetAddress.getByName(server2);
793                        if (!serverIP1.equals(serverIP2)) {
794                            break; // server IPs are not equal, not same RM
795                        }
796                    } catch (UnknownHostException ue) {
797                        break;
798                    }
799                }
800                if (conn_.netAgent_.port_ != derbyxares.conn_.netAgent_.port_) {
801                    break; // ports are not equal, not same RM
802                }
803                isSame = true; // everything the same, set RMs are the same
804                break;
805            }
806        }
807 
808        if (conn_.agent_.loggingEnabled()) {
809            conn_.agent_.logWriter_.traceExit
810                    (this, "isSameRM", isSame);
811        }
812        return isSame;
813    }
814    
815    public static boolean xidsEqual(Xid xid1, Xid xid2) { // determine if the 2 xids contain the same values even if not same object
816        // comapre the format ids
817        if (xid1.getFormatId() != xid2.getFormatId()) {
818            return false; // format ids are not the same
819        }
820 
821        // compare the global transaction ids
822        int xid1Length = xid1.getGlobalTransactionId().length;
823        if (xid1Length != xid2.getGlobalTransactionId().length) {
824            return false; // length of the global trans ids are not the same
825        }
826        byte[] xid1Bytes = xid1.getGlobalTransactionId();
827        byte[] xid2Bytes = xid2.getGlobalTransactionId();
828        int i;
829        for (i = 0; i < xid1Length; ++i) { // check all bytes are the same
830            if (xid1Bytes[i] != xid2Bytes[i]) {
831                return false; // bytes in the global trans ids are not the same
832            }
833        }
834 
835        // compare the branch qualifiers
836        xid1Length = xid1.getBranchQualifier().length;
837        if (xid1Length != xid2.getBranchQualifier().length) {
838            return false; // length of the global trans ids are not the same
839        }
840        xid1Bytes = xid1.getBranchQualifier();
841        xid2Bytes = xid2.getBranchQualifier();
842        for (i = 0; i < xid1Length; ++i) { // check all bytes are the same
843            if (xid1Bytes[i] != xid2Bytes[i]) {
844                return false; // bytes in the global trans ids are not the same
845            }
846        }
847 
848        return true; // all of the fields are the same, xid1 == xid2
849    }
850 
851 
852    public List getSpecialRegisters() {
853        return specialRegisters_;
854    }
855 
856    public void addSpecialRegisters(String s) {
857        if (s.substring(0, 1).equals("@")) {
858            // SET statement is coming from Client
859            if (specialRegisters_.remove(s.substring(1))) {
860                specialRegisters_.remove(s);
861                specialRegisters_.add(s.substring(1));
862            } else {
863                specialRegisters_.remove(s);
864                specialRegisters_.add(s);
865            }
866        } else { // SET statement is coming from Server
867            specialRegisters_.remove(s);
868            specialRegisters_.add(s);
869        }
870    }
871 
872    private void connectionClosedFailure() throws XAException { // throw an XAException XAER_RMFAIL, with a chained SqlException - closed
873        exceptionsOnXA = org.apache.derby.client.am.Utils.accumulateSQLException
874                (new SqlException(null, 
875                        new ClientMessageId(SQLState.NO_CURRENT_CONNECTION)),
876                        exceptionsOnXA);
877        throwXAException(javax.transaction.xa.XAException.XAER_RMFAIL);
878    }
879 
880    private String getXAFuncStr(int xaFunc) {
881        switch (xaFunc) {
882        case XAFUNC_COMMIT:
883            return XAFUNCSTR_COMMIT;
884        case XAFUNC_END:
885            return XAFUNCSTR_END;
886        case XAFUNC_FORGET:
887            return XAFUNCSTR_FORGET;
888        case XAFUNC_PREPARE:
889            return XAFUNCSTR_PREPARE;
890        case XAFUNC_RECOVER:
891            return XAFUNCSTR_RECOVER;
892        case XAFUNC_ROLLBACK:
893            return XAFUNCSTR_ROLLBACK;
894        case XAFUNC_START:
895            return XAFUNCSTR_START;
896        }
897        return XAFUNCSTR_NONE;
898    }
899 
900    protected int xaRetValErrorAccumSQL(NetXACallInfo callInfo, int currentRC) {
901 
902        // xaRetVal_ is set by the server to be one of the
903        // standard constants from XAException.
904        int rc = callInfo.xaRetVal_;
905 
906        if (rc != XAResource.XA_OK) { // error was detected
907            // create an SqlException to report this error within
908            SqlException accumSql = new SqlException(conn_.netAgent_.logWriter_,
909                new ClientMessageId(SQLState.NET_XARETVAL_ERROR),
910                getXAFuncStr(callInfo.xaFunction_),
911                getXAExceptionText(rc),
912                org.apache.derby.client.am.SqlCode.queuedXAError);
913            exceptionsOnXA = org.apache.derby.client.am.Utils.accumulateSQLException
914                    (accumSql, exceptionsOnXA);
915 
916            if (currentRC != XAResource.XA_OK) { // the rc passed into this function had an error also, prioritize error
917                if (currentRC < 0) { // rc passed in was a major error use it instead of current error
918                    return currentRC;
919                }
920            }
921        }
922        return rc;
923    }
924 
925    private String processLocalHost(String serverName) {
926        if (serverName.equalsIgnoreCase("localhost")) { // this is a localhost, find hostname
927            try {
928                InetAddress localhostNameIA = InetAddress.getLocalHost();
929                String localhostName = localhostNameIA.getHostName();
930                return localhostName;
931            } catch (SecurityException se) {
932                return serverName;
933            } catch (UnknownHostException ue) {
934                return serverName;
935            }
936        }
937        // not "localhost", return original server name
938        return serverName;
939    }
940 
941    protected void removeXaresFromSameRMchain() {
942        // check all NetXAResources on the same RM for the NetXAResource to remove
943        try {
944            this.ignoreMe_ = true; // use the ignoreMe_ flag to indicate the
945            // XAResource to remove
946            NetXAResource prevXAResource = null;
947            NetXAResource currXAResource;
948            synchronized (xaResourceSameRMGroup_) { // make sure no one changes this vector list
949                currXAResource = (NetXAResource) xaResourceSameRMGroup_.elementAt(sameRMGroupIndex_);
950                while (currXAResource != null) { // is this the XAResource to remove?
951                    if (currXAResource.ignoreMe_) { // this NetXAResource is the one to remove
952                        if (prevXAResource != null) { // this XAResource is not first in chain, just move next to prev
953                            prevXAResource.nextSameRM_ = currXAResource.nextSameRM_;
954                        } else { // this XAResource is  first in chain, just move next to root
955                            xaResourceSameRMGroup_.set(sameRMGroupIndex_,
956                                    currXAResource.nextSameRM_);
957                        }
958                        return;
959                    }
960                    // this is not the NetXAResource to remove, try the next one
961                    prevXAResource = currXAResource;
962                    currXAResource = currXAResource.nextSameRM_;
963                }
964            }
965        } finally {
966            this.ignoreMe_ = false;
967        }
968    }
969 
970 
971    public void initForReuse() {
972        // add this new XAResource to the list of other XAResources for the Same RM
973        // first find out if there are any other XAResources for the same RM
974        // then check to make sure it is not already in the chain
975        synchronized (xaResourceSameRMGroup_) { // make sure no one changes this vector list
976            int groupCount = xaResourceSameRMGroup_.size();
977            int index = 0;
978            int firstFreeElement = -1;
979            NetXAResource xaResourceGroup = null;
980 
981            for (; index < groupCount; ++index) { // check if this group is the same RM
982                xaResourceGroup = (NetXAResource) xaResourceSameRMGroup_.elementAt(index);
983                if (xaResourceGroup == null) { // this is a free element, save its index if first found
984                    if (firstFreeElement == -1) { // first free element, save index
985                        firstFreeElement = index;
986                    }
987                    continue; // go to next element
988                }
989                try {
990                    if (xaResourceGroup.isSameRM(this)) { // it is the same RM add this XAResource to the chain if not there
991                        NetXAResource nextXares = (NetXAResource)
992                                xaResourceSameRMGroup_.elementAt(sameRMGroupIndex_);
993                        while (nextXares != null) { // is this NetXAResource the one we are trying to add?
994                            if (nextXares.equals(this)) { // the XAResource to be added already is in chain, don't add
995                                break;
996                            }
997                            // Xid was not on that NetXAResource, try the next one
998                            nextXares = nextXares.nextSameRM_;
999                        }
1000 
1001                        if (nextXares == null) { // XAResource to be added is not in the chain already, add it
1002                            // add it at the head of the chain
1003                            sameRMGroupIndex_ = index;
1004                            this.nextSameRM_ = xaResourceGroup.nextSameRM_;
1005                            xaResourceGroup.nextSameRM_ = this;
1006                        }
1007                        return; // done
1008                    }
1009                } catch (XAException xae) {
1010                }
1011            }
1012 
1013            // no other same RM was found, add this as first of new group
1014            if (firstFreeElement == -1) { // no free element found, add new element to end
1015                xaResourceSameRMGroup_.add(this);
1016                sameRMGroupIndex_ = groupCount;
1017            } else { // use first free element found
1018                xaResourceSameRMGroup_.setElementAt(this, firstFreeElement);
1019                sameRMGroupIndex_ = firstFreeElement;
1020            }
1021        }
1022    }
1023}

[all classes][org.apache.derby.client.net]
EMMA 2.0.5312 (C) Vladimir Roubtsov