1 6 7 package org.jfox.jdbc.xa; 8 9 import java.sql.Connection ; 10 import java.sql.SQLException ; 11 import javax.sql.ConnectionEvent ; 12 import javax.sql.ConnectionEventListener ; 13 import javax.sql.XAConnection ; 14 import javax.transaction.Status ; 15 import javax.transaction.Synchronization ; 16 import javax.transaction.Transaction ; 17 import javax.transaction.TransactionManager ; 18 import javax.transaction.xa.XAResource ; 19 20 import org.jfox.ioc.logger.Logger; 21 import org.jfox.jdbc.ClientConnection; 22 import org.jfox.pool.PoolableObject; 23 24 27 28 public class PoolableXAConnection implements PoolableObject, XAConnection { 29 private XAConnection xaconn = null; 30 private XAResource xares = null; 31 32 private Connection underlying = null; 34 35 private ConnectionEventListener txConnListener = null; 36 37 Logger logger = Logger.getLogger(PoolableXAConnection.class.getName()); 38 39 private boolean poolable = true; 41 private boolean errored = false; 43 44 private static TransactionManager tm = TxDataSource.getTransactionManager(); 45 private Synchronization txSync = new XASynchronization(); 46 47 private XAConnectionPool pool = null; 48 49 private boolean passivated = true; 51 52 private String dbUrl = null; 53 private String user = null; 54 private String password = null; 55 56 private long startSleepTime = System.currentTimeMillis(); 57 58 59 public PoolableXAConnection(XAConnection xaconn, int transactionIsolation, String dbUrl, String user, String password) { 60 this.xaconn = xaconn; 61 this.dbUrl = dbUrl; 62 this.user = user; 63 this.password = password; 64 try { 65 xares = xaconn.getXAResource(); 66 underlying = xaconn.getConnection(); 67 underlying.setAutoCommit(false); 68 logger.debug("set underlying connection transaction isolation: " + transactionIsolation); 69 underlying.setTransactionIsolation(transactionIsolation); 70 } 71 catch(SQLException e) { 72 throw new RuntimeException ("can not init PoolableXAConnection, because getConnection failed.", e); 73 } 74 txConnListener = new TxConnectionListener(); 75 xaconn.addConnectionEventListener(txConnListener); 76 txSync = new XASynchronization(); 77 } 78 79 84 public void activate() throws Exception { 85 logger.debug("activate callback, tx status = " + tm.getStatus()); 86 passivated = false; 87 if(tm.getStatus() != Status.STATUS_NO_TRANSACTION) { 88 Transaction tran = tm.getTransaction(); 89 tran.enlistResource(xares); 90 tran.registerSynchronization(txSync); 91 XAConnectionManager.associate(tran, this, dbUrl, user, password); 92 } 93 94 startSleepTime = System.currentTimeMillis(); 95 } 96 97 105 public void passivate() throws Exception { 106 logger.debug("passivate callback"); 107 passivated = true; 108 int txStatus = tm.getStatus(); 109 if(txStatus != Status.STATUS_NO_TRANSACTION) { 110 XAConnectionManager.disassociate(tm.getTransaction(), dbUrl, user, password); 111 } 112 113 startSleepTime = System.currentTimeMillis(); 114 } 115 116 public boolean isAvailable() { 117 return poolable && !errored && !passivated; 118 } 119 120 public XAResource getXAResource() throws SQLException { 121 if(passivated) { 122 throw new SQLException ("XAConnection have returned to pool, re-retrieve it for use"); 123 } 124 return xares; 125 } 126 127 public void close() throws SQLException { 128 poolable = false; 129 underlying.close(); 130 xaconn.close(); 131 } 132 133 public Connection getConnection() throws SQLException { 134 if(passivated) { 135 throw new SQLException ("XAConnection have returned to pool, re-retrieve it for use"); 136 } 137 return new ClientConnection(underlying); 138 } 139 140 public void addConnectionEventListener(ConnectionEventListener listener) { 141 if(!passivated) { 142 xaconn.addConnectionEventListener(listener); 143 } 144 } 145 146 public void removeConnectionEventListener(ConnectionEventListener listener) { 147 if(!passivated) { 148 xaconn.removeConnectionEventListener(listener); 149 } 150 } 151 152 private void markedError() { 155 logger.warn("xaconn error occurred, to be marked error"); 156 errored = true; 157 } 158 159 165 void notPoolable() { 166 poolable = false; 167 } 168 169 void setPool(XAConnectionPool pool) { 170 this.pool = pool; 171 } 172 173 public long getSleepTime() { 174 return System.currentTimeMillis() - startSleepTime; 175 } 176 177 public static void main(String [] args) { 178 179 } 180 181 186 private class TxConnectionListener implements ConnectionEventListener { 187 188 public void connectionClosed(ConnectionEvent event) { 189 logger.debug("connection closed event: " + event); 190 194 if(passivated) return; 195 XAConnection xaconn = (XAConnection ) event.getSource(); 196 Transaction trans = null; 197 try { 198 if(tm.getStatus() != Status.STATUS_NO_TRANSACTION) { 199 trans = tm.getTransaction(); 200 XAResource res = (XAResource ) xaconn.getXAResource(); 201 if(res != null) { 202 trans.delistResource(res, XAResource.TMSUCCESS); 203 XAConnectionManager.disassociate(trans, dbUrl, user, password); 204 pool.restoreObject(PoolableXAConnection.this); 206 } 207 else { 208 logger.warn("can not getXAResource from " + xaconn); 209 } 210 } 211 } 212 catch(Exception e) { 213 throw new RuntimeException ("TxConnectionListener.connectionClosed() error", e); 214 } 215 } 216 217 222 public void connectionErrorOccurred(ConnectionEvent event) { 223 logger.debug("connection error occurred: " + event.getSQLException()); 225 PoolableXAConnection.this.markedError(); 226 } 227 } 228 229 class XASynchronization implements Synchronization { 230 231 public void beforeCompletion() { 232 233 } 234 235 241 public void afterCompletion(int status) { 242 logger.debug("PoolableXAConnection.XASynchronization.afterCompletion " + status); 243 pool.restoreObject(PoolableXAConnection.this); 244 245 } 246 } 247 248 } 249 250 | Popular Tags |