0001: /*
0002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
0003: *
0004: * This file is part of Resin(R) Open Source
0005: *
0006: * Each copy or derived work must preserve the copyright notice and this
0007: * notice unmodified.
0008: *
0009: * Resin Open Source is free software; you can redistribute it and/or modify
0010: * it under the terms of the GNU General Public License as published by
0011: * the Free Software Foundation; either version 2 of the License, or
0012: * (at your option) any later version.
0013: *
0014: * Resin Open Source is distributed in the hope that it will be useful,
0015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
0016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
0017: * of NON-INFRINGEMENT. See the GNU General Public License for more
0018: * details.
0019: *
0020: * You should have received a copy of the GNU General Public License
0021: * along with Resin Open Source; if not, write to the
0022: *
0023: * Free Software Foundation, Inc.
0024: * 59 Temple Place, Suite 330
0025: * Boston, MA 02111-1307 USA
0026: *
0027: * @author Scott Ferguson
0028: */
0029:
0030: package com.caucho.jca;
0031:
0032: import com.caucho.log.Log;
0033: import com.caucho.util.Alarm;
0034: import com.caucho.util.L10N;
0035:
0036: import javax.resource.NotSupportedException;
0037: import javax.resource.ResourceException;
0038: import javax.resource.spi.ConnectionEvent;
0039: import javax.resource.spi.ConnectionEventListener;
0040: import javax.resource.spi.ConnectionRequestInfo;
0041: import javax.resource.spi.LocalTransaction;
0042: import javax.resource.spi.ManagedConnection;
0043: import javax.resource.spi.ManagedConnectionFactory;
0044: import javax.security.auth.Subject;
0045: import javax.transaction.xa.XAException;
0046: import javax.transaction.xa.XAResource;
0047: import javax.transaction.xa.Xid;
0048: import java.util.logging.Level;
0049: import java.util.logging.Logger;
0050:
0051: /**
0052: * Implementation of the connection manager manager.
0053: */
0054: class PoolItem implements ConnectionEventListener, XAResource {
0055: private static final L10N L = new L10N(PoolItem.class);
0056: private static final Logger log = Log.open(PoolItem.class);
0057:
0058: private ConnectionPool _cm;
0059:
0060: private ManagedConnectionFactory _mcf;
0061: private ManagedConnection _mConn;
0062:
0063: private UserTransactionImpl _transaction;
0064:
0065: private String _id;
0066:
0067: private XAResource _xaResource;
0068: private LocalTransaction _localTransaction;
0069: private int _defaultTransactionTimeout;
0070: private int _transactionTimeout;
0071:
0072: private Subject _subject;
0073: private ConnectionRequestInfo _requestInfo;
0074:
0075: final Object _shareLock = new Object();
0076:
0077: // The head shared connection for transaction
0078: // The UserPoolItem code is responsible for this field
0079: UserPoolItem _shareHead;
0080:
0081: // The other pool items joined transaction
0082: private PoolItem _xaHead;
0083: private PoolItem _xaNext;
0084:
0085: private boolean _hasConnectionError;
0086:
0087: private long _poolStartTime;
0088: private long _poolEventTime;
0089:
0090: private Xid _xid;
0091: private int _endFlags = -1;
0092:
0093: // flag forcing an XA transaction (for the local transaction optimization)
0094: private boolean _isXATransaction = true;
0095:
0096: // true if in local transaction
0097: private boolean _isLocalTransaction;
0098:
0099: private IllegalStateException _allocationStackTrace;
0100:
0101: public PoolItem(ConnectionPool cm, ManagedConnectionFactory mcf,
0102: ManagedConnection conn) {
0103: _cm = cm;
0104:
0105: _id = _cm.generateId();
0106:
0107: _mcf = mcf;
0108: _mConn = conn;
0109:
0110: _poolStartTime = Alarm.getCurrentTime();
0111: _poolEventTime = Alarm.getCurrentTime();
0112:
0113: // Gets the resource object from the driver
0114: try {
0115: if (cm.isXATransaction()) {
0116: XAResource xaResource = conn.getXAResource();
0117:
0118: try {
0119: _defaultTransactionTimeout = xaResource
0120: .getTransactionTimeout();
0121: } catch (Throwable e) {
0122: log.log(Level.FINE, e.toString(), e);
0123: }
0124:
0125: _xaResource = xaResource;
0126: }
0127: } catch (NotSupportedException e) {
0128: _cm.setXATransaction(false);
0129: log.log(Level.FINER, e.toString(), e);
0130: } catch (Exception e) {
0131: log.log(Level.FINE, e.toString(), e);
0132: }
0133:
0134: if (_xaResource == null)
0135: _isXATransaction = false;
0136:
0137: // Gets the local transaction from the driver
0138: try {
0139: if (_cm.isLocalTransaction())
0140: _localTransaction = conn.getLocalTransaction();
0141: } catch (NotSupportedException e) {
0142: _cm.setLocalTransaction(false);
0143: log.log(Level.FINE, e.toString(), e);
0144: } catch (Exception e) {
0145: log.log(Level.FINE, e.toString(), e);
0146: }
0147:
0148: _mConn.addConnectionEventListener(this );
0149:
0150: if (log.isLoggable(Level.FINE))
0151: log.fine("create: " + this + "(active:"
0152: + _cm.getConnectionActiveCount() + ", total:"
0153: + _cm.getConnectionCount() + ")");
0154: }
0155:
0156: /**
0157: * Sets the subject.
0158: */
0159: public void setSubject(Subject subject) {
0160: _subject = subject;
0161: }
0162:
0163: /**
0164: * Sets the info.
0165: */
0166: public void setInfo(ConnectionRequestInfo info) {
0167: _requestInfo = info;
0168: }
0169:
0170: /**
0171: * Returns true if the connection is active.
0172: */
0173: public boolean isActive() {
0174: return _shareHead != null;
0175: }
0176:
0177: /**
0178: * Returns true if the connection is dead
0179: */
0180: public boolean isDead() {
0181: return _mConn == null;
0182: }
0183:
0184: /**
0185: * Returns the time of the last event.
0186: */
0187: public long getEventTime() {
0188: return _poolEventTime;
0189: }
0190:
0191: /**
0192: * Returns the time the connection was first used.
0193: */
0194: public long getStartTime() {
0195: return _poolStartTime;
0196: }
0197:
0198: /**
0199: * Sets the item's transaction.
0200: */
0201: void setTransaction(UserTransactionImpl transaction) {
0202: _transaction = transaction;
0203: }
0204:
0205: /**
0206: * Make this connection active.
0207: *
0208: * @return true if the pool item is valid, false if it should be removed.
0209: */
0210: synchronized UserPoolItem toActive(Subject subject,
0211: ConnectionRequestInfo info, UserPoolItem userPoolItem)
0212: throws ResourceException {
0213: long now = Alarm.getCurrentTime();
0214:
0215: long maxIdleTime = _cm.getMaxIdleTime();
0216: long maxPoolTime = _cm.getMaxPoolTime();
0217:
0218: if (_hasConnectionError)
0219: return null;
0220: else if (0 < maxIdleTime && _poolEventTime + maxIdleTime < now)
0221: return null;
0222: else if (0 < maxPoolTime && _poolStartTime + maxPoolTime < now)
0223: return null;
0224: else if (_shareHead != null)
0225: throw new IllegalStateException(L
0226: .l("trying to activate active pool item."));
0227:
0228: _poolEventTime = now;
0229: _isXATransaction = _xaResource != null; // disable LT-optim by default
0230:
0231: if (userPoolItem != null) {
0232: Object uConn = userPoolItem.getUserConnection();
0233:
0234: if (uConn != null)
0235: _mConn.associateConnection(uConn);
0236:
0237: userPoolItem.associatePoolItem(this );
0238: } else
0239: userPoolItem = new UserPoolItem(_cm, this );
0240:
0241: if (!isValid(subject, info, userPoolItem))
0242: return null;
0243:
0244: _subject = subject;
0245: _requestInfo = info;
0246: userPoolItem.associate(this , _mcf, subject, info);
0247:
0248: if (log.isLoggable(Level.FINE))
0249: log.fine("allocate " + this );
0250:
0251: if (_cm.getSaveAllocationStackTrace())
0252: _allocationStackTrace = new IllegalStateException(L.l(
0253: "Connection {0} allocation stack trace", this ));
0254:
0255: return userPoolItem;
0256: }
0257:
0258: /**
0259: * Checks if the pool item is still valid.
0260: *
0261: * @return true if the pool item is valid, false if it should be removed.
0262: */
0263: synchronized boolean isValid() {
0264: long now = Alarm.getCurrentTime();
0265:
0266: long maxIdleTime = _cm.getMaxIdleTime();
0267: long maxPoolTime = _cm.getMaxPoolTime();
0268: long maxActiveTime = _cm.getMaxActiveTime();
0269:
0270: boolean isActive = isActive() || _xid != null;
0271: boolean isDead = false;
0272:
0273: if (!isActive && _hasConnectionError) {
0274: isDead = true;
0275: log.fine("closing pool item from connection error:" + this );
0276: } else if (!isActive && 0 < maxIdleTime
0277: && _poolEventTime + maxIdleTime < now) {
0278: isDead = true;
0279: log.fine("closing pool item from idle timeout:" + this );
0280: } else if (!isActive && 0 < maxPoolTime
0281: && _poolStartTime + maxPoolTime < now) {
0282: isDead = true;
0283: log.fine("closing pool item from pool timeout:" + this );
0284: } else if (isActive && 0 < maxActiveTime
0285: && _poolEventTime + maxActiveTime < now) {
0286: isDead = true;
0287: log
0288: .warning("closing pool item from active timeout:"
0289: + this );
0290: }
0291:
0292: if (isDead) {
0293: _hasConnectionError = true;
0294: return false;
0295: } else
0296: return true;
0297: }
0298:
0299: /**
0300: * Use the item only if it's already been used for the current transaction
0301: * and is available. allocateXA returns the same connection for the
0302: * following case:
0303: *
0304: * <pre>
0305: * UserTransaction.begin();
0306: *
0307: * conn = ds.getConnection();
0308: * ...
0309: * conn.close();
0310: *
0311: * conn = ds.getConnection();
0312: * ...
0313: * conn.close();
0314: * </pre>
0315: *
0316: * <p>Nested connections are not reused.
0317: *
0318: * @param xid the current transaction id
0319: *
0320: * @return true if the pool item has been allocated
0321: */
0322: UserPoolItem allocateXA(ManagedConnectionFactory mcf,
0323: Subject subject, ConnectionRequestInfo info) {
0324: if (_mConn == null) // already closed
0325: return null;
0326: else if (_subject != subject)
0327: return null;
0328: else if (_requestInfo != info)
0329: return null;
0330: else if (_mcf != mcf)
0331: return null;
0332: else if (_shareHead != null && !_cm.isShareable()) // is currently in use
0333: return null;
0334: else if (_hasConnectionError) // had a fatal error
0335: return null;
0336:
0337: if (log.isLoggable(Level.FINER))
0338: log.finer("sharing xa-pool item: " + this );
0339:
0340: UserPoolItem userPoolItem = new UserPoolItem(_cm);
0341: userPoolItem.associate(this , _mcf, _subject, _requestInfo);
0342:
0343: return userPoolItem;
0344: }
0345:
0346: /**
0347: * Returns true if the tested pool item is the Xid leader.
0348: */
0349: boolean isJoin(PoolItem item) {
0350: if (this == item)
0351: return false;
0352: else if (_xid != item._xid)
0353: return false;
0354: else if (_mcf != item._mcf)
0355: return false;
0356: else
0357: return true;
0358: }
0359:
0360: /**
0361: * Try to share the connection.
0362: */
0363: boolean share(UserPoolItem userPoolItem) {
0364: if (this == userPoolItem.getOwnPoolItem())
0365: return true;
0366: else if (_mConn == null) // already closed
0367: return false;
0368: else if (!_cm.isShareable()) // not shareable
0369: return false;
0370: else if (_mcf != userPoolItem.getManagedConnectionFactory())
0371: return false;
0372: else if (_subject != userPoolItem.getSubject())
0373: return false;
0374: else if (_requestInfo != userPoolItem.getInfo())
0375: return false;
0376: else if (_hasConnectionError) // had a fatal error
0377: return false;
0378:
0379: // skip for now
0380: if (true)
0381: return false;
0382:
0383: userPoolItem.associate(this , _mcf, _subject, _requestInfo);
0384:
0385: return true;
0386: }
0387:
0388: /**
0389: * Returns the managed connection.
0390: */
0391: ManagedConnection getManagedConnection() {
0392: return _mConn;
0393: }
0394:
0395: /**
0396: * Returns the user connection.
0397: */
0398: /*
0399: Object getUserConnection()
0400: throws ResourceException
0401: {
0402: return _userPoolItem.getUserConnection();
0403: }
0404: */
0405:
0406: /**
0407: * Returns the user connection.
0408: */
0409: Object allocateConnection() throws ResourceException {
0410: return _mConn.getConnection(_subject, _requestInfo);
0411: }
0412:
0413: /**
0414: * Returns true for a valid connection.
0415: */
0416: boolean isValid(Subject subject, ConnectionRequestInfo requestInfo,
0417: UserPoolItem userPoolItem) {
0418: try {
0419: ManagedConnection mConn = getManagedConnection();
0420:
0421: if (mConn == null)
0422: return false;
0423:
0424: Object userConn = userPoolItem.getUserConnection();
0425:
0426: if (userConn == null) {
0427: userConn = mConn.getConnection(subject, requestInfo);
0428:
0429: userPoolItem.setUserConnection(userConn);
0430: }
0431:
0432: return userConn != null;
0433: } catch (ResourceException e) {
0434: log.log(Level.WARNING, e.toString(), e);
0435:
0436: return false;
0437: }
0438: }
0439:
0440: /**
0441: * Returns the XA resource.
0442: */
0443: void enableLocalTransactionOptimization(boolean enableOptimization) {
0444: if (_xaResource == null)
0445: _isXATransaction = false;
0446: else if (_localTransaction == null)
0447: _isXATransaction = true;
0448: else if (!_cm.isLocalTransactionOptimization())
0449: _isXATransaction = true;
0450: else if (!_cm.isShareable())
0451: _isXATransaction = true;
0452: else
0453: _isXATransaction = !enableOptimization;
0454: }
0455:
0456: /**
0457: * Returns true if the pooled connection supports transactions.
0458: */
0459: boolean supportsTransaction() {
0460: // server/164j
0461: return _xaResource != null || _localTransaction != null;
0462: }
0463:
0464: /**
0465: * Returns the XA resource.
0466: */
0467: XAResource getXAResource() {
0468: return _xaResource;
0469: }
0470:
0471: /**
0472: * Returns the Xid resource.
0473: */
0474: Xid getXid() {
0475: return _xid;
0476: }
0477:
0478: /**
0479: * Notifies that an application has closed the connection.
0480: */
0481: public void connectionClosed(ConnectionEvent event) {
0482: boolean addIdle = false;
0483:
0484: Object handle = event.getConnectionHandle();
0485:
0486: if (!_hasConnectionError && handle == null
0487: && _shareHead != null) {
0488: log
0489: .fine(L
0490: .l(
0491: "JCA close event '{0}' for {1} did not have a connection handle. Please notify the JCA resource provider.",
0492: event, _mConn));
0493: }
0494:
0495: if (_shareHead == null) {
0496: toIdle();
0497: return;
0498: }
0499:
0500: UserPoolItem userPoolItem = _shareHead;
0501:
0502: while (userPoolItem != null) {
0503: UserPoolItem next = userPoolItem.getShareNext();
0504:
0505: Object userConn = userPoolItem.getUserConnection();
0506:
0507: if (userConn == handle || handle == null)
0508: userPoolItem.close();
0509:
0510: userPoolItem = next;
0511: }
0512: }
0513:
0514: /**
0515: * Notifies that a local transaction has started.
0516: */
0517: public void localTransactionStarted(ConnectionEvent event) {
0518: if (_isLocalTransaction || _xid != null)
0519: throw new IllegalStateException(
0520: L
0521: .l("attempted to start local transaction while transaction is in progress."));
0522:
0523: if (_localTransaction != null) {
0524: try {
0525: _localTransaction.begin();
0526: _isLocalTransaction = true;
0527: } catch (ResourceException e) {
0528: log.log(Level.WARNING, e.toString(), e);
0529: }
0530: }
0531: }
0532:
0533: /**
0534: * Notifies that a local transaction has committed.
0535: */
0536: public void localTransactionCommitted(ConnectionEvent event) {
0537: if (_xid != null)
0538: throw new IllegalStateException(
0539: L
0540: .l("attempted to commit() local transaction from an active XA transaction."));
0541: else if (!_isLocalTransaction)
0542: throw new IllegalStateException(
0543: L
0544: .l("attempted to commit() with no active local transaction."));
0545:
0546: if (_localTransaction != null && _isLocalTransaction) {
0547: try {
0548: _isLocalTransaction = false;
0549: _localTransaction.commit();
0550: } catch (ResourceException e) {
0551: log.log(Level.WARNING, e.toString(), e);
0552: }
0553: }
0554: }
0555:
0556: /**
0557: * Notifies that a local transaction has rolled back.
0558: */
0559: public void localTransactionRolledback(ConnectionEvent event) {
0560: if (_xid != null)
0561: throw new IllegalStateException(
0562: L
0563: .l("attempted to rollback() local transaction from an active XA transaction."));
0564: else if (!_isLocalTransaction)
0565: throw new IllegalStateException(
0566: L
0567: .l("attempted to rollback() with no active local transaction."));
0568:
0569: if (_localTransaction != null) {
0570: try {
0571: _isLocalTransaction = false;
0572: _localTransaction.rollback();
0573: } catch (ResourceException e) {
0574: log.log(Level.WARNING, e.toString(), e);
0575: }
0576: }
0577: }
0578:
0579: /**
0580: * Notifies that a connection error has occurred.
0581: */
0582: public void connectionErrorOccurred(ConnectionEvent event) {
0583: _hasConnectionError = true;
0584: }
0585:
0586: /**
0587: * Notifies that a connection error has occurred.
0588: */
0589: public void setConnectionError() {
0590: _hasConnectionError = true;
0591: }
0592:
0593: /**
0594: * Returns true if there was a connection error.
0595: */
0596: public boolean isConnectionError() {
0597: return _hasConnectionError;
0598: }
0599:
0600: /**
0601: * Returns the allocation stack trace.
0602: */
0603: public IllegalStateException getAllocationStackTrace() {
0604: return _allocationStackTrace;
0605: }
0606:
0607: /**
0608: * Returns true if there is a connection error.
0609: */
0610:
0611: // XAResource stuff
0612: /**
0613: * identity of resources
0614: */
0615: public boolean isSameRM(XAResource resource) throws XAException {
0616: if (!(resource instanceof PoolItem))
0617: return false;
0618:
0619: PoolItem poolItem = (PoolItem) resource;
0620:
0621: //if (_cm == poolItem._cm)
0622: // return true;
0623:
0624: if (_xaResource == null)
0625: return false;
0626:
0627: boolean isSameRM = _xaResource.isSameRM(poolItem._xaResource);
0628:
0629: if (log.isLoggable(Level.FINER))
0630: log.finer("isSameRM->" + isSameRM + " " + _xaResource);
0631:
0632: return isSameRM;
0633: }
0634:
0635: /**
0636: * starts work on a transaction branch
0637: */
0638: public void start(Xid xid, int flags) throws XAException {
0639: if (_xid != null) {
0640: if (log.isLoggable(Level.FINER))
0641: log.finer("connection pool start XA: rejoin " + this );
0642:
0643: return;
0644: }
0645:
0646: if (flags == TMJOIN && _xid == null) {
0647: // TMJOIN means the resource manager is managing more than one
0648: // connection. The delegates tie the PoolItems managed by
0649: // the same resource manager together.
0650:
0651: _xid = xid;
0652:
0653: UserTransactionImpl trans = _cm.getTransaction();
0654:
0655: if (trans != null) {
0656: PoolItem xaHead = trans.findJoin(this );
0657:
0658: if (xaHead != null) {
0659: _xaNext = xaHead._xaNext;
0660: _xaHead = xaHead;
0661: xaHead._xaNext = this ;
0662: }
0663: }
0664:
0665: /* XXX: is this still an issue?
0666: if (_xaDelegate != this)
0667: throw new IllegalStateException("pool state exception");
0668:
0669: PoolItem delegate = _cm.getDelegatePoolItem(xid);
0670:
0671: // set to the delegate
0672: _xaDelegate = delegate._xaDelegate;
0673:
0674: // single link list of parents
0675: _xaDelegateNext = _xaDelegate._xaDelegateNext;
0676: _xaDelegate._xaDelegateNext = this;
0677: */
0678:
0679: /*
0680: if (log.isLoggable(Level.FINER))
0681: log.finer("start XA: using delegate " + _xaDelegate + " for XID " + xid);
0682: return;
0683: */
0684: }
0685:
0686: // local transaction optimization
0687: if (!_isXATransaction && flags != TMJOIN
0688: && _localTransaction != null) {
0689: // XXX: server/1810, etc
0690: // && _xaResource == null) { // XXX: temp disable for ActiveMQ
0691: try {
0692: if (log.isLoggable(Level.FINER))
0693: log.finer("begin-local-XA: " + xid + " "
0694: + _localTransaction);
0695:
0696: _localTransaction.begin();
0697: } catch (ResourceException e) {
0698: throw new XAExceptionWrapper(e);
0699: }
0700:
0701: _xid = xid;
0702:
0703: return;
0704: }
0705:
0706: if (_xaResource != null) {
0707: if (log.isLoggable(Level.FINER))
0708: log.finer("start-XA: " + xid + " " + _xaResource);
0709:
0710: _xaResource.start(xid, flags);
0711: _isXATransaction = true;
0712: } else {
0713: if (log.isLoggable(Level.FINER))
0714: log.finer("start-XA with non XA resource: " + xid + " "
0715: + _xaResource);
0716: }
0717:
0718: _xid = xid;
0719: }
0720:
0721: /**
0722: * Sets the transaction timeout
0723: */
0724: public boolean setTransactionTimeout(int seconds)
0725: throws XAException {
0726: if (seconds == _transactionTimeout)
0727: return true;
0728:
0729: XAResource xaResource = _xaResource;
0730:
0731: _transactionTimeout = seconds;
0732:
0733: if (xaResource == null)
0734: return true;
0735: else if (seconds == 0)
0736: return xaResource
0737: .setTransactionTimeout(_defaultTransactionTimeout);
0738: else
0739: return xaResource.setTransactionTimeout(seconds);
0740: }
0741:
0742: /**
0743: * Returns the timeout of the underlying resource.
0744: */
0745: public int getTransactionTimeout() throws XAException {
0746: return _transactionTimeout;
0747: }
0748:
0749: /**
0750: * forget about the transaction
0751: */
0752: public void forget(Xid xid) throws XAException {
0753: try {
0754: if (_isXATransaction)
0755: _xaResource.forget(xid);
0756: } finally {
0757: clearXid();
0758: }
0759: }
0760:
0761: /**
0762: * Vote using phase-1 of the 2-phase commit.
0763: */
0764: public int prepare(Xid xid) throws XAException {
0765: if (_endFlags != -1) {
0766: int endFlags = _endFlags;
0767: _endFlags = -1;
0768:
0769: if (_isXATransaction)
0770: endResource(xid, endFlags);
0771: }
0772:
0773: if (_isXATransaction) {
0774: try {
0775: if (log.isLoggable(Level.FINER))
0776: log.finer("prepare-XA: " + xid + " " + _xaResource);
0777:
0778: int result = _xaResource.prepare(xid);
0779:
0780: if (result == XA_RDONLY) {
0781: if (_xaResource != null)
0782: _isXATransaction = true;
0783:
0784: clearXid();
0785: }
0786:
0787: return result;
0788: } catch (XAException e) {
0789: if (log.isLoggable(Level.FINER))
0790: log.finer("failed prepare-XA: " + xid + " "
0791: + _xaResource + " " + e);
0792:
0793: throw e;
0794: }
0795: } else
0796: return XA_OK;
0797: }
0798:
0799: /**
0800: * recover the transaction
0801: */
0802: public Xid[] recover(int flag) throws XAException {
0803: if (_isXATransaction)
0804: return _xaResource.recover(flag);
0805: else
0806: return null;
0807: }
0808:
0809: /**
0810: * Ends work with the resource. Called before commit/rollback.
0811: */
0812: public void end(Xid xid, int flags) throws XAException {
0813: /* XXX:
0814: if (_xid == null)
0815: throw new IllegalStateException("ending with no transaction");
0816: */
0817:
0818: //if (log.isLoggable(Level.FINER))
0819: // log.finer("connection pool end XA: " + this + " xa=" + xid + " flags=" + flags);
0820: _endFlags = flags;
0821:
0822: // XXX: In theory, drop the _xid. The underlying XADataSource
0823: // can handle combining the connections itself.
0824:
0825: // Don't call the underlying _xaResource.end. The commit or rollback
0826: // will handle that automatically.
0827: }
0828:
0829: /**
0830: * rollback the resource
0831: */
0832: public void rollback(Xid xid) throws XAException {
0833: try {
0834: if (_endFlags != -1) {
0835: try {
0836: int endFlags = _endFlags;
0837: _endFlags = -1;
0838:
0839: if (_isXATransaction)
0840: endResource(xid, endFlags);
0841: } catch (Throwable e) {
0842: log.log(Level.WARNING, e.toString(), e);
0843: if (_isXATransaction)
0844: _xaResource.rollback(xid);
0845: return;
0846: }
0847: }
0848:
0849: if (log.isLoggable(Level.FINER))
0850: log.finer("connection pool rollback XA: " + this );
0851:
0852: if (_isXATransaction)
0853: _xaResource.rollback(xid);
0854: else if (_localTransaction != null) {
0855: try {
0856: _isLocalTransaction = false;
0857: _localTransaction.rollback();
0858: } catch (ResourceException e) {
0859: throw new XAExceptionWrapper(e);
0860: }
0861: }
0862: } finally {
0863: if (_xaResource != null)
0864: _isXATransaction = true;
0865:
0866: clearXid();
0867: }
0868: }
0869:
0870: /**
0871: * commit the resource
0872: */
0873: public void commit(Xid xid, boolean onePhase) throws XAException {
0874: boolean logFiner = log.isLoggable(Level.FINER);
0875:
0876: try {
0877: if (_endFlags != -1) {
0878: try {
0879: int endFlags = _endFlags;
0880: _endFlags = -1;
0881:
0882: if (_isXATransaction)
0883: endResource(xid, endFlags);
0884: } catch (XAException e) {
0885: log.log(Level.WARNING, e.toString(), e);
0886: _xaResource.rollback(xid);
0887: throw e;
0888: } catch (Throwable e) {
0889: log.log(Level.WARNING, e.toString(), e);
0890: _xaResource.rollback(xid);
0891: throw new XAException(XAException.XA_RBOTHER);
0892: }
0893: }
0894:
0895: if (_isXATransaction) {
0896: if (logFiner) {
0897: log.finer("commit-XA" + (onePhase ? "-1p: " : ": ")
0898: + xid + " " + _xaResource);
0899: }
0900:
0901: try {
0902: _xaResource.commit(xid, onePhase);
0903: } catch (XAException e) {
0904: if (logFiner)
0905: log.finer("commit-XA failed: " + _xaResource
0906: + " " + e);
0907:
0908: throw e;
0909: }
0910: } else if (_localTransaction != null) {
0911: if (logFiner)
0912: log.finer("commit-local: " + _localTransaction);
0913:
0914: try {
0915: _isLocalTransaction = false;
0916: _localTransaction.commit();
0917: } catch (ResourceException e) {
0918: if (logFiner)
0919: log.finer("commit failed: " + _localTransaction
0920: + " " + e);
0921:
0922: throw new XAExceptionWrapper(e);
0923: }
0924: } else {
0925: if (logFiner)
0926: log
0927: .finer("commit for resource with no XA support: "
0928: + this );
0929: }
0930: } finally {
0931: if (_xaResource != null)
0932: _isXATransaction = true;
0933:
0934: clearXid();
0935: }
0936: }
0937:
0938: /**
0939: * Ends the resource.
0940: */
0941: private void endResource(Xid xid, int flags) throws XAException {
0942: PoolItem xaPtr = this ;
0943:
0944: for (; xaPtr != null; xaPtr = xaPtr._xaNext) {
0945: if (xaPtr._xaResource != null)
0946: xaPtr._xaResource.end(xid, flags);
0947: }
0948: }
0949:
0950: /**
0951: * Restores the delegation for the entire chain.
0952: */
0953: private void clearXid() {
0954: _xid = null;
0955:
0956: UserPoolItem shareHead = _shareHead;
0957: // _shareHead is nullified at end for timing reasons
0958:
0959: PoolItem xaPtr = _xaNext;
0960: _xaHead = null;
0961: _xaNext = null;
0962:
0963: boolean isClosed = true;
0964:
0965: UserPoolItem ptr = shareHead;
0966: while (ptr != null) {
0967: UserPoolItem next = ptr.getShareNext();
0968:
0969: if (ptr.getOwnPoolItem() == this )
0970: isClosed = false;
0971:
0972: try {
0973: ptr.reassociatePoolItem();
0974: } catch (Throwable e) {
0975: log.log(Level.WARNING, e.toString(), e);
0976: }
0977:
0978: ptr = next;
0979: }
0980:
0981: while (xaPtr != null) {
0982: PoolItem next = xaPtr._xaNext;
0983: xaPtr._xaNext = null;
0984: xaPtr._xaHead = null;
0985:
0986: xaPtr.clearXid();
0987:
0988: xaPtr = next;
0989: }
0990:
0991: if (!isClosed) {
0992: } else if (_hasConnectionError) {
0993: toDead();
0994: } else {
0995: toIdle();
0996: }
0997: }
0998:
0999: /**
1000: * Changes the state to idle.
1001: */
1002: void toIdle() {
1003: if (_shareHead != null)
1004: return;
1005: else if (_xid != null || _isLocalTransaction)
1006: return;
1007: else if (_hasConnectionError) {
1008: toDead();
1009: return;
1010: }
1011:
1012: UserTransactionImpl transaction = _transaction;
1013: _transaction = null;
1014:
1015: if (transaction != null) {
1016: try {
1017: transaction.delistPoolItem(this , XAResource.TMSUCCESS);
1018: } catch (Throwable e) {
1019: log.log(Level.FINE, e.toString(), e);
1020: }
1021: }
1022:
1023: _isLocalTransaction = false;
1024:
1025: if (log.isLoggable(Level.FINE))
1026: log.fine("idle " + this );
1027:
1028: _poolEventTime = Alarm.getCurrentTime();
1029: _cm.toIdle(this );
1030: }
1031:
1032: /**
1033: * Closes the connection.
1034: */
1035: void abortConnection() {
1036: toDead();
1037: }
1038:
1039: /**
1040: * Kills the connection.
1041: */
1042: private void toDead() {
1043: _cm.toDead(this );
1044: }
1045:
1046: /**
1047: * Closes the connection.
1048: */
1049: void destroy() throws ResourceException {
1050: ManagedConnection mConn = _mConn;
1051: _mConn = null;
1052:
1053: UserTransactionImpl transaction = _transaction;
1054: _transaction = null;
1055:
1056: if (mConn == null)
1057: return;
1058:
1059: UserPoolItem userItem = _shareHead;
1060:
1061: if (log.isLoggable(Level.FINE))
1062: log.fine("connection pool destroy " + this );
1063:
1064: try {
1065: while (userItem != null) {
1066: UserPoolItem next = userItem.getShareNext();
1067:
1068: userItem.close();
1069:
1070: userItem = next;
1071: }
1072:
1073: if (transaction != null)
1074: transaction.delistPoolItem(this , XAResource.TMFAIL);
1075: } catch (Throwable e) {
1076: log.log(Level.FINE, e.toString(), e);
1077: }
1078:
1079: mConn.destroy();
1080: }
1081:
1082: public String toString() {
1083: if (_mConn != null) {
1084: return ("PoolItem[" + _cm.getName() + "," + _id + ","
1085: + _mConn.getClass().getSimpleName() + "]");
1086: } else {
1087: return ("PoolItem[" + _cm.getName() + "," + _id + ",null]");
1088: }
1089: }
1090: }
|