|
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using Microsoft.Xml;
using System.IO;
using System.Collections.Generic;
namespace System.ServiceModel.Channels
{
public abstract class MessageBuffer : IDisposable
{
public abstract int BufferSize { get; }
void IDisposable.Dispose()
{
Close();
}
public abstract void Close();
public virtual void WriteMessage(Stream stream)
{
if (stream == null)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("stream"));
Message message = CreateMessage();
using (message)
{
XmlDictionaryWriter writer = XmlDictionaryWriter.CreateBinaryWriter(stream, XD.Dictionary, null, false);
using (writer)
{
message.WriteMessage(writer);
}
}
}
public virtual string MessageContentType
{
get { return FramingEncodingString.Binary; }
}
public abstract Message CreateMessage();
internal Exception CreateBufferDisposedException()
{
return new ObjectDisposedException("", SRServiceModel.MessageBufferIsClosed);
}
}
internal class DefaultMessageBuffer : MessageBuffer
{
private XmlBuffer _msgBuffer;
private KeyValuePair<string, object>[] _properties;
private bool[] _understoodHeaders;
private bool _closed;
private MessageVersion _version;
private Uri _to;
private string _action;
private bool _isNullMessage;
public DefaultMessageBuffer(Message message, XmlBuffer msgBuffer)
{
_msgBuffer = msgBuffer;
_version = message.Version;
_isNullMessage = message is NullMessage;
_properties = new KeyValuePair<string, object>[message.Properties.Count];
((ICollection<KeyValuePair<string, object>>)message.Properties).CopyTo(_properties, 0);
_understoodHeaders = new bool[message.Headers.Count];
for (int i = 0; i < _understoodHeaders.Length; ++i)
_understoodHeaders[i] = message.Headers.IsUnderstood(i);
if (_version == MessageVersion.None)
{
_to = message.Headers.To;
_action = message.Headers.Action;
}
}
private object ThisLock
{
get { return _msgBuffer; }
}
public override int BufferSize
{
get { return _msgBuffer.BufferSize; }
}
public override void Close()
{
lock (ThisLock)
{
if (_closed)
return;
_closed = true;
for (int i = 0; i < _properties.Length; i++)
{
IDisposable disposable = _properties[i].Value as IDisposable;
if (disposable != null)
disposable.Dispose();
}
}
}
public override Message CreateMessage()
{
if (_closed)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateBufferDisposedException());
Message msg;
if (_isNullMessage)
{
msg = new NullMessage();
}
else
{
msg = Message.CreateMessage(_msgBuffer.GetReader(0), int.MaxValue, _version);
}
lock (ThisLock)
{
msg.Properties.CopyProperties(_properties);
}
for (int i = 0; i < _understoodHeaders.Length; ++i)
{
if (_understoodHeaders[i])
msg.Headers.AddUnderstood(i);
}
if (_to != null)
{
msg.Headers.To = _to;
}
if (_action != null)
{
msg.Headers.Action = _action;
}
return msg;
}
}
internal class BufferedMessageBuffer : MessageBuffer
{
private IBufferedMessageData _messageData;
private KeyValuePair<string, object>[] _properties;
private bool _closed;
private object _thisLock = new object();
private bool[] _understoodHeaders;
private bool _understoodHeadersModified;
public BufferedMessageBuffer(IBufferedMessageData messageData,
KeyValuePair<string, object>[] properties, bool[] understoodHeaders, bool understoodHeadersModified)
{
_messageData = messageData;
_properties = properties;
_understoodHeaders = understoodHeaders;
_understoodHeadersModified = understoodHeadersModified;
messageData.Open();
}
public override int BufferSize
{
get
{
lock (ThisLock)
{
if (_closed)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateBufferDisposedException());
return _messageData.Buffer.Count;
}
}
}
public override void WriteMessage(Stream stream)
{
if (stream == null)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("stream"));
lock (ThisLock)
{
if (_closed)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateBufferDisposedException());
ArraySegment<byte> buffer = _messageData.Buffer;
stream.Write(buffer.Array, buffer.Offset, buffer.Count);
}
}
public override string MessageContentType
{
get
{
lock (ThisLock)
{
if (_closed)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateBufferDisposedException());
return _messageData.MessageEncoder.ContentType;
}
}
}
private object ThisLock
{
get { return _thisLock; }
}
public override void Close()
{
lock (ThisLock)
{
if (!_closed)
{
_closed = true;
_messageData.Close();
_messageData = null;
}
}
}
public override Message CreateMessage()
{
lock (ThisLock)
{
if (_closed)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateBufferDisposedException());
RecycledMessageState recycledMessageState = _messageData.TakeMessageState();
if (recycledMessageState == null)
recycledMessageState = new RecycledMessageState();
BufferedMessage bufferedMessage = new BufferedMessage(_messageData, recycledMessageState, _understoodHeaders, _understoodHeadersModified);
bufferedMessage.Properties.CopyProperties(_properties);
_messageData.Open();
return bufferedMessage;
}
}
}
internal class BodyWriterMessageBuffer : MessageBuffer
{
private BodyWriter _bodyWriter;
private KeyValuePair<string, object>[] _properties;
private MessageHeaders _headers;
private bool _closed;
private object _thisLock = new object();
public BodyWriterMessageBuffer(MessageHeaders headers,
KeyValuePair<string, object>[] properties, BodyWriter bodyWriter)
{
_bodyWriter = bodyWriter;
_headers = new MessageHeaders(headers);
_properties = properties;
}
protected object ThisLock
{
get { return _thisLock; }
}
public override int BufferSize
{
get { return 0; }
}
public override void Close()
{
lock (ThisLock)
{
if (!_closed)
{
_closed = true;
_bodyWriter = null;
_headers = null;
_properties = null;
}
}
}
public override Message CreateMessage()
{
lock (ThisLock)
{
if (_closed)
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(CreateBufferDisposedException());
return new BodyWriterMessage(_headers, _properties, _bodyWriter);
}
}
protected BodyWriter BodyWriter
{
get { return _bodyWriter; }
}
protected MessageHeaders Headers
{
get { return _headers; }
}
protected KeyValuePair<string, object>[] Properties
{
get { return _properties; }
}
protected bool Closed
{
get { return _closed; }
}
}
}
|