/*
 * JOnAS: Java(TM) Open Application Server
 * Copyright (C) 1999 Bull S.A.
 * Contact: jonas-team@objectweb.org
 * 
 * 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
 *
 * Initial developer(s): ____________________________________.
 * Contributor(s): ______________________________________.
 *
 * --------------------------------------------------------------------------
 * $Id$
 * --------------------------------------------------------------------------
 */

package org.objectweb.security.propagation;

import org.objectweb.jeremie.services.handler.api.Service;
import org.objectweb.jonathan.apis.kernel.Context;
import org.objectweb.jonathan.apis.kernel.JonathanException;
import org.objectweb.jonathan.presentation.api.Marshaller;
import org.objectweb.jonathan.presentation.api.MarshallerFactory;
import org.objectweb.jonathan.presentation.api.UnMarshaller;
import org.objectweb.jonathan.resources.api.Chunk;
import org.objectweb.jonathan.helpers.MessageHelpers;
import org.objectweb.security.context.SecurityContext;
import org.omg.IOP.ServiceContext;

public class SSHandler implements Service {

    private SecuritySender sender = null;
    private SecurityReceiver receiver = null;
    private MarshallerFactory mf;
    private int service_id = 200; // default value
   
    /** 
     * Creates a new SSHandler instance.
     */
    public SSHandler(Context c, Object[] used_components) throws JonathanException {
        int sid = ((Integer) used_components[0]).intValue();
        if (sid != Integer.MAX_VALUE) {
            service_id = sid;
        }
	
        try {
            sender = (SecuritySender) used_components[1];
            receiver = (SecurityReceiver) used_components[2];
            mf = (MarshallerFactory) used_components[3];
        } catch (Exception e) {
            throw new JonathanException(e);
        }
    }
    

    /** 
     * Returns a request context.
     * <p>
     * If sender is not null, this method encodes the security context 
     * returned by the sending_request method of the sender, else it returns null.
     * 
     * @param request_id        the request identifier;
     * @param response_expected unused;
     * @param object_key        unused.
     * @return                  a service context.
     */
    public ServiceContext getRequestContext(int request_id, 
                                            boolean response_expected, 
                                            byte[] object_key,
                                            Context kContext) {
        if (sender == null) {
            return null;
        }
        SecurityContext ctx = sender.sending_request(request_id);
        return encodeContext(ctx);
    }
	 
    
    /** 
     * Returns a reply context.
     * <p>
     * this method encodes the security context 
     * returned by its <code>sending_reply</code> method, else it returns null.
     *
     * @param request_id the corresponding request id.
     * @return           a service context.
     */
    public ServiceContext getReplyContext(int request_id, Context kContext) {
        if (receiver == null) {
            return null;
        }
        SecurityContext ctx = receiver.sending_reply(request_id);
        return encodeContext(ctx);
    }
    
    /** 
     * This method is called by the services handler to let the operations 
     * related to the target service be performed on request arrival.
     *
     * @param context            the service context of the request;
     * @param request_id         the request identifier;
     * @param response_expected  unused;
     * @param object_key         unused.
     */
    public void handleRequestContext(ServiceContext context, 
                                     int request_id,
                                     boolean response_expected, 
                                     byte[] object_key,
                                     Context kContext) {
        if ((receiver == null) ||
            (context == null) || 
            (context.context_data == null) || 
            (context.context_data.length == 0)) {
            return;
        }
        SecurityContext ctx = decodeContext(context);
        if (ctx != null) {
            receiver.received_request(request_id, ctx);
        }
    }
    
    /** 
     * This method is called by the services handler to let the operations 
     * related to the target service be performed on reply arrival.
     *
     * @param context     the service context of the reply;
     * @param request_id  the corresponding request identifier.
     */
    public void handleReplyContext(ServiceContext context, int request_id, Context kContext) {
        if ((receiver == null) ||
            (context == null) || 
            (context.context_data == null) || 
            (context.context_data.length == 0)) {
            return;
        }
        SecurityContext ctx = decodeContext(context);
        if (ctx != null) {
            sender.received_reply(request_id, ctx);
        }
    }
    
    /**
     * Encodes a Security context into an IOP service context.
     *
     * @param ctx the propagation context to be encoded.
     * @return the resulting IOP service context.
     */
    private ServiceContext encodeContext(SecurityContext ctx) {
        if (ctx == null) {
            return null;
        }
        Marshaller marshaller = mf.newMarshaller();
        byte[] byteArray = null;
        try {
            marshaller.writeReference(ctx);
            byteArray = MessageHelpers.copy(marshaller);
            marshaller.close();
        } catch (Exception e) {
            System.err.println("SSHandler.encodeContext: exception");
            e.printStackTrace();
        }
        return new ServiceContext(service_id, byteArray);
    }

    
    /**
     * Decodes a Security context from an IOP service context.
     *
     * @param ctx the IOP service context containing the encoded security context.
     * @return the decoded security context.
     */
    private SecurityContext decodeContext(ServiceContext sc) {
        if ((sc == null) ||
            (sc.context_data == null) ||
            (sc.context_data.length == 0)) {
            return null;
        }
        SecurityContext ctx = null;
        byte[] byteArray = sc.context_data;
        UnMarshaller unmarshaller = 
            mf.newUnMarshaller(new Chunk(byteArray, 0, byteArray.length), 0);
        try {
            ctx = (SecurityContext) unmarshaller.readReference();
            unmarshaller.close();
        } catch (Exception e) {
            System.err.println("SSHandler.decodeContext: exception");
            System.err.println(e.toString() + "\n");
        }
        return ctx;
    }  
   
}
