📄 xaconnectionfactory.java
字号:
/* * Licensed under the X license (see http://www.x.org/terms.htm) */package org.ofbiz.minerva.pool.jdbc.xa;import javax.sql.ConnectionEvent;import javax.sql.ConnectionEventListener;import javax.sql.XAConnection;import javax.sql.XADataSource;import javax.transaction.Status;import javax.transaction.Transaction;import javax.transaction.TransactionManager;import javax.transaction.xa.XAResource;import java.sql.Connection;import java.sql.SQLException;import java.util.Collections;import java.util.HashMap;import java.util.Map;import org.apache.log4j.Logger;import org.ofbiz.minerva.pool.ObjectPool;import org.ofbiz.minerva.pool.PoolObjectFactory;import org.ofbiz.minerva.pool.jdbc.xa.wrapper.TransactionListener;import org.ofbiz.minerva.pool.jdbc.xa.wrapper.XAConnectionImpl;import org.ofbiz.minerva.pool.jdbc.xa.wrapper.XADataSourceImpl;import org.ofbiz.minerva.pool.jdbc.xa.wrapper.XAResourceImpl;/** * Object factory for JDBC 2.0 standard extension XAConnections. You pool the * XAConnections instead of the java.sql.Connections since with vendor * conformant drivers, you don't have direct access to the java.sql.Connection, * and any work done isn't associated with the java.sql.Connection anyway. * <P><B>Note:</B> This implementation requires that the TransactionManager * be bound to a JNDI name.</P> * <P><B>Note:</B> This implementation has special handling for Minerva JDBC * 1/2 XA Wrappers. Namely, when a request comes in, if it is for a wrapper * connection and it has the same current transaction as a previous active * connection, the same previous connection will be returned. Otherwise, * you won't be able to share changes across connections like you can with * the native JDBC 2 Standard Extension implementations.</P> * * @author Aaron Mulder (ammulder@alumni.princeton.edu) * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * * REVISIONS: * 20010703 bill added code for transaction isolation @version $Rev: 5462 $ */public class XAConnectionFactory extends PoolObjectFactory { public static final int DEFAULT_ISOLATION = -1; private XADataSource source; private String userName; private String password; private int psCacheSize = 10; private boolean releaseOnCommit = false; private boolean saveStackTrace = false; private int transactionIsolation = DEFAULT_ISOLATION; private ConnectionEventListener listener, errorListener; private TransactionListener transListener; private ObjectPool pool; private final Map wrapperTx = Collections.synchronizedMap(new HashMap()); private final Map rms = Collections.synchronizedMap(new HashMap()); private TransactionManager tm; private static Logger log = Logger.getLogger(XAConnectionFactory.class); /** * Creates a new factory. You must set the XADataSource and * TransactionManager JNDI name before the factory can be used. */ public XAConnectionFactory() { final boolean trace = log.isDebugEnabled(); //wrapperTx = new HashMap(); //rms = new HashMap(); errorListener = new ConnectionEventListener() { public void connectionErrorOccurred(ConnectionEvent evt) { if (pool.isInvalidateOnError()) { pool.markObjectAsInvalid(evt.getSource()); } } public void connectionClosed(ConnectionEvent evt) { } }; listener = new ConnectionEventListener() { public void connectionErrorOccurred(ConnectionEvent evt) { if (pool.isInvalidateOnError()) { pool.markObjectAsInvalid(evt.getSource()); }// closeConnection(evt, XAResource.TMFAIL); } public void connectionClosed(ConnectionEvent evt) { closeConnection(evt, XAResource.TMSUCCESS); } private void closeConnection(ConnectionEvent evt, int status) { XAConnection con = (XAConnection) evt.getSource(); try { con.removeConnectionEventListener(listener); } catch (IllegalArgumentException e) { return; // Removed twice somehow? } Transaction trans = null; try { if (tm.getStatus() != Status.STATUS_NO_TRANSACTION) { trans = tm.getTransaction(); XAResource res = (XAResource) rms.remove(con); if (res != null) { trans.delistResource(res, status); if (trace) log.debug("delisted resource from TM - " + res); } // end of if () else { log.warn("no xares in rms for con " + con); } // end of else } } catch (Exception e) { log.error("Unable to deregister with TransactionManager", e); throw new RuntimeException("Unable to deregister with TransactionManager: " + e); } if (!(con instanceof XAConnectionImpl)) { // Real XAConnection -> not associated w/ transaction pool.releaseObject(con); } else { XAConnectionImpl xaCon = (XAConnectionImpl) con; if (!((XAResourceImpl) xaCon.getXAResource()).isTransaction()) { // Wrapper - we can only release it if there's no current transaction // Can't just check TM because con may have been committed but left open // so if there's a current transaction it may not apply to the con. if (trace) log.debug("XAConnectionImpl: " + xaCon + " has no current tx!"); try { xaCon.rollback(); } catch (SQLException e) { pool.markObjectAsInvalid(con); } pool.releaseObject(con); } else { // Still track errors, but don't try to close again. con.addConnectionEventListener(errorListener); } } } }; transListener = new TransactionListener() { public void transactionFinished(XAConnectionImpl con) { con.clearTransactionListener(); Object tx = wrapperTx.remove(con); //System.out.println("removing con: " + con + "from wrapperTx, tx: " + tx); if (tx != null) wrapperTx.remove(tx); try { con.removeConnectionEventListener(errorListener); } catch (IllegalArgumentException e) { // connection was not closed, but transaction ended if (!releaseOnCommit) { return; } else { rms.remove(con); pool.markObjectAsInvalid(con); con.forceClientConnectionsClose(); } } pool.releaseObject(con); } public void transactionFailed(XAConnectionImpl con) { con.clearTransactionListener(); Object tx = wrapperTx.remove(con); if (tx != null) wrapperTx.remove(tx); //System.out.println("removing con: " + con + "from wrapperTx, tx: " + tx); pool.markObjectAsInvalid(con); try { con.removeConnectionEventListener(errorListener); } catch (IllegalArgumentException e) { if (!releaseOnCommit) { return; } else { rms.remove(con); con.forceClientConnectionsClose(); } } pool.releaseObject(con); } }; } /** * Sets the user name used to generate XAConnections. This is optional, * and will only be used if present. */ public void setUser(String userName) { this.userName = userName; } /** * Gets the user name used to generate XAConnections. */ public String getUser() { return userName; } /** * Sets the password used to generate XAConnections. This is optional, * and will only be used if present. */ public void setPassword(String password) { this.password = password; } /** * Gets the password used to generate XAConnections. */ public String getPassword() { return password; } public boolean getReleaseOnCommit() { return releaseOnCommit; } public void setReleaseOnCommit(boolean rel) { releaseOnCommit = rel; } /** * Sets the number of PreparedStatements to be cached for each * Connection. Your DB product may impose a limit on the number * of open PreparedStatements. The default value is 10. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -