001: /*
002: * XAPool: Open Source XA JDBC Pool
003: * Copyright (C) 2003 Objectweb.org
004: * Initial Developer: Lutris Technologies Inc.
005: * Contact: xapool-public@lists.debian-sf.objectweb.org
006: *
007: * This library is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU Lesser General Public
009: * License as published by the Free Software Foundation; either
010: * version 2.1 of the License, or any later version.
011: *
012: * This library is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this library; if not, write to the Free Software
019: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
020: * USA
021: */
022: package org.enhydra.jdbc.standard;
023:
024: import java.sql.Connection;
025: import java.sql.SQLException;
026: import javax.sql.XAConnection;
027: import javax.transaction.xa.XAException;
028: import javax.transaction.xa.XAResource;
029: import javax.transaction.xa.Xid;
030: import javax.naming.NamingException;
031: import javax.naming.Reference;
032: import javax.naming.Referenceable;
033: import javax.naming.StringRefAddr;
034: import javax.transaction.Status;
035: import javax.transaction.TransactionManager;
036:
037: /**
038: * Provides a generic wrapper for JDBC 1 drivers. JDBC 1 drivers always
039: * associate a single transaction at every point in time with a physical
040: * connection. J2EE drivers, on the other hand, allow an XAResource (and
041: * therefore an XAConnection with which it has a one to one mapping) to
042: * switch between global transactions.
043: * <P>
044: * To accomodate this, the StandardXADataSource class maintains a list of
045: * Connection objects. When the Transaction Manager associates an XID
046: * with a StandardXAConnection, it looks for a physical connection which
047: * is associated with that transaction.
048: * <P>
049: * The "current" connection (super.con and curCon) is the connection
050: * currently being used by the application (i.e. getConnection has
051: * been called, but not Connection.close()). The current connection
052: * is removed and handed to the data source if it becomes associated
053: * with a global transaction.
054: */
055: public class StandardXAConnection extends StandardPooledConnection
056: implements XAConnection, XAResource, Referenceable, Runnable {
057:
058: protected StandardXAStatefulConnection curCon;
059: // the "current" stateful connection, null if none
060: private boolean commitOnPrepare;
061: // true if commit takes place during prepare call
062: boolean isClosed; // true if this connection has been closed
063: private int timeoutSecs; // timeout in seconds
064: private long timeoutPeriod = 60000; // interval in ms to check for timeouts
065: private long nextTimeout; // time when next timeout occurs
066: public Thread timerThread; // the thread that checks for timeouts
067: public TransactionManager transactionManager;
068: public StandardXAConnectionHandle connectionHandle;
069: protected StandardXADataSource xaDataSource;
070: public boolean this AutoCommit = true;
071:
072: /**
073: * Creates the first free connection.
074: */
075: public StandardXAConnection(StandardXADataSource dataSource,
076: String user, String password) throws SQLException {
077: super (dataSource, user, password);
078: // creates the first Connection object
079:
080: // Save the constructor parameters.
081: this .xaDataSource = dataSource;
082: curCon = new StandardXAStatefulConnection(dataSource, con);
083: // wrap connection as a stateful connection
084:
085: // NOTE - the current connection is not made known to the data source
086: // so it is not eligible for re-use. It only goes on the data source list
087: // if it ever becomes associated with a global transaction.
088:
089: /*
090: // get the timer thread
091: if (xaDataSource.getThreadFactory() != null) {
092: dataSource.log.debug("StandardXAConnection: Getting thread from factory");
093: timerThread = xaDataSource.getThreadFactory().getThread(this);
094: dataSource.log.debug("StandardXAConnection: Got thread from factory");
095: } else {
096: dataSource.log.debug("StandardXAConnection: Getting thread from new Thread()");
097: timerThread = new Thread (this); // create the backgroup thread to check for timeouts
098: }
099:
100: timerThread.start(); // start the timer thread
101: //timerThread.suspend(); // and suspend until some timeouts get set up
102: */
103: dataSource.log.debug("StandardXAConnection created");
104: }
105:
106: /**
107: * We are required to maintain a 1-1 mapping between an XAConnection
108: * and its corresponding XAResource. We achieve this by implementing
109: * both interfaces in the same class.
110: */
111: public XAResource getXAResource() {
112: return this ;
113: }
114:
115: /**
116: * Creates a new StandardXAConnectionHandle for use by an application.
117: * If there is already an StandardXAConnectionHandle in use then it is
118: * closed (i.e. the application has the connection withdrawn).
119: * <P>
120: * This method always returns a Connection in the free state (i.e.
121: * (not associated with an Xid). This is necessary since, unless
122: * Start (Xid, flags) gets called, the Connection must do local
123: * transaction processing.
124: */
125: public synchronized Connection getConnection() throws SQLException {
126: dataSource.log.debug("StandardXAConnection:getConnection");
127: if (connectionHandle != null) {
128: // if there's already a delegated connection
129: if (!connectionHandle.isClosed()) // and it hasn't been closed
130: connectionHandle.close(); // close it now
131: }
132: if (curCon == null) { // if there's no current connection
133:
134: curCon = xaDataSource.getFreeConnection();
135: // find or create a free connection
136: con = curCon.con; // save it's Connection
137: }
138:
139: // Note that we share the PreparedStatement cache across many physical
140: // connections. This is OK since the connection is used in the lookup key.
141:
142: this .newConnectionHandle();
143: dataSource.log
144: .debug("StandardXAConnection:getConnection return a connection");
145: return connectionHandle;
146: }
147:
148: protected void newConnectionHandle() {
149: connectionHandle = new StandardXAConnectionHandle(this ,
150: dataSource.getMasterPrepStmtCache(), dataSource
151: .getPreparedStmtCacheSize(), transactionManager);
152: }
153:
154: public void setTransactionManager(TransactionManager tm) {
155: this .transactionManager = tm;
156: }
157:
158: /**
159: * Close this XA connection.
160: */
161: public synchronized void close() throws java.sql.SQLException {
162: dataSource.log
163: .debug("StandardXAConnection:close the XAConnection");
164: // if (con != null) { // if we have a current connection
165: // con.close(); // then close it
166: // dataSource.getMasterPrepStmtCache().remove(con.toString());
167: // }
168: //commenented by karthicks - in case of transacted connection curcon will be null and physical connection con will not be null
169: //and physical will be part of freeconnection which would be used by some other instance of XAConnection object at this instant
170: //so only the curCon and its is associated connected should be closed
171: //it will happen fro non transacted connections.
172: //in case of tx connectioins else part will come to play and close any freeconnections
173: if (curCon != null && !curCon.con.isClosed()) { // if we have a current connection
174: curCon.con.close(); // then close it
175: dataSource.getMasterPrepStmtCache().remove(
176: curCon.toString());
177: } else { // no "current" connection
178: if (xaDataSource.freeConnections.size() > 1) {
179: // if there are some free connections
180: //curCon.con.setAutoCommit(thisAutoCommit);
181: curCon = xaDataSource.getFreeConnection();
182: // get one of the free connections
183: curCon.con.close(); // close it
184: dataSource.getMasterPrepStmtCache().remove(
185: curCon.con.toString());
186: }
187: }
188: curCon = null; // remove stateful connection
189: con = null; // and physical connection
190: xaDataSource.connectionClosed();
191: // tell data source that connection's gone
192:
193: isClosed = true; // connection is now closed
194: connectionHandle = null;
195: //timerThread.resume(); // stop the timeout checking
196: nextTimeout = 0; // I don't know how the above line was
197: // supposed to stop the thread but we
198: // should really just set the condition
199: // and let the thread stop itself
200: }
201:
202: /**
203: * Does most of the work of the start() call (below). Kept as
204: * a separate method so that subclasses can call it and retain
205: * the curCon property.
206: */
207: public synchronized void doStart(Xid xid, int flags)
208: throws XAException {
209: dataSource.log.debug("StandardXAConnection:doStart xid='" + xid
210: + "' flags='" + flags + "'");
211: if (xid == null)
212: throw new XAException(XAException.XAER_INVAL);
213:
214: // should only get called after a new/free connection has been made current
215: /* commented by karthick
216: if (curCon == null) {
217: try {
218: curCon = xaDataSource.getFreeConnection();
219: } catch (Exception e) {
220: }
221: dataSource.log.debug("StandardXAConnection:doStart curCon is null");
222: //throw new XAException (XAException.XAER_PROTO);
223: }
224: */
225:
226: /*
227: if ((curCon.getState() != Status.STATUS_NO_TRANSACTION) && (curCon.xid != xid )){
228: dataSource.log.error("StandardXAConnection:doStart Invalid state:status="
229: + curCon.getState() + ":id=" + curCon.id);
230: throw new XAException (XAException.XAER_PROTO);
231: }
232: */
233:
234: if (flags == TMRESUME || flags == TMJOIN) {
235: // if resuming or joining an existing transaction
236: try {
237: xaDataSource.processToWait();
238: } catch (Exception e) {
239: throw new XAException("Exception : " + e.toString());
240: }
241: synchronized (xaDataSource) {
242: if (curCon != null) {
243: //free connections will be added if this is a new XAConnection object or previously an non transacted connection
244: // so no need to check fori contains any as a precaution
245: //commented by karthicks
246: if (!xaDataSource.freeConnections.contains(curCon)) {
247: xaDataSource.freeConnections.addElement(curCon);
248: }
249: }
250: // save the current connection
251: }
252: curCon = xaDataSource.getConnection(xid, true);
253: // must find connection handling xid
254: con = curCon.con; // must use correct physical connection
255: } // else {
256: // xaDataSource.getConnection(xid, false);
257: // // must NOT find connection handling xid
258: // }
259: //commented by karthicks -unnecessary fetch
260:
261: //moved by karthicks
262: // should only get called after a new/free which has been called in different tx earlier
263: if (curCon == null) {
264: try {
265: curCon = xaDataSource.getFreeConnection();
266: con = curCon.con;
267: } catch (Exception e) {
268: dataSource.log.error("error while gettting connection "
269: + e, e);
270: }
271: dataSource.log
272: .debug("StandardXAConnection:doStart curCon is null");
273: //throw new XAException (XAException.XAER_PROTO);
274: }
275:
276: //on suspend all enlisted resource will get called so resetonresume will be set "true" to those StdxaconnHandle
277: //on resume viceversa(deleisted resource ) will get enlisted again so start will get called and current tx will be reset
278: //by - karthicks
279: StandardXAConnectionHandle xad = connectionHandle;
280: try {
281: xad.setGlobalTransaction(true);
282: if (flags == TMRESUME && xad.resetTxonResume) {
283: xad.resetTxonResume = false;
284: if (transactionManager != null && xad.tx == null) {
285: try {
286: connectionHandle.tx = transactionManager
287: .getTransaction();
288: } catch (javax.transaction.SystemException se) {
289: throw new XAException(se.toString());
290: }
291: }
292: }
293:
294: // delegate must use current physical connection
295: } catch (SQLException e) {
296: throw new XAException(e.toString());
297: }
298:
299: if (timeoutSecs != 0) { // if a timeout has been defined
300: curCon.timeout = System.currentTimeMillis() // set the timeout
301: + timeoutSecs * 1000;
302: if (nextTimeout == 0) {
303: // if there are currently no timeouts set up
304: nextTimeout = curCon.timeout; // set new timeout
305: notify();
306: //timerThread.resume(); // start checking for timeouts
307: } else { // some timeouts already exist
308: if (curCon.timeout < nextTimeout) {
309: // if this expires sooner than next timeout
310: nextTimeout = curCon.timeout; // set new timeout
311: }
312: }
313: }
314:
315: curCon.xid = xid; // connection now associated with this XID
316: curCon.timedOut = false; // forget about any old timeouts
317: curCon.commitOnPrepare = commitOnPrepare;
318: // tell it when to do a commit
319: if (!xaDataSource.xidConnections.containsKey(xid)) {
320: try {
321: log
322: .debug("StandardXAConnection:dostart before processToWait");
323: xaDataSource.processToWait();
324: log
325: .debug("StandardXAConnection:dostart after processToWait");
326: } catch (Exception e) {
327: throw new XAException("Exception : " + e.toString());
328: }
329: synchronized (xaDataSource) {
330: xaDataSource.xidConnections.put(xid, curCon);
331: // place on allocated list
332: }
333: }
334: curCon.setState(Status.STATUS_ACTIVE); // set new connection state
335: }
336:
337: /**
338: * Associates this XAConnection with a global transaction. This
339: * is the only method which can associate the current connection
340: * with a global transaction. It acts only on the current
341: * connection which must have been previously established using
342: * getConnection.
343: */
344: public synchronized void start(Xid xid, int flags)
345: throws XAException {
346: dataSource.log
347: .debug("StandardXAConnection:start associate the current connection with a global transaction");
348: doStart(xid, flags); // do most of the work
349: curCon = null; // no longer owned by this object
350: //con = null; // ditto
351: }
352:
353: /**
354: * Ends a connection's association with a global transaction.
355: * <P>
356: * It need not act on the current transaction. There is an
357: * interval between being returned to the pool manager and
358: * being invoked by the transaction manager during which the
359: * current connection can change.
360: * <P>
361: * Note that the only effect is to change the connection state.
362: */
363: public synchronized void end(Xid xid, int flags) throws XAException { //not tested XS
364: dataSource.log.debug("StandardXAConnection:end");
365: dataSource.log.debug("StandardXAConnection:end xid='" + xid
366: + "' flags='" + flags + "'");
367:
368: if (xid == null)
369: throw new XAException(XAException.XAER_INVAL);
370: StandardXAStatefulConnection statecon = xaDataSource
371: .getConnection(xid, true);
372: // must find connection for this transaction
373: int state = statecon.getState(); // get current state of connection
374: if (state != Status.STATUS_ACTIVE) // must have had start() called
375: throw new XAException(XAException.XAER_PROTO);
376: /*System.out.println("connectionHandle.globalTransaction = false;\n"+
377: "connectionHandle.setAutoCommit(true);");
378: connectionHandle.globalTransaction = false;
379: try {
380: connectionHandle.setAutoCommit(true);
381: } catch (SQLException sqle) {
382: dataSource.log("StandardXAConnection pb: "+sqle);
383: }*/
384: // try {
385: //on suspend all end of enlisted resource will get called so resetonresume will be set "true" to those StdxaconnHandle
386: //on resume viceversa(deleisted resource ) will get enlisted again so start will get called and current tx will be reset
387: //by - karthicks
388: if (connectionHandle.tx != null) {
389: connectionHandle.resetTxonResume = true;
390: }
391: connectionHandle.tx = null;
392: connectionHandle.globalTransaction = false;
393:
394: /* connectionHandle.setGlobalTransaction(false);
395: } catch (SQLException sqle) {
396: dataSource.log.error("StandardXAConnection:end pb "+sqle);
397: }
398: */
399: }
400:
401: /**
402: * Does most of the work of a generic prepare. Kept as a
403: * separate method so that sub-classes can call it and get
404: * the StandardXAStatefulConnection back.
405: */
406: public StandardXAStatefulConnection checkPreparedState(Xid xid)
407: throws XAException {
408: dataSource.log.debug("StandardXAConnection:checkPreparedState");
409: if (xid == null)
410: throw new XAException(XAException.XAER_INVAL);
411: StandardXAStatefulConnection statecon = xaDataSource
412: .getConnection(xid, true);
413: // must find connection for this transaction
414:
415: try {
416: if (statecon.commitOnPrepare) { // if early commit is required
417: statecon.con.commit(); // perform the commit operation now
418: statecon.setState(Status.STATUS_PREPARING);
419: // heuristaclly committed
420: } else {
421: statecon.setState(Status.STATUS_PREPARED); // prepared
422: }
423: } catch (SQLException e) {
424: dataSource.log
425: .error("StandardXAConnection:checkPrepareState Exception on prepare, rolling back");
426: statecon.setState(Status.STATUS_NO_TRANSACTION);
427: // release connection
428: throw new XAException(XAException.XA_RBROLLBACK);
429: // rollback will have been performed
430: }
431:
432: return statecon;
433: }
434:
435: /**
436: * Prepares to perform a commit. May actually perform a commit
437: * in the flag commitOnPrepare is set to true.
438: */
439: public int prepare(Xid xid) throws XAException {
440: dataSource.log
441: .debug("StandardXAConnection:prepare prepare to perform a commit");
442: checkPreparedState(xid);
443: return XA_OK;
444: }
445:
446: /**
447: * Performs a commit on this resource manager's branch of
448: * the global transaction.
449: */
450: public synchronized void commit(Xid xid, boolean onePhase)
451: throws XAException {
452: dataSource.log
453: .debug("StandardXAConnection:commit perform a commit");
454: if (xid == null)
455: throw new XAException(XAException.XAER_INVAL);
456:
457: StandardXAStatefulConnection statecon = xaDataSource
458: .getConnection(xid, true);
459: // must find connection for this transaction
460: dataSource.log.debug("StandardXAConnection:commit case(state)");
461:
462: try {
463: switch (statecon.getState()) { // action depends on current state
464: case Status.STATUS_PREPARING: // already commited
465: break; // ...so do nothing
466: case Status.STATUS_PREPARED: // ready to do commit
467: try {
468: dataSource.log
469: .debug("StandardXAConnection:commit try to commit a connection (STATUS_PREPARED)");
470: statecon.con.commit();
471: // perform the commit operation now
472: dataSource.log
473: .debug("StandardXAConnection:commit commit is ok");
474: } catch (SQLException e) {
475: throw new XAException(XAException.XA_RBROLLBACK);
476: // rollback will have been performed
477: }
478: break;
479: case Status.STATUS_COMMITTED: // could be a 1-phase commit
480: case Status.STATUS_ACTIVE:
481: if (!onePhase) { // if not a one-phase commit
482: throw new XAException(XAException.XAER_PROTO);
483: }
484:
485: try {
486: dataSource.log
487: .debug("StandardXAConnection:commit try to commit a connection (STATUS_ACTIVE)");
488: statecon.con.commit();
489: // perform the commit operation now
490: dataSource.log
491: .debug("StandardXAConnection:commit commit is ok");
492: } catch (SQLException e) {
493: throw new XAException(XAException.XA_RBROLLBACK);
494: // rollback will have been performed
495: }
496: break;
497: default: {
498: dataSource.log
499: .debug("StandardXAConnection:commit UNKNOWN STATUS!:"
500: + statecon.getState());
501: throw new XAException(XAException.XAER_PROTO);
502: }
503: }
504: } catch (XAException e) {
505: throw e;
506: } finally {
507: try {
508: dataSource.log
509: .debug("StandardXAConnection:commit setAutoCommit to '"
510: + this AutoCommit + "'");
511: statecon.con.setAutoCommit(this AutoCommit);
512: } catch (SQLException e) {
513: dataSource.log
514: .debug("StandardXAConnection:commit setAutoCommit problem");
515: }
516:
517: xaDataSource.freeConnection(xid, false);
518: }
519: }
520:
521: /**
522: * PERFORMS a rollback on this resource manager's branch of
523: * the global transaction.
524: */
525: public synchronized void rollback(Xid xid) throws XAException {
526: dataSource.log.debug("StandardXAConnection:rollback");
527: if (xid == null)
528: throw new XAException(XAException.XAER_INVAL);
529:
530: StandardXAStatefulConnection statecon = xaDataSource
531: .getConnection(xid, true);
532: // must find connection for this transaction
533:
534: try {
535: switch (statecon.getState()) { // action depends on current state
536: case Status.STATUS_PREPARING: // already commited
537: throw new XAException(XAException.XA_HEURCOM);
538: case Status.STATUS_PREPARED: // ready to do rollback
539: case Status.STATUS_ROLLING_BACK:
540: case Status.STATUS_ACTIVE:
541: try {
542: dataSource.log
543: .debug("StandardXAConnection:rollback try to perform the rollback operation");
544: statecon.con.rollback();
545: // perform the rollback operation
546: dataSource.log
547: .debug("StandardXAConnection:rollback performed the rollback");
548: } catch (SQLException e) {
549: throw new XAException(XAException.XA_RBROLLBACK);
550: // rollback will have been performed
551: }
552: break;
553: default:
554: throw new XAException(XAException.XAER_PROTO);
555: }
556: } catch (XAException e) {
557: throw e;
558: } finally {
559: try {
560: dataSource.log
561: .debug("StandardXAConnection:rollback setAutoCommit to '"
562: + this AutoCommit + "'");
563: statecon.con.setAutoCommit(this AutoCommit);
564: } catch (SQLException e) {
565: dataSource.log
566: .debug("StandardXAConnection:rollback setAutoCommit problem");
567: }
568: xaDataSource.freeConnection(xid, false);
569: }
570: }
571:
572: public boolean isSameRM(XAResource xares) throws XAException {
573: dataSource.log.debug("StandardXAConnection:isSameRM");
574: if (equals(xares)) { // if the same object
575: dataSource.log
576: .debug("StandardXAConnection:isSameRM isSameRM");
577: return true; // then definitely the same RM
578: }
579: if (!(xares instanceof StandardXAConnection)) {
580: // if it's not one of our wrappers
581: dataSource.log
582: .debug("StandardXAConnection:isSameRM not isSameRM");
583: return false; // then it's definitely not the same RM
584: }
585: StandardXAConnection xac = (StandardXAConnection) xares;
586: // cast to something more convenient
587: if (dataSource.equals(xac.dataSource)) {
588: // if they originate from same data source
589: dataSource.log
590: .debug("StandardXAConnection:isSameRM isSameRM (equal datasource)");
591: return true; // then they're the same RM
592: } else {
593: dataSource.log
594: .debug("StandardXAConnection:isSameRM not isSameRM (not equal datasource)");
595: return false;
596: }
597: }
598:
599: /**
600: * This is called by a TM when the RM has reported a heuristic
601: * completion. It must retain the transaction context until told
602: * to forget about it.
603: */
604: public void forget(Xid xid) throws XAException {
605: dataSource.log
606: .debug("StandardXAConnection:forget forget with Xid");
607: if (xid == null)
608: throw new XAException(XAException.XAER_INVAL);
609:
610: //StandardXAStatefulConnection statecon = xaDataSource.getConnection (xid, true);// must find connection for this transaction
611: xaDataSource.freeConnection(xid, false);
612: // finished with this transaction
613: }
614:
615: /**
616: * Called by the transaction manager during recovery. If it was the
617: * transaction manager or another compoenent which failed then we
618: * can supply our known Xids. However if we failed then this method
619: * does nothing - we need to know about database internals to do that.
620: */
621: public Xid[] recover(int flag) throws XAException {
622: dataSource.log
623: .debug("StandardXAConnection:recover recover flag="
624: + flag);
625: if (flag != TMSTARTRSCAN && flag != TMENDRSCAN
626: && flag != TMNOFLAGS) {
627: throw new XAException(XAException.XAER_INVAL);
628: }
629:
630: Xid[] retval = null;
631: retval = xaDataSource.recover(); // get all valid Xids
632: return retval;
633: }
634:
635: /**
636: * Accessor methods for timeout.
637: */
638: public boolean setTransactionTimeout(int seconds) {
639: timeoutSecs = seconds;
640: return false;
641: }
642:
643: public int getTransactionTimeout() {
644: return timeoutSecs;
645: }
646:
647: public void setCommitOnPrepare(boolean commitOnPrepare) {
648: this .commitOnPrepare = commitOnPrepare;
649: }
650:
651: public boolean getCommitOnPrepare() {
652: return commitOnPrepare;
653: }
654:
655: /**
656: * Periodically checks for timed out connections.
657: */
658: public void run() {
659: //dataSource.log.debug("StandardXAConnection:run check for timed out connections");
660: while (true) { // loop forever
661: /*
662: if (nextTimeout == 0) { // if there are no more timeouts scheduled
663: timerThread.suspend(); // then go to sleep
664: if (isClosed) return; // exit if connection is closed
665: }
666: */
667: try {
668: synchronized (this ) {
669: while (nextTimeout == 0) {
670: wait();
671: }
672: }
673: } catch (InterruptedException e) {
674: }
675:
676: if (isClosed) {
677: return;
678: }
679:
680: try {
681: Thread.sleep(timeoutPeriod); // sleep for a few seconds
682: if (isClosed)
683: return; // exit if connection is closed
684: } catch (InterruptedException e) {
685: e.printStackTrace(); // we don't expect any of these
686: }
687:
688: long curTime = System.currentTimeMillis(); // get system time
689: if (curTime < nextTimeout)
690: continue; // check for time still to go
691:
692: // One or more transactions have timeout out.
693: try {
694: nextTimeout = xaDataSource.checkTimeouts(curTime);
695: // check to see if connections have timeout out
696: } catch (Exception e) {
697: e.printStackTrace(); // we don't expect any of these
698: }
699: }
700: }
701:
702: public Reference getReference() throws NamingException {
703: // Note that we use getClass().getName() to provide the factory
704: // class name. It is assumed that this class, and all of its
705: // descendants are their own factories.
706: dataSource.log
707: .debug("StandardXAConnection:getReference return a reference of the object");
708: Reference ref = new Reference(getClass().getName(), getClass()
709: .getName(), null);
710: ref.add(new StringRefAddr("commitOnPrepare", String
711: .valueOf(getCommitOnPrepare())));
712: ref.add(new StringRefAddr("timeoutSecs", Integer
713: .toString(getTransactionTimeout())));
714: return ref;
715: }
716:
717: public String toString() {
718: StringBuffer sb = new StringBuffer();
719: sb.append("StandardXAConnection:\n");
720: sb.append(" commit on prepare =<" + this .commitOnPrepare
721: + ">\n");
722: sb.append(" is closed =<" + this .isClosed + ">\n");
723: sb.append(" this autoCommit =<" + this .this AutoCommit
724: + ">\n");
725: sb.append(" listeners size =<" + this .listeners.size()
726: + ">\n");
727: sb.append(" next timeOut =<" + this .nextTimeout + ">\n");
728: sb
729: .append(" timeOut period =<" + this .timeoutPeriod
730: + ">\n");
731: sb.append(" timeOut secs =<" + this .timeoutSecs + ">\n");
732: sb.append(" transaction manager=<"
733: + this .transactionManager + ">\n");
734: sb.append(this.xaDataSource.toString());
735: sb.append(this.dataSource.toString());
736: if (curCon != null)
737: sb.append(this.curCon.toString());
738: if (connectionHandle != null)
739: sb.append(this.connectionHandle.toString());
740: sb.append(this.con.toString());
741:
742: return sb.toString();
743:
744: }
745: }
|