db-derby-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From d..@apache.org
Subject svn commit: r389570 - in /db/derby/code/trunk/java: engine/org/apache/derby/jdbc/ testing/org/apache/derbyTesting/functionTests/master/
Date Tue, 28 Mar 2006 18:25:49 GMT
Author: djd
Date: Tue Mar 28 10:25:47 2006
New Revision: 389570

URL: http://svn.apache.org/viewcvs?rev=389570&view=rev
Log:
DERBY-1155 Introduced new class EmbedXARessource. This class implements XAResources. I have moved all XAResource methods to this class.

Modified classes
EmbedXAConnection
Removed all the XAResource methods.
XATransactionState
This class now uses EmbedXAResource (earlier it was using EmbedXAConnection because it also had implementation of XAResource)

Patch contributed by Anurag Shekhar - anurag.shekhar@sun.com

Added:
    db/derby/code/trunk/java/engine/org/apache/derby/jdbc/EmbedXAResource.java   (with props)
Modified:
    db/derby/code/trunk/java/engine/org/apache/derby/jdbc/EmbedXAConnection.java
    db/derby/code/trunk/java/engine/org/apache/derby/jdbc/XATransactionState.java
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/checkDataSource.out
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/checkDataSource30.out

Modified: db/derby/code/trunk/java/engine/org/apache/derby/jdbc/EmbedXAConnection.java
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/engine/org/apache/derby/jdbc/EmbedXAConnection.java?rev=389570&r1=389569&r2=389570&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/jdbc/EmbedXAConnection.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/jdbc/EmbedXAConnection.java Tue Mar 28 10:25:47 2006
@@ -20,35 +20,19 @@
 
 package org.apache.derby.jdbc;
 
-import org.apache.derby.iapi.store.access.xa.XAXactId;
-import org.apache.derby.iapi.store.access.xa.XAResourceManager;
-import org.apache.derby.iapi.store.access.XATransactionController;
 import org.apache.derby.impl.jdbc.Util;
-import org.apache.derby.impl.jdbc.EmbedConnection;
-import org.apache.derby.impl.jdbc.TransactionResourceImpl;
-import org.apache.derby.iapi.error.StandardException;
 import org.apache.derby.iapi.jdbc.EngineConnection;
 import org.apache.derby.iapi.jdbc.ResourceAdapter;
-import org.apache.derby.iapi.jdbc.BrokeredConnection;
-
-import org.apache.derby.iapi.services.context.ContextManager;
-import org.apache.derby.iapi.services.context.ContextService;
-import org.apache.derby.iapi.services.sanity.SanityManager;
 
 import org.apache.derby.iapi.reference.SQLState;
 import org.apache.derby.iapi.reference.JDBC30Translation;
-import org.apache.derby.iapi.services.info.JVMInfo;
 
 import java.sql.Connection;
 import java.sql.SQLException;
 import java.sql.Statement;
 import java.sql.PreparedStatement;
 import java.sql.CallableStatement;
-
-/* import jta packages */
-import javax.transaction.xa.Xid;
 import javax.transaction.xa.XAResource;
-import javax.transaction.xa.XAException;
 
 /** -- jdbc 2.0. extension -- */
 import javax.sql.XAConnection;
@@ -56,21 +40,16 @@
 /** 
  */
 final class EmbedXAConnection extends EmbedPooledConnection
-		implements XAConnection, XAResource
+		implements XAConnection
 
 {
 
-
-	final ResourceAdapter ra;
-
-	XAXactId	currentXid;
-
+        private EmbedXAResource xaRes;
 
 	EmbedXAConnection(EmbeddedDataSource ds, ResourceAdapter ra, String u, String p, boolean requestPassword) throws SQLException
 	{
 		super(ds, u, p, requestPassword);
-		this.ra = ra;
-
+                xaRes = new EmbedXAResource (this, ra);
 	}
 
 	/*
@@ -79,636 +58,7 @@
 
 	public final synchronized XAResource getXAResource() throws SQLException {
 		checkActive();
-		return this;
-	}
-
-	/*
-	** XAResource methods
-	*/
-
-	/**
-		Start work on behalf of a transaction branch specified in xid If TMJOIN
-		is specified, the start is for joining a transaction previously seen by
-		the resource manager. If TMRESUME is specified, the start is to resume
-		a suspended transaction specified in the parameter xid. If neither
-		TMJOIN nor TMRESUME is specified and the transaction specified by xid
-		has previously been seen by the resource manager, the resource manager
-		throws the XAException exception with XAER_DUPID error code.
-
-		@param xid A global transaction identifier to be associated with the
-				resource 
-		@param flags One of TMNOFLAGS, TMJOIN, or TMRESUME 
-
-		@exception XAException An error has occurred. Possible exceptions are
-		XA_RB*, XAER_RMERR, XAER_RMFAIL, XAER_DUPID, XAER_OUTSIDE, XAER_NOTA,
-		XAER_INVAL, or XAER_PROTO.
-	 */
-	public final synchronized void start(Xid xid, int flags) throws XAException
-	{
-		checkXAActive();
-
-		// JDBC 3.0 section 12.3 - One transaction associated with a XAConnection
-		if (currentXid != null)
-			throw new XAException(XAException.XAER_PROTO);
-
-		// ensure immtable and correct equals method.
-		XAXactId xid_im = new XAXactId(xid);
-
-		XATransactionState tranState = getTransactionState(xid_im);
-
-		switch (flags) {
-		case XAResource.TMNOFLAGS:
-			if (tranState != null)
-				throw new XAException(XAException.XAER_DUPID);
-
-			try {
-
-				if (realConnection == null) {
-					openRealConnection();
-
-					if (currentConnectionHandle != null) {
-
-						// since this is a new connection, set its complete
-						// state according to the application's Connection
-						// handle view of the world.
-						currentConnectionHandle.setState(true);
-						realConnection.setApplicationConnection(currentConnectionHandle);
-					}
-
-				} else {
-
-					// XAResource.start() auto commits in DB2 when in auto commit mode.
-					if (currentConnectionHandle != null) {
-						if (currentConnectionHandle.getAutoCommit())
-							currentConnectionHandle.rollback();
-					}
-					if (!realConnection.transactionIsIdle())
-						throw new XAException(XAException.XAER_OUTSIDE);
-
-					if (currentConnectionHandle != null) {
-						// It is possible that the isolation level state in connection
-						// handle has gotten out of sync with the real isolation level.
-						// This can happen if SLQ instead of JDBC api has been used to
-						// set the isolation level. The code below will check if isolation
-						// was set using JDBC or SQL and if yes, then it will update the
-						// isolation state in BrokeredConnection with EmbedConnection's
-						// isolation level.
-						currentConnectionHandle.getIsolationUptoDate();
-						// we have a current handle so we need to keep
-						// the connection state of the current connection.
-						currentConnectionHandle.setState(true);
-
-						// At the local to global transition we need to discard
-						// and close any open held result sets, a rollback will do this.
-						realConnection.rollback();
-					} else {
-						resetRealConnection();
-					}
-
-				}
-
-				// Global connections are always in auto commit false mode.
-				realConnection.setAutoCommit(false);
-
-				// and holdability false (cannot hold cursors across XA transactions.
-				realConnection.setHoldability(JDBC30Translation.CLOSE_CURSORS_AT_COMMIT);
-
-				realConnection.getLanguageConnection().
-					getTransactionExecute().createXATransactionFromLocalTransaction(
-						 xid_im.getFormatId(),
-						 xid_im.getGlobalTransactionId(),
-						 xid_im.getBranchQualifier());
-
-
-			} catch (StandardException se) {
-				throw wrapInXAException(se);
-			} catch (SQLException sqle) {
-				throw wrapInXAException(sqle);
-			}
-
-
-			if (!ra.addConnection(xid_im, new XATransactionState(realConnection.getContextManager(), realConnection, this, xid_im)))
-				throw new XAException(XAException.XAER_DUPID);
-
-			break;
-
-		case XAResource.TMRESUME:
-		case XAResource.TMJOIN:
-			if (tranState == null)
-				throw new XAException(XAException.XAER_NOTA);
-
-			tranState.start(this, flags);
-
-			if (tranState.conn != realConnection) {
-
-				if (realConnection != null) {
-
-					if (!realConnection.transactionIsIdle())
-						throw new XAException(XAException.XAER_OUTSIDE);
-
-					closeUnusedConnection(realConnection);
-				}
-				realConnection = tranState.conn;
-
-				if (currentConnectionHandle != null) {
-
-					try {
-						// only reset the non-transaction specific Connection state.
-						currentConnectionHandle.setState(false);
-						realConnection.setApplicationConnection(currentConnectionHandle);
-					} catch (SQLException sqle) {
-						throw wrapInXAException(sqle);
-					}
-				}
-
-			}
-
-
-			break;
-
-		default:
-			throw new XAException(XAException.XAER_INVAL);
-		}
-
-		currentXid = xid_im;
-	}
-
-
-	/**
-		Ends the work performed on behalf of a transaction branch. The resource
-		manager disassociates the XA resource from the transaction branch
-		specified and let the transaction be completed.  
-
-		<p> If TMSUSPEND is specified in flags, the transaction branch is
-		temporarily suspended in incomplete state. The transaction context 
-		is in suspened state and must be resumed via start with TMRESUME
-		specified. 
-
-		<p> If TMFAIL is specified, the portion of work has failed. The
-		resource manager may mark the transaction as rollback-only 
-
-		<p> If TMSUCCESS is specified, the portion of work has completed
-		successfully. 
-
-		@param xid A global transaction identifier that is the same as what was
-				used previously in the start method. 
-		@param flags One of TMSUCCESS, TMFAIL, or TMSUSPEND
-
-		@exception XAException An error has occurred. 
-		Possible XAException values are XAER_RMERR, XAER_RMFAILED, XAER_NOTA,
-		XAER_INVAL, XAER_PROTO, or XA_RB*. 
-	 */
-	public final synchronized void end(Xid xid, int flags) throws XAException
-	{
-		checkXAActive();
-
-		try {
-			// It is possible that the isolation level state in connection
-			// handle has gotten out of sync with the real isolation level.
-			// This can happen if SLQ instead of JDBC api has been used to
-			// set the isolation level. The code below will check if isolation
-			// was set using JDBC or SQL and if yes, then it will update the
-			// isolation state in BrokeredConnection with EmbedConnection's
-			// isolation level.
-			if (currentConnectionHandle != null)
-				currentConnectionHandle.getIsolationUptoDate();
-		} catch (SQLException sqle) {
-			throw wrapInXAException(sqle);
-		}
-
-		// ensure immtable and correct equals method.
-		XAXactId xid_im = new XAXactId(xid);
-
-		boolean endingCurrentXid = false;
-
-		// must match the Xid from start()
-		if (currentXid != null) {
-			if (!currentXid.equals(xid_im))
-				throw new XAException(XAException.XAER_PROTO);
-			endingCurrentXid = true;
-		}
-
-		XATransactionState tranState = getTransactionState(xid_im);
-		if (tranState == null)
-			throw new XAException(XAException.XAER_NOTA);
-
-		boolean rollbackOnly = tranState.end(this, flags, endingCurrentXid);
-
-		// RESOLVE - what happens to the connection on a fail
-		// where we are not ending the current XID.
-		if (endingCurrentXid) {
-			currentXid = null;
-
-			realConnection = null;
-		}
-
-		if (rollbackOnly)
-			throw new XAException(tranState.rollbackOnlyCode); 
-
-	}
-
-	/**
-		Ask the resource manager to prepare for a transaction commit of the
-		transaction specified in xid. 
-
-		@param xid A global transaction identifier
-
-		@return A value indicating the resource manager's vote on the outcome
-		of the transaction. The possible values are: XA_RDONLY or XA_OK. If the
-		resource manager wants to roll back the transaction, it should do so by
-		raising an appropriate XAException in the prepare method.
-
-		@exception XAException An error has occurred. Possible exception values
-		are: XA_RB*, XAER_RMERR, XAER_RMFAIL, XAER_NOTA, XAER_INVAL, or
-		XAER_PROTO.
-
-	 */
-	public final synchronized int prepare(Xid xid) throws XAException
-	{
-		checkXAActive();
-
-		// ensure immtable and correct equals method.
-		XAXactId xid_im = new XAXactId(xid);
-
-		XATransactionState tranState = getTransactionState(xid_im);
-
-		if (tranState == null) {
-			XAResourceManager rm = ra.getXAResourceManager();
-
-			ContextManager inDoubtCM = rm.find(xid);
-
-			// RM also does not know about this xid.
-			if (inDoubtCM == null)
-				throw new XAException(XAException.XAER_NOTA);
-
-			// cannot prepare in doubt transactions
-			throw new XAException(XAException.XAER_PROTO);
-
-		}
-
-		synchronized (tranState) {
-
-			checkUserCredentials(tranState.creatingResource);
-
-			// Check the transaction is no associated with
-			// any XAResource.
-			switch (tranState.associationState) {
-			case XATransactionState.T0_NOT_ASSOCIATED:
-				break;
-
-			case XATransactionState.TRO_FAIL:
-				throw new XAException(tranState.rollbackOnlyCode);
-
-			default:
-				throw new XAException(XAException.XAER_PROTO);
-			}
-
-			if (tranState.suspendedList != null && tranState.suspendedList.size() != 0)
-				throw new XAException(XAException.XAER_PROTO);
-
-			if (tranState.isPrepared)
-				throw new XAException(XAException.XAER_PROTO);
-
-			EmbedConnection conn = tranState.conn; 
-
-			try {
-
-				int ret = conn.xa_prepare();
-
-				if (ret == XATransactionController.XA_OK) {
-					tranState.isPrepared = true;
-
-					return XAResource.XA_OK;
-				} else {
-
-					returnConnectionToResource(tranState, xid_im);
-					return XAResource.XA_RDONLY;
-				}
-			} catch (SQLException sqle) {
-				throw wrapInXAException(sqle);
-			}
-		}
-	
-	}
-
-	/**
-		Commit the global transaction specified by xid.
-		@param xid A global transaction identifier
-		@param onePhase If true, the resource manager should use a one-phase
-				commit protocol to commit the work done on behalf of xid.
-
-		@exception XAException An error has occurred. Possible XAExceptions are
-				XA_HEURHAZ, XA_HEURCOM, XA_HEURRB, XA_HEURMIX, XAER_RMERR,
-				XAER_RMFAIL, XAER_NOTA, XAER_INVAL, or XAER_PROTO.  
-				<P>If the resource manager did not commit the transaction and
-				the paramether onePhase is set to true, the resource manager 
-				may throw one of the XA_RB* exceptions. Upon return, the
-				resource manager has rolled back the branch's work and has 
-				released all held resources.
-	*/
-	public final synchronized void commit(Xid xid, boolean onePhase) throws XAException
-	{
-		checkXAActive();
-
-		// ensure immtable and correct equals method.
-		XAXactId xid_im = new XAXactId(xid);
-
-		XATransactionState tranState = getTransactionState(xid_im);
-
-		if (tranState == null) {
-
-			XAResourceManager rm = ra.getXAResourceManager();
-
-			ContextManager inDoubtCM = rm.find(xid);
-
-			// RM also does not know about this xid.
-			if (inDoubtCM == null)
-				throw new XAException(XAException.XAER_NOTA);
-
-			ContextService csf = ContextService.getFactory();
-
-			csf.setCurrentContextManager(inDoubtCM);
-			try
-			{
-				rm.commit(inDoubtCM, xid_im, onePhase);
-
-				// close the connection/transaction since it can never be used again.
-				inDoubtCM.cleanupOnError(StandardException.closeException());
-				return;
-			}
-			catch (StandardException se)
-			{
-				// The rm threw an exception, clean it up in the approprate
-				// context.  There is no transactionResource to handle the
-				// exception for us.
-				inDoubtCM.cleanupOnError(se);
-				throw wrapInXAException(se);
-			}
-			finally
-			{
-				csf.resetCurrentContextManager(inDoubtCM);
-			}
-
-		}
-
-		synchronized (tranState) {
-			checkUserCredentials(tranState.creatingResource);
-		
-			// Check the transaction is no associated with
-			// any XAResource.
-			switch (tranState.associationState) {
-			case XATransactionState.T0_NOT_ASSOCIATED:
-				break;
-
-			case XATransactionState.TRO_FAIL:
-				throw new XAException(tranState.rollbackOnlyCode);
-
-			default:
-				throw new XAException(XAException.XAER_PROTO);
-			}
-
-			if (tranState.suspendedList != null && tranState.suspendedList.size() != 0)
-				throw new XAException(XAException.XAER_PROTO);
-
-			if (tranState.isPrepared == onePhase)
-				throw new XAException(XAException.XAER_PROTO);
-
-			EmbedConnection conn = tranState.conn; 
-
-			try {
-
-				conn.xa_commit(onePhase);
-
-			} catch (SQLException sqle) {
-				throw wrapInXAException(sqle);
-			} finally {
-				returnConnectionToResource(tranState, xid_im);
-			}
-		}
-	}
-
-	/** 
-		Inform the resource manager to roll back work done on behalf of a
-		transaction branch
-
-		@param xid A global transaction identifier
-		@exception XAException - An error has occurred 
-	*/
-	public final synchronized void rollback(Xid xid) throws XAException
-	{
-		checkXAActive();
-
-		// ensure immtable and correct equals method.
-		XAXactId xid_im = new XAXactId(xid);
-
-		XATransactionState tranState = getTransactionState(xid_im);
-
-		if (tranState == null) {
-			XAResourceManager rm = ra.getXAResourceManager();
-
-			ContextManager inDoubtCM = rm.find(xid);
-
-			// RM also does not know about this xid.
-			if (inDoubtCM == null)
-				throw new XAException(XAException.XAER_NOTA);
-
-			ContextService csf = ContextService.getFactory();
-
-			csf.setCurrentContextManager(inDoubtCM);
-			try
-			{
-				rm.rollback(inDoubtCM, xid_im);
-
-				// close the connection/transaction since it can never be used again.
-				inDoubtCM.cleanupOnError(StandardException.closeException());
-				return;
-			}
-			catch (StandardException se)
-			{
-				// The rm threw an exception, clean it up in the approprate
-				// context.  There is no transactionResource to handle the
-				// exception for us.
-				inDoubtCM.cleanupOnError(se);
-				throw wrapInXAException(se);
-			}
-			finally
-			{
-				csf.resetCurrentContextManager(inDoubtCM);
-			}
-
-		}
-
-		synchronized (tranState) {
-		
-			// Check the transaction is no associated with
-			// any XAResource.
-			switch (tranState.associationState) {
-			case XATransactionState.T0_NOT_ASSOCIATED:
-			case XATransactionState.TRO_FAIL:
-				break;
-				
-			default:
-				throw new XAException(XAException.XAER_PROTO);
-			}
-
-			if (tranState.suspendedList != null && tranState.suspendedList.size() != 0)
-				throw new XAException(XAException.XAER_PROTO);
-
-			checkUserCredentials(tranState.creatingResource);
-
-			try {
-
-				tranState.conn.xa_rollback();
-			} catch (SQLException sqle) {
-				throw wrapInXAException(sqle);
-			} finally {
-				returnConnectionToResource(tranState, xid_im);
-			}
-		}
-	}
-
-	/**
-		Obtain a list of prepared transaction branches from a resource
-		manager. The transaction manager calls this method during recovery to
-		obtain the list of transaction branches that are currently in prepared
-		or heuristically completed states. 
-
-		@param flag One of TMSTARTRSCAN, TMENDRSCAN, TMNOFLAGS. TMNOFLAGS must
-		be used when no other flags are set in flags.
-
-		@return The resource manager returns zero or more XIDs for the
-		transaction branches that are currently in a prepared or heuristically
-		completed state. If an error occurs during the operation, the resource
-		manager should throw the appropriate XAException.
-
-		@exception XAException An error has occurred. Possible values are
-		XAER_RMERR, XAER_RMFAIL, XAER_INVAL, and XAER_PROTO.
-
-	*/
-	public final synchronized Xid[] recover(int flag) throws XAException
-	{
-		checkXAActive();
-
-		try
-		{
-			return ra.getXAResourceManager().recover(flag);
-		}
-		catch (StandardException se)
-		{
-			throw wrapInXAException(se);
-		}
-	}
-
-	/**
-		Tell the resource manager to forget about a heuristically completed
-		transaction branch. 
-
-		@param xid A global transaction identifier
-		@exception XAException An error has occurred. Possible exception values
-		are XAER_RMERR, XAER_RMFAIL, XAER_NOTA, XAER_INVAL, or XAER_PROTO.
-	 */
-	public final synchronized void forget(Xid xid) throws XAException {
-
-		checkXAActive();
-
-		// ensure immtable and correct equals method.
-		XAXactId xid_im = new XAXactId(xid);
-
-		XATransactionState tranState = getTransactionState(xid_im);
-		if (tranState == null) {
-			XAResourceManager rm = ra.getXAResourceManager();
-
-			ContextManager inDoubtCM = rm.find(xid);
-
-			// RM also does not know about this xid.
-			if (inDoubtCM == null)
-				throw new XAException(XAException.XAER_NOTA);
-
-			ContextService csf = ContextService.getFactory();
-
-			csf.setCurrentContextManager(inDoubtCM);
-			try
-			{
-				rm.forget(inDoubtCM, xid_im);
-
-				// close the connection/transaction since it can never be used again.
-				inDoubtCM.cleanupOnError(StandardException.closeException());
-				return;
-			}
-			catch (StandardException se)
-			{
-				// The rm threw an exception, clean it up in the approprate
-				// context.  There is no transactionResource to handle the
-				// exception for us.
-				inDoubtCM.cleanupOnError(se);
-				throw wrapInXAException(se);
-			}
-			finally
-			{
-				csf.resetCurrentContextManager(inDoubtCM);
-			}
-
-		}
-
-		throw new XAException(tranState.isPrepared ? XAException.XAER_NOTA : XAException.XAER_PROTO);
-
-	}
-	/** 
-		This method is called to determine if the resource manager instance
-		represented by the target object is the same as the resouce manager
-		instance represented by the parameter xares.
-
-		@param xares An XAResource object whose resource manager instance is to
-		be compared with the resource manager instance of the target object.
-
-		@return true if it's the same RM instance; otherwise false.
- 		@exception XAException An error has occurred. Possible exception values
-		are XAER_RMERR, XAER_RMFAIL. 
-	 */
-	public final synchronized boolean isSameRM(XAResource xares) throws XAException {
-		checkXAActive();
-
-		if (xares instanceof EmbedXAConnection) {
-
-			return ra == ((EmbedXAConnection) xares).ra;
-		}
-
-		return false;
-	}
-	/**
-		Obtain the current transaction timeout value set for this XAResource
-		instance. If XAResource.setTransactionTimeout was not use prior to
-		invoking this method, the return value is the default timeout set for
-		the resource manager; otherwise, the value used in the previous
-		setTransactionTimeout call is returned. 
-
-		@return the transaction timeout value in seconds.
-	 */
-	public int getTransactionTimeout()
-	{
-		return 0;
-	}
-
-	/**
-		Set the current transaction timeout value for this XAResource
-		instance. Once set, this timeout value is effective until
-		setTransactionTimeout is invoked again with a different value. To reset
-		the timeout value to the default value used by the resource manager,
-		set the value to zero. If the timeout operation is performed
-		successfully, the method returns true; otherwise false. If a resource
-		manager does not support transaction timeout value to be set
-		explicitly, this method returns false.
-
-		@param seconds the transaction timeout value in seconds.
-		@return true if transaction timeout value is set successfully;
-		otherwise false. 
-
-		@exception XAException - An error has occurred. Possible exception
-		values are XAER_RMERR, XAER_RMFAIL, or XAER_INVAL.
-	 */
-	public boolean setTransactionTimeout(int seconds)
-	{
-		return false;
+		return xaRes;
 	}
 
 	/*
@@ -718,7 +68,7 @@
 		Allow control over setting auto commit mode.
 	*/
 	public void checkAutoCommit(boolean autoCommit) throws SQLException {
-		if (autoCommit && (currentXid != null))
+		if (autoCommit && (xaRes.getCurrentXid () != null))
 			throw Util.generateCsSQLException(SQLState.CANNOT_AUTOCOMMIT_XA);
 
 		super.checkAutoCommit(autoCommit);
@@ -729,7 +79,7 @@
 	public void checkHoldCursors(int holdability) throws SQLException {
 
 		if (holdability == JDBC30Translation.HOLD_CURSORS_OVER_COMMIT) {		
-			if (currentXid != null)
+			if (xaRes.getCurrentXid () != null)
 				throw Util.generateCsSQLException(SQLState.CANNOT_HOLD_CURSOR_XA);
 		}
 
@@ -741,7 +91,7 @@
 	*/
 	public void checkSavepoint() throws SQLException {
 
-		if (currentXid != null)
+		if (xaRes.getCurrentXid () != null)
 			throw Util.generateCsSQLException(SQLState.CANNOT_ROLLBACK_XA);
 
 		super.checkSavepoint();
@@ -752,7 +102,7 @@
 	*/
 	public void checkRollback() throws SQLException {
 
-		if (currentXid != null)
+		if (xaRes.getCurrentXid () != null)
 			throw Util.generateCsSQLException(SQLState.CANNOT_ROLLBACK_XA);
 
 		super.checkRollback();
@@ -762,7 +112,7 @@
 	*/
 	public void checkCommit() throws SQLException {
 
-		if (currentXid != null)
+		if (xaRes.getCurrentXid () != null)
 			throw Util.generateCsSQLException(SQLState.CANNOT_COMMIT_XA);
 
 		super.checkCommit();
@@ -773,7 +123,7 @@
 		Connection handle;
 
 		// Is this just a local transaction?
-		if (currentXid == null) {
+		if (xaRes.getCurrentXid () == null) {
 			handle = super.getConnection();
 		} else {
 
@@ -845,148 +195,5 @@
 		currentConnectionHandle.setState(true);
 
 		return realConnection;
-	}
-
-
-	/*
-	** Class specific methods
-	*/
-
-	private XATransactionState getTransactionState(XAXactId xid_im) {
-
-		return (XATransactionState) ra.findConnection(xid_im);
-	}
-
-
-	/**
-		Map a SQL exception to appropriate XAException.
-		Return the mapped XAException.
-	 */
-	private static XAException wrapInXAException(SQLException se)
-    {
-		// Map interesting exceptions to XAException
-		String sqlstate = se.getSQLState();
-		String message = se.getMessage();
-
-		XAException xae;
-
-		if (sqlstate == null)
-		{
-			// no idea what was wrong, throw non-descript error. 
-			if (message != null)
-				xae = new XAException(message);
-			else
-				xae = new XAException(XAException.XAER_RMERR);
-		}
-		else if (sqlstate.equals(StandardException.getSQLStateFromIdentifier(SQLState.STORE_XA_XAER_DUPID)))
-			xae = new XAException(XAException.XAER_DUPID);
-		else if (sqlstate.equals(StandardException.getSQLStateFromIdentifier(SQLState.STORE_XA_PROTOCOL_VIOLATION)))
-			xae = new XAException(XAException.XA_RBPROTO);
-		else if (sqlstate.equals(SQLState.DEADLOCK))
-			xae = new XAException(XAException.XA_RBDEADLOCK);
-		else if (sqlstate.equals(SQLState.LOCK_TIMEOUT))
-			xae = new XAException(XAException.XA_RBTIMEOUT);
-		else if (message != null)
-			xae = new XAException(message);
-		else
-			xae = new XAException(XAException.XAER_RMERR);
-
-		if (JVMInfo.JDK_ID >= JVMInfo.J2SE_14)
-			xae.initCause(se);
-		return xae;
-	}
-	/**
-		Map a Standard exception to appropriate XAException.
-		Return the mapped XAException.
-	 */
-	private static XAException wrapInXAException(StandardException se)
-	{
-		return wrapInXAException(TransactionResourceImpl.wrapInSQLException((SQLException) null, se));
-	}
-
-	void removeXATransaction(XAXactId xid_im) {
-		XATransactionState tranState = (XATransactionState) ra.removeConnection(xid_im);
-		if (tranState != null)
-			tranState.popMe();
-	}
-
-
-	/**
-		Return an underlying connection object back to its XAResource
-		if possible. If not close the connection.
-	*/
-	private void returnConnectionToResource(XATransactionState tranState, XAXactId xid_im) {
-
-		removeXATransaction(xid_im);
-
-		synchronized (tranState) {
-			// global transaction is over.
-			tranState.associationState = XATransactionState.TC_COMPLETED;
-			tranState.notifyAll();
-
-			EmbedConnection conn = tranState.conn;
-
-			// already set in its own resource
-			// or can it be returned to its original resource?
-			if ((tranState.creatingResource.realConnection == conn) ||
-				(tranState.creatingResource.realConnection == null)) {
-
-				tranState.creatingResource.realConnection = conn;
-
-				BrokeredConnection handle = tranState.creatingResource.currentConnectionHandle;
-
-				conn.setApplicationConnection(handle);
-
-				if (handle != null) {
-					try {
-						handle.setState(true);
-					} catch (SQLException sqle) {
-
-						// couldn't reset the connection
-						closeUnusedConnection(tranState.conn);
-						tranState.creatingResource.realConnection = null;
-					}
-				}
-				return;
-			}
-		}
-
-		// nowhere to place it, close it.
-		closeUnusedConnection(tranState.conn);
-	}
-
-	private void checkXAActive() throws XAException {
-
-		try {
-			checkActive();
-		} catch (SQLException sqle) {
-			throw wrapInXAException(sqle);
-		}
-	}
-
-	private void checkUserCredentials(EmbedXAConnection original)
-		throws XAException {
-
-		if (original == this)
-			return;
-
-		if (original.getPassword().equals(getPassword()) && (original.getUsername().equals(getUsername())))
-			return;
-
-
-		throw new XAException(XAException.XA_RBINTEGRITY);
-	}
-
-	/**
-		Close  an underlying connection object when there is
-		no active XAResource to hand it to.
-	*/
-	private static void closeUnusedConnection(EmbedConnection conn) {
-		if (conn != null) {
-			try {
-				conn.close();
-			} catch (SQLException sqle) {
-			}
-		}
 	}
 }

Added: db/derby/code/trunk/java/engine/org/apache/derby/jdbc/EmbedXAResource.java
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/engine/org/apache/derby/jdbc/EmbedXAResource.java?rev=389570&view=auto
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/jdbc/EmbedXAResource.java (added)
+++ db/derby/code/trunk/java/engine/org/apache/derby/jdbc/EmbedXAResource.java Tue Mar 28 10:25:47 2006
@@ -0,0 +1,829 @@
+/*
+
+   Derby - Class org.apache.derby.jdbc.EmbedXAResource
+
+   Copyright 2003, 2006 The Apache Software Foundation or its licensors, as applicable.
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+ */
+
+package org.apache.derby.jdbc;
+
+import java.sql.SQLException;
+import javax.transaction.xa.XAResource;
+import javax.transaction.xa.Xid;
+import javax.transaction.xa.XAException;
+
+import org.apache.derby.iapi.error.StandardException;
+import org.apache.derby.iapi.jdbc.BrokeredConnection;
+import org.apache.derby.iapi.jdbc.ResourceAdapter;
+import org.apache.derby.iapi.reference.SQLState;
+import org.apache.derby.iapi.reference.JDBC30Translation;
+import org.apache.derby.iapi.services.context.ContextManager;
+import org.apache.derby.iapi.services.context.ContextService;
+import org.apache.derby.iapi.services.info.JVMInfo;
+import org.apache.derby.iapi.store.access.XATransactionController;
+import org.apache.derby.iapi.store.access.xa.XAResourceManager;
+import org.apache.derby.iapi.store.access.xa.XAXactId;
+import org.apache.derby.impl.jdbc.EmbedConnection;
+import org.apache.derby.impl.jdbc.TransactionResourceImpl;
+
+/**
+ * Implements XAResource
+ */
+class EmbedXAResource implements XAResource {
+
+    private EmbedPooledConnection con;
+    private ResourceAdapter ra;
+    private XAXactId currentXid;    
+    
+    EmbedXAResource (EmbedPooledConnection con, ResourceAdapter ra) {
+        this.con = con;
+        this.ra = ra;
+    }
+    
+    /**
+     * Commit the global transaction specified by xid.
+     * @param xid A global transaction identifier
+     * @param onePhase If true, the resource manager should use a one-phase
+     * commit protocol to commit the work done on behalf of xid.
+
+     * @exception XAException An error has occurred. Possible XAExceptions are
+     * XA_HEURHAZ, XA_HEURCOM, XA_HEURRB, XA_HEURMIX, XAER_RMERR,
+     * XAER_RMFAIL, XAER_NOTA, XAER_INVAL, or XAER_PROTO.  
+     * <P>If the resource manager did not commit the transaction and
+     * the paramether onePhase is set to true, the resource manager 
+     * may throw one of the XA_RB* exceptions. Upon return, the
+     * resource manager has rolled back the branch's work and has 
+     * released all held resources.
+     */    
+    public final synchronized void commit(Xid xid, boolean onePhase) 
+                                            throws XAException {
+        checkXAActive();
+        // ensure immtable and correct equals method.
+        XAXactId xid_im = new XAXactId(xid);
+        XATransactionState tranState = getTransactionState(xid_im);
+        
+        if (tranState == null) {
+            XAResourceManager rm = ra.getXAResourceManager();
+            ContextManager inDoubtCM = rm.find(xid);
+            // RM also does not know about this xid.
+            if (inDoubtCM == null)
+                throw new XAException(XAException.XAER_NOTA);
+            ContextService csf = ContextService.getFactory();
+            csf.setCurrentContextManager(inDoubtCM);
+            try {
+                rm.commit(inDoubtCM, xid_im, onePhase);
+                
+                // close the connection/transaction since it can never
+                // be used again.
+                inDoubtCM.cleanupOnError(StandardException.closeException());
+                return;
+            } catch (StandardException se) {
+                // The rm threw an exception, clean it up in the approprate
+                // context.  There is no transactionResource to handle the
+                // exception for us.
+                inDoubtCM.cleanupOnError(se);
+                throw wrapInXAException(se);
+            } finally {
+                csf.resetCurrentContextManager(inDoubtCM);
+            }
+            
+        }
+        
+        synchronized (tranState) {
+            checkUserCredentials(tranState.creatingResource);
+            
+            // Check the transaction is no associated with
+            // any XAResource.
+            switch (tranState.associationState) {
+                case XATransactionState.T0_NOT_ASSOCIATED:
+                    break;
+                    
+                case XATransactionState.TRO_FAIL:
+                    throw new XAException(tranState.rollbackOnlyCode);
+                    
+                default:
+                    throw new XAException(XAException.XAER_PROTO);
+            }
+            
+            if (tranState.suspendedList != null && tranState.suspendedList.size() != 0)
+                throw new XAException(XAException.XAER_PROTO);
+            
+            if (tranState.isPrepared == onePhase)
+                throw new XAException(XAException.XAER_PROTO);
+            
+            EmbedConnection conn = tranState.conn;
+            
+            try {
+                conn.xa_commit(onePhase);
+            } catch (SQLException sqle) {
+                throw wrapInXAException(sqle);
+            } finally {
+                returnConnectionToResource(tranState, xid_im);
+            }
+        }
+    }
+
+    /**
+     * Ends the work performed on behalf of a transaction branch. The resource
+     * manager disassociates the XA resource from the transaction branch
+     * specified and let the transaction be completed.
+     *
+     * <p> If TMSUSPEND is specified in flags, the transaction branch is
+     * temporarily suspended in incomplete state. The transaction context
+     * is in suspened state and must be resumed via start with TMRESUME
+     * specified.
+     *
+     * <p> If TMFAIL is specified, the portion of work has failed. The
+     * resource manager may mark the transaction as rollback-only
+     *
+     * <p> If TMSUCCESS is specified, the portion of work has completed
+     * successfully.
+     *
+     * @param xid A global transaction identifier that is the same as what was
+     * used previously in the start method.
+     * @param flags One of TMSUCCESS, TMFAIL, or TMSUSPEND
+     *
+     * @exception XAException An error has occurred.
+     * Possible XAException values are XAER_RMERR, XAER_RMFAILED, XAER_NOTA,
+     * XAER_INVAL, XAER_PROTO, or XA_RB*.
+     */
+    public final synchronized void end(Xid xid, int flags) throws XAException {
+        checkXAActive();
+        
+        try {
+            // It is possible that the isolation level state in connection
+            // handle has gotten out of sync with the real isolation level.
+            // This can happen if SLQ instead of JDBC api has been used to
+            // set the isolation level. The code below will check if isolation
+            // was set using JDBC or SQL and if yes, then it will update the
+            // isolation state in BrokeredConnection with EmbedConnection's
+            // isolation level.
+            if (con.currentConnectionHandle != null)
+                con.currentConnectionHandle.getIsolationUptoDate();
+        } catch (SQLException sqle) {
+            throw wrapInXAException(sqle);
+        }
+        
+        // ensure immtable and correct equals method.
+        XAXactId xid_im = new XAXactId(xid);
+        
+        boolean endingCurrentXid = false;
+        
+        // must match the Xid from start()
+        if (currentXid != null) {
+            if (!currentXid.equals(xid_im))
+                throw new XAException(XAException.XAER_PROTO);
+            endingCurrentXid = true;
+        }
+        
+        XATransactionState tranState = getTransactionState(xid_im);
+        if (tranState == null)
+            throw new XAException(XAException.XAER_NOTA);
+        
+        boolean rollbackOnly = tranState.end(this, flags, endingCurrentXid);
+        
+        // RESOLVE - what happens to the connection on a fail
+        // where we are not ending the current XID.
+        if (endingCurrentXid) {
+            currentXid = null;            
+            con.realConnection = null;
+        }
+        
+        if (rollbackOnly)
+            throw new XAException(tranState.rollbackOnlyCode);        
+    }
+
+    /**
+     * Ask the resource manager to prepare for a transaction commit of the
+     * transaction specified in xid.
+     *
+     * @param xid A global transaction identifier
+     *
+     * @return A value indicating the resource manager's vote on the outcome
+     * of the transaction. The possible values are: XA_RDONLY or XA_OK. If the
+     * resource manager wants to roll back the transaction, it should do so by
+     * raising an appropriate XAException in the prepare method.
+     *
+     * @exception XAException An error has occurred. Possible exception values
+     * are: XA_RB*, XAER_RMERR, XAER_RMFAIL, XAER_NOTA, XAER_INVAL, or
+     * XAER_PROTO.
+     *
+     */
+    public final synchronized int prepare(Xid xid) throws XAException {
+        checkXAActive();
+        
+        // ensure immtable and correct equals method.
+        XAXactId xid_im = new XAXactId(xid);
+        
+        XATransactionState tranState = getTransactionState(xid_im);
+        
+        if (tranState == null) {
+            XAResourceManager rm = ra.getXAResourceManager();
+            
+            ContextManager inDoubtCM = rm.find(xid);
+            
+            // RM also does not know about this xid.
+            if (inDoubtCM == null)
+                throw new XAException(XAException.XAER_NOTA);
+            
+            // cannot prepare in doubt transactions
+            throw new XAException(XAException.XAER_PROTO);
+            
+        }
+        
+        synchronized (tranState) {
+            
+            checkUserCredentials(tranState.creatingResource);
+            
+            // Check the transaction is no associated with
+            // any XAResource.
+            switch (tranState.associationState) {
+                case XATransactionState.T0_NOT_ASSOCIATED:
+                    break;
+                    
+                case XATransactionState.TRO_FAIL:
+                    throw new XAException(tranState.rollbackOnlyCode);
+                    
+                default:
+                    throw new XAException(XAException.XAER_PROTO);
+            }
+            
+            if (tranState.suspendedList != null 
+                    && tranState.suspendedList.size() != 0)
+                throw new XAException(XAException.XAER_PROTO);
+            
+            if (tranState.isPrepared)
+                throw new XAException(XAException.XAER_PROTO);
+            
+            EmbedConnection conn = tranState.conn;
+            
+            try {
+                
+                int ret = conn.xa_prepare();
+                
+                if (ret == XATransactionController.XA_OK) {
+                    tranState.isPrepared = true;
+                    
+                    return XAResource.XA_OK;
+                } else {
+                    
+                    returnConnectionToResource(tranState, xid_im);
+                    return XAResource.XA_RDONLY;
+                }
+            } catch (SQLException sqle) {
+                throw wrapInXAException(sqle);
+            }
+        }
+        
+    }
+
+    /**
+     * Obtain the current transaction timeout value set for this XAResource
+     * instance. If XAResource.setTransactionTimeout was not use prior to
+     * invoking this method, the return value is the default timeout set for
+     * the resource manager; otherwise, the value used in the previous
+     * setTransactionTimeout call is returned.
+     *
+     * @return the transaction timeout value in seconds.
+     */
+    public int getTransactionTimeout() {
+        return 0;
+    }
+
+    /**
+     * This method is called to determine if the resource manager instance
+     * represented by the target object is the same as the resouce manager
+     * instance represented by the parameter xares.
+     *
+     * @param xares An XAResource object whose resource manager instance is to
+     * be compared with the resource manager instance of the target object.
+     *
+     * @return true if it's the same RM instance; otherwise false.
+     * @exception XAException An error has occurred. Possible exception values
+     * are XAER_RMERR, XAER_RMFAIL.
+     */
+    public final synchronized boolean isSameRM(XAResource xares) 
+                                                        throws XAException {
+        checkXAActive();        
+        if (xares instanceof EmbedXAResource) {            
+            return ra == ((EmbedXAResource) xares).ra;
+        }        
+        return false;
+    }
+    
+    /**
+     * Obtain a list of prepared transaction branches from a resource
+     * manager. The transaction manager calls this method during recovery to
+     * obtain the list of transaction branches that are currently in prepared
+     * or heuristically completed states.
+     *
+     * @param flag One of TMSTARTRSCAN, TMENDRSCAN, TMNOFLAGS. TMNOFLAGS must
+     * be used when no other flags are set in flags.
+     *
+     * @return The resource manager returns zero or more XIDs for the
+     * transaction branches that are currently in a prepared or heuristically
+     * completed state. If an error occurs during the operation, the resource
+     * manager should throw the appropriate XAException.
+     *
+     * @exception XAException An error has occurred. Possible values are
+     * XAER_RMERR, XAER_RMFAIL, XAER_INVAL, and XAER_PROTO.
+     *
+     */
+    public final synchronized Xid[] recover(int flag) throws XAException {
+        checkXAActive();
+        
+        try {
+            return ra.getXAResourceManager().recover(flag);
+        } catch (StandardException se) {
+            throw wrapInXAException(se);
+        }
+    }
+    
+    /**
+     * Tell the resource manager to forget about a heuristically completed
+     * transaction branch.
+     *
+     * @param xid A global transaction identifier
+     * @exception XAException An error has occurred. Possible exception values
+     * are XAER_RMERR, XAER_RMFAIL, XAER_NOTA, XAER_INVAL, or XAER_PROTO.
+     */
+    public final synchronized void forget(Xid xid) throws XAException {
+        
+        checkXAActive();
+        
+        // ensure immtable and correct equals method.
+        XAXactId xid_im = new XAXactId(xid);
+        
+        XATransactionState tranState = getTransactionState(xid_im);
+        if (tranState == null) {
+            XAResourceManager rm = ra.getXAResourceManager();
+            
+            ContextManager inDoubtCM = rm.find(xid);
+            
+            // RM also does not know about this xid.
+            if (inDoubtCM == null)
+                throw new XAException(XAException.XAER_NOTA);
+            
+            ContextService csf = ContextService.getFactory();
+            
+            csf.setCurrentContextManager(inDoubtCM);
+            try {
+                rm.forget(inDoubtCM, xid_im);
+                
+                // close the connection/transaction since it can never be used again.
+                inDoubtCM.cleanupOnError(StandardException.closeException());
+                return;
+            } catch (StandardException se) {
+                // The rm threw an exception, clean it up in the approprate
+                // context.  There is no transactionResource to handle the
+                // exception for us.
+                inDoubtCM.cleanupOnError(se);
+                throw wrapInXAException(se);
+            } finally {
+                csf.resetCurrentContextManager(inDoubtCM);
+            }
+            
+        }
+        
+        throw new XAException(tranState.isPrepared
+            ? XAException.XAER_NOTA 
+            : XAException.XAER_PROTO);
+    }    
+
+    /**
+     * Inform the resource manager to roll back work done on behalf of a
+     * transaction branch
+     *
+     * @param xid A global transaction identifier
+     * @exception XAException - An error has occurred
+     */
+    public final synchronized void rollback(Xid xid) throws XAException {
+        checkXAActive();
+        
+        // ensure immtable and correct equals method.
+        XAXactId xid_im = new XAXactId(xid);
+        
+        XATransactionState tranState = getTransactionState(xid_im);
+        
+        if (tranState == null) {
+            XAResourceManager rm = ra.getXAResourceManager();
+            
+            ContextManager inDoubtCM = rm.find(xid);
+            
+            // RM also does not know about this xid.
+            if (inDoubtCM == null)
+                throw new XAException(XAException.XAER_NOTA);
+            
+            ContextService csf = ContextService.getFactory();
+            
+            csf.setCurrentContextManager(inDoubtCM);
+            try {
+                rm.rollback(inDoubtCM, xid_im);
+                
+                // close the connection/transaction since it can never be used again.
+                inDoubtCM.cleanupOnError(StandardException.closeException());
+                return;
+            } catch (StandardException se) {
+                // The rm threw an exception, clean it up in the approprate
+                // context.  There is no transactionResource to handle the
+                // exception for us.
+                inDoubtCM.cleanupOnError(se);
+                throw wrapInXAException(se);
+            } finally {
+                csf.resetCurrentContextManager(inDoubtCM);
+            }
+            
+        }
+        
+        synchronized (tranState) {
+            
+            // Check the transaction is no associated with
+            // any XAResource.
+            switch (tranState.associationState) {
+                case XATransactionState.T0_NOT_ASSOCIATED:
+                case XATransactionState.TRO_FAIL:
+                    break;
+                    
+                default:
+                    throw new XAException(XAException.XAER_PROTO);
+            }
+            
+            if (tranState.suspendedList != null 
+                    && tranState.suspendedList.size() != 0)
+                throw new XAException(XAException.XAER_PROTO);
+            
+            checkUserCredentials(tranState.creatingResource);
+            
+            try {
+                
+                tranState.conn.xa_rollback();
+            } catch (SQLException sqle) {
+                throw wrapInXAException(sqle);
+            } finally {
+                returnConnectionToResource(tranState, xid_im);
+            }
+        }
+    }
+
+
+    /**
+     * Set the current transaction timeout value for this XAResource
+     * instance. Once set, this timeout value is effective until
+     * setTransactionTimeout is invoked again with a different value. To reset
+     * the timeout value to the default value used by the resource manager,
+     * set the value to zero. If the timeout operation is performed
+     * successfully, the method returns true; otherwise false. If a resource
+     * manager does not support transaction timeout value to be set
+     * explicitly, this method returns false.
+     *
+     * @param seconds the transaction timeout value in seconds.
+     * @return true if transaction timeout value is set successfully;
+     * otherwise false.
+     *
+     * @exception XAException - An error has occurred. Possible exception
+     * values are XAER_RMERR, XAER_RMFAIL, or XAER_INVAL.
+     */
+    public boolean setTransactionTimeout(int seconds) {
+        return false;
+    }
+
+    /**
+     * Start work on behalf of a transaction branch specified in xid If TMJOIN
+     * is specified, the start is for joining a transaction previously seen by
+     * the resource manager. If TMRESUME is specified, the start is to resume
+     * a suspended transaction specified in the parameter xid. If neither
+     * TMJOIN nor TMRESUME is specified and the transaction specified by xid
+     * has previously been seen by the resource manager, the resource manager
+     * throws the XAException exception with XAER_DUPID error code.
+     *
+     * @param xid A global transaction identifier to be associated with the
+     * resource
+     * @param flags One of TMNOFLAGS, TMJOIN, or TMRESUME
+     *
+     * @exception XAException An error has occurred. Possible exceptions are
+     * XA_RB*, XAER_RMERR, XAER_RMFAIL, XAER_DUPID, XAER_OUTSIDE, XAER_NOTA,
+     * XAER_INVAL, or XAER_PROTO.
+     */
+    public final synchronized void start(Xid xid, 
+                                        int flags) throws XAException {
+        checkXAActive();
+        
+        // JDBC 3.0 section 12.3 - One transaction associated with a XAConnection
+        if (currentXid != null)
+            throw new XAException(XAException.XAER_PROTO);
+        
+        // ensure immtable and correct equals method.
+        XAXactId xid_im = new XAXactId(xid);
+        
+        XATransactionState tranState = getTransactionState(xid_im);
+        
+        switch (flags) {
+            case XAResource.TMNOFLAGS:
+                if (tranState != null)
+                    throw new XAException(XAException.XAER_DUPID);
+                
+                try {
+                    
+                    if (con.realConnection == null) {
+                        con.openRealConnection();
+                        
+                        if (con.currentConnectionHandle != null) {
+                            
+                            // since this is a new connection, set its complete
+                            // state according to the application's Connection
+                            // handle view of the world.
+                            con.currentConnectionHandle.setState(true);
+                            con.realConnection.setApplicationConnection
+                                    (con.currentConnectionHandle);
+                        }
+                        
+                    } else {
+                        
+                        // XAResource.start() auto commits in DB2 when in 
+                        // auto commit mode.
+                        if (con.currentConnectionHandle != null) {
+                            if (con.currentConnectionHandle.getAutoCommit())
+                                con.currentConnectionHandle.rollback();
+                        }
+                        if (!con.realConnection.transactionIsIdle())
+                            throw new XAException(XAException.XAER_OUTSIDE);
+                        
+                        if (con.currentConnectionHandle != null) {
+                            // It is possible that the isolation level state 
+                            // in connection handle has gotten out of sync 
+                            // with the real isolation level. This can happen 
+                            // if SLQ instead of JDBC api has been used to set 
+                            // the isolation level. The code below will check 
+                            // if isolation was set using JDBC or SQL and if 
+                            // yes, then it will update the isolation state 
+                            // in BrokeredConnection with EmbedConnection's
+                            // isolation level.
+                            con.currentConnectionHandle.getIsolationUptoDate();
+                            // we have a current handle so we need to keep
+                            // the connection state of the current connection.
+                            con.currentConnectionHandle.setState(true);
+                            
+                            // At the local to global transition we need 
+                            // to discard and close any open held result 
+                            // sets, a rollback will do this.
+                            con.realConnection.rollback();
+                        } else {
+                            con.resetRealConnection();
+                        }
+                        
+                    }
+                    
+                    // Global connections are always in auto commit false mode.
+                    con.realConnection.setAutoCommit(false);
+                    
+                    // and holdability false (cannot hold cursors across 
+                    // XA transactions.
+                    con.realConnection.setHoldability(
+                            JDBC30Translation.CLOSE_CURSORS_AT_COMMIT);
+                    
+                    con.realConnection.getLanguageConnection().
+                            getTransactionExecute().
+                            createXATransactionFromLocalTransaction(
+                                                xid_im.getFormatId(),
+                                                xid_im.getGlobalTransactionId(),
+                                                xid_im.getBranchQualifier());
+                    
+                    
+                } catch (StandardException se) {
+                    throw wrapInXAException(se);
+                } catch (SQLException sqle) {
+                    throw wrapInXAException(sqle);
+                }
+                
+                
+                if (!ra.addConnection(xid_im, 
+                        new XATransactionState(
+                        con.realConnection.getContextManager(), 
+                        con.realConnection, this, xid_im)))
+                    throw new XAException(XAException.XAER_DUPID);
+                
+                break;
+                
+            case XAResource.TMRESUME:
+            case XAResource.TMJOIN:
+                if (tranState == null)
+                    throw new XAException(XAException.XAER_NOTA);
+                
+                tranState.start(this, flags);
+                
+                if (tranState.conn != con.realConnection) {
+                    
+                    if (con.realConnection != null) {
+                        
+                        if (!con.realConnection.transactionIsIdle())
+                            throw new XAException(XAException.XAER_OUTSIDE);
+                        
+                        closeUnusedConnection(con.realConnection);
+                    }
+                    con.realConnection = tranState.conn;
+                    
+                    if (con.currentConnectionHandle != null) {
+                        
+                        try {
+                            // only reset the non-transaction specific 
+                            // Connection state.
+                            con.currentConnectionHandle.setState(false);
+                            con.realConnection.setApplicationConnection(
+                                    con.currentConnectionHandle);
+                        } catch (SQLException sqle) {
+                            throw wrapInXAException(sqle);
+                        }
+                    }
+                    
+                }
+                
+                
+                break;
+                
+            default:
+                throw new XAException(XAException.XAER_INVAL);
+        }
+        
+        currentXid = xid_im;
+    }
+    
+    /**
+     * Resturns currently active xid
+     * @return Xid
+     */
+    Xid getCurrentXid () {
+        return currentXid;
+    }
+
+    /**
+     * Returns the XATransactionState of the the transaction
+     * @param xid_im 
+     * @return XATransactionState
+     */
+    private XATransactionState getTransactionState(XAXactId xid_im) {
+        return (XATransactionState) ra.findConnection(xid_im);
+    }
+
+    /**
+     * Compares the user name and password of the XAResource with
+     * user name and password of this and throws XAException if there is 
+     * a mismatch
+     * @param original EmbedXAResource
+     */
+    private void checkUserCredentials(EmbedXAResource original)
+                                                        throws XAException {        
+        if (original == this)
+            return;        
+        if (original.con.getPassword().equals(con.getPassword()) && 
+                (original.con.getUsername().equals(con.getUsername())))
+            return;                
+        throw new XAException(XAException.XA_RBINTEGRITY);
+    }
+    
+    /**
+     * Checks if currently associated connection is active
+     * throws exception if not
+     */
+    private void checkXAActive() throws XAException {    
+        try {
+            con.checkActive();
+        } catch (SQLException sqle) {
+            throw wrapInXAException(sqle);
+        }
+    }
+    
+    /**
+     * Map a SQL exception to appropriate XAException.
+     * Return the mapped XAException.
+     */
+    private static XAException wrapInXAException(SQLException se) {
+        // Map interesting exceptions to XAException
+        String sqlstate = se.getSQLState();
+        String message = se.getMessage();
+        
+        XAException xae;
+        
+        if (sqlstate == null) {
+            // no idea what was wrong, throw non-descript error.
+            if (message != null)
+                xae = new XAException(message);
+            else
+                xae = new XAException(XAException.XAER_RMERR);
+        } else if (sqlstate.equals(StandardException.getSQLStateFromIdentifier(
+                            SQLState.STORE_XA_XAER_DUPID)))
+            xae = new XAException(XAException.XAER_DUPID);
+        else if (sqlstate.equals(StandardException.getSQLStateFromIdentifier(
+                                SQLState.STORE_XA_PROTOCOL_VIOLATION)))
+            xae = new XAException(XAException.XA_RBPROTO);
+        else if (sqlstate.equals(SQLState.DEADLOCK))
+            xae = new XAException(XAException.XA_RBDEADLOCK);
+        else if (sqlstate.equals(SQLState.LOCK_TIMEOUT))
+            xae = new XAException(XAException.XA_RBTIMEOUT);
+        else if (message != null)
+            xae = new XAException(message);
+        else
+            xae = new XAException(XAException.XAER_RMERR);
+        
+        if (JVMInfo.JDK_ID >= JVMInfo.J2SE_14)
+            xae.initCause(se);
+        return xae;
+    }
+	
+    /**
+     * Map a Standard exception to appropriate XAException.
+     * Return the mapped XAException.
+     */
+    private static XAException wrapInXAException(StandardException se) {
+        return wrapInXAException(
+                TransactionResourceImpl.wrapInSQLException(
+                (SQLException) null, se));
+    }
+    
+    /**
+     * Return an underlying connection object back to its XAResource
+     * if possible. If not close the connection.
+     * @param tranState 
+     * @param xid_im 
+     */
+    private void returnConnectionToResource(XATransactionState tranState, 
+                                                            XAXactId xid_im) {
+        
+        removeXATransaction(xid_im);    
+        synchronized (tranState) {
+            // global transaction is over.
+            tranState.associationState = XATransactionState.TC_COMPLETED;
+            tranState.notifyAll();
+            
+            EmbedConnection conn = tranState.conn;
+            
+            // already set in its own resource
+            // or can it be returned to its original resource?
+            if ((tranState.creatingResource.con.realConnection == conn) ||
+                    (tranState.creatingResource.con.realConnection == null)) {
+                
+                tranState.creatingResource.con.realConnection = conn;
+                
+                BrokeredConnection handle = 
+                        tranState.creatingResource.con.currentConnectionHandle;
+                
+                conn.setApplicationConnection(handle);
+                
+                if (handle != null) {
+                    try {
+                        handle.setState(true);
+                    } catch (SQLException sqle) {
+                        
+                        // couldn't reset the connection
+                        closeUnusedConnection(tranState.conn);
+                        tranState.creatingResource.con.realConnection = null;
+                    }
+                }
+                return;
+            }
+        }
+        
+        // nowhere to place it, close it.
+        closeUnusedConnection(tranState.conn);
+    }
+
+
+    /**
+     * Close  an underlying connection object when there is
+     * no active XAResource to hand it to.
+     * @param conn 
+     */
+    private static void closeUnusedConnection(EmbedConnection conn) {
+        if (conn != null) {
+            try {
+                conn.close();
+            } catch (SQLException sqle) {
+                
+            }
+        }
+    }
+
+    /**
+     * Removes the xid from currently active transactions
+     * @param xid_im 
+     */
+    private void removeXATransaction(XAXactId xid_im) {
+        XATransactionState tranState = 
+                (XATransactionState) ra.removeConnection(xid_im);
+        if (tranState != null)
+            tranState.popMe();
+    }
+    
+}

Propchange: db/derby/code/trunk/java/engine/org/apache/derby/jdbc/EmbedXAResource.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: db/derby/code/trunk/java/engine/org/apache/derby/jdbc/XATransactionState.java
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/engine/org/apache/derby/jdbc/XATransactionState.java?rev=389570&r1=389569&r2=389570&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/jdbc/XATransactionState.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/jdbc/XATransactionState.java Tue Mar 28 10:25:47 2006
@@ -46,8 +46,9 @@
 	final static int TC_COMPLETED				= 3; // rollback/commit called
 
 	final EmbedConnection	conn;
-	final EmbedXAConnection creatingResource;
-	private EmbedXAConnection  associatedResource;	// owning XAResource
+	final EmbedXAResource creatingResource;
+        // owning XAResource
+	private EmbedXAResource  associatedResource;	
 	final XAXactId			xid;	
 	/**
 		When an XAResource suspends a transaction (end(TMSUSPEND)) it must be resumed
@@ -72,7 +73,8 @@
 	*/
 	boolean isPrepared;
 
-	XATransactionState(ContextManager cm, EmbedConnection conn, EmbedXAConnection resource, XAXactId xid) {
+	XATransactionState(ContextManager cm, EmbedConnection conn, 
+                EmbedXAResource resource, XAXactId xid) {
 
 		super(cm, "XATransactionState");
 		this.conn = conn;
@@ -112,7 +114,7 @@
 		}
 	}
 
-	void start(EmbedXAConnection resource, int flags) throws XAException {
+	void start(EmbedXAResource resource, int flags) throws XAException {
 
 		synchronized (this) {
 			if (associationState == XATransactionState.TRO_FAIL)
@@ -163,7 +165,8 @@
 		}
 	}
 
-	boolean end(EmbedXAConnection resource, int flags, boolean endingCurrentXid) throws XAException {
+	boolean end(EmbedXAResource resource, int flags, 
+                boolean endingCurrentXid) throws XAException {
 
 		boolean rollbackOnly = false;
 		synchronized (this) {

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/checkDataSource.out
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/checkDataSource.out?rev=389570&r1=389569&r2=389570&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/checkDataSource.out (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/checkDataSource.out Tue Mar 28 10:25:47 2006
@@ -692,4 +692,5 @@
 Checked class declared as: javax.sql.DataSource
 Checked class declared as: javax.sql.PooledConnection
 Checked class declared as: javax.sql.XAConnection
+Checked class declared as: javax.transaction.xa.XAResource
 Completed checkDataSource

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/checkDataSource30.out
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/checkDataSource30.out?rev=389570&r1=389569&r2=389570&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/checkDataSource30.out (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/checkDataSource30.out Tue Mar 28 10:25:47 2006
@@ -882,4 +882,5 @@
 Checked class declared as: javax.sql.DataSource
 Checked class declared as: javax.sql.PooledConnection
 Checked class declared as: javax.sql.XAConnection
+Checked class declared as: javax.transaction.xa.XAResource
 Completed checkDataSource30



Mime
View raw message