/**
* High Availability Service (HA) for JOnAS
*
* 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
*
* --------------------------------------------------------------------------
* $Id$
* --------------------------------------------------------------------------
*/

package org.objectweb.jonas.ha.interceptor;

import java.io.IOException;
import java.util.Stack;

import org.objectweb.carol.cmi.DistributedEquiv;
import org.objectweb.carol.cmi.configuration.TraceCmi;
import org.objectweb.carol.cmi.ha.Constants;
import org.objectweb.carol.cmi.ha.ViewIdWrapper;
import org.objectweb.carol.rmi.jrmp.interceptor.JServerRequestInfo;
import org.objectweb.carol.rmi.jrmp.interceptor.JServerRequestInterceptor;
import org.omg.PortableInterceptor.ForwardRequest;
import org.omg.PortableInterceptor.ServerRequestInfo;

/**
 * This class represents the server side of the interceptor mechanism
 * implemented to transfer replication related information between client
 * and server sides
 * @author Francisco Perez-Sorrosal (fpsorrosal@no-spam@fi.upm.es)
 * @author Alberto Paz-Jimenez (apaz@no-spam@fi.upm.es)
 */
public class HAServerInterceptor implements JServerRequestInterceptor {

    /**
     * Interceptor name
     */
    private String interceptorName = "HAServerInterceptor";

    /**
     * Constructor
     */
    public HAServerInterceptor() {
    }

    /**
     * Get the name of this interceptor
     * @return name
     */
    public String name() {
        return interceptorName;
    }

    /**
     * Analyzes the HAContext received and constructs the required
     * context on the HA current context (the thread associated class) on
     * the server side.
     */
    public void receive_request(JServerRequestInfo jri) throws IOException {
        TraceCmi.debugCmiHA("----------------------------------");
        TraceCmi.debugCmiHA("HAServerInterceptor: receive_request");
        // Get the HAContext from the received info
        HAContext receivedCtx = (HAContext) jri.get_request_service_context(Constants.HA_CTX_ID);
           if (TraceCmi.isDebugCmiHA()) {
               TraceCmi.debugCmiHA("receivedCtx" + receivedCtx);
        }
        // Get the current Thread/HAContext association class
        HACurrentDelegateImpl current = HACurrentDelegateImpl.getCurrent();

        if (receivedCtx != null) {
            Stack requests = receivedCtx.getRequests();
            current.setRequests(requests);
            current.pushServerViewIdWrapper(receivedCtx.getViewIdWrapper());
        } else {
            if (TraceCmi.isDebugCmiHA()) {
                TraceCmi.debugCmiHA("No HA context");
            }
        }

        boolean onFailover = receivedCtx.isOnFailover();
        current.setOnFailover(onFailover);

           TraceCmi.debugCmiHA("HACtx associated to Thread");
          TraceCmi.debugCmiHA("----------------------------------");
    }

    public void send_reply(JServerRequestInfo jri) throws IOException {
        if (TraceCmi.isDebugCmiHA()) {
            TraceCmi.debugCmiHA("----------------------------------");
            TraceCmi.debugCmiHA("HAClientInterceptor: send_reply");
        }
        putHAContext(jri);
        if (TraceCmi.isDebugCmiHA()) {
            TraceCmi.debugCmiHA("----------------------------------");
        }
    }

    public void destroy() {

    }

    public void receive_request_service_contexts(ServerRequestInfo ri)
            throws ForwardRequest {
    }

    public void send_exception(JServerRequestInfo jri) throws IOException {
        if (TraceCmi.isDebugCmiHA()) {
            TraceCmi.debugCmiHA("----------------------------------");
            TraceCmi.debugCmiHA("HAClientInterceptor: send_exception");
        }
        putHAContext(jri);
        if (TraceCmi.isDebugCmiHA()) {
            TraceCmi.debugCmiHA("----------------------------------");
        }
    }

    public void send_other(JServerRequestInfo jri) throws IOException {
        if (TraceCmi.isDebugCmiHA()) {
            TraceCmi.debugCmiHA("----------------------------------");
            TraceCmi.debugCmiHA("HAClientInterceptor: send_other");
        }
        putHAContext(jri);
        if (TraceCmi.isDebugCmiHA()) {
            TraceCmi.debugCmiHA("----------------------------------");
        }
    }

    private void putHAContext(JServerRequestInfo jri) {
        // invoke the viewId checking
        DistributedEquiv.doViewIdChecking();

        // Get the current HA Context info associated to the thread
        HACurrentDelegateImpl current = HACurrentDelegateImpl.getCurrent();
        // Create the new HAContext to propagate between interceptors
        HAContext newHACtx = new HAContext();

        Stack requests = current.getRequests();
        newHACtx.setRequests(requests);
        ViewIdWrapper wrapper = current.getServerViewIdWrapper();
        newHACtx.setViewIdWrapper(wrapper);

        if (TraceCmi.isDebugCmiHA()) {
            TraceCmi.debugCmiHA("newHACtx: " + newHACtx);
        }
        // Finally, include the new HAContext created to be propagated through
        // the interceptor
        jri.add_reply_service_context(newHACtx);
    }
}
