/**
 * High Availability Service (HA) for JOnAS
 *
 * Copyright (C) 2007,2008 Bull S.A.S.
 * 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.ow2.jonas.lib.ejb21.ha.interceptors.iiop;

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

import org.objectweb.util.monolog.api.BasicLevel;
import org.objectweb.util.monolog.api.Logger;
import org.omg.IOP.ServiceContext;
import org.omg.PortableInterceptor.ForwardRequest;
import org.omg.PortableInterceptor.ServerRequestInfo;
import org.omg.PortableInterceptor.ServerRequestInterceptor;
import org.ow2.cmi.ha.RequestId;
import org.ow2.cmi.ha.interceptor.HAContext;
import org.ow2.cmi.ha.interceptor.HACurrent;
import org.ow2.jonas.lib.ejb21.ha.interceptors.jrmp.HAServiceContext;
import org.ow2.jonas.lib.util.Log;

/**
 * This class represents the server side of the interceptor mechanism
 * implemented to transfer replication related information between client
 * and server sides
 * @author Loris Bouzonnet
 */
public class HAServerInterceptor
extends HAInterceptor implements ServerRequestInterceptor {

    /**
     * Id for serializable class.
     */
    private static final long serialVersionUID = 686400419582706917L;

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

    /**
     * Logger for traces
     */
    private static Logger logger = Log.getLogger("org.ow2.jonas.lib.ejb21.ha.interceptors.iiop");

    private HAContext receivedCtx;

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

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


    public void receive_request_service_contexts(final ServerRequestInfo ri)
    throws ForwardRequest {
        logger.log(BasicLevel.DEBUG, "");
        try {
            ServiceContext serviceContext = ri.get_request_service_context(HAServiceContext.HA_CTX_ID);
            receivedCtx = unmarshallHAContext(serviceContext.context_data);
            if (logger.isLoggable(BasicLevel.DEBUG)) {
                logger.log(BasicLevel.DEBUG, receivedCtx.toString());
            }
        } catch (org.omg.CORBA.BAD_PARAM e) {
            // No HA context, do nothing
        } catch (IOException e) {
            logger.log(BasicLevel.ERROR, "Error while unmarshalling", e);
        } catch (ClassNotFoundException e) {
            logger.log(BasicLevel.ERROR, "Error while unmarshalling", e);
        }
    }

    /**
     * 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(final ServerRequestInfo jri) throws ForwardRequest {

        if(receivedCtx != null) {
            // Get the current Thread/HAContext association class
            HACurrent current = HACurrent.getHACurrent();
            Stack<RequestId> requests = receivedCtx.getRequests();
            current.setRequests(requests);

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

            if (logger.isLoggable(BasicLevel.DEBUG)) {
                logger.log(BasicLevel.DEBUG, "HACtx associated to Thread");
            }
        }
    }

    public void send_reply(final ServerRequestInfo jri) {
        logger.log(BasicLevel.DEBUG, "");
        putHAContext(jri);
    }

    public void destroy() {

    }

    public void send_exception(final ServerRequestInfo jri) throws ForwardRequest {
        logger.log(BasicLevel.DEBUG, "");
        putHAContext(jri);
    }

    public void send_other(final ServerRequestInfo jri) throws ForwardRequest {
        logger.log(BasicLevel.DEBUG, "");
        putHAContext(jri);
    }

    private void putHAContext(final ServerRequestInfo serverRequestInfo) {
        // Get the current HA Context info associated to the thread
        HACurrent current = HACurrent.getHACurrent();

        HAContext haContext = new HAContext();

        Stack<RequestId> requests = current.getRequests();
        haContext.setRequests(requests);

        if (logger.isLoggable(BasicLevel.DEBUG)) {
            logger.log(BasicLevel.DEBUG, "newHACtx: " + haContext);
        }
        ServiceContext serviceContext;
        try {
            serviceContext = new ServiceContext(HA_CTX_ID, marshallHAContext(haContext));
            serverRequestInfo.add_reply_service_context(serviceContext, true);
        } catch (IOException e) {
            logger.log(BasicLevel.ERROR, "Error while marshalling " + haContext, e);
        }
    }

}
