File: System\ServiceModel\Channels\BodyWriter.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.Xml;
    using System.Diagnostics;
    using System.Runtime;
    using System.Threading;
 
    public abstract class BodyWriter
    {
        bool isBuffered;
        bool canWrite;
        object thisLock;
 
        protected BodyWriter(bool isBuffered)
        {
            this.isBuffered = isBuffered;
            this.canWrite = true;
            if (!this.isBuffered)
            {
                this.thisLock = new object();
            }
        }
 
        public bool IsBuffered
        {
            get { return this.isBuffered; }
        }
 
        internal virtual bool IsEmpty
        {
            get { return false; }
        }
 
        internal virtual bool IsFault
        {
            get { return false; }
        }
 
        public BodyWriter CreateBufferedCopy(int maxBufferSize)
        {
            if (maxBufferSize < 0)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException("maxBufferSize", maxBufferSize,
                                                    SR.GetString(SR.ValueMustBeNonNegative)));
            if (this.isBuffered)
            {
                return this;
            }
            else
            {
                lock (this.thisLock)
                {
                    if (!this.canWrite)
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.BodyWriterCanOnlyBeWrittenOnce)));
                    this.canWrite = false;
                }
                BodyWriter bodyWriter = OnCreateBufferedCopy(maxBufferSize);
                if (!bodyWriter.IsBuffered)
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.BodyWriterReturnedIsNotBuffered)));
                return bodyWriter;
            }
        }
 
        protected virtual BodyWriter OnCreateBufferedCopy(int maxBufferSize)
        {
            return OnCreateBufferedCopy(maxBufferSize, XmlDictionaryReaderQuotas.Max);
        }
 
        internal BodyWriter OnCreateBufferedCopy(int maxBufferSize, XmlDictionaryReaderQuotas quotas)
        {
            XmlBuffer buffer = new XmlBuffer(maxBufferSize);
            using (XmlDictionaryWriter writer = buffer.OpenSection(quotas))
            {
                writer.WriteStartElement("a");
                OnWriteBodyContents(writer);
                writer.WriteEndElement();
            }
            buffer.CloseSection();
            buffer.Close();
            return new BufferedBodyWriter(buffer);
        }
 
        protected abstract void OnWriteBodyContents(XmlDictionaryWriter writer);
 
        protected virtual IAsyncResult OnBeginWriteBodyContents(XmlDictionaryWriter writer, AsyncCallback callback, object state)
        {
            return new OnWriteBodyContentsAsyncResult(writer, this, callback, state);
        }
 
        protected virtual void OnEndWriteBodyContents(IAsyncResult result)
        {
            OnWriteBodyContentsAsyncResult.End(result);
        }
 
        void EnsureWriteBodyContentsState(XmlDictionaryWriter writer)
        {
            if (writer == null)
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("writer"));
            if (!this.isBuffered)
            {
                lock (this.thisLock)
                {
                    if (!this.canWrite)
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.BodyWriterCanOnlyBeWrittenOnce)));
                    this.canWrite = false;
                }
            }
        }
 
        public void WriteBodyContents(XmlDictionaryWriter writer)
        {
            EnsureWriteBodyContentsState(writer);
            OnWriteBodyContents(writer);
        }
 
        public IAsyncResult BeginWriteBodyContents(XmlDictionaryWriter writer, AsyncCallback callback, object state)
        {
            EnsureWriteBodyContentsState(writer);
            return OnBeginWriteBodyContents(writer, callback, state);
        }
 
        public void EndWriteBodyContents(IAsyncResult result)
        {
            OnEndWriteBodyContents(result);
        }
 
        class BufferedBodyWriter : BodyWriter
        {
            XmlBuffer buffer;
 
            public BufferedBodyWriter(XmlBuffer buffer)
                : base(true)
            {
                this.buffer = buffer;
            }
 
            protected override void OnWriteBodyContents(XmlDictionaryWriter writer)
            {
                XmlDictionaryReader reader = this.buffer.GetReader(0);
                using (reader)
                {
                    reader.ReadStartElement();
                    while (reader.NodeType != XmlNodeType.EndElement)
                    {
                        writer.WriteNode(reader, false);
                    }
                    reader.ReadEndElement();
                }
            }
        }
 
        class OnWriteBodyContentsAsyncResult : ScheduleActionItemAsyncResult
        {
            BodyWriter bodyWriter;
            XmlDictionaryWriter writer;
 
            public OnWriteBodyContentsAsyncResult(XmlDictionaryWriter writer, BodyWriter bodyWriter, AsyncCallback callback, object state)
                : base(callback, state)
            {
                Fx.Assert(bodyWriter != null, "bodyWriter should never be null");
 
                this.writer = writer;
                this.bodyWriter = bodyWriter;
 
                Schedule();
            }
 
            protected override void OnDoWork()
            {
                this.bodyWriter.OnWriteBodyContents(this.writer);
            }
        }
    }
}