/*
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 1999 Bull S.A.
 * Contact: jonas-team@objectweb.org
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
 * USA
 *
 * --------------------------------------------------------------------------
 * $Id$
 * --------------------------------------------------------------------------
 */


package org.objectweb.jonas.resource;

import javax.transaction.Synchronization;

import org.objectweb.util.monolog.api.BasicLevel;

import java.util.Iterator;
import java.util.Map;

/**
 * This class is an implementation of the Synchronization interface, used by a
 * ConnectionManagerImpl instance. The aim of this class is to close a
 * ManagedConnection when a transaction finishes. This class is necessary when
 * the commit or the rollback action is after a connection close.
 *
 *@author     sebastien.chassande@inrialpes.fr
 *@author     Eric.Hardesty@bull.com
 */
public class MySynchro implements Synchronization {

    /**
     * The ManagedConnection descriptor linked to this Synchronization
     * implementation
     */
    private MCInfo mci = null;
    /**
     * The ConnectionManagerImpl instance which manages this synchronization
     */
    private ConnectionManagerImpl cm = null;


    /**
     *  Constructor for the MySynchro object
     *
     *@param pCm   ConnectionManager object
     *@param pMci  ManagedConnection information object
     *
     */
    public MySynchro(ConnectionManagerImpl pCm, MCInfo pMci) {
        mci = pMci;
        cm = pCm;
        mci.synchro = this;
        cm.synchros.add(mci);
    }


    /**
     *  This method is called by the transaction manager after the transaction is
     *  committed or rolled back. Release the mci from the pool
     *
     *@param  status  The transaction flag
     */
    public void afterCompletion(int status) {
        if (mci == null) {
            return;
        }
        synchronized (cm.poolMCs) {
            mci.synchro = null;
            cm.synchros.remove(mci);
            if (!mci.usedCs.isEmpty()) {
                // The transaction is finished but the connection isn't closed
                // then just to dissociate the tx to the mci
                cm.usedMCs.remove(mci.getGlobalTx());
                mci.setGlobalTx(null);
            } else {
                // The transaction is finished and the logical connections have
                // previously closed. Then release the mci
                try {
                    cm.mcs.remove(mci);
                    if (mci.getGlobalTx() != null) {
                        cm.usedMCs.remove(mci.getGlobalTx());
                    } else {
                        Iterator it = cm.usedMCs.entrySet().iterator();
                        while (it.hasNext()) {
                            Map.Entry me = (Map.Entry) it.next();
                            if (mci.equals(me.getValue())) {
                                it.remove();
                            }
                        }
                    }

                    mci.setGlobalTx(null);
                    mci.mc.cleanup();

                    cm.poolMCs.releaseResource(mci.mc, false);
                    if (ConnectionManagerImpl.trace.isLoggable(BasicLevel.DEBUG)) {
                        ConnectionManagerImpl.trace.log(BasicLevel.DEBUG, "Later releasing of MC=" + mci.mc);
                    }
                    mci = null;
                    if (ConnectionManagerImpl.poolTrace.isLoggable(BasicLevel.DEBUG)) {
                        ConnectionManagerImpl.poolTrace.log(BasicLevel.DEBUG, "state\n" + cm.getState("\t"));
                    }
                } catch (Exception e) {
                    ConnectionManagerImpl.trace.log(BasicLevel.ERROR,
                            "an error related during releasing of ManagedConection",
                            e, "MySynchro", "afterCompletion");
                }
            }
            mci = null;
            cm = null;
        }
    }


    /**
     *  This method is called by the transaction manager prior to the start of the
     *  transaction completion process.
     */
    public void beforeCompletion() {
    }
}

