/*-----------------------------------------------------------------------------
 *
 * Enhydra InstantDB
 * The Initial Developer of the Original Code is Lutris Technologies Inc.
 * Portions created by Lutris are Copyright 1997-2000 Lutris Technologies Inc.
 * All Rights Reserved.
 *
 * The contents of this file are subject to the Enhydra Public License
 * Version 1.1 (the "License"); you may not use this file except in compliance
 * with the License. You may obtain a copy of the License at
 * www.enhydra.org/license/epl.html
 *
 * Software distributed under the License is distributed on an "ASIS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
 * the specific language governing rights and limitations under the License.
 *
 * -----------------------------------------------------------------------------
 * $Id$
 * -----------------------------------------------------------------------------
 */
package org.enhydra.jdbc.oracle;

import java.sql.*;
import java.util.*;
import javax.sql.*;
import javax.transaction.xa.*;
import oracle.jdbc.xa.client.OracleXAResource;
import oracle.jdbc.xa.OracleXid;
import org.enhydra.jdbc.standard.*;

/**
 * Provides an Oracle specific instance of StandardXAConnection. Almost all of
 * the required functionality is provided curtesy of the generic super class
 * which looks after most of the transaction state management. Oracle's
 * own resource manager is informed that it is part of a global transaction
 * and looks after the detail thereafter.
 */
public final class OracleXAConnection extends StandardXAConnection {

    private XAResource xarsrc = null;
    private static Hashtable txctxs = new Hashtable();

    /**
     * Creates the first free connection.
     */
    public OracleXAConnection (StandardXADataSource dataSource, String user, String password) throws SQLException {
	    super (dataSource, user, password);					// creates the first Connection object
    } // method JDBCXAConnection

    private OracleXid getOracleXid(Xid xid) throws XAException {
	if (!(xid instanceof OracleXid)) {
	    byte[] txctx = (byte[])txctxs.get(xid);
	    dataSource.log("txctx is " + txctx);
	    OracleXid newXid = new OracleXid(xid.getFormatId(), xid.getGlobalTransactionId(), xid.getBranchQualifier(), txctx);
	    return newXid;
	} else {
	    return (OracleXid)xid;
	}
    }

    public void commit(Xid xid, boolean flag) throws XAException {
	dataSource.log("commit:" + xid.getGlobalTransactionId());
	xarsrc.commit(getOracleXid(xid), flag);
	xaDataSource.freeConnection(xid, false);
	txctxs.remove(xid);
    }

    public void end(Xid xid, int flags) throws XAException {
	dataSource.log("end" + ":" + xid.getFormatId() + ":" + xid.getGlobalTransactionId() + ":" + xid.getBranchQualifier() + ":" + flags);
	xarsrc.end(getOracleXid(xid), flags);
    }

    public void forget(Xid xid) throws XAException {
	dataSource.log("forget" + ":" + xid.getGlobalTransactionId());
	xarsrc.forget(getOracleXid(xid));
	xaDataSource.freeConnection(xid, false);
	txctxs.remove(xid);
    }

    public int prepare(Xid xid) throws XAException {
	dataSource.log("prepare" + ":" + xid.getGlobalTransactionId());
	int res = xarsrc.prepare(getOracleXid(xid));
	if (res == XA_RDONLY) {
	    xaDataSource.freeConnection(xid, false);
	    txctxs.remove(xid);
	}
	return res;
    }

    public void rollback(Xid xid) throws XAException {
	dataSource.log("rollback" + ":" + xid.getGlobalTransactionId());
	xarsrc.rollback(getOracleXid(xid));
	xaDataSource.freeConnection(xid, false);
	txctxs.remove(xid);
    }

    public void start(Xid xid, int flags) throws XAException {
	dataSource.log("start" + ":" + xid.getFormatId() + ":" + xid.getGlobalTransactionId() + ":" + xid.getBranchQualifier() + ":" + flags);
	doStart(xid, flags);
	xarsrc = new OracleXAResource(curCon.con);
	OracleXid oXid = getOracleXid(xid);
	xarsrc.start(oXid, flags);
	txctxs.put(xid, oXid.getTxContext());
	curCon = null;
	con = null;
    }

    public boolean isSameRM(XAResource res) throws XAException {
	if (!(res instanceof OracleXAConnection)) {
	    dataSource.log("isSameRM returning false");
	    return false;
	}
	OracleXAConnection ores = (OracleXAConnection)res;
	if (ores.xarsrc.isSameRM(xarsrc)) {
	    dataSource.log("isSameRM returning true");
	    return true;
	}
	dataSource.log("isSameRM returning false");
	return false;
    }

} // class OracleXAConnection
