context: // **********************************************************************
  //
  // Copyright (c) 2003-2017 ZeroC, Inc. All rights reserved.
  //
  // This copy of Ice is licensed to you under the terms described in the
  // ICE_LICENSE file included in this distribution.
  //
  // **********************************************************************
  
  using System;
  using System.Collections;
  using System.Collections.Generic;
  using System.Diagnostics;
  using System.Threading;
  using Ice.Instrumentation;
  
  namespace IceInternal
  {
      public class CollocatedRequestHandler : RequestHandler, ResponseHandler
      {
          private void
          fillInValue(Ice.OutputStream os, int pos, int value)
          {
              os.rewriteInt(value, pos);
          }
  
          public
          CollocatedRequestHandler(Reference @ref, Ice.ObjectAdapter adapter)
          {
              _reference = @ref;
              _dispatcher = _reference.getInstance().initializationData().dispatcher != null;
              _response = _reference.getMode() == Reference.Mode.ModeTwoway;
              _adapter = (Ice.ObjectAdapterI)adapter;
  
              _logger = _reference.getInstance().initializationData().logger; // Cached for better performance.
              _traceLevels = _reference.getInstance().traceLevels(); // Cached for better performance.
              _requestId = 0;
          }
  
          public RequestHandler update(RequestHandler previousHandler, RequestHandler newHandler)
          {
              return previousHandler == this ? newHandler : this;
          }
  
          public int sendAsyncRequest(ProxyOutgoingAsyncBase outAsync)
          {
              return outAsync.invokeCollocated(this);
          }
  
          public void asyncRequestCanceled(OutgoingAsyncBase outAsync, Ice.LocalException ex)
          {
              lock(this)
              {
                  int requestId;
                  if(_sendAsyncRequests.TryGetValue(outAsync, out requestId))
                  {
                      if(requestId > 0)
                      {
                          _asyncRequests.Remove(requestId);
                      }
                      _sendAsyncRequests.Remove(outAsync);
                      if(outAsync.exception(ex))
                      {
                          outAsync.invokeExceptionAsync();
                      }
                      _adapter.decDirectCount(); // invokeAll won't be called, decrease the direct count.
                      return;
                  }
                  if(outAsync is OutgoingAsync)
                  {
                      OutgoingAsync o = (OutgoingAsync)outAsync;
                      Debug.Assert(o != null);
                      foreach(KeyValuePair<int, OutgoingAsyncBase> e in _asyncRequests)
                      {
                          if(e.Value == o)
                          {
                              _asyncRequests.Remove(e.Key);
                              if(outAsync.exception(ex))
                              {
                                  outAsync.invokeExceptionAsync();
                              }
                              return;
                          }
                      }
                  }
              }
          }
  
          public void sendResponse(int requestId, Ice.OutputStream os, byte status, bool amd)
          {
              OutgoingAsyncBase outAsync;
              lock(this)
              {
                  Debug.Assert(_response);
  
                  if(_traceLevels.protocol >= 1)
                  {
                      fillInValue(os, 10, os.size());
                  }
  
                  // Adopt the OutputStream's buffer.
                  Ice.InputStream iss = new Ice.InputStream(os.instance(), os.getEncoding(), os.getBuffer(), true);
  
                  iss.pos(Protocol.replyHdr.Length + 4);
  
                  if(_traceLevels.protocol >= 1)
                  {
                      TraceUtil.traceRecv(iss, _logger, _traceLevels);
                  }
  
                  if(_asyncRequests.TryGetValue(requestId, out outAsync))
                  {
                      outAsync.getIs().swap(iss);
                      if(!outAsync.response())
                      {
                          outAsync = null;
                      }
                      _asyncRequests.Remove(requestId);
                  }
              }
  
              if(outAsync != null)
              {
                  if(amd)
                  {
                      outAsync.invokeResponseAsync();
                  }
                  else
                  {
                      outAsync.invokeResponse();
                  }
              }
              _adapter.decDirectCount();
          }
  
          public void
          sendNoResponse()
          {
              _adapter.decDirectCount();
          }
  
          public bool
          systemException(int requestId, Ice.SystemException ex, bool amd)
          {
              handleException(requestId, ex, amd);
              _adapter.decDirectCount();
              return true;
          }
  
          public void
          invokeException(int requestId, Ice.LocalException ex, int invokeNum, bool amd)
          {
              handleException(requestId, ex, amd);
              _adapter.decDirectCount();
          }
  
          public Reference
          getReference()
          {
              return _reference;
          }
  
          public Ice.ConnectionI
          getConnection()
          {
              return null;
          }
  
          public int invokeAsyncRequest(OutgoingAsyncBase outAsync, int batchRequestNum, bool synchronous)
          {
              //
              // Increase the direct count to prevent the thread pool from being destroyed before
              // invokeAll is called. This will also throw if the object adapter has been deactivated.
              //
              _adapter.incDirectCount();
  
              int requestId = 0;
              try
              {
                  lock(this)
                  {
                      outAsync.cancelable(this); // This will throw if the request is canceled
  
                      if(_response)
                      {
                          requestId = ++_requestId;
                          _asyncRequests.Add(requestId, outAsync);
                      }
  
                      _sendAsyncRequests.Add(outAsync, requestId);
                  }
              }
              catch(Exception)
              {
                  _adapter.decDirectCount();
                  throw;
              }
  
              outAsync.attachCollocatedObserver(_adapter, requestId);
              if(!synchronous || !_response || _reference.getInvocationTimeout() > 0)
              {
                  // Don't invoke from the user thread if async or invocation timeout is set
                  _adapter.getThreadPool().dispatch(
                      () =>
                      {
                          if (sentAsync(outAsync))
                          {
                              invokeAll(outAsync.getOs(), requestId, batchRequestNum);
                          }
                      }, null);
              }
              else if(_dispatcher)
              {
                  _adapter.getThreadPool().dispatchFromThisThread(
                      () =>
                      {
                          if (sentAsync(outAsync))
                          {
                              invokeAll(outAsync.getOs(), requestId, batchRequestNum);
                          }
                      }, null);
              }
              else // Optimization: directly call invokeAll if there's no dispatcher.
              {
                  if(sentAsync(outAsync))
                  {
  
gt:                     invokeAll(outAsync.getOs(), requestId, batchRequestNum);