/**
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 1999-2007 Bull S.A.S.
 * Contact: jonas-team@ow2.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: JSynchronization.java 21566 2011-08-08 12:28:12Z cazauxj $
 * --------------------------------------------------------------------------
 */

package org.ow2.jonas.resource.internal.cm.jta;

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

import javax.resource.spi.ManagedConnection;
import javax.transaction.Synchronization;

import org.objectweb.util.monolog.api.BasicLevel;
import org.ow2.jonas.resource.internal.cm.ConnectionManagerImpl;
import org.ow2.jonas.resource.internal.cm.ManagedConnectionInfo;

/**
 * This class is an implementation of the {@link Synchronization} interface, used by a
 * {@link ConnectionManagerImpl} instance. The aim of this class is to close a
 * {@link 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 JSynchronization implements Synchronization {

    /**
     * The descriptor linked to this Synchronization
     * implementation
     */
    private ManagedConnectionInfo mci = null;

    /**
     * The instance which manages this synchronization
     */
    private ConnectionManagerImpl cm = null;


    /**
     *  Constructor for the MySynchro object
     *
     *@param pCm   ConnectionManager object
     *@param pMci  ManagedConnection information object
     *
     */
    public JSynchronization(final ConnectionManagerImpl pCm, final ManagedConnectionInfo pMci) {
        mci = pMci;
        cm = pCm;
        mci.synchro = this;
        cm.getSynchros().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(final int status) {
        if (mci == null) {
            return;
        }
        synchronized (cm.getPool()) {
            mci.synchro = null;
            cm.getSynchros().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.getUsedManagedConnections().remove(mci.getGlobalTx());
                mci.setGlobalTx(null);
                if (cm.poolTrace.isLoggable(BasicLevel.DEBUG)) {
                    cm.poolTrace.log(BasicLevel.DEBUG, "state:\n" + cm.getState("\t"));
                }
            } else {
                // The transaction is finished and the logical connections have
                // previously closed. Then release the mci
                try {
                    cm.getManagedConnectionsWithoutTransaction().remove(mci);
                    if (mci.getGlobalTx() != null) {
                        cm.getUsedManagedConnections().remove(mci.getGlobalTx());
                    } else {
                        Iterator it = cm.getUsedManagedConnections().entrySet().iterator();
                        while (it.hasNext()) {
                            Map.Entry me = (Map.Entry) it.next();
                            if (mci.equals(me.getValue())) {
                                it.remove();
                            }
                        }
                    }

                    mci.setGlobalTx(null);

                    // force close pstmt
                    cm.closePStmts(mci);

                    mci.mc.cleanup();

                    cm.getPool().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 ManagedConnection",
                            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() {
    }
}

