File: System\ServiceModel\Channels\LayeredChannelListener.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.Runtime;
    using System.ServiceModel;
 
    abstract class LayeredChannelListener<TChannel>
        : ChannelListenerBase<TChannel>
        where TChannel : class, IChannel
    {
        IChannelListener innerChannelListener;
        bool sharedInnerListener;
        EventHandler onInnerListenerFaulted;
 
        protected LayeredChannelListener(IDefaultCommunicationTimeouts timeouts, IChannelListener innerChannelListener)
            : this(false, timeouts, innerChannelListener)
        {
        }
 
        protected LayeredChannelListener(bool sharedInnerListener)
            : this(sharedInnerListener, null, null)
        {
        }
 
        protected LayeredChannelListener(bool sharedInnerListener, IDefaultCommunicationTimeouts timeouts)
            : this(sharedInnerListener, timeouts, null)
        {
        }
 
        protected LayeredChannelListener(bool sharedInnerListener, IDefaultCommunicationTimeouts timeouts, IChannelListener innerChannelListener)
            : base(timeouts)
        {
            this.sharedInnerListener = sharedInnerListener;
            this.innerChannelListener = innerChannelListener;
            this.onInnerListenerFaulted = new EventHandler(OnInnerListenerFaulted);
            if (this.innerChannelListener != null)
            {
                this.innerChannelListener.Faulted += onInnerListenerFaulted;
            }
        }
 
        internal virtual IChannelListener InnerChannelListener
        {
            get
            {
                return innerChannelListener;
            }
            set
            {
                lock (ThisLock)
                {
                    ThrowIfDisposedOrImmutable();
                    if (this.innerChannelListener != null)
                    {
                        this.innerChannelListener.Faulted -= onInnerListenerFaulted;
                    }
                    this.innerChannelListener = value;
                    if (this.innerChannelListener != null)
                    {
                        this.innerChannelListener.Faulted += onInnerListenerFaulted;
                    }
                }
            }
        }
 
        internal bool SharedInnerListener
        {
            get { return sharedInnerListener; }
        }
 
        public override Uri Uri
        {
            get { return GetInnerListenerSnapshot().Uri; }
        }
 
        public override T GetProperty<T>()
        {
            T baseProperty = base.GetProperty<T>();
            if (baseProperty != null)
            {
                return baseProperty;
            }
 
            IChannelListener channelListener = this.InnerChannelListener;
            if (channelListener != null)
            {
                return channelListener.GetProperty<T>();
            }
            else
            {
                return default(T);
            }
        }
 
        protected override void OnAbort()
        {
            lock (ThisLock)
            {
                this.OnCloseOrAbort();
            }
            IChannelListener channelListener = this.InnerChannelListener;
            if (channelListener != null && !sharedInnerListener)
            {
                channelListener.Abort();
            }
        }
 
        protected override IAsyncResult OnBeginClose(TimeSpan timeout, AsyncCallback callback, object state)
        {
            this.OnCloseOrAbort();
            return new CloseAsyncResult(InnerChannelListener, sharedInnerListener, timeout, callback, state);
        }
 
        protected override void OnEndClose(IAsyncResult result)
        {
            CloseAsyncResult.End(result);
        }
 
        protected override void OnClose(TimeSpan timeout)
        {
            this.OnCloseOrAbort();
            if (InnerChannelListener != null && !sharedInnerListener)
            {
                InnerChannelListener.Close(timeout);
            }
        }
 
        void OnCloseOrAbort()
        {
            IChannelListener channelListener = this.InnerChannelListener;
            if (channelListener != null)
            {
                channelListener.Faulted -= onInnerListenerFaulted;
            }
        }
 
        protected override IAsyncResult OnBeginOpen(TimeSpan timeout, AsyncCallback callback, object state)
        {
            return new OpenAsyncResult(InnerChannelListener, sharedInnerListener, timeout, callback, state);
        }
 
        protected override void OnEndOpen(IAsyncResult result)
        {
            OpenAsyncResult.End(result);
        }
 
        protected override void OnOpen(TimeSpan timeout)
        {
            if (InnerChannelListener != null && !sharedInnerListener)
                InnerChannelListener.Open(timeout);
        }
 
        protected override void OnOpening()
        {
            base.OnOpening();
            ThrowIfInnerListenerNotSet();
        }
 
        void OnInnerListenerFaulted(object sender, EventArgs e)
        {
            // if our inner listener faulted, we should fault as well
            this.Fault();
        }
 
        internal void ThrowIfInnerListenerNotSet()
        {
            if (this.InnerChannelListener == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.InnerListenerFactoryNotSet, this.GetType().ToString())));
            }
        }
 
        internal IChannelListener GetInnerListenerSnapshot()
        {
            IChannelListener innerChannelListener = this.InnerChannelListener;
 
            if (innerChannelListener == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.InnerListenerFactoryNotSet, this.GetType().ToString())));
            }
 
            return innerChannelListener;
        }
 
        class OpenAsyncResult : AsyncResult
        {
            ICommunicationObject communicationObject;
            static AsyncCallback onOpenComplete = Fx.ThunkCallback(new AsyncCallback(OnOpenComplete));
 
            public OpenAsyncResult(ICommunicationObject communicationObject, bool sharedInnerListener, TimeSpan timeout, AsyncCallback callback, object state)
                : base(callback, state)
            {
                this.communicationObject = communicationObject;
 
                if (this.communicationObject == null || sharedInnerListener)
                {
                    this.Complete(true);
                    return;
                }
 
                IAsyncResult result = this.communicationObject.BeginOpen(timeout, onOpenComplete, this);
                if (result.CompletedSynchronously)
                {
                    this.communicationObject.EndOpen(result);
                    this.Complete(true);
                }
            }
 
            static void OnOpenComplete(IAsyncResult result)
            {
                if (result.CompletedSynchronously)
                    return;
 
                OpenAsyncResult thisPtr = (OpenAsyncResult)result.AsyncState;
                Exception exception = null;
 
                try
                {
                    thisPtr.communicationObject.EndOpen(result);
                }
#pragma warning suppress 56500 // covered by FxCOP
                catch (Exception e)
                {
                    if (Fx.IsFatal(e))
                        throw;
 
                    exception = e;
                }
 
                thisPtr.Complete(false, exception);
            }
 
            public static void End(IAsyncResult result)
            {
                AsyncResult.End<OpenAsyncResult>(result);
            }
        }
 
        class CloseAsyncResult : AsyncResult
        {
            ICommunicationObject communicationObject;
            static AsyncCallback onCloseComplete = Fx.ThunkCallback(new AsyncCallback(OnCloseComplete));
 
            public CloseAsyncResult(ICommunicationObject communicationObject, bool sharedInnerListener, TimeSpan timeout, AsyncCallback callback, object state)
                : base(callback, state)
            {
                this.communicationObject = communicationObject;
 
                if (this.communicationObject == null || sharedInnerListener)
                {
                    this.Complete(true);
                    return;
                }
 
                IAsyncResult result = this.communicationObject.BeginClose(timeout, onCloseComplete, this);
 
                if (result.CompletedSynchronously)
                {
                    this.communicationObject.EndClose(result);
                    this.Complete(true);
                }
            }
 
            static void OnCloseComplete(IAsyncResult result)
            {
                if (result.CompletedSynchronously)
                    return;
 
                CloseAsyncResult thisPtr = (CloseAsyncResult)result.AsyncState;
                Exception exception = null;
 
                try
                {
                    thisPtr.communicationObject.EndClose(result);
                }
#pragma warning suppress 56500 // covered by FxCOP
                catch (Exception e)
                {
                    if (Fx.IsFatal(e))
                        throw;
 
                    exception = e;
                }
 
                thisPtr.Complete(false, exception);
            }
 
            public static void End(IAsyncResult result)
            {
                AsyncResult.End<CloseAsyncResult>(result);
            }
        }
    }
 
    abstract class LayeredChannelAcceptor<TChannel, TInnerChannel> : ChannelAcceptor<TChannel>
        where TChannel : class, IChannel
        where TInnerChannel : class, IChannel
    {
        IChannelListener<TInnerChannel> innerListener;
 
        protected LayeredChannelAcceptor(ChannelManagerBase channelManager, IChannelListener<TInnerChannel> innerListener)
            : base(channelManager)
        {
            this.innerListener = innerListener;
        }
 
        protected abstract TChannel OnAcceptChannel(TInnerChannel innerChannel);
 
        public override TChannel AcceptChannel(TimeSpan timeout)
        {
            TInnerChannel innerChannel = this.innerListener.AcceptChannel(timeout);
            if (innerChannel == null)
                return null;
            else
                return OnAcceptChannel(innerChannel);
        }
 
        public override IAsyncResult BeginAcceptChannel(TimeSpan timeout, AsyncCallback callback, object state)
        {
            return this.innerListener.BeginAcceptChannel(timeout, callback, state);
        }
 
        public override TChannel EndAcceptChannel(IAsyncResult result)
        {
            TInnerChannel innerChannel = this.innerListener.EndAcceptChannel(result);
            if (innerChannel == null)
                return null;
            else
                return OnAcceptChannel(innerChannel);
        }
 
        public override bool WaitForChannel(TimeSpan timeout)
        {
            return this.innerListener.WaitForChannel(timeout);
        }
 
        public override IAsyncResult BeginWaitForChannel(TimeSpan timeout, AsyncCallback callback, object state)
        {
            return this.innerListener.BeginWaitForChannel(timeout, callback, state);
        }
 
        public override bool EndWaitForChannel(IAsyncResult result)
        {
            return this.innerListener.EndWaitForChannel(result);
        }
    }
}