536cd135cc
Former-commit-id: 5624ac747d633e885131e8349322922b6a59baaa
321 lines
16 KiB
C#
321 lines
16 KiB
C#
//-----------------------------------------------------------------------------
|
|
// Copyright (c) Microsoft Corporation. All rights reserved.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
namespace System.ServiceModel.Description
|
|
{
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Globalization;
|
|
using System.Runtime;
|
|
using System.ServiceModel.Channels;
|
|
using System.Xml;
|
|
|
|
public abstract partial class MetadataImporter
|
|
{
|
|
//Consider, Microsoft: make this public
|
|
internal static IEnumerable<PolicyConversionContext> GetPolicyConversionContextEnumerator(ServiceEndpoint endpoint, PolicyAlternatives policyAlternatives)
|
|
{
|
|
return ImportedPolicyConversionContext.GetPolicyConversionContextEnumerator(endpoint, policyAlternatives, MetadataImporterQuotas.Defaults);
|
|
}
|
|
|
|
internal static IEnumerable<PolicyConversionContext> GetPolicyConversionContextEnumerator(ServiceEndpoint endpoint, PolicyAlternatives policyAlternatives,
|
|
MetadataImporterQuotas quotas)
|
|
{
|
|
return ImportedPolicyConversionContext.GetPolicyConversionContextEnumerator(endpoint, policyAlternatives, quotas);
|
|
}
|
|
|
|
internal sealed class ImportedPolicyConversionContext : PolicyConversionContext
|
|
{
|
|
BindingElementCollection bindingElements = new BindingElementCollection();
|
|
readonly PolicyAssertionCollection endpointAssertions;
|
|
readonly Dictionary<OperationDescription, PolicyAssertionCollection> operationBindingAssertions = new Dictionary<OperationDescription, PolicyAssertionCollection>();
|
|
readonly Dictionary<MessageDescription, PolicyAssertionCollection> messageBindingAssertions = new Dictionary<MessageDescription, PolicyAssertionCollection>();
|
|
readonly Dictionary<FaultDescription, PolicyAssertionCollection> faultBindingAssertions = new Dictionary<FaultDescription, PolicyAssertionCollection>();
|
|
|
|
ImportedPolicyConversionContext(ServiceEndpoint endpoint, IEnumerable<XmlElement> endpointAssertions,
|
|
Dictionary<OperationDescription, IEnumerable<XmlElement>> operationBindingAssertions,
|
|
Dictionary<MessageDescription, IEnumerable<XmlElement>> messageBindingAssertions,
|
|
Dictionary<FaultDescription, IEnumerable<XmlElement>> faultBindingAssertions,
|
|
MetadataImporterQuotas quotas)
|
|
: base(endpoint)
|
|
{
|
|
int remainingAssertionsAllowed = quotas.MaxPolicyAssertions;
|
|
|
|
this.endpointAssertions = new PolicyAssertionCollection(new MaxItemsEnumerable<XmlElement>(endpointAssertions, remainingAssertionsAllowed));
|
|
|
|
remainingAssertionsAllowed -= this.endpointAssertions.Count;
|
|
|
|
foreach (OperationDescription operationDescription in endpoint.Contract.Operations)
|
|
{
|
|
this.operationBindingAssertions.Add(operationDescription, new PolicyAssertionCollection());
|
|
|
|
foreach (MessageDescription messageDescription in operationDescription.Messages)
|
|
{
|
|
this.messageBindingAssertions.Add(messageDescription, new PolicyAssertionCollection());
|
|
}
|
|
|
|
foreach (FaultDescription faultDescription in operationDescription.Faults)
|
|
{
|
|
this.faultBindingAssertions.Add(faultDescription, new PolicyAssertionCollection());
|
|
}
|
|
}
|
|
|
|
|
|
foreach (KeyValuePair<OperationDescription, IEnumerable<XmlElement>> entry in operationBindingAssertions)
|
|
{
|
|
this.operationBindingAssertions[entry.Key].AddRange(new MaxItemsEnumerable<XmlElement>(entry.Value, remainingAssertionsAllowed));
|
|
remainingAssertionsAllowed -= this.operationBindingAssertions[entry.Key].Count;
|
|
}
|
|
|
|
foreach (KeyValuePair<MessageDescription, IEnumerable<XmlElement>> entry in messageBindingAssertions)
|
|
{
|
|
this.messageBindingAssertions[entry.Key].AddRange(new MaxItemsEnumerable<XmlElement>(entry.Value, remainingAssertionsAllowed));
|
|
remainingAssertionsAllowed -= this.messageBindingAssertions[entry.Key].Count;
|
|
}
|
|
|
|
foreach (KeyValuePair<FaultDescription, IEnumerable<XmlElement>> entry in faultBindingAssertions)
|
|
{
|
|
this.faultBindingAssertions[entry.Key].AddRange(new MaxItemsEnumerable<XmlElement>(entry.Value, remainingAssertionsAllowed));
|
|
remainingAssertionsAllowed -= this.faultBindingAssertions[entry.Key].Count;
|
|
}
|
|
}
|
|
|
|
//
|
|
// PolicyConversionContext implementation
|
|
//
|
|
|
|
public override BindingElementCollection BindingElements { get { return this.bindingElements; } }
|
|
|
|
public override PolicyAssertionCollection GetBindingAssertions()
|
|
{
|
|
return this.endpointAssertions;
|
|
}
|
|
|
|
public override PolicyAssertionCollection GetOperationBindingAssertions(OperationDescription operation)
|
|
{
|
|
return this.operationBindingAssertions[operation];
|
|
}
|
|
|
|
public override PolicyAssertionCollection GetMessageBindingAssertions(MessageDescription message)
|
|
{
|
|
return this.messageBindingAssertions[message];
|
|
}
|
|
|
|
public override PolicyAssertionCollection GetFaultBindingAssertions(FaultDescription message)
|
|
{
|
|
return this.faultBindingAssertions[message];
|
|
}
|
|
|
|
//
|
|
// Policy Alternative Enumeration code
|
|
//
|
|
|
|
public static IEnumerable<PolicyConversionContext> GetPolicyConversionContextEnumerator(ServiceEndpoint endpoint,
|
|
PolicyAlternatives policyAlternatives, MetadataImporterQuotas quotas)
|
|
{
|
|
IEnumerable<Dictionary<MessageDescription, IEnumerable<XmlElement>>> messageAssertionEnumerator;
|
|
IEnumerable<Dictionary<FaultDescription, IEnumerable<XmlElement>>> faultAssertionEnumerator;
|
|
IEnumerable<Dictionary<OperationDescription, IEnumerable<XmlElement>>> operationAssertionEnumerator;
|
|
faultAssertionEnumerator = PolicyIterationHelper.GetCartesianProduct<FaultDescription, IEnumerable<XmlElement>>(policyAlternatives.FaultBindingAlternatives);
|
|
messageAssertionEnumerator = PolicyIterationHelper.GetCartesianProduct<MessageDescription, IEnumerable<XmlElement>>(policyAlternatives.MessageBindingAlternatives);
|
|
operationAssertionEnumerator = PolicyIterationHelper.GetCartesianProduct<OperationDescription, IEnumerable<XmlElement>>(policyAlternatives.OperationBindingAlternatives);
|
|
|
|
foreach (Dictionary<FaultDescription, IEnumerable<XmlElement>> faultAssertionsSelection in faultAssertionEnumerator)
|
|
{
|
|
foreach (Dictionary<MessageDescription, IEnumerable<XmlElement>> messageAssertionsSelection in messageAssertionEnumerator)
|
|
{
|
|
foreach (Dictionary<OperationDescription, IEnumerable<XmlElement>> operationAssertionsSelection in operationAssertionEnumerator)
|
|
{
|
|
foreach (IEnumerable<XmlElement> endpointAssertionsSelection in policyAlternatives.EndpointAlternatives)
|
|
{
|
|
ImportedPolicyConversionContext conversionContext;
|
|
try
|
|
{
|
|
conversionContext = new ImportedPolicyConversionContext(endpoint, endpointAssertionsSelection,
|
|
operationAssertionsSelection, messageAssertionsSelection, faultAssertionsSelection,
|
|
quotas);
|
|
}
|
|
catch (MaxItemsEnumeratorExceededMaxItemsException) { yield break; }
|
|
|
|
yield return conversionContext;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
internal class MaxItemsEnumerable<T> : IEnumerable<T>
|
|
{
|
|
IEnumerable<T> inner;
|
|
int maxItems;
|
|
|
|
public MaxItemsEnumerable(IEnumerable<T> inner, int maxItems)
|
|
{
|
|
this.inner = inner;
|
|
this.maxItems = maxItems;
|
|
}
|
|
|
|
public IEnumerator<T> GetEnumerator()
|
|
{
|
|
return new MaxItemsEnumerator<T>(inner.GetEnumerator(), maxItems);
|
|
}
|
|
|
|
IEnumerator IEnumerable.GetEnumerator()
|
|
{
|
|
return (IEnumerator)GetEnumerator();
|
|
}
|
|
}
|
|
|
|
internal class MaxItemsEnumerator<T> : IEnumerator<T>
|
|
{
|
|
int maxItems;
|
|
int currentItem;
|
|
IEnumerator<T> inner;
|
|
|
|
public MaxItemsEnumerator(IEnumerator<T> inner, int maxItems)
|
|
{
|
|
this.maxItems = maxItems;
|
|
this.currentItem = 0;
|
|
this.inner = inner;
|
|
}
|
|
|
|
public T Current
|
|
{
|
|
get { return inner.Current; }
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
inner.Dispose();
|
|
}
|
|
|
|
object IEnumerator.Current
|
|
{
|
|
get { return ((IEnumerator)inner).Current; }
|
|
}
|
|
|
|
public bool MoveNext()
|
|
{
|
|
bool moveNext = inner.MoveNext();
|
|
if (++currentItem > maxItems)
|
|
{
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MaxItemsEnumeratorExceededMaxItemsException());
|
|
}
|
|
return moveNext;
|
|
}
|
|
|
|
public void Reset()
|
|
{
|
|
currentItem = 0;
|
|
inner.Reset();
|
|
}
|
|
}
|
|
|
|
internal class MaxItemsEnumeratorExceededMaxItemsException : Exception { }
|
|
|
|
static class PolicyIterationHelper
|
|
{
|
|
// This method returns an iterator over the cartesian product of a colleciton of sets.
|
|
// e.g. If the following 3 sets are provided:
|
|
// i) { 1, 2, 3 }
|
|
// ii) { a, b }
|
|
// iii) { x, y, z }
|
|
//
|
|
// You would get an enumerator that returned the following 18 collections:
|
|
// { 1, a, x}, { 2, a, x}, { 3, a, x}, { 1, b, x}, { 2, b, x}, { 3, b, x},
|
|
// { 1, a, y}, { 2, a, y}, { 3, a, y}, { 1, b, y}, { 2, b, y}, { 3, b, y},
|
|
// { 1, a, z}, { 2, a, z}, { 3, a, z}, { 1, b, z}, { 2, b, z}, { 3, b, z}
|
|
//
|
|
// This method allows us to enumerate over all the possible policy selections in a
|
|
// dictiaonary of policy alternatives.
|
|
// e.g. given all the policy alternatives in all the messages in a contract,
|
|
// we can enumerate over all the possilbe policy selections.
|
|
//
|
|
// Note: A general implementation of this method would differ in that it would probably use a List<T> or an array instead of
|
|
// a dictionary and it would yield clones of the the counterValue.
|
|
// - We don't clone because we know that we don't need to based on our useage
|
|
// - We use a dictionary because we need to correlate the selections with the alternative source.
|
|
//
|
|
internal static IEnumerable<Dictionary<K, V>> GetCartesianProduct<K, V>(Dictionary<K, IEnumerable<V>> sets)
|
|
{
|
|
Dictionary<K, V> counterValue = new Dictionary<K, V>(sets.Count);
|
|
|
|
// The iterator is implemented as a counter with each digit being an IEnumerator over one of the sets.
|
|
KeyValuePair<K, IEnumerator<V>>[] digits = InitializeCounter<K, V>(sets, counterValue);
|
|
|
|
do
|
|
{
|
|
yield return (Dictionary<K, V>)counterValue;
|
|
} while (IncrementCounter<K, V>(digits, sets, counterValue));
|
|
|
|
}
|
|
|
|
static KeyValuePair<K, IEnumerator<V>>[] InitializeCounter<K, V>(Dictionary<K, IEnumerable<V>> sets, Dictionary<K, V> counterValue)
|
|
{
|
|
KeyValuePair<K, IEnumerator<V>>[] digits = new KeyValuePair<K, IEnumerator<V>>[sets.Count];
|
|
|
|
// Initialize the digit enumerators and set the counter's current Value.
|
|
int i = 0;
|
|
foreach (KeyValuePair<K, IEnumerable<V>> kvp in sets)
|
|
{
|
|
digits[i] = new KeyValuePair<K, IEnumerator<V>>(kvp.Key, kvp.Value.GetEnumerator());
|
|
if (!(digits[i].Value.MoveNext()))
|
|
{
|
|
Fx.Assert("each set must have at least one item in it");
|
|
throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, "Each set must have at least one item in it")));
|
|
}
|
|
counterValue[digits[i].Key] = digits[i].Value.Current;
|
|
i++;
|
|
}
|
|
|
|
return digits;
|
|
}
|
|
|
|
static bool IncrementCounter<K, V>(KeyValuePair<K, IEnumerator<V>>[] digits, Dictionary<K, IEnumerable<V>> sets, Dictionary<K, V> counterValue)
|
|
{
|
|
|
|
//
|
|
// Do rollover and carryying for digits.
|
|
// - starting at least significant digit, move digits to next value.
|
|
// if digit rolls over, carry to next digit and repeat.
|
|
//
|
|
int currentDigit;
|
|
for (currentDigit = 0; currentDigit < digits.Length && !digits[currentDigit].Value.MoveNext(); currentDigit++)
|
|
{
|
|
IEnumerator<V> newDigit = sets[digits[currentDigit].Key].GetEnumerator();
|
|
digits[currentDigit] = new KeyValuePair<K, IEnumerator<V>>(digits[currentDigit].Key, newDigit);
|
|
digits[currentDigit].Value.MoveNext();
|
|
}
|
|
|
|
//
|
|
// if we just rolled over on the most significant digit, return false
|
|
//
|
|
if (currentDigit == digits.Length)
|
|
return false;
|
|
|
|
//
|
|
// update countervalue stores for all digits that changed.
|
|
//
|
|
for (int i = currentDigit; i >= 0; i--)
|
|
{
|
|
counterValue[digits[i].Key] = digits[i].Value.Current;
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
internal class PolicyAlternatives
|
|
{
|
|
public IEnumerable<IEnumerable<XmlElement>> EndpointAlternatives;
|
|
public Dictionary<OperationDescription, IEnumerable<IEnumerable<XmlElement>>> OperationBindingAlternatives;
|
|
public Dictionary<MessageDescription, IEnumerable<IEnumerable<XmlElement>>> MessageBindingAlternatives;
|
|
public Dictionary<FaultDescription, IEnumerable<IEnumerable<XmlElement>>> FaultBindingAlternatives;
|
|
}
|
|
|
|
}
|
|
}
|