/*
 * JBoss, the OpenSource J2EE webOS
 *
 * Distributable under LGPL license.
 * See terms of license at gnu.org.
 */

package org.jboss.resource.adapter.jdbc.xa;

import java.sql.SQLException;
import java.util.Properties;

import javax.resource.ResourceException;
import javax.resource.spi.LocalTransaction;
import javax.sql.XAConnection;
import javax.transaction.xa.XAException;
import javax.transaction.xa.XAResource;
import javax.transaction.xa.Xid;

import org.jboss.resource.JBossResourceException;
import org.jboss.resource.adapter.jdbc.BaseWrapperManagedConnection;

/**
 * XAManagedConnection.java
 * 
 * 
 * Created: Mon Aug 12 23:02:44 2002
 * 
 * @author <a href="mailto:d_jencks@users.sourceforge.net">David Jencks </a>
 * @version $Revision: 1.14.6.1 $
 */

public class XAManagedConnection extends BaseWrapperManagedConnection implements XAResource
{

	protected final XAConnection xaConnection;

	protected final XAResource xaResource;

	protected Xid currentXid;

	public XAManagedConnection(XAManagedConnectionFactory mcf, XAConnection xaConnection, Properties props,
			int transactionIsolation, int psCacheSize) throws SQLException
	{
		super(mcf, xaConnection.getConnection(), props, transactionIsolation, psCacheSize);
		this.xaConnection = xaConnection;
		xaConnection.addConnectionEventListener(new javax.sql.ConnectionEventListener()
		{
			public void connectionClosed(javax.sql.ConnectionEvent ce)
			{
				//only we can do this, ignore
			}

			public void connectionErrorOccurred(javax.sql.ConnectionEvent ce)
			{
				SQLException ex = ce.getSQLException();
				broadcastConnectionError(ex);
			}
		});
		this.xaResource = xaConnection.getXAResource();
	}

	/**
	 * Describe <code>broadcastConnectionError</code> method here. this is
	 * present so the ConnectionEventListener inner class can access the method.
	 * 
	 * @param e a <code>SQLException</code> value
	 */
	protected void broadcastConnectionError(SQLException e)
	{
		super.broadcastConnectionError(e);
	}

	/**
	 * @return <description>
	 * @exception javax.resource.ResourceException <description>
	 */
	public LocalTransaction getLocalTransaction() throws ResourceException
	{
		throw new JBossResourceException("xa tx only!");
	}

	/**
	 * @return <description>
	 * @exception javax.resource.ResourceException <description>
	 */
	public XAResource getXAResource() throws ResourceException
	{
		return this;
	}

	/**
	 * @exception javax.resource.ResourceException <description>
	 */
	public void destroy() throws ResourceException
	{
		try
		{
			super.destroy();
		}
		finally
		{
			try
			{
				xaConnection.close();
			}
			catch (SQLException e)
			{
				checkException(e);
			} // end of try-catch
		} // end of try-catch
	}

	// implementation of javax.transaction.xa.XAResource interface

	/**
	 * @param param1 <description>
	 * @param param2 <description>
	 * @exception javax.transaction.xa.XAException <description>
	 */
	public void start(Xid xid, int flags) throws XAException
	{
		try
		{
			checkState();
		}
		catch (SQLException e)
		{
			getLog().warn("Error setting state ", e);
		}
		xaResource.start(xid, flags);
      synchronized (stateLock)
      {
         currentXid = xid;
         inManagedTransaction = true;
      }
	}

	/**
	 * @param param1 <description>
	 * @param param2 <description>
	 * @exception javax.transaction.xa.XAException <description>
	 */
	public void end(Xid xid, int flags) throws XAException
	{
		xaResource.end(xid, flags);
		//we want to allow ending transactions that are not the current
		//one. When one does this, inManagedTransaction is still true.
      synchronized (stateLock)
      {
         if (currentXid != null && currentXid.equals(xid))
         {
            inManagedTransaction = false;
            currentXid = null;
         }
      }
	}

	/**
	 * @param param1 <description>
	 * @return <description>
	 * @exception javax.transaction.xa.XAException <description>
	 */
	public int prepare(Xid xid) throws XAException
	{
		return xaResource.prepare(xid);
	}

	/**
	 * @param param1 <description>
	 * @param param2 <description>
	 * @exception javax.transaction.xa.XAException <description>
	 */
	public void commit(Xid xid, boolean onePhase) throws XAException
	{
		xaResource.commit(xid, onePhase);
	}

	/**
	 * @param param1 <description>
	 * @exception javax.transaction.xa.XAException <description>
	 */
	public void rollback(Xid xid) throws XAException
	{
		xaResource.rollback(xid);
	}

	/**
	 * @param param1 <description>
	 * @exception javax.transaction.xa.XAException <description>
	 */
	public void forget(Xid xid) throws XAException
	{
		xaResource.forget(xid);
	}

	/**
	 * @param param1 <description>
	 * @return <description>
	 * @exception javax.transaction.xa.XAException <description>
	 */
	public Xid[] recover(int flag) throws XAException
	{
		return xaResource.recover(flag);
	}

	/**
	 * @param param1 <description>
	 * @return <description>
	 * @exception javax.transaction.xa.XAException <description>
	 */
	public boolean isSameRM(XAResource other) throws XAException
	{
		Boolean overrideValue = ((XAManagedConnectionFactory) mcf).getIsSameRMOverrideValue();
		if (overrideValue != null)
		{
			return overrideValue.booleanValue();
		} // end of if ()

		// compare apples to apples
		return (other instanceof XAManagedConnection)
				? xaResource.isSameRM(((XAManagedConnection) other).xaResource)
				: xaResource.isSameRM(other);
	}

	/**
	 * @return <description>
	 * @exception javax.transaction.xa.XAException <description>
	 */
	public int getTransactionTimeout() throws XAException
	{
		return xaResource.getTransactionTimeout();
	}

	/**
	 * @param param1 <description>
	 * @return <description>
	 * @exception javax.transaction.xa.XAException <description>
	 */
	public boolean setTransactionTimeout(int seconds) throws XAException
	{
		return xaResource.setTransactionTimeout(seconds);
	}

	/**
	 * Describe <code>getProps</code> method here. for the mcf to access in
	 * matchManagedConnection
	 * 
	 * @return a <code>Properties</code> value
	 */
	Properties getProps()
	{
		return props;
	}

}
