/*
 * 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.jonas.rmifilters;

import org.objectweb.david.apis.services.handler.Service;
import org.objectweb.jonas_tm.TransactionContext;
import org.objectweb.jonathan.apis.kernel.Context;
import org.objectweb.jonathan.apis.kernel.JonathanException;
import org.objectweb.jonathan.apis.presentation.MarshallerFactory;
import org.objectweb.jonathan.apis.presentation.Marshaller;
import org.objectweb.jonathan.apis.presentation.UnMarshaller;
import org.objectweb.jonathan.apis.resources.Chunk;
import org.objectweb.jonathan.libs.helpers.MessageHelpers;
import org.omg.IOP.ServiceContext;

public class TSHandler implements Service {

    private JonasTransactionSender sender = null;
    private JonasTransactionReceiver receiver = null;
    private MarshallerFactory mf;
    private int service_id = 0;

   /** 
    * Builds a new Jeremie transaction service handler instance.
    * @param c unused
    * @param used_components the components used to initialize the new TSHandler.
    * @exception JonathanException if something goes wrong.
    */
   public TSHandler(Context c, Object[] used_components) throws JonathanException {
       int sid = ((Integer) used_components[0]).intValue();
       if (sid != Integer.MAX_VALUE) {
	   service_id = sid;
       }
       try {
	   sender = (JonasTransactionSender) used_components[1];
	   receiver = (JonasTransactionReceiver) used_components[2];
	   mf = (MarshallerFactory) used_components[3];
       } catch (Exception e) {
	   throw new JonathanException(e);
       }
   }
   
    /** 
     * Returns a request context.
     * @return                  a service context.
     */
    public ServiceContext getRequestContext(int id, boolean r, byte[] key, Context k) {
	if (sender == null) {
	    return null;
	}
	TransactionContext ctx = sender.sending_request();
	return encodeContext(ctx);
    }
	 
    
    /** 
     * Returns a reply context.
     * @return           a service context.
     */
    public ServiceContext getReplyContext(int id, Context k) {
	if (receiver == null) {
	    return null;
	}
	TransactionContext ctx = receiver.sending_reply();
	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;
     */
    public void handleRequestContext(ServiceContext context, int id, boolean r, byte[] key, Context k) {
	if (receiver == null || context == null) {
	    return;
	}
	TransactionContext ctx = decodeContext(context);
	if (ctx != null) {
	    receiver.received_request(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;
     */
    public void handleReplyContext(ServiceContext context, int id, Context k) {
	if (sender == null || context == null) {
	    return;
	}
	TransactionContext ctx = decodeContext(context);
	if (ctx != null) {
	    sender.received_reply(ctx);
	}
    }
    
   /**
    * Encodes a Transaction Service propagation context into an IOP service
    * context.
    * @param ctx the propagation context to be encoded.
    * @return the resulting IOP service context.
    */
   private ServiceContext encodeContext(TransactionContext ctx) {
      if (ctx == null) {
         return null;
      }
      Marshaller marshaller = mf.newMarshaller();
      byte[] byteArray = null;
      try {
         marshaller.writeValue(ctx);
         byteArray = MessageHelpers.copy(marshaller);
         marshaller.close();
      } catch (Exception e) {
         System.err.println("TSHandler.encodeContext: exception");
      }
      return new ServiceContext(service_id, byteArray);
   }
   
   /**
    * Decodes a Transaction Service propagation context from an IOP service
    * context.
    *
    * @param ctx the IOP service context containing the encoded propagation
    *    context.
    * @return the decoded propagation context.
    */
   private TransactionContext decodeContext(ServiceContext sc) {
      if (sc == null || sc.context_data == null || sc.context_data.length == 0 ) {
         return null;
      }
      TransactionContext ctx = null;
      byte[] byteArray = sc.context_data;
      UnMarshaller unmarshaller = 
         mf.newUnMarshaller(new Chunk(byteArray, 0, byteArray.length), 0);
      try {
         ctx = (TransactionContext) unmarshaller.readValue();
         unmarshaller.close();
      } catch (Exception e) {
         System.err.println("TSHandler.decodeContext: exception");
         System.err.println(e.toString() + "\n");
      }
      return ctx;
   }
   
}
