/**
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 2006 Bull S.A.S.
 * Contact: jonas-team@objectweb.org
 * Copyright (C) 2006 Distributed Systems Lab.
 * Universidad Polit??cnica 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
 *
 * --------------------------------------------------------------------------
 *
 * --------------------------------------------------------------------------
 */

package org.objectweb.jonas_ejb.container;

import java.io.StringWriter;
import java.rmi.RemoteException;

import javax.ejb.EJBException;

import org.objectweb.carol.cmi.ClusterOIdFactory;
import org.objectweb.carol.cmi.ObjectId;
import org.objectweb.carol.cmi.ServerConfigException;
import org.objectweb.carol.cmi.configuration.TraceCmi;

/**
 * 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 {

    public ObjectId clusterOId = null;

    /**
     * constructor
     * @param bf The Session Factory
     * @throws Exception 
     */
    public JRepStatefulLocal(JSessionFactory bf) {
        super(bf);
        if (TraceCmi.isDebugCmiHA()) {
            TraceCmi.debugCmiHA("JRepStatefulLocal : this=" + this);
        }

        // COMPLETE: Handle errors
        // Obtain a new cluster object id
        try {
            clusterOId = ClusterOIdFactory.getInstance().getId();
        } catch (ServerConfigException e) {
            java.io.StringWriter sw = new StringWriter(); 
            java.io.PrintWriter pw = new java.io.PrintWriter(sw);
            e.printStackTrace(pw);
            TraceCmi.error("JRepStatefulLocal constructor: " + sw.toString(), e);
        }
    }

    /**
     * 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.
     */
    public RequestCtx preInvoke(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
     * @parem 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(RequestCtx rctx, boolean remove) {
        /* ******************REPLICATION CODE STARTS HERE*********************** */
        try {
            postInvokeHook(rctx, remove); // Replication algorithm
                                                    // link
        /* **********************END OF REPLICATION CODE************************ */
        } catch (Exception e) {
            e.printStackTrace();
            TraceCmi.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() {
        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(RequestCtx rctx) {
        try {
            JRepUtil.preInvokeHook(bs, clusterOId, rctx);
        } catch (EJBException e) {
            // COMPLETE: Handle errors
            e.printStackTrace();
            TraceCmi.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()
     * @parem 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(RequestCtx rctx, boolean remove) {
        JRepUtil.postInvokeHook(rctx, this.clusterOId, bs, remove);
    }

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

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

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