User: mulder
Date: 00/08/30 05:41:52
Modified: src/main/org/jboss/minerva/factories
XAConnectionFactory.java
Log:
Updates to Minerva.
- You can kick an object out of the pool, and set it to do so
automatically when error events are received
- You can enable or disable Minerva logging with a jboss.jcml setting
- JDBC 1/2 wrappers return the same connection for multiple requests
within one transaction
- Remove some .* imports
Still outstanding:
- You can't keep a connection open across commits/rollbacks
- Think about removing "xa." and "jdbc." prefixes from JNDI names
- Think about renaming services to "Minerva XA" and "Minerva JDBC" or
something along those lines to make logging more helpful
Revision Changes Path
1.6 +58 -15
jboss/src/main/org/jboss/minerva/factories/XAConnectionFactory.java
Index: XAConnectionFactory.java
===================================================================
RCS file:
/products/cvs/ejboss/jboss/src/main/org/jboss/minerva/factories/XAConnectionFactory.java,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -r1.5 -r1.6
--- XAConnectionFactory.java 2000/08/18 03:21:08 1.5
+++ XAConnectionFactory.java 2000/08/30 12:41:51 1.6
@@ -7,13 +7,22 @@
package org.jboss.minerva.factories;
import java.io.PrintWriter;
-import java.sql.*;
-import javax.sql.*;
-import javax.naming.*;
-import javax.transaction.*;
-import javax.transaction.xa.*;
-import org.jboss.minerva.pools.*;
-import org.jboss.minerva.xa.*;
+import java.sql.SQLException;
+import java.util.HashMap;
+import javax.sql.ConnectionEvent;
+import javax.sql.ConnectionEventListener;
+import javax.sql.XAConnection;
+import javax.sql.XADataSource;
+import javax.naming.InitialContext;
+import javax.naming.NamingException;
+import javax.transaction.Status;
+import javax.transaction.Transaction;
+import javax.transaction.TransactionManager;
+import javax.transaction.xa.XAResource;
+import org.jboss.minerva.pools.ObjectPool;
+import org.jboss.minerva.pools.PoolObjectFactory;
+import org.jboss.minerva.xa.TransactionListener;
+import org.jboss.minerva.xa.XAConnectionImpl;
import org.jboss.logging.Logger;
/**
@@ -23,7 +32,13 @@
* 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>
- * @version $Revision: 1.5 $
+ * <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>
+ * @version $Revision: 1.6 $
* @author Aaron Mulder ([EMAIL PROTECTED])
*/
public class XAConnectionFactory extends PoolObjectFactory {
@@ -36,6 +51,7 @@
private TransactionListener transListener;
private ObjectPool pool;
private PrintWriter log;
+ private HashMap wrapperTx;
/**
* Creates a new factory. You must set the XADataSource and
@@ -43,6 +59,7 @@
*/
public XAConnectionFactory() throws NamingException {
ctx = new InitialContext();
+ wrapperTx = new HashMap();
listener = new ConnectionEventListener() {
public void connectionErrorOccurred(ConnectionEvent evt) {
closeConnection(evt, XAResource.TMFAIL);
@@ -54,12 +71,12 @@
private void closeConnection(ConnectionEvent evt, int status) {
XAConnection con = (XAConnection)evt.getSource();
- boolean transaction = false;
+ Transaction trans = null;
try {
TransactionManager tm =
(TransactionManager)ctx.lookup(tmJndiName);
if(tm.getStatus() != Status.STATUS_NO_TRANSACTION) {
- transaction = true;
- tm.getTransaction().delistResource(con.getXAResource(),
status);
+ trans = tm.getTransaction();
+ trans.delistResource(con.getXAResource(), status);
}
} catch(Exception e) {
Logger.exception(e);
@@ -71,7 +88,7 @@
// Real XAConnection -> not associated w/ transaction
pool.releaseObject(con);
} else {
- if(!transaction) {
+ if(trans == null) {
// Wrapper - we can only release it if there's no current
transaction
((XAConnectionImpl)con).rollback();
pool.releaseObject(con);
@@ -82,6 +99,9 @@
transListener = new TransactionListener() {
public void transactionFinished(XAConnectionImpl con) {
con.clearTransactionListener();
+ Object tx = wrapperTx.remove(con);
+ if(tx != null)
+ wrapperTx.remove(tx);
pool.releaseObject(con);
}
};
@@ -174,10 +194,12 @@
*/
public Object prepareObject(Object pooledObject) {
XAConnection con = (XAConnection)pooledObject;
+ TransactionManager tm = null;
+ Transaction trans = null;
try {
- TransactionManager tm = (TransactionManager)ctx.lookup(tmJndiName);
+ tm = (TransactionManager)ctx.lookup(tmJndiName);
if(tm.getStatus() != Status.STATUS_NO_TRANSACTION) {
- Transaction trans = tm.getTransaction();
+ trans = tm.getTransaction();
trans.enlistResource(con.getXAResource());
con.addConnectionEventListener(listener);
if(log != null) log.println("Enlisted with transaction.");
@@ -188,8 +210,13 @@
Logger.exception(e);
throw new RuntimeException("Unable to register with TransactionManager:
"+e);
}
- if(con instanceof XAConnectionImpl)
+ if(con instanceof XAConnectionImpl) {
((XAConnectionImpl)con).setTransactionListener(transListener);
+ if(trans != null) {
+ wrapperTx.put(con, trans); // For JDBC 1/2 wrappers, remember which
+ wrapperTx.put(trans, con); // connection goes with a given
transaction
+ }
+ }
return con;
}
@@ -201,5 +228,21 @@
try {
con.close();
} catch(SQLException e) {}
+ }
+
+ /**
+ * If a new object is requested and it is a JDBC 1/2 wrapper connection
+ * in the same Transaction as an existing connection, return that same
+ * connection.
+ */
+ public Object isUniqueRequest() {
+ try {
+ TransactionManager tm = (TransactionManager)ctx.lookup(tmJndiName);
+ if(tm.getStatus() != Status.STATUS_NO_TRANSACTION) {
+ Transaction trans = tm.getTransaction();
+ return wrapperTx.get(trans);
+ }
+ } catch(Exception e) {}
+ return null;
}
}