/**
* High Availability Service (HA) for JOnAS
*
* Copyright (C) 2007,2008 Bull S.A.S.
* Copyright (C) 2006 Distributed Systems Lab.
* Universidad Politecnica de Madrid (Spain)
* Contact: http://lsd.ls.fi.upm.es/lsd
*
* 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.ow2.jonas.lib.ejb21.ha;


import java.rmi.RemoteException;

import javax.ejb.EJBException;

import org.objectweb.util.monolog.api.BasicLevel;
import org.objectweb.util.monolog.api.Logger;
import org.ow2.cmi.controller.common.ClusterViewManager;
import org.ow2.cmi.controller.factory.ClusterViewManagerFactory;
import org.ow2.cmi.ha.SessionId;
import org.ow2.jonas.lib.ejb21.JSessionFactory;
import org.ow2.jonas.lib.ejb21.JSessionLocal;
import org.ow2.jonas.lib.ejb21.JStatefulSwitch;
import org.ow2.jonas.lib.ejb21.RequestCtx;
import org.ow2.jonas.lib.util.Log;

/**
 * Generic part of the EJBObject implementation for replicated SFSBs
 * @author Francisco Perez-Sorrosal (fpsorrosal@no-spam@fi.upm.es)
 * @author Alberto Paz-Jimenez (apaz@no-spam@fi.upm.es)
 */
public abstract class JRepStatefulLocal extends JSessionLocal {

    /**
     * Logger for traces
     */
    protected static Logger cmilogger = Log.getLogger("org.ow2.jonas.lib.ejb21.ha");

    public SessionId clusterOId = null;

    /**
     * constructor
     * @param bf The Session Factory
     * @throws Exception
     */
    public JRepStatefulLocal(final JSessionFactory bf) {
        super(bf);
        ClusterViewManager clusterViewManager =
            ClusterViewManagerFactory.getFactory().getClusterViewManager();
        if(clusterViewManager != null) {
            if (cmilogger.isLoggable(BasicLevel.DEBUG)) {
                cmilogger.log(BasicLevel.DEBUG, "JRepStatefulLocal : this=" + this);
            }
            clusterOId =
                clusterViewManager.getSessionId();
        }
    }

    /**
     * preInvoke is called before any request.
     * @param txa Transaction Attribute (Supports, Required, ...)
     * @return A RequestCtx object
     * @throws RemoteException Thrown when the method failed due to a
     *         system-level failure.
     */
    @Override
    public RequestCtx preInvoke(final int txa) {
        RequestCtx rctx = super.preInvoke(txa);
        /* ******************REPLICATION CODE STARTS HERE*********************** */
        preInvokeHook(rctx); // Replication algorithm link
        /* **********************END OF REPLICATION CODE************************ */
        return rctx;
    }

    /**
     * postInvoke is called after any request.
     * @param rctx The RequestCtx that was returned at preInvoke()
     * @param remove TODO
     * @param response The response that is going to be returned to the client
     *        (Needed by HA)
     * @throws RemoteException Thrown when the method failed due to a
     *         system-level failure.
     */
    public void postInvoke(final RequestCtx rctx, final boolean remove) {
        /* ******************REPLICATION CODE STARTS HERE*********************** */
        try {
            postInvokeHook(rctx, remove); // Replication algorithm
            // link
            /* **********************END OF REPLICATION CODE************************ */
        } catch (Exception e) {
            e.printStackTrace();
            cmilogger.log(BasicLevel.ERROR, "Error calling postInvokeHook in sfsb.", e);
        } finally {
            super.postInvoke(rctx);
        }
    }

    /* ******************REPLICATION CODE STARTS HERE*********************** */

    // ------------------------------------------------------------------------
    // Protected methods ------------------------------------------------------
    // ------------------------------------------------------------------------
    /**
     * Injects the state of the bean if the cluster object id received in the
     * request is in the current node. It extracts the object id passed through
     * the interceptors from the request id included in the current HA context.
     */
    protected void injectState() {
        if(clusterOId != null) {
            JRepUtil.injectState(this.clusterOId, (JStatefulSwitch) this.bs);
        }
    }

    // ------------------------------------------------------------------------
    // Private methods --------------------------------------------------------
    // ------------------------------------------------------------------------

    /**
     * preInvokeHook implements the hook to perform the required replication
     * tasks before the bean context has been established. In this case, it
     * saves the current state of the bean before perform the invocation, in the
     * request context.
     * @param rctx The RequestCtx that was returned at preInvoke()
     */
    private void preInvokeHook(final RequestCtx rctx) {
        if(clusterOId != null) {
            try {
                JRepUtil.preInvokeHook(bs, clusterOId, rctx);
            } catch (EJBException e) {
                // COMPLETE: Handle errors
                e.printStackTrace();
                cmilogger.log(BasicLevel.ERROR, "Error in preInvokeHook in sfsb.", e);
            }
        }
    }

    /**
     * postInvokeHook implements the hook to perform the required replication
     * tasks after the bean context has been established
     * @param rctx The RequestCtx that was returned at preInvoke()
     * @param response The response that is going to be returned to the client
     * @param remove true if it is an invocation to a remove method
     */
    private void postInvokeHook(final RequestCtx rctx, final boolean remove) {
        if(clusterOId != null) {
            JRepUtil.postInvokeHook(rctx, this.clusterOId, bs, remove);
        }
    }

    /**
     * Gets the clusterOId
     * @return the clusterOid
     */
    public SessionId getClusterOId() {
        return clusterOId;
    }

    /**
     * Sets the clusterOId
     * @param oid
     */
    public void setClusterOId(final SessionId oid) {
        clusterOId = oid;
    }

    /* **********************END OF REPLICATION CODE************************ */
}
