//$Header$
/////////////////////////////////////////////////////////////////////////////
//PROPRIETARY RIGHTS STATEMENT
//The contents of this file represent confidential information that is the
//proprietary property of Active Endpoints, Inc.  Viewing or use of
//this information is prohibited without the express written consent of
//Active Endpoints, Inc. Removal of this PROPRIETARY RIGHTS STATEMENT
//is strictly forbidden. Copyright (c) 2002-2004 All rights reserved.
/////////////////////////////////////////////////////////////////////////////
package org.apache.sandesha.server;

import org.apache.axis.MessageContext;
import org.apache.axis.components.logger.LogFactory;
import org.apache.axis.components.uuid.UUIDGen;
import org.apache.axis.components.uuid.UUIDGenFactory;
import org.apache.axis.message.addressing.AddressingHeaders;
import org.apache.axis.providers.java.JavaProvider;
import org.apache.commons.logging.Log;
import org.apache.sandesha.Constants;
import org.apache.sandesha.IStorageManager;
import org.apache.sandesha.RMMessageContext;
import org.apache.sandesha.util.PropertyLoader;
import org.apache.sandesha.util.RMMessageCreator;

/**
 *  
 */
public class RMInvokerDelegate
{

   private static final Log sLog = LogFactory.getLog(RMInvokerDelegate.class.getName());
   private static final UUIDGen sUuidGen = UUIDGenFactory.getUUIDGen();

   private RMMessageContext mMessageContext;
   private IStorageManager mStorageManager;
   
   

   public RMInvokerDelegate(IStorageManager aStorageManager, RMMessageContext aMessageContext)
   {
      mMessageContext = aMessageContext;
      mStorageManager = aStorageManager;
   }

   protected boolean doRealInvoke() throws Exception
   {
      Class c = Class.forName(PropertyLoader.getProvider());
      JavaProvider provider = (JavaProvider) c.newInstance();
      provider.invoke(getRMMessageContext().getMsgContext());
      return getRMMessageContext().getMsgContext().getOperation().getMethod().getReturnType() == Void.TYPE;
   }

   public void doDelegateInvoke()
   {
      try
      {
         AddressingHeaders addrHeaders = getRMMessageContext()
               .getAddressingHeaders();
         boolean isVoid = doRealInvoke();

         if( !isVoid )
         {

            String oldAction = getRMMessageContext().getAddressingHeaders()
                  .getAction().toString();
            getRMMessageContext().getAddressingHeaders().setAction(
                  oldAction + Constants.RESPONSE);
            if( getRMMessageContext().isLastMessage() )
            {
               //Insert Terminate Sequnce.
               if( addrHeaders.getReplyTo() != null )
               {
                  String replyTo = addrHeaders.getReplyTo().getAddress()
                        .toString();
                  RMMessageContext terminateMsg = RMMessageCreator
                        .createTerminateSeqMsg(getRMMessageContext(),
                              Constants.SERVER);
                  terminateMsg.setOutGoingAddress(replyTo);
                  getStorageManager().insertTerminateSeqMessage(terminateMsg);
               }
               else
               {
                  sLog
                        .error(Constants.ErrorMessages.CANNOT_SEND_THE_TERMINATE_SEQ);
               }
            }
            //Store the message in the response queue. If there is an
            // application
            // response then that
            // response is always sent using a new HTTP connection and the
            // <replyTo> header is
            // used in this case. This is done by the RMSender.
            getRMMessageContext().setMessageType(
                  Constants.MSG_TYPE_SERVICE_RESPONSE);

            boolean hasResponseSeq = getStorageManager()
                  .isResponseSequenceExist(
                        getRMMessageContext().getSequenceID());
            boolean firstMsgOfResponseSeq = false;
            if( !(hasResponseSeq && getRMMessageContext().getRMHeaders()
                  .getSequence().getMessageNumber().getMessageNumber() == 1) )
            {
               firstMsgOfResponseSeq = !hasResponseSeq;
            }

            getRMMessageContext().setMsgNumber(
                  getStorageManager().getNextMessageNumber(
                        getRMMessageContext().getSequenceID()));
            getStorageManager().insertOutgoingMessage(getRMMessageContext());

            if( firstMsgOfResponseSeq )
            {
               String msgIdStr = generateUUID();

               RMMessageContext csRMMsgCtx = RMMessageCreator
                     .createCreateSeqMsg(getRMMessageContext(),
                           Constants.SERVER, msgIdStr, null);
               csRMMsgCtx.setOutGoingAddress(getRMMessageContext()
                     .getAddressingHeaders().getReplyTo().getAddress()
                     .toString());

               csRMMsgCtx.addToMsgIdList(msgIdStr);
               csRMMsgCtx.setMessageID(msgIdStr);

               getStorageManager().setTemporaryOutSequence(
                     csRMMsgCtx.getSequenceID(), msgIdStr);
               getStorageManager().addCreateSequenceRequest(csRMMsgCtx);
            }
         }
      }
      catch( InterruptedException error )
      {
         error.printStackTrace();
         sLog.error(error);
      }
      catch( Exception error )
      {
         error.printStackTrace();
         sLog.error(error);
      }
   }

   protected String generateUUID()
   {
      return Constants.UUID + sUuidGen.nextUUID();
   }

   /**
    * @return Returns the storageManager.
    */
   protected IStorageManager getStorageManager()
   {
      return mStorageManager;
   }

   protected RMMessageContext getRMMessageContext()
   {
      return mMessageContext;
   }
}