File: System\ServiceModel\Channels\ReplyAdapterChannelListener.cs
Project: ndp\cdf\src\WCF\ServiceModel\System.ServiceModel.csproj (System.ServiceModel)
//----------------------------------------------------------
// Copyright (c) Microsoft Corporation.  All rights reserved.
//------------------------------------------------------------
 
namespace System.ServiceModel.Channels
{
    using System.Collections.Generic;
    using System.ServiceModel;
    using System.Runtime.Serialization;
    using System.Diagnostics;
    using System.ServiceModel.Diagnostics;
    using System.Xml;
    using System.Threading;
 
    abstract class ReplyOverDuplexChannelListenerBase<TOuterChannel, TInnerChannel> : LayeredChannelListener<TOuterChannel>
        where TOuterChannel : class, IReplyChannel
        where TInnerChannel : class, IDuplexChannel
    {
        IChannelListener<TInnerChannel> innerChannelListener;
 
        public ReplyOverDuplexChannelListenerBase(BindingContext context)
            : base(context.Binding, context.BuildInnerChannelListener<TInnerChannel>())
        {
        }
 
        protected override void OnOpening()
        {
            this.innerChannelListener = (IChannelListener<TInnerChannel>)this.InnerChannelListener;
            base.OnOpening();
        }
 
        protected override TOuterChannel OnAcceptChannel(TimeSpan timeout)
        {
            TInnerChannel innerChannel = this.innerChannelListener.AcceptChannel(timeout);
            return WrapInnerChannel(innerChannel);
        }
 
 
        protected override IAsyncResult OnBeginAcceptChannel(TimeSpan timeout, AsyncCallback callback, object state)
        {
            return this.innerChannelListener.BeginAcceptChannel(timeout, callback, state);
        }
 
        protected override TOuterChannel OnEndAcceptChannel(IAsyncResult result)
        {
            TInnerChannel innerChannel = this.innerChannelListener.EndAcceptChannel(result);
            return WrapInnerChannel(innerChannel);
        }
 
        protected override bool OnWaitForChannel(TimeSpan timeout)
        {
            return this.innerChannelListener.WaitForChannel(timeout);
        }
 
        protected override IAsyncResult OnBeginWaitForChannel(TimeSpan timeout, AsyncCallback callback, object state)
        {
            return this.innerChannelListener.BeginWaitForChannel(timeout, callback, state);
        }
 
        protected override bool OnEndWaitForChannel(IAsyncResult result)
        {
            return this.innerChannelListener.EndWaitForChannel(result);
        }
 
        protected abstract TOuterChannel CreateWrappedChannel(ChannelManagerBase channelManager, TInnerChannel innerChannel);
 
        TOuterChannel WrapInnerChannel(TInnerChannel innerChannel)
        {
            if (innerChannel == null)
            {
                return null;
            }
            else
            {
                return CreateWrappedChannel(this, innerChannel);
            }
        }
    }
 
    class ReplyOverDuplexChannelListener : ReplyOverDuplexChannelListenerBase<IReplyChannel, IDuplexChannel>
    {
        public ReplyOverDuplexChannelListener(BindingContext context)
            : base(context)
        {
        }
 
        protected override IReplyChannel CreateWrappedChannel(ChannelManagerBase channelManager, IDuplexChannel innerChannel)
        {
            return new ReplyOverDuplexChannel(channelManager, innerChannel);
        }
    }
 
    class ReplySessionOverDuplexSessionChannelListener : ReplyOverDuplexChannelListenerBase<IReplySessionChannel, IDuplexSessionChannel>
    {
        public ReplySessionOverDuplexSessionChannelListener(BindingContext context)
            : base(context)
        {
        }
 
        protected override IReplySessionChannel CreateWrappedChannel(ChannelManagerBase channelManager, IDuplexSessionChannel innerChannel)
        {
            return new ReplySessionOverDuplexSessionChannel(channelManager, innerChannel);
        }
    }
 
 
    abstract class ReplyOverDuplexChannelBase<TInnerChannel> : LayeredChannel<TInnerChannel>, IReplyChannel
        where TInnerChannel : class, IDuplexChannel
    {
        public ReplyOverDuplexChannelBase(ChannelManagerBase channelManager, TInnerChannel innerChannel)
            : base(channelManager, innerChannel)
        {
        }
 
        public EndpointAddress LocalAddress
        {
            get
            {
                return this.InnerChannel.LocalAddress;
            }
        }
 
        public RequestContext ReceiveRequest()
        {
            return ReceiveRequest(this.DefaultReceiveTimeout);
        }
 
        public RequestContext ReceiveRequest(TimeSpan timeout)
        {
            return ReplyChannel.HelpReceiveRequest(this, timeout);
        }
 
        public IAsyncResult BeginReceiveRequest(AsyncCallback callback, object state)
        {
            return BeginReceiveRequest(this.DefaultReceiveTimeout, callback, state);
        }
 
        public IAsyncResult BeginReceiveRequest(TimeSpan timeout, AsyncCallback callback, object state)
        {
            return ReplyChannel.HelpBeginReceiveRequest(this, timeout, callback, state);
        }
 
        public RequestContext EndReceiveRequest(IAsyncResult result)
        {
            return ReplyChannel.HelpEndReceiveRequest(result);
        }
 
        public bool TryReceiveRequest(TimeSpan timeout, out RequestContext context)
        {
            Message message;
            if (!this.InnerChannel.TryReceive(timeout, out message))
            {
                context = null;
                return false;
            }
            context = WrapInnerMessage(message);
            return true;
        }
 
        public IAsyncResult BeginTryReceiveRequest(TimeSpan timeout, AsyncCallback callback, object state)
        {
            return this.InnerChannel.BeginTryReceive(timeout, callback, state);
        }
 
        public bool EndTryReceiveRequest(IAsyncResult result, out RequestContext context)
        {
            Message message;
            if (!this.InnerChannel.EndTryReceive(result, out message))
            {
                context = null;
                return false;
            }
            context = WrapInnerMessage(message);
            return true;
        }
 
        public bool WaitForRequest(TimeSpan timeout)
        {
            return this.InnerChannel.WaitForMessage(timeout);
        }
 
        public IAsyncResult BeginWaitForRequest(TimeSpan timeout, AsyncCallback callback, object state)
        {
            return this.InnerChannel.BeginWaitForMessage(timeout, callback, state);
        }
 
        public bool EndWaitForRequest(IAsyncResult result)
        {
            return this.InnerChannel.EndWaitForMessage(result);
        }
 
        RequestContext WrapInnerMessage(Message message)
        {
            if (message == null)
            {
                return null;
            }
            else
            {
                return new DuplexRequestContext(message, this.Manager, this.InnerChannel);
            }
        }
 
        class DuplexRequestContext : RequestContext
        {
            IDuplexChannel innerChannel;
            IDefaultCommunicationTimeouts defaultTimeouts;
            Message request;
            EndpointAddress replyTo;
            bool disposed;
            Object thisLock;
 
            public DuplexRequestContext(Message request, IDefaultCommunicationTimeouts defaultTimeouts, IDuplexChannel innerChannel)
            {
                this.request = request;
                this.defaultTimeouts = defaultTimeouts;
                this.innerChannel = innerChannel;
                if (request != null)
                {
                    replyTo = request.Headers.ReplyTo;
                }
                thisLock = new Object();
            }
 
            public override Message RequestMessage
            {
                get
                {
                    return this.request;
                }
            }
 
            public override void Abort()
            {
                Dispose(true);
            }
 
            public override void Close()
            {
                this.Close(this.defaultTimeouts.CloseTimeout);
            }
 
            public override void Close(TimeSpan timeout)
            {
                this.Dispose(true);
            }
 
            public override void Reply(Message message)
            {
                this.Reply(message, this.defaultTimeouts.SendTimeout);
            }
 
            public override void Reply(Message message, TimeSpan timeout)
            {
                PrepareReply(message);
                this.innerChannel.Send(message);
            }
 
            public override IAsyncResult BeginReply(Message message, AsyncCallback callback, object state)
            {
                return BeginReply(message, this.defaultTimeouts.SendTimeout, callback, state);
            }
 
            public override IAsyncResult BeginReply(Message message, TimeSpan timeout, AsyncCallback callback, object state)
            {
                PrepareReply(message);
                return this.innerChannel.BeginSend(message, timeout, callback, state);
            }
 
            public override void EndReply(IAsyncResult result)
            {
                this.innerChannel.EndSend(result);
            }
 
            void PrepareReply(Message message)
            {
                if (this.replyTo != null)
                {
                    this.replyTo.ApplyTo(message);
                }
            }
 
            protected override void Dispose(bool disposing)
            {
                bool cleanup = false;
                lock (thisLock)
                {
                    if (!disposed)
                    {
                        this.disposed = true;
                        cleanup = true;
                    }
                }
                if (cleanup && this.request != null)
                {
                    this.request.Close();
                }
            }
        }
    }
 
    class ReplyOverDuplexChannel : ReplyOverDuplexChannelBase<IDuplexChannel>
    {
        public ReplyOverDuplexChannel(ChannelManagerBase channelManager, IDuplexChannel innerChannel)
            : base(channelManager, innerChannel)
        {
        }
    }
 
    class ReplySessionOverDuplexSessionChannel : ReplyOverDuplexChannelBase<IDuplexSessionChannel>, IReplySessionChannel
    {
        ReplySessionOverDuplexSession session;
 
        public ReplySessionOverDuplexSessionChannel(ChannelManagerBase channelManager, IDuplexSessionChannel innerChannel)
            : base(channelManager, innerChannel)
        {
            this.session = new ReplySessionOverDuplexSession(innerChannel.Session);
        }
 
        public IInputSession Session
        {
            get
            {
                return this.session;
            }
        }
 
        class ReplySessionOverDuplexSession : IInputSession
        {
            IDuplexSession innerSession;
 
            public ReplySessionOverDuplexSession(IDuplexSession innerSession)
            {
                if (innerSession == null)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("innerSession");
                }
                this.innerSession = innerSession;
            }
 
            public string Id
            {
                get
                {
                    return this.innerSession.Id;
                }
            }
        }
    }
 
    class ReplyAdapterBindingElement : BindingElement
    {
        public ReplyAdapterBindingElement()
        {
        }
 
        public override IChannelListener<TChannel> BuildChannelListener<TChannel>(BindingContext context)
        {
            if (!this.CanBuildChannelListener<TChannel>(context))
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument("TChannel", SR.GetString(SR.ChannelTypeNotSupported, typeof(TChannel)));
            }
 
            if (context.CanBuildInnerChannelListener<IReplySessionChannel>() ||
                context.CanBuildInnerChannelListener<IReplyChannel>())
            {
                return context.BuildInnerChannelListener<TChannel>();
            }
            else if ((typeof(TChannel) == typeof(IReplySessionChannel)) && context.CanBuildInnerChannelListener<IDuplexSessionChannel>())
            {
                return (IChannelListener<TChannel>)new ReplySessionOverDuplexSessionChannelListener(context);
            }
            else if ((typeof(TChannel) == typeof(IReplyChannel)) && context.CanBuildInnerChannelListener<IDuplexChannel>())
            {
                return (IChannelListener<TChannel>)new ReplyOverDuplexChannelListener(context);
            }
            else
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument("TChannel", SR.GetString(SR.ChannelTypeNotSupported, typeof(TChannel)));
            }
        }
 
        public override bool CanBuildChannelListener<TChannel>(BindingContext context)
        {
            if (typeof(TChannel) == typeof(IReplySessionChannel))
            {
                return (context.CanBuildInnerChannelListener<IReplySessionChannel>()
                        || context.CanBuildInnerChannelListener<IDuplexSessionChannel>());
            }
            else if (typeof(TChannel) == typeof(IReplyChannel))
            {
                return (context.CanBuildInnerChannelListener<IReplyChannel>()
                    || context.CanBuildInnerChannelListener<IDuplexChannel>());
            }
            else
            {
                return false;
            }
        }
 
        public override BindingElement Clone()
        {
            return new ReplyAdapterBindingElement();
        }
 
        public override T GetProperty<T>(BindingContext context)
        {
            return context.GetInnerProperty<T>();
        }
    }
}