/*
* The Apache Software License, Version 1.1
*
*
* Copyright (c) 2001-2003 The Apache Software Foundation.  All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
*    notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
*    notice, this list of conditions and the following disclaimer in
*    the documentation and/or other materials provided with the
*    distribution.
*
* 3. The end-user documentation included with the redistribution,
*    if any, must include the following acknowledgment:
*       "This product includes software developed by the
*        Apache Software Foundation (http://www.apache.org/)."
*    Alternately, this acknowledgment may appear in the software itself,
*    if and wherever such third-party acknowledgments normally appear.
*
* 4. The names "Axis" and "Apache Software Foundation" must
*    not be used to endorse or promote products derived from this
*    software without prior written permission. For written
*    permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache",
*    nor may "Apache" appear in their name, without prior written
*    permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation.  For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/

package org.jboss.axis.providers.java;

import org.jboss.axis.AxisFault;
import org.jboss.axis.MessageContext;
import org.jboss.axis.description.OperationDesc;
import org.jboss.axis.message.SOAPEnvelopeAxisImpl;
import org.jboss.axis.utils.Messages;
import org.jboss.logging.Logger;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * Implement message processing by walking over RPCElements of the
 * envelope body, invoking the appropriate methods on the service object.
 *
 * @author Doug Davis (dug@us.ibm.com)
 */
public class RPCProvider extends JavaProvider
{

   private static Logger log = Logger.getLogger(RPCProvider.class.getName());

   /**
    * The key for the invocation object in the MessageContext
    */
   public final static String RPC_INVOCATION = "axis.provider.java.rpc-invocation";

   /**
    * Process the current message.
    * Result in resEnv.
    *
    * @param msgContext self-explanatory
    * @param reqEnv     the request envelope
    * @param resEnv     the response envelope
    * @param obj        the service object itself
    */
   public void processMessage(MessageContext msgContext, SOAPEnvelopeAxisImpl reqEnv, SOAPEnvelopeAxisImpl resEnv, Object obj)
           throws Exception
   {

      if (log.isDebugEnabled())
      {
         log.debug("Enter: RPCProvider.processMessage()");
      }

      RPCInvocation invocation = createRPCInvocation(msgContext, reqEnv, resEnv, obj);
      invocation.prepareFromRequestEnvelope();

      OperationDesc operation = invocation.getOperation();
      Object[] argValues = invocation.getArgValues();

      // store it in the messsage context, so that ws4ee handlers
      // can pick it up and modify the invocation if neccessary
      msgContext.setProperty(RPC_INVOCATION, invocation);

      // This is a hack that disables AsString representation of the SOAPPart
      // for as long as we are processing the message. WS4EE need access to the SOAPEnvelope's DOM model.
      // TDI 15-June-2004
      reqEnv.setProcessingRPCInvocation(true);
      resEnv.setProcessingRPCInvocation(true);

      // OK!  Now we can invoke the method
      try
      {
         Object resObj = invokeTarget(invocation);
         invocation.prepareResponseEnvelope(resObj);
      }
      catch (IllegalArgumentException e)
      {
         String methodSig = operation.toString();
         String argClasses = "";
         for (int i = 0; i < argValues.length; i++)
         {
            if (argValues[i] == null)
            {
               argClasses += "null";
            }
            else
            {
               argClasses += argValues[i].getClass().getName();
            }
            if (i + 1 < argValues.length)
            {
               argClasses += ",";
            }
         }
         log.info(Messages.getMessage("dispatchIAE00", new String[]{methodSig, argClasses}), e);
         throw new AxisFault(Messages.getMessage("dispatchIAE00", new String[]{methodSig, argClasses}), e);
      }
      finally
      {
         reqEnv.setProcessingRPCInvocation(false);
         resEnv.setProcessingRPCInvocation(false);
      }
   }

   public RPCInvocation createRPCInvocation(MessageContext msgContext, SOAPEnvelopeAxisImpl reqEnv, SOAPEnvelopeAxisImpl resEnv, Object obj)
   {
      RPCInvocation invocation = new RPCInvocation(this, msgContext, reqEnv, resEnv, obj);
      return invocation;
   }

   /**
    * Unwraps the invocation and calls invokeMethod
    *
    * @param invocation The invocation
    * @return Return value from invokeMethod
    * @throws Exception Any client Exception
    */
   protected Object invokeTarget(RPCInvocation invocation) throws Exception
   {

      MessageContext msgContext = invocation.getMessageContext();
      Object targetObject = invocation.getTargetObject();
      Method method = invocation.getOperation().getMethod();
      Object[] argValues = invocation.getArgValues();

      try
      {
         Object objRes = invokeMethod(msgContext, method, targetObject, argValues);
         return objRes;
      }
      catch (InvocationTargetException e)
      {
         if (e.getTargetException() instanceof Exception)
            throw (Exception)e.getTargetException();
         else
            throw e;
      }
      finally
      {
         msgContext.setPastPivot(true);
      }
   }

   /**
    * This method encapsulates the method invocation.
    *
    * @param msgContext MessageContext
    * @param method     the target method.
    * @param obj        the target object
    * @param argValues  the method arguments
    */
   protected Object invokeMethod(MessageContext msgContext, Method method, Object obj, Object[] argValues)
           throws Exception
   {

      return (method.invoke(obj, argValues));
   }

   /**
    * Throw an AxisFault if the requested method is not allowed.
    *
    * @param msgContext     MessageContext
    * @param allowedMethods list of allowed methods
    * @param methodName     name of target method
    */
   protected void checkMethodName(MessageContext msgContext, String allowedMethods, String methodName)
           throws Exception
   {

      // Our version doesn't need to do anything, though inherited ones might.
   }
}