aliyun-net-sdk-dybaseapi/Dybaseapi/MNS/Runtime/Pipeline/RuntimePipeline.cs (260 lines of code) (raw):
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using Aliyun.Acs.Dybaseapi.MNS.Runtime.Internal.Util;
namespace Aliyun.Acs.Dybaseapi.MNS.Runtime.Pipeline
{
/// <summary>
/// A runtime pipeline contains a collection of handlers which represent
/// different stages of request and response processing.
/// </summary>
public partial class RuntimePipeline : IDisposable
{
#region Private members
bool _disposed;
// The top-most handler in the pipeline.
IPipelineHandler _handler;
#endregion
#region Properties
/// <summary>
/// The top-most handler in the pipeline.
/// </summary>
public IPipelineHandler Handler
{
get { return _handler; }
}
#endregion
#region Constructors
/// <summary>
/// Constructor for RuntimePipeline.
/// </summary>
/// <param name="handler">The handler with which the pipeline is initalized.</param>
public RuntimePipeline(IPipelineHandler handler)
{
if (handler == null)
throw new ArgumentNullException("handler");
_handler = handler;
}
/// <summary>
/// Constructor for RuntimePipeline.
/// </summary>
/// <param name="handlers">List of handlers with which the pipeline is initialized.</param>
public RuntimePipeline(IList<IPipelineHandler> handlers)
{
if (handlers == null || handlers.Count == 0)
throw new ArgumentNullException("handlers");
foreach (var handler in handlers)
{
this.AddHandler(handler);
}
}
#endregion
#region Invoke methods
/// <summary>
/// Invokes the pipeline synchronously.
/// </summary>
/// <param name="executionContext">Request context</param>
/// <returns>Response context</returns>
public IResponseContext InvokeSync(IExecutionContext executionContext)
{
ThrowIfDisposed();
_handler.InvokeSync(executionContext);
return executionContext.ResponseContext;
}
/// <summary>
/// Invokes the pipeline asynchronously.
/// </summary>
/// <param name="executionContext">Request context</param>
/// <returns>IAsyncResult which represents the in progress asynchronous operation.</returns>
public IAsyncResult InvokeAsync(IAsyncExecutionContext executionContext)
{
ThrowIfDisposed();
return _handler.InvokeAsync(executionContext);
}
#endregion
#region Handler methods
/// <summary>
/// Adds a new handler to the top of the pipeline.
/// </summary>
/// <param name="handler">The handler to be added to the pipeline.</param>
public void AddHandler(IPipelineHandler handler)
{
if (handler == null)
throw new ArgumentNullException("handler");
ThrowIfDisposed();
var innerMostHandler = GetInnermostHandler(handler);
if (_handler != null)
{
innerMostHandler.InnerHandler = _handler;
_handler.OuterHandler = innerMostHandler;
}
_handler = handler;
SetHandlerProperties(handler);
}
/// <summary>
/// Adds a handler after the first instance of handler of type T.
/// </summary>
/// <typeparam name="T">Type of the handler after which the given handler instance is added.</typeparam>
/// <param name="handler">The handler to be added to the pipeline.</param>
public void AddHandlerAfter<T>(IPipelineHandler handler)
where T : IPipelineHandler
{
if (handler == null)
throw new ArgumentNullException("handler");
ThrowIfDisposed();
var type = typeof(T);
var current = _handler;
while (current != null)
{
if (current.GetType() == type)
{
InsertHandler(handler, current);
SetHandlerProperties(handler);
return;
}
current = current.InnerHandler;
}
throw new InvalidOperationException(
string.Format(CultureInfo.InvariantCulture, "Cannot find a handler of type {0}", type.Name));
}
/// <summary>
/// Adds a handler before the first instance of handler of type T.
/// </summary>
/// <typeparam name="T">Type of the handler before which the given handler instance is added.</typeparam>
/// <param name="handler">The handler to be added to the pipeline.</param>
public void AddHandlerBefore<T>(IPipelineHandler handler)
where T : IPipelineHandler
{
if (handler == null)
throw new ArgumentNullException("handler");
ThrowIfDisposed();
var type = typeof(T);
if (_handler.GetType() == type)
{
// Add the handler to the top of the pipeline
AddHandler(handler);
SetHandlerProperties(handler);
return;
}
var current = _handler;
while (current != null)
{
if (current.InnerHandler != null &&
current.InnerHandler.GetType() == type)
{
InsertHandler(handler, current);
SetHandlerProperties(handler);
return;
}
current = current.InnerHandler;
}
throw new InvalidOperationException(
string.Format(CultureInfo.InvariantCulture, "Cannot find a handler of type {0}", type.Name));
}
/// <summary>
/// Removes the first occurance of a handler of type T.
/// </summary>
/// <typeparam name="T">Type of the handler which will be removed.</typeparam>
public void RemoveHandler<T>()
{
ThrowIfDisposed();
var type = typeof(T);
IPipelineHandler previous = null;
var current = _handler;
while (current != null)
{
if (current.GetType() == type)
{
// Cannot remove the handler if it's the only one in the pipeline
if (current == _handler && _handler.InnerHandler == null)
{
throw new InvalidOperationException(
"The pipeline contains a single handler, cannot remove the only handler in the pipeline.");
}
// current is the top, point top to current's inner handler
if (current == _handler)
_handler = current.InnerHandler;
// Wireup outer handler to current's inner handler
if (current.OuterHandler != null)
current.OuterHandler.InnerHandler = current.InnerHandler;
// Wireup inner handler to current's outer handler
if (current.InnerHandler != null)
current.InnerHandler.OuterHandler = current.OuterHandler;
// Cleanup current
current.InnerHandler = null;
current.OuterHandler = null;
return;
}
previous = current;
current = current.InnerHandler;
}
throw new InvalidOperationException(
string.Format(CultureInfo.InvariantCulture, "Cannot find a handler of type {0}", type.Name));
}
/// <summary>
/// Replaces the first occurance of a handler of type T with the given handler.
/// </summary>
/// <typeparam name="T">Type of the handler which will be replaced.</typeparam>
/// <param name="handler">The handler to be added to the pipeline.</param>
public void ReplaceHandler<T>(IPipelineHandler handler)
where T : IPipelineHandler
{
if (handler == null)
throw new ArgumentNullException("handler");
ThrowIfDisposed();
var type = typeof(T);
IPipelineHandler previous = null;
var current = _handler;
while (current != null)
{
if (current.GetType() == type)
{
// Replace current with handler.
handler.InnerHandler = current.InnerHandler;
handler.OuterHandler = current.OuterHandler;
if(previous != null)
{
// Wireup previous handler
previous.InnerHandler = handler;
}
else
{
// Current is the top, replace it.
_handler = handler;
}
if (current.InnerHandler != null)
{
// Wireup next handler
current.InnerHandler.OuterHandler = handler;
}
// Cleanup current
current.InnerHandler = null;
current.OuterHandler = null;
SetHandlerProperties(handler);
return;
}
previous = current;
current = current.InnerHandler;
}
throw new InvalidOperationException(
string.Format(CultureInfo.InvariantCulture, "Cannot find a handler of type {0}", type.Name));
}
/// <summary>
/// Inserts the given handler after current handler in the pipeline.
/// </summary>
/// <param name="handler">Handler to be inserted in the pipeline.</param>
/// <param name="current">Handler after which the given handler is inserted.</param>
private static void InsertHandler(IPipelineHandler handler, IPipelineHandler current)
{
var next = current.InnerHandler;
current.InnerHandler = handler;
handler.OuterHandler = current;
if (next!=null)
{
var innerMostHandler = GetInnermostHandler(handler);
innerMostHandler.InnerHandler = next;
next.OuterHandler = innerMostHandler;
}
}
/// <summary>
/// Gets the innermost handler by traversing the inner handler till
/// it reaches the last one.
/// </summary>
private static IPipelineHandler GetInnermostHandler(IPipelineHandler handler)
{
Debug.Assert(handler != null);
var current = handler;
while (current.InnerHandler != null)
{
current = current.InnerHandler;
}
return current;
}
private void SetHandlerProperties(IPipelineHandler handler)
{
ThrowIfDisposed();
}
/// <summary>
/// Retrieves a list of handlers, in the order of their execution.
/// </summary>
/// <returns>Handlers in the current pipeline.</returns>
public List<IPipelineHandler> Handlers
{
get
{
return EnumerateHandlers().ToList();
}
}
/// <summary>
/// Retrieves current handlers, in the order of their execution.
/// </summary>
/// <returns>Handlers in the current pipeline.</returns>
public IEnumerable<IPipelineHandler> EnumerateHandlers()
{
var handler = this.Handler;
while(handler != null)
{
yield return handler;
handler = handler.InnerHandler;
}
}
#endregion
#region Dispose methods
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (_disposed)
return;
if (disposing)
{
var handler = this.Handler;
while (handler != null)
{
var innerHandler = handler.InnerHandler;
var disposable = handler as IDisposable;
if (disposable != null)
{
disposable.Dispose();
}
handler = innerHandler;
}
_disposed = true;
}
}
private void ThrowIfDisposed()
{
if (this._disposed)
throw new ObjectDisposedException(GetType().FullName);
}
#endregion
}
}