public ServerProcessing ProcessMessage(IServerChannelSinkStack sinkStack, IMessage requestMsg, ITransportHeaders requestHeaders, Stream requestStream, out IMessage responseMsg, out ITransportHeaders responseHeaders, out Stream responseStream)
        {
            if (requestMsg != null)
            {
                // the message has already been deserialized so delegate to the next sink
                return(_nextSink.ProcessMessage(
                           sinkStack,
                           requestMsg, requestHeaders, requestStream,
                           out responseMsg, out responseHeaders, out responseStream));
            }

            // parameters validation
            if (sinkStack == null)
            {
                throw new ArgumentNullException("sinkStack");
            }
            if (requestHeaders == null)
            {
                throw new ArgumentNullException("requestHeaders");
            }
            if (requestStream == null)
            {
                throw new ArgumentNullException("requestStream");
            }

            // deserialize request
            IMethodCallMessage methodCall = _formatter.DeserializeRequest(requestHeaders, requestStream);

            requestStream.Close();

            // prepare stack for request processing
            sinkStack.Push(this, null);

            // process request
            ServerProcessing     processing;
            IMethodReturnMessage methodReturn = null;

            try
            {
                // call next sink to dispatch method call
                processing = _nextSink.ProcessMessage(
                    sinkStack,
                    methodCall, requestHeaders, null,
                    out responseMsg, out responseHeaders, out responseStream);

                if (processing == ServerProcessing.Complete)
                {
                    // response headers and stream must be null at this point!
                    if (responseHeaders != null)
                    {
                        throw new NotSupportedException();
                    }
                    if (responseStream != null)
                    {
                        throw new NotSupportedException();
                    }

                    // check response
                    methodReturn = responseMsg as IMethodReturnMessage;
                    if (methodReturn == null)
                    {
                        throw new NotSupportedException();
                    }
                }
            }
            catch (Exception ex)
            {
                processing   = ServerProcessing.Complete;
                methodReturn = new ReturnMessage(ex, methodCall);

                responseMsg     = methodReturn;
                responseHeaders = null;
                responseStream  = null;
            }

            // handle response
            switch (processing)
            {
            case ServerProcessing.Complete:
            {
                // call proceeded synchronously - serialize response
                sinkStack.Pop(this);
                SerializeResponse(sinkStack, methodReturn, out responseHeaders, out responseStream);
                break;
            }

            case ServerProcessing.OneWay:
            {
                // no response needed
                sinkStack.Pop(this);
                break;
            }

            case ServerProcessing.Async:
            {
                // call proceeded asynchronously
                sinkStack.Store(this, null);
                break;
            }

            default:
                throw new NotSupportedException();
            }

            return(processing);
        }