#include "ClientInterceptorAdapter.h"

#if TAO_HAS_INTERCEPTORS == 1

#if !defined (__ACE_INLINE__)
#include "ClientInterceptorAdapter.inl"
#endif /* defined INLINE */

#include "ClientRequestInfo.h"
#include "ClientRequestInfo_i.h"
#include "Invocation.h"
#include "ORB_Core.h"

ACE_RCSID (tao,
           ClientInterceptorAdapter,
           "ClientInterceptorAdapter.cpp,v 1.7 2002/03/08 04:46:31 ossama Exp")

TAO_ClientRequestInterceptor_Adapter::
~TAO_ClientRequestInterceptor_Adapter (void)
{
}

void
TAO_ClientRequestInterceptor_Adapter::
send_request (TAO_ClientRequestInfo_i *ri
              ACE_ENV_ARG_DECL)
{
  // This method implements one of the "starting" client side
  // interception point.

  ACE_TRY
    {
      // Only perform the TSS access if interceptors were registered
      // with the ORB.
      if (this->len_ > 0)
        this->info_ =
          this->invocation_->orb_core ()->
          get_tss_resources ()->client_request_info_;

      TAO_ClientRequestInfo_Guard info_guard (this->info_, ri);

      for (size_t i = 0 ; i < this->len_; ++i)
        {
          this->interceptors_[i]->send_request (this->info_
                                                ACE_ENV_ARG_PARAMETER);
          ACE_TRY_CHECK;

          // The starting interception point completed successfully.
          // Push  the interceptor on to the flow stack.
          ++this->stack_size_;
        }
    }
  ACE_CATCH (PortableInterceptor::ForwardRequest, exc)
    {
      this->process_forward_request (ri, exc ACE_ENV_ARG_PARAMETER);
      ACE_TRY_CHECK;
    }
  ACE_ENDTRY;
  ACE_CHECK;
}

void
TAO_ClientRequestInterceptor_Adapter::
receive_reply (TAO_ClientRequestInfo_i *ri
               ACE_ENV_ARG_DECL)
{
  // This is an "ending" interception point so we only process the
  // interceptors pushed on to the flow stack.

  // Notice that the interceptors are processed in the opposite order
  // they were pushed onto the stack since this is an "ending"
  // interception point.

  TAO_ClientRequestInfo_Guard info_guard (this->info_, ri);

  // Unwind the stack.
  size_t len = this->stack_size_;
  for (size_t i = 0; i < len; ++i)
    {
      // Pop the interceptor off of the flow stack before it is
      // invoked.  This is necessary to prevent an interceptor already
      // invoked in this "ending" interception point from being
      // invoked in another "ending" interception point.
      --this->stack_size_;

      this->interceptors_[this->stack_size_]->receive_reply (
        this->info_
        ACE_ENV_ARG_PARAMETER);
      ACE_CHECK;
    }

  // The receive_reply() interception point does not raise a
  // PortableInterceptor::ForwardRequest exception so there is no need
  // to attempt to catch it here.
}

void
TAO_ClientRequestInterceptor_Adapter::
receive_exception (TAO_ClientRequestInfo_i *ri
                   ACE_ENV_ARG_DECL)
{
  // This is an "ending" interception point so we only process the
  // interceptors pushed on to the flow stack.

  // Notice that the interceptors are processed in the opposite order
  // they were pushed onto the stack since this is an "ending"
  // interception point.

  ACE_TRY
    {
      TAO_ClientRequestInfo_Guard info_guard (this->info_, ri);

      // Unwind the flow stack.
      size_t len = this->stack_size_;
      for (size_t i = 0; i < len; ++i)
        {
          // Pop the interceptor off of the flow stack before it is
          // invoked.  This is necessary to prevent an interceptor
          // already invoked in this "ending" interception point from
          // being invoked in another "ending" interception point.
          --this->stack_size_;

          this->interceptors_[this->stack_size_]->receive_exception (
            this->info_
            ACE_ENV_ARG_PARAMETER);
          ACE_TRY_CHECK;
        }
    }
  ACE_CATCH (PortableInterceptor::ForwardRequest, exc)
    {
      this->process_forward_request (ri, exc ACE_ENV_ARG_PARAMETER);
      ACE_TRY_CHECK;
    }
  ACE_CATCHANY
    {
      // The receive_exception() interception point in the remaining
      // interceptors must be called so call this method (not the
      // interceptor's corresponding method) recursively.  The call is
      // made recursively since the caught exception must survive
      // until the remaining interceptors have been called.

      // Note that the recursion will stop once the flow stack size
      // drops to zero, i.e., once each interceptor has been invoked.
      // This prevents infinite recursion from occuring.

      ri->exception (&ACE_ANY_EXCEPTION);

      this->receive_exception (ri ACE_ENV_ARG_PARAMETER);
      ACE_TRY_CHECK;

      PortableInterceptor::ReplyStatus status =
        ri->reply_status (ACE_ENV_SINGLE_ARG_PARAMETER);
      ACE_TRY_CHECK;

      // Only re-throw the exception if it hasn't been transformed by
      // the receive_exception() interception point (e.g. to a
      // LOCATION_FORWARD).
      if (status == PortableInterceptor::SYSTEM_EXCEPTION
          || status == PortableInterceptor::USER_EXCEPTION)
        ACE_RE_THROW;
    }
  ACE_ENDTRY;
  ACE_CHECK;
}

void
TAO_ClientRequestInterceptor_Adapter::
receive_other (TAO_ClientRequestInfo_i *ri
               ACE_ENV_ARG_DECL)
{
  // This is an "ending" interception point so we only process the
  // interceptors pushed on to the flow stack.

  // Notice that the interceptors are processed in the opposite order
  // they were pushed onto the stack since this is an "ending"
  // interception point.

  ACE_TRY
    {
      TAO_ClientRequestInfo_Guard info_guard (this->info_, ri);

      // Unwind the stack.
      size_t len = this->stack_size_;
      for (size_t i = 0; i < len; ++i)
        {
          // Pop the interceptor off of the flow stack before it is
          // invoked.  This is necessary to prevent an interceptor
          // already invoked in this "ending" interception point from
          // being invoked in another "ending" interception point.
          --this->stack_size_;

          this->interceptors_[this->stack_size_]->receive_other (
            this->info_
            ACE_ENV_ARG_PARAMETER);
          ACE_TRY_CHECK;
        }
    }
  ACE_CATCH (PortableInterceptor::ForwardRequest, exc)
    {
      this->process_forward_request (ri, exc ACE_ENV_ARG_PARAMETER);
      ACE_TRY_CHECK;
    }
  ACE_ENDTRY;
  ACE_CHECK;
}

void
TAO_ClientRequestInterceptor_Adapter::process_forward_request (
  TAO_ClientRequestInfo_i *ri,
  PortableInterceptor::ForwardRequest &exc
  ACE_ENV_ARG_DECL)
{
  ri->forward_reference (exc);

  this->invoke_status_ =
    this->invocation_->location_forward (exc.forward.in ()
                                         ACE_ENV_ARG_PARAMETER);
  ACE_CHECK;

  // receive_other() is potentially invoked recursively.
  this->receive_other (ri
                       ACE_ENV_ARG_PARAMETER);
  ACE_CHECK;
}

#endif /* TAO_HAS_INTERCEPTORS == 1 */
