001: /*
002:
003: Derby - Class org.apache.derby.jdbc.EmbedXAResource
004:
005: Licensed to the Apache Software Foundation (ASF) under one or more
006: contributor license agreements. See the NOTICE file distributed with
007: this work for additional information regarding copyright ownership.
008: The ASF licenses this file to You under the Apache License, Version 2.0
009: (the "License"); you may not use this file except in compliance with
010: the License. You may obtain a copy of the License at
011:
012: http://www.apache.org/licenses/LICENSE-2.0
013:
014: Unless required by applicable law or agreed to in writing, software
015: distributed under the License is distributed on an "AS IS" BASIS,
016: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
017: See the License for the specific language governing permissions and
018: limitations under the License.
019:
020: */
021:
022: package org.apache.derby.jdbc;
023:
024: import java.sql.SQLException;
025: import javax.transaction.xa.XAResource;
026: import javax.transaction.xa.Xid;
027: import javax.transaction.xa.XAException;
028:
029: import org.apache.derby.iapi.error.StandardException;
030: import org.apache.derby.iapi.jdbc.BrokeredConnection;
031: import org.apache.derby.iapi.jdbc.ResourceAdapter;
032: import org.apache.derby.iapi.reference.SQLState;
033: import org.apache.derby.iapi.reference.JDBC30Translation;
034: import org.apache.derby.iapi.services.context.ContextManager;
035: import org.apache.derby.iapi.services.context.ContextService;
036: import org.apache.derby.iapi.services.info.JVMInfo;
037: import org.apache.derby.iapi.store.access.XATransactionController;
038: import org.apache.derby.iapi.store.access.xa.XAResourceManager;
039: import org.apache.derby.iapi.store.access.xa.XAXactId;
040: import org.apache.derby.impl.jdbc.EmbedConnection;
041: import org.apache.derby.impl.jdbc.TransactionResourceImpl;
042:
043: /**
044: * Implements XAResource
045: */
046: class EmbedXAResource implements XAResource {
047:
048: private EmbedPooledConnection con;
049: private ResourceAdapter ra;
050: private XAXactId currentXid;
051:
052: EmbedXAResource(EmbedPooledConnection con, ResourceAdapter ra) {
053: this .con = con;
054: this .ra = ra;
055: }
056:
057: /**
058: * Commit the global transaction specified by xid.
059: * @param xid A global transaction identifier
060: * @param onePhase If true, the resource manager should use a one-phase
061: * commit protocol to commit the work done on behalf of xid.
062:
063: * @exception XAException An error has occurred. Possible XAExceptions are
064: * XA_HEURHAZ, XA_HEURCOM, XA_HEURRB, XA_HEURMIX, XAER_RMERR,
065: * XAER_RMFAIL, XAER_NOTA, XAER_INVAL, or XAER_PROTO.
066: * <P>If the resource manager did not commit the transaction and
067: * the paramether onePhase is set to true, the resource manager
068: * may throw one of the XA_RB* exceptions. Upon return, the
069: * resource manager has rolled back the branch's work and has
070: * released all held resources.
071: */
072: public final synchronized void commit(Xid xid, boolean onePhase)
073: throws XAException {
074: checkXAActive();
075: // ensure immtable and correct equals method.
076: XAXactId xid_im = new XAXactId(xid);
077: XATransactionState tranState = getTransactionState(xid_im);
078:
079: if (tranState == null) {
080: XAResourceManager rm = ra.getXAResourceManager();
081: ContextManager inDoubtCM = rm.find(xid);
082: // RM also does not know about this xid.
083: if (inDoubtCM == null)
084: throw new XAException(XAException.XAER_NOTA);
085: ContextService csf = ContextService.getFactory();
086: csf.setCurrentContextManager(inDoubtCM);
087: try {
088: rm.commit(inDoubtCM, xid_im, onePhase);
089:
090: // close the connection/transaction since it can never
091: // be used again.
092: inDoubtCM.cleanupOnError(StandardException
093: .closeException());
094: return;
095: } catch (StandardException se) {
096: // The rm threw an exception, clean it up in the approprate
097: // context. There is no transactionResource to handle the
098: // exception for us.
099: inDoubtCM.cleanupOnError(se);
100: throw wrapInXAException(se);
101: } finally {
102: csf.resetCurrentContextManager(inDoubtCM);
103: }
104:
105: }
106:
107: synchronized (tranState) {
108: checkUserCredentials(tranState.creatingResource);
109:
110: // Check the transaction is no associated with
111: // any XAResource.
112: switch (tranState.associationState) {
113: case XATransactionState.T0_NOT_ASSOCIATED:
114: break;
115:
116: case XATransactionState.TRO_FAIL:
117: throw new XAException(tranState.rollbackOnlyCode);
118:
119: default:
120: throw new XAException(XAException.XAER_PROTO);
121: }
122:
123: if (tranState.suspendedList != null
124: && tranState.suspendedList.size() != 0)
125: throw new XAException(XAException.XAER_PROTO);
126:
127: if (tranState.isPrepared == onePhase)
128: throw new XAException(XAException.XAER_PROTO);
129:
130: EmbedConnection conn = tranState.conn;
131:
132: try {
133: conn.xa_commit(onePhase);
134: } catch (SQLException sqle) {
135: throw wrapInXAException(sqle);
136: } finally {
137: returnConnectionToResource(tranState, xid_im);
138: }
139: }
140: }
141:
142: /**
143: * Ends the work performed on behalf of a transaction branch. The resource
144: * manager disassociates the XA resource from the transaction branch
145: * specified and let the transaction be completed.
146: *
147: * <p> If TMSUSPEND is specified in flags, the transaction branch is
148: * temporarily suspended in incomplete state. The transaction context
149: * is in suspened state and must be resumed via start with TMRESUME
150: * specified.
151: *
152: * <p> If TMFAIL is specified, the portion of work has failed. The
153: * resource manager may mark the transaction as rollback-only
154: *
155: * <p> If TMSUCCESS is specified, the portion of work has completed
156: * successfully.
157: *
158: * @param xid A global transaction identifier that is the same as what was
159: * used previously in the start method.
160: * @param flags One of TMSUCCESS, TMFAIL, or TMSUSPEND
161: *
162: * @exception XAException An error has occurred.
163: * Possible XAException values are XAER_RMERR, XAER_RMFAILED, XAER_NOTA,
164: * XAER_INVAL, XAER_PROTO, or XA_RB*.
165: */
166: public final synchronized void end(Xid xid, int flags)
167: throws XAException {
168: checkXAActive();
169:
170: try {
171: // It is possible that the isolation level state in connection
172: // handle has gotten out of sync with the real isolation level.
173: // This can happen if SLQ instead of JDBC api has been used to
174: // set the isolation level. The code below will check if isolation
175: // was set using JDBC or SQL and if yes, then it will update the
176: // isolation state in BrokeredConnection with EmbedConnection's
177: // isolation level.
178: if (con.currentConnectionHandle != null)
179: con.currentConnectionHandle.getIsolationUptoDate();
180: } catch (SQLException sqle) {
181: throw wrapInXAException(sqle);
182: }
183:
184: // ensure immtable and correct equals method.
185: XAXactId xid_im = new XAXactId(xid);
186:
187: boolean endingCurrentXid = false;
188:
189: // must match the Xid from start()
190: if (currentXid != null) {
191: if (!currentXid.equals(xid_im))
192: throw new XAException(XAException.XAER_PROTO);
193: endingCurrentXid = true;
194: }
195:
196: XATransactionState tranState = getTransactionState(xid_im);
197: if (tranState == null)
198: throw new XAException(XAException.XAER_NOTA);
199:
200: boolean rollbackOnly = tranState.end(this , flags,
201: endingCurrentXid);
202:
203: // RESOLVE - what happens to the connection on a fail
204: // where we are not ending the current XID.
205: if (endingCurrentXid) {
206: currentXid = null;
207: con.realConnection = null;
208: }
209:
210: if (rollbackOnly)
211: throw new XAException(tranState.rollbackOnlyCode);
212: }
213:
214: /**
215: * Ask the resource manager to prepare for a transaction commit of the
216: * transaction specified in xid.
217: *
218: * @param xid A global transaction identifier
219: *
220: * @return A value indicating the resource manager's vote on the outcome
221: * of the transaction. The possible values are: XA_RDONLY or XA_OK. If the
222: * resource manager wants to roll back the transaction, it should do so by
223: * raising an appropriate XAException in the prepare method.
224: *
225: * @exception XAException An error has occurred. Possible exception values
226: * are: XA_RB*, XAER_RMERR, XAER_RMFAIL, XAER_NOTA, XAER_INVAL, or
227: * XAER_PROTO.
228: *
229: */
230: public final synchronized int prepare(Xid xid) throws XAException {
231: checkXAActive();
232:
233: // ensure immtable and correct equals method.
234: XAXactId xid_im = new XAXactId(xid);
235:
236: XATransactionState tranState = getTransactionState(xid_im);
237:
238: if (tranState == null) {
239: XAResourceManager rm = ra.getXAResourceManager();
240:
241: ContextManager inDoubtCM = rm.find(xid);
242:
243: // RM also does not know about this xid.
244: if (inDoubtCM == null)
245: throw new XAException(XAException.XAER_NOTA);
246:
247: // cannot prepare in doubt transactions
248: throw new XAException(XAException.XAER_PROTO);
249:
250: }
251:
252: synchronized (tranState) {
253:
254: checkUserCredentials(tranState.creatingResource);
255:
256: // Check the transaction is no associated with
257: // any XAResource.
258: switch (tranState.associationState) {
259: case XATransactionState.T0_NOT_ASSOCIATED:
260: break;
261:
262: case XATransactionState.TRO_FAIL:
263: throw new XAException(tranState.rollbackOnlyCode);
264:
265: default:
266: throw new XAException(XAException.XAER_PROTO);
267: }
268:
269: if (tranState.suspendedList != null
270: && tranState.suspendedList.size() != 0)
271: throw new XAException(XAException.XAER_PROTO);
272:
273: if (tranState.isPrepared)
274: throw new XAException(XAException.XAER_PROTO);
275:
276: EmbedConnection conn = tranState.conn;
277:
278: try {
279:
280: int ret = conn.xa_prepare();
281:
282: if (ret == XATransactionController.XA_OK) {
283: tranState.isPrepared = true;
284:
285: return XAResource.XA_OK;
286: } else {
287:
288: returnConnectionToResource(tranState, xid_im);
289: return XAResource.XA_RDONLY;
290: }
291: } catch (SQLException sqle) {
292: throw wrapInXAException(sqle);
293: }
294: }
295:
296: }
297:
298: /**
299: * Obtain the current transaction timeout value set for this XAResource
300: * instance. If XAResource.setTransactionTimeout was not use prior to
301: * invoking this method, the return value is the default timeout set for
302: * the resource manager; otherwise, the value used in the previous
303: * setTransactionTimeout call is returned.
304: *
305: * @return the transaction timeout value in seconds.
306: */
307: public int getTransactionTimeout() {
308: return 0;
309: }
310:
311: /**
312: * This method is called to determine if the resource manager instance
313: * represented by the target object is the same as the resouce manager
314: * instance represented by the parameter xares.
315: *
316: * @param xares An XAResource object whose resource manager instance is to
317: * be compared with the resource manager instance of the target object.
318: *
319: * @return true if it's the same RM instance; otherwise false.
320: * @exception XAException An error has occurred. Possible exception values
321: * are XAER_RMERR, XAER_RMFAIL.
322: */
323: public final synchronized boolean isSameRM(XAResource xares)
324: throws XAException {
325: checkXAActive();
326: if (xares instanceof EmbedXAResource) {
327: return ra == ((EmbedXAResource) xares).ra;
328: }
329: return false;
330: }
331:
332: /**
333: * Obtain a list of prepared transaction branches from a resource
334: * manager. The transaction manager calls this method during recovery to
335: * obtain the list of transaction branches that are currently in prepared
336: * or heuristically completed states.
337: *
338: * @param flag One of TMSTARTRSCAN, TMENDRSCAN, TMNOFLAGS. TMNOFLAGS must
339: * be used when no other flags are set in flags.
340: *
341: * @return The resource manager returns zero or more XIDs for the
342: * transaction branches that are currently in a prepared or heuristically
343: * completed state. If an error occurs during the operation, the resource
344: * manager should throw the appropriate XAException.
345: *
346: * @exception XAException An error has occurred. Possible values are
347: * XAER_RMERR, XAER_RMFAIL, XAER_INVAL, and XAER_PROTO.
348: *
349: */
350: public final synchronized Xid[] recover(int flag)
351: throws XAException {
352: checkXAActive();
353:
354: try {
355: return ra.getXAResourceManager().recover(flag);
356: } catch (StandardException se) {
357: throw wrapInXAException(se);
358: }
359: }
360:
361: /**
362: * Tell the resource manager to forget about a heuristically completed
363: * transaction branch.
364: *
365: * @param xid A global transaction identifier
366: * @exception XAException An error has occurred. Possible exception values
367: * are XAER_RMERR, XAER_RMFAIL, XAER_NOTA, XAER_INVAL, or XAER_PROTO.
368: */
369: public final synchronized void forget(Xid xid) throws XAException {
370:
371: checkXAActive();
372:
373: // ensure immtable and correct equals method.
374: XAXactId xid_im = new XAXactId(xid);
375:
376: XATransactionState tranState = getTransactionState(xid_im);
377: if (tranState == null) {
378: XAResourceManager rm = ra.getXAResourceManager();
379:
380: ContextManager inDoubtCM = rm.find(xid);
381:
382: // RM also does not know about this xid.
383: if (inDoubtCM == null)
384: throw new XAException(XAException.XAER_NOTA);
385:
386: ContextService csf = ContextService.getFactory();
387:
388: csf.setCurrentContextManager(inDoubtCM);
389: try {
390: rm.forget(inDoubtCM, xid_im);
391:
392: // close the connection/transaction since it can never be used again.
393: inDoubtCM.cleanupOnError(StandardException
394: .closeException());
395: return;
396: } catch (StandardException se) {
397: // The rm threw an exception, clean it up in the approprate
398: // context. There is no transactionResource to handle the
399: // exception for us.
400: inDoubtCM.cleanupOnError(se);
401: throw wrapInXAException(se);
402: } finally {
403: csf.resetCurrentContextManager(inDoubtCM);
404: }
405:
406: }
407:
408: throw new XAException(
409: tranState.isPrepared ? XAException.XAER_NOTA
410: : XAException.XAER_PROTO);
411: }
412:
413: /**
414: * Inform the resource manager to roll back work done on behalf of a
415: * transaction branch
416: *
417: * @param xid A global transaction identifier
418: * @exception XAException - An error has occurred
419: */
420: public final synchronized void rollback(Xid xid) throws XAException {
421: checkXAActive();
422:
423: // ensure immtable and correct equals method.
424: XAXactId xid_im = new XAXactId(xid);
425:
426: XATransactionState tranState = getTransactionState(xid_im);
427:
428: if (tranState == null) {
429: XAResourceManager rm = ra.getXAResourceManager();
430:
431: ContextManager inDoubtCM = rm.find(xid);
432:
433: // RM also does not know about this xid.
434: if (inDoubtCM == null)
435: throw new XAException(XAException.XAER_NOTA);
436:
437: ContextService csf = ContextService.getFactory();
438:
439: csf.setCurrentContextManager(inDoubtCM);
440: try {
441: rm.rollback(inDoubtCM, xid_im);
442:
443: // close the connection/transaction since it can never be used again.
444: inDoubtCM.cleanupOnError(StandardException
445: .closeException());
446: return;
447: } catch (StandardException se) {
448: // The rm threw an exception, clean it up in the approprate
449: // context. There is no transactionResource to handle the
450: // exception for us.
451: inDoubtCM.cleanupOnError(se);
452: throw wrapInXAException(se);
453: } finally {
454: csf.resetCurrentContextManager(inDoubtCM);
455: }
456:
457: }
458:
459: synchronized (tranState) {
460:
461: // Check the transaction is no associated with
462: // any XAResource.
463: switch (tranState.associationState) {
464: case XATransactionState.T0_NOT_ASSOCIATED:
465: case XATransactionState.TRO_FAIL:
466: break;
467:
468: default:
469: throw new XAException(XAException.XAER_PROTO);
470: }
471:
472: if (tranState.suspendedList != null
473: && tranState.suspendedList.size() != 0)
474: throw new XAException(XAException.XAER_PROTO);
475:
476: checkUserCredentials(tranState.creatingResource);
477:
478: try {
479:
480: tranState.conn.xa_rollback();
481: } catch (SQLException sqle) {
482: throw wrapInXAException(sqle);
483: } finally {
484: returnConnectionToResource(tranState, xid_im);
485: }
486: }
487: }
488:
489: /**
490: * Set the current transaction timeout value for this XAResource
491: * instance. Once set, this timeout value is effective until
492: * setTransactionTimeout is invoked again with a different value. To reset
493: * the timeout value to the default value used by the resource manager,
494: * set the value to zero. If the timeout operation is performed
495: * successfully, the method returns true; otherwise false. If a resource
496: * manager does not support transaction timeout value to be set
497: * explicitly, this method returns false.
498: *
499: * @param seconds the transaction timeout value in seconds.
500: * @return true if transaction timeout value is set successfully;
501: * otherwise false.
502: *
503: * @exception XAException - An error has occurred. Possible exception
504: * values are XAER_RMERR, XAER_RMFAIL, or XAER_INVAL.
505: */
506: public boolean setTransactionTimeout(int seconds) {
507: return false;
508: }
509:
510: /**
511: * Start work on behalf of a transaction branch specified in xid If TMJOIN
512: * is specified, the start is for joining a transaction previously seen by
513: * the resource manager. If TMRESUME is specified, the start is to resume
514: * a suspended transaction specified in the parameter xid. If neither
515: * TMJOIN nor TMRESUME is specified and the transaction specified by xid
516: * has previously been seen by the resource manager, the resource manager
517: * throws the XAException exception with XAER_DUPID error code.
518: *
519: * @param xid A global transaction identifier to be associated with the
520: * resource
521: * @param flags One of TMNOFLAGS, TMJOIN, or TMRESUME
522: *
523: * @exception XAException An error has occurred. Possible exceptions are
524: * XA_RB*, XAER_RMERR, XAER_RMFAIL, XAER_DUPID, XAER_OUTSIDE, XAER_NOTA,
525: * XAER_INVAL, or XAER_PROTO.
526: */
527: public final synchronized void start(Xid xid, int flags)
528: throws XAException {
529: checkXAActive();
530:
531: // JDBC 3.0 section 12.3 - One transaction associated with a XAConnection
532: if (currentXid != null)
533: throw new XAException(XAException.XAER_PROTO);
534:
535: // ensure immtable and correct equals method.
536: XAXactId xid_im = new XAXactId(xid);
537:
538: XATransactionState tranState = getTransactionState(xid_im);
539:
540: switch (flags) {
541: case XAResource.TMNOFLAGS:
542: if (tranState != null)
543: throw new XAException(XAException.XAER_DUPID);
544:
545: try {
546:
547: if (con.realConnection == null) {
548: con.openRealConnection();
549:
550: if (con.currentConnectionHandle != null) {
551:
552: // since this is a new connection, set its complete
553: // state according to the application's Connection
554: // handle view of the world.
555: con.currentConnectionHandle.setState(true);
556: con.realConnection
557: .setApplicationConnection(con.currentConnectionHandle);
558: }
559:
560: } else {
561:
562: // XAResource.start() auto commits in DB2 when in
563: // auto commit mode.
564: if (con.currentConnectionHandle != null) {
565: if (con.currentConnectionHandle.getAutoCommit())
566: con.currentConnectionHandle.rollback();
567: }
568: if (!con.realConnection.transactionIsIdle())
569: throw new XAException(XAException.XAER_OUTSIDE);
570:
571: if (con.currentConnectionHandle != null) {
572: // It is possible that the isolation level state
573: // in connection handle has gotten out of sync
574: // with the real isolation level. This can happen
575: // if SLQ instead of JDBC api has been used to set
576: // the isolation level. The code below will check
577: // if isolation was set using JDBC or SQL and if
578: // yes, then it will update the isolation state
579: // in BrokeredConnection with EmbedConnection's
580: // isolation level.
581: con.currentConnectionHandle
582: .getIsolationUptoDate();
583: // we have a current handle so we need to keep
584: // the connection state of the current connection.
585: con.currentConnectionHandle.setState(true);
586:
587: // At the local to global transition we need
588: // to discard and close any open held result
589: // sets, a rollback will do this.
590: con.realConnection.rollback();
591: } else {
592: con.resetRealConnection();
593: }
594:
595: }
596:
597: // Global connections are always in auto commit false mode.
598: con.realConnection.setAutoCommit(false);
599:
600: // and holdability false (cannot hold cursors across
601: // XA transactions.
602: con.realConnection
603: .setHoldability(JDBC30Translation.CLOSE_CURSORS_AT_COMMIT);
604:
605: con.realConnection.getLanguageConnection()
606: .getTransactionExecute()
607: .createXATransactionFromLocalTransaction(
608: xid_im.getFormatId(),
609: xid_im.getGlobalTransactionId(),
610: xid_im.getBranchQualifier());
611:
612: } catch (StandardException se) {
613: throw wrapInXAException(se);
614: } catch (SQLException sqle) {
615: throw wrapInXAException(sqle);
616: }
617:
618: if (!ra.addConnection(xid_im, new XATransactionState(
619: con.realConnection.getContextManager(),
620: con.realConnection, this , xid_im)))
621: throw new XAException(XAException.XAER_DUPID);
622:
623: break;
624:
625: case XAResource.TMRESUME:
626: case XAResource.TMJOIN:
627: if (tranState == null)
628: throw new XAException(XAException.XAER_NOTA);
629:
630: tranState.start(this , flags);
631:
632: if (tranState.conn != con.realConnection) {
633:
634: if (con.realConnection != null) {
635:
636: if (!con.realConnection.transactionIsIdle())
637: throw new XAException(XAException.XAER_OUTSIDE);
638:
639: // We need to get the isolation level up to date same
640: // way as it is done at start of a transaction. Before
641: // joining the transaction, it is possible that the
642: // isolation level was updated using SQL. We need to
643: // get this state and store in the connection handle so
644: // that we can restore the isolation when we are in the
645: // local mode.
646: try {
647: if (con.currentConnectionHandle != null) {
648: con.currentConnectionHandle
649: .getIsolationUptoDate();
650: }
651: } catch (SQLException sqle) {
652: throw wrapInXAException(sqle);
653: }
654:
655: closeUnusedConnection(con.realConnection);
656: }
657: con.realConnection = tranState.conn;
658:
659: if (con.currentConnectionHandle != null) {
660:
661: try {
662: // only reset the non-transaction specific
663: // Connection state.
664: con.currentConnectionHandle.setState(false);
665: con.realConnection
666: .setApplicationConnection(con.currentConnectionHandle);
667: } catch (SQLException sqle) {
668: throw wrapInXAException(sqle);
669: }
670: }
671:
672: }
673:
674: break;
675:
676: default:
677: throw new XAException(XAException.XAER_INVAL);
678: }
679:
680: currentXid = xid_im;
681: }
682:
683: /**
684: * Resturns currently active xid
685: * @return Xid
686: */
687: Xid getCurrentXid() {
688: return currentXid;
689: }
690:
691: /**
692: * Returns the XATransactionState of the the transaction
693: * @param xid_im
694: * @return XATransactionState
695: */
696: private XATransactionState getTransactionState(XAXactId xid_im) {
697: return (XATransactionState) ra.findConnection(xid_im);
698: }
699:
700: /**
701: * Compares the user name and password of the XAResource with
702: * user name and password of this and throws XAException if there is
703: * a mismatch
704: * @param original EmbedXAResource
705: */
706: private void checkUserCredentials(EmbedXAResource original)
707: throws XAException {
708: if (original == this )
709: return;
710: if (original.con.getPassword().equals(con.getPassword())
711: && (original.con.getUsername()
712: .equals(con.getUsername())))
713: return;
714: throw new XAException(XAException.XA_RBINTEGRITY);
715: }
716:
717: /**
718: * Checks if currently associated connection is active
719: * throws exception if not
720: */
721: private void checkXAActive() throws XAException {
722: try {
723: con.checkActive();
724: } catch (SQLException sqle) {
725: throw wrapInXAException(sqle);
726: }
727: }
728:
729: /**
730: * Map a SQL exception to appropriate XAException.
731: * Return the mapped XAException.
732: */
733: private static XAException wrapInXAException(SQLException se) {
734: // Map interesting exceptions to XAException
735: String sqlstate = se.getSQLState();
736: String message = se.getMessage();
737:
738: XAException xae;
739:
740: if (sqlstate == null) {
741: // no idea what was wrong, throw non-descript error.
742: if (message != null)
743: xae = new XAException(message);
744: else
745: xae = new XAException(XAException.XAER_RMERR);
746: } else if (sqlstate
747: .equals(StandardException
748: .getSQLStateFromIdentifier(SQLState.STORE_XA_XAER_DUPID)))
749: xae = new XAException(XAException.XAER_DUPID);
750: else if (sqlstate
751: .equals(StandardException
752: .getSQLStateFromIdentifier(SQLState.STORE_XA_PROTOCOL_VIOLATION)))
753: xae = new XAException(XAException.XA_RBPROTO);
754: else if (sqlstate.equals(SQLState.DEADLOCK))
755: xae = new XAException(XAException.XA_RBDEADLOCK);
756: else if (sqlstate.equals(SQLState.LOCK_TIMEOUT))
757: xae = new XAException(XAException.XA_RBTIMEOUT);
758: else if (message != null)
759: xae = new XAException(message);
760: else
761: xae = new XAException(XAException.XAER_RMERR);
762:
763: if (JVMInfo.JDK_ID >= JVMInfo.J2SE_14)
764: xae.initCause(se);
765: return xae;
766: }
767:
768: /**
769: * Map a Standard exception to appropriate XAException.
770: * Return the mapped XAException.
771: */
772: private static XAException wrapInXAException(StandardException se) {
773: return wrapInXAException(TransactionResourceImpl
774: .wrapInSQLException((SQLException) null, se));
775: }
776:
777: /**
778: * Return an underlying connection object back to its XAResource
779: * if possible. If not close the connection.
780: * @param tranState
781: * @param xid_im
782: */
783: private void returnConnectionToResource(
784: XATransactionState tranState, XAXactId xid_im) {
785:
786: removeXATransaction(xid_im);
787: synchronized (tranState) {
788: // global transaction is over.
789: tranState.associationState = XATransactionState.TC_COMPLETED;
790: tranState.notifyAll();
791:
792: EmbedConnection conn = tranState.conn;
793:
794: // already set in its own resource
795: // or can it be returned to its original resource?
796: if ((tranState.creatingResource.con.realConnection == conn)
797: || (tranState.creatingResource.con.realConnection == null)) {
798:
799: tranState.creatingResource.con.realConnection = conn;
800:
801: BrokeredConnection handle = tranState.creatingResource.con.currentConnectionHandle;
802:
803: conn.setApplicationConnection(handle);
804:
805: if (handle != null) {
806: try {
807: handle.setState(true);
808: } catch (SQLException sqle) {
809:
810: // couldn't reset the connection
811: closeUnusedConnection(tranState.conn);
812: tranState.creatingResource.con.realConnection = null;
813: }
814: }
815: return;
816: }
817: }
818:
819: // nowhere to place it, close it.
820: closeUnusedConnection(tranState.conn);
821: }
822:
823: /**
824: * Close an underlying connection object when there is
825: * no active XAResource to hand it to.
826: * @param conn
827: */
828: private static void closeUnusedConnection(EmbedConnection conn) {
829: if (conn != null) {
830: try {
831: conn.close();
832: } catch (SQLException sqle) {
833:
834: }
835: }
836: }
837:
838: /**
839: * Removes the xid from currently active transactions
840: * @param xid_im
841: */
842: private void removeXATransaction(XAXactId xid_im) {
843: XATransactionState tranState = (XATransactionState) ra
844: .removeConnection(xid_im);
845: if (tranState != null)
846: tranState.popMe();
847: }
848:
849: }
|