/**
 * 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.ClientRequestInfo;
import org.omg.PortableInterceptor.ClientRequestInterceptor;
import org.omg.PortableInterceptor.ForwardRequest;
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.util.Log;

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

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

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

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

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

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

    /**
     * Constructs the HAContext with the required replication information on
     * the client side
     */
    public void send_request(final ClientRequestInfo jri) throws ForwardRequest {
        logger.log(BasicLevel.DEBUG, "");

        // Get the current HA Context info associated to the thread
        HACurrent current = HACurrent.getHACurrent();
        // Fill the "req_id" field to propagate through the interceptor if the
        // nextReq has been included in the HA current context (held in the
        // thread-local variable) by the stub

        HAContext newHACtx = new HAContext();

        Stack<RequestId> requests = current.getRequests();
        newHACtx.setRequests(requests);
        newHACtx.setOnFailover(current.isOnFailover());
        if (logger.isLoggable(BasicLevel.DEBUG)) {
            logger.log(BasicLevel.DEBUG, "Propagating requests chain: " + newHACtx);
        }
        ServiceContext serviceContext;
        try {
            serviceContext = new ServiceContext(HA_CTX_ID, marshallHAContext(newHACtx));
            jri.add_request_service_context(serviceContext, true);
        } catch (IOException e) {
            logger.log(BasicLevel.ERROR, "Error while marshalling " + newHACtx, e);
        }
    }

    public void receive_reply(final ClientRequestInfo jri) {
        logger.log(BasicLevel.DEBUG, "");
        getHAContext(jri);
    }

    public void receive_exception(final ClientRequestInfo jri) throws ForwardRequest {
        logger.log(BasicLevel.DEBUG, "");
        getHAContext(jri);
    }

    public void receive_other(final ClientRequestInfo jri) throws ForwardRequest {
        logger.log(BasicLevel.DEBUG, "");
        getHAContext(jri);
    }

    //-------------------------------------------------------------------------
    // Other public unused methods
    //-------------------------------------------------------------------------

    public void destroy() {
    }

    public void send_poll(final ClientRequestInfo jri) {
    }

    private void getHAContext(final ClientRequestInfo clientRequestInfo) {
        try {
            ServiceContext serviceContext = clientRequestInfo.get_request_service_context(HA_CTX_ID);
            HAContext receivedCtx = unmarshallHAContext(serviceContext.context_data);
            if (logger.isLoggable(BasicLevel.DEBUG)) {
                logger.log(BasicLevel.DEBUG, "receivedCtx: " + receivedCtx);
            }
            // Get the current Thread/HAContext association class
            HACurrent current = HACurrent.getHACurrent();

            Stack<RequestId> requests = receivedCtx.getRequests();
            current.setRequests(requests);
        } 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);
        }
    }

}
