ImportedPolicyConversionContext.cs 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) Microsoft Corporation. All rights reserved.
  3. //-----------------------------------------------------------------------------
  4. namespace System.ServiceModel.Description
  5. {
  6. using System.Collections;
  7. using System.Collections.Generic;
  8. using System.Globalization;
  9. using System.Runtime;
  10. using System.ServiceModel.Channels;
  11. using System.Xml;
  12. public abstract partial class MetadataImporter
  13. {
  14. //Consider, [....]: make this public
  15. internal static IEnumerable<PolicyConversionContext> GetPolicyConversionContextEnumerator(ServiceEndpoint endpoint, PolicyAlternatives policyAlternatives)
  16. {
  17. return ImportedPolicyConversionContext.GetPolicyConversionContextEnumerator(endpoint, policyAlternatives, MetadataImporterQuotas.Defaults);
  18. }
  19. internal static IEnumerable<PolicyConversionContext> GetPolicyConversionContextEnumerator(ServiceEndpoint endpoint, PolicyAlternatives policyAlternatives,
  20. MetadataImporterQuotas quotas)
  21. {
  22. return ImportedPolicyConversionContext.GetPolicyConversionContextEnumerator(endpoint, policyAlternatives, quotas);
  23. }
  24. internal sealed class ImportedPolicyConversionContext : PolicyConversionContext
  25. {
  26. BindingElementCollection bindingElements = new BindingElementCollection();
  27. readonly PolicyAssertionCollection endpointAssertions;
  28. readonly Dictionary<OperationDescription, PolicyAssertionCollection> operationBindingAssertions = new Dictionary<OperationDescription, PolicyAssertionCollection>();
  29. readonly Dictionary<MessageDescription, PolicyAssertionCollection> messageBindingAssertions = new Dictionary<MessageDescription, PolicyAssertionCollection>();
  30. readonly Dictionary<FaultDescription, PolicyAssertionCollection> faultBindingAssertions = new Dictionary<FaultDescription, PolicyAssertionCollection>();
  31. ImportedPolicyConversionContext(ServiceEndpoint endpoint, IEnumerable<XmlElement> endpointAssertions,
  32. Dictionary<OperationDescription, IEnumerable<XmlElement>> operationBindingAssertions,
  33. Dictionary<MessageDescription, IEnumerable<XmlElement>> messageBindingAssertions,
  34. Dictionary<FaultDescription, IEnumerable<XmlElement>> faultBindingAssertions,
  35. MetadataImporterQuotas quotas)
  36. : base(endpoint)
  37. {
  38. int remainingAssertionsAllowed = quotas.MaxPolicyAssertions;
  39. this.endpointAssertions = new PolicyAssertionCollection(new MaxItemsEnumerable<XmlElement>(endpointAssertions, remainingAssertionsAllowed));
  40. remainingAssertionsAllowed -= this.endpointAssertions.Count;
  41. foreach (OperationDescription operationDescription in endpoint.Contract.Operations)
  42. {
  43. this.operationBindingAssertions.Add(operationDescription, new PolicyAssertionCollection());
  44. foreach (MessageDescription messageDescription in operationDescription.Messages)
  45. {
  46. this.messageBindingAssertions.Add(messageDescription, new PolicyAssertionCollection());
  47. }
  48. foreach (FaultDescription faultDescription in operationDescription.Faults)
  49. {
  50. this.faultBindingAssertions.Add(faultDescription, new PolicyAssertionCollection());
  51. }
  52. }
  53. foreach (KeyValuePair<OperationDescription, IEnumerable<XmlElement>> entry in operationBindingAssertions)
  54. {
  55. this.operationBindingAssertions[entry.Key].AddRange(new MaxItemsEnumerable<XmlElement>(entry.Value, remainingAssertionsAllowed));
  56. remainingAssertionsAllowed -= this.operationBindingAssertions[entry.Key].Count;
  57. }
  58. foreach (KeyValuePair<MessageDescription, IEnumerable<XmlElement>> entry in messageBindingAssertions)
  59. {
  60. this.messageBindingAssertions[entry.Key].AddRange(new MaxItemsEnumerable<XmlElement>(entry.Value, remainingAssertionsAllowed));
  61. remainingAssertionsAllowed -= this.messageBindingAssertions[entry.Key].Count;
  62. }
  63. foreach (KeyValuePair<FaultDescription, IEnumerable<XmlElement>> entry in faultBindingAssertions)
  64. {
  65. this.faultBindingAssertions[entry.Key].AddRange(new MaxItemsEnumerable<XmlElement>(entry.Value, remainingAssertionsAllowed));
  66. remainingAssertionsAllowed -= this.faultBindingAssertions[entry.Key].Count;
  67. }
  68. }
  69. //
  70. // PolicyConversionContext implementation
  71. //
  72. public override BindingElementCollection BindingElements { get { return this.bindingElements; } }
  73. public override PolicyAssertionCollection GetBindingAssertions()
  74. {
  75. return this.endpointAssertions;
  76. }
  77. public override PolicyAssertionCollection GetOperationBindingAssertions(OperationDescription operation)
  78. {
  79. return this.operationBindingAssertions[operation];
  80. }
  81. public override PolicyAssertionCollection GetMessageBindingAssertions(MessageDescription message)
  82. {
  83. return this.messageBindingAssertions[message];
  84. }
  85. public override PolicyAssertionCollection GetFaultBindingAssertions(FaultDescription message)
  86. {
  87. return this.faultBindingAssertions[message];
  88. }
  89. //
  90. // Policy Alternative Enumeration code
  91. //
  92. public static IEnumerable<PolicyConversionContext> GetPolicyConversionContextEnumerator(ServiceEndpoint endpoint,
  93. PolicyAlternatives policyAlternatives, MetadataImporterQuotas quotas)
  94. {
  95. IEnumerable<Dictionary<MessageDescription, IEnumerable<XmlElement>>> messageAssertionEnumerator;
  96. IEnumerable<Dictionary<FaultDescription, IEnumerable<XmlElement>>> faultAssertionEnumerator;
  97. IEnumerable<Dictionary<OperationDescription, IEnumerable<XmlElement>>> operationAssertionEnumerator;
  98. faultAssertionEnumerator = PolicyIterationHelper.GetCartesianProduct<FaultDescription, IEnumerable<XmlElement>>(policyAlternatives.FaultBindingAlternatives);
  99. messageAssertionEnumerator = PolicyIterationHelper.GetCartesianProduct<MessageDescription, IEnumerable<XmlElement>>(policyAlternatives.MessageBindingAlternatives);
  100. operationAssertionEnumerator = PolicyIterationHelper.GetCartesianProduct<OperationDescription, IEnumerable<XmlElement>>(policyAlternatives.OperationBindingAlternatives);
  101. foreach (Dictionary<FaultDescription, IEnumerable<XmlElement>> faultAssertionsSelection in faultAssertionEnumerator)
  102. {
  103. foreach (Dictionary<MessageDescription, IEnumerable<XmlElement>> messageAssertionsSelection in messageAssertionEnumerator)
  104. {
  105. foreach (Dictionary<OperationDescription, IEnumerable<XmlElement>> operationAssertionsSelection in operationAssertionEnumerator)
  106. {
  107. foreach (IEnumerable<XmlElement> endpointAssertionsSelection in policyAlternatives.EndpointAlternatives)
  108. {
  109. ImportedPolicyConversionContext conversionContext;
  110. try
  111. {
  112. conversionContext = new ImportedPolicyConversionContext(endpoint, endpointAssertionsSelection,
  113. operationAssertionsSelection, messageAssertionsSelection, faultAssertionsSelection,
  114. quotas);
  115. }
  116. catch (MaxItemsEnumeratorExceededMaxItemsException) { yield break; }
  117. yield return conversionContext;
  118. }
  119. }
  120. }
  121. }
  122. }
  123. internal class MaxItemsEnumerable<T> : IEnumerable<T>
  124. {
  125. IEnumerable<T> inner;
  126. int maxItems;
  127. public MaxItemsEnumerable(IEnumerable<T> inner, int maxItems)
  128. {
  129. this.inner = inner;
  130. this.maxItems = maxItems;
  131. }
  132. public IEnumerator<T> GetEnumerator()
  133. {
  134. return new MaxItemsEnumerator<T>(inner.GetEnumerator(), maxItems);
  135. }
  136. IEnumerator IEnumerable.GetEnumerator()
  137. {
  138. return (IEnumerator)GetEnumerator();
  139. }
  140. }
  141. internal class MaxItemsEnumerator<T> : IEnumerator<T>
  142. {
  143. int maxItems;
  144. int currentItem;
  145. IEnumerator<T> inner;
  146. public MaxItemsEnumerator(IEnumerator<T> inner, int maxItems)
  147. {
  148. this.maxItems = maxItems;
  149. this.currentItem = 0;
  150. this.inner = inner;
  151. }
  152. public T Current
  153. {
  154. get { return inner.Current; }
  155. }
  156. public void Dispose()
  157. {
  158. inner.Dispose();
  159. }
  160. object IEnumerator.Current
  161. {
  162. get { return ((IEnumerator)inner).Current; }
  163. }
  164. public bool MoveNext()
  165. {
  166. bool moveNext = inner.MoveNext();
  167. if (++currentItem > maxItems)
  168. {
  169. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new MaxItemsEnumeratorExceededMaxItemsException());
  170. }
  171. return moveNext;
  172. }
  173. public void Reset()
  174. {
  175. currentItem = 0;
  176. inner.Reset();
  177. }
  178. }
  179. internal class MaxItemsEnumeratorExceededMaxItemsException : Exception { }
  180. static class PolicyIterationHelper
  181. {
  182. // This method returns an iterator over the cartesian product of a colleciton of sets.
  183. // e.g. If the following 3 sets are provided:
  184. // i) { 1, 2, 3 }
  185. // ii) { a, b }
  186. // iii) { x, y, z }
  187. //
  188. // You would get an enumerator that returned the following 18 collections:
  189. // { 1, a, x}, { 2, a, x}, { 3, a, x}, { 1, b, x}, { 2, b, x}, { 3, b, x},
  190. // { 1, a, y}, { 2, a, y}, { 3, a, y}, { 1, b, y}, { 2, b, y}, { 3, b, y},
  191. // { 1, a, z}, { 2, a, z}, { 3, a, z}, { 1, b, z}, { 2, b, z}, { 3, b, z}
  192. //
  193. // This method allows us to enumerate over all the possible policy selections in a
  194. // dictiaonary of policy alternatives.
  195. // e.g. given all the policy alternatives in all the messages in a contract,
  196. // we can enumerate over all the possilbe policy selections.
  197. //
  198. // Note: A general implementation of this method would differ in that it would probably use a List<T> or an array instead of
  199. // a dictionary and it would yield clones of the the counterValue.
  200. // - We don't clone because we know that we don't need to based on our useage
  201. // - We use a dictionary because we need to correlate the selections with the alternative source.
  202. //
  203. internal static IEnumerable<Dictionary<K, V>> GetCartesianProduct<K, V>(Dictionary<K, IEnumerable<V>> sets)
  204. {
  205. Dictionary<K, V> counterValue = new Dictionary<K, V>(sets.Count);
  206. // The iterator is implemented as a counter with each digit being an IEnumerator over one of the sets.
  207. KeyValuePair<K, IEnumerator<V>>[] digits = InitializeCounter<K, V>(sets, counterValue);
  208. do
  209. {
  210. yield return (Dictionary<K, V>)counterValue;
  211. } while (IncrementCounter<K, V>(digits, sets, counterValue));
  212. }
  213. static KeyValuePair<K, IEnumerator<V>>[] InitializeCounter<K, V>(Dictionary<K, IEnumerable<V>> sets, Dictionary<K, V> counterValue)
  214. {
  215. KeyValuePair<K, IEnumerator<V>>[] digits = new KeyValuePair<K, IEnumerator<V>>[sets.Count];
  216. // Initialize the digit enumerators and set the counter's current Value.
  217. int i = 0;
  218. foreach (KeyValuePair<K, IEnumerable<V>> kvp in sets)
  219. {
  220. digits[i] = new KeyValuePair<K, IEnumerator<V>>(kvp.Key, kvp.Value.GetEnumerator());
  221. if (!(digits[i].Value.MoveNext()))
  222. {
  223. Fx.Assert("each set must have at least one item in it");
  224. throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, "Each set must have at least one item in it")));
  225. }
  226. counterValue[digits[i].Key] = digits[i].Value.Current;
  227. i++;
  228. }
  229. return digits;
  230. }
  231. static bool IncrementCounter<K, V>(KeyValuePair<K, IEnumerator<V>>[] digits, Dictionary<K, IEnumerable<V>> sets, Dictionary<K, V> counterValue)
  232. {
  233. //
  234. // Do rollover and carryying for digits.
  235. // - starting at least significant digit, move digits to next value.
  236. // if digit rolls over, carry to next digit and repeat.
  237. //
  238. int currentDigit;
  239. for (currentDigit = 0; currentDigit < digits.Length && !digits[currentDigit].Value.MoveNext(); currentDigit++)
  240. {
  241. IEnumerator<V> newDigit = sets[digits[currentDigit].Key].GetEnumerator();
  242. digits[currentDigit] = new KeyValuePair<K, IEnumerator<V>>(digits[currentDigit].Key, newDigit);
  243. digits[currentDigit].Value.MoveNext();
  244. }
  245. //
  246. // if we just rolled over on the most significant digit, return false
  247. //
  248. if (currentDigit == digits.Length)
  249. return false;
  250. //
  251. // update countervalue stores for all digits that changed.
  252. //
  253. for (int i = currentDigit; i >= 0; i--)
  254. {
  255. counterValue[digits[i].Key] = digits[i].Value.Current;
  256. }
  257. return true;
  258. }
  259. }
  260. }
  261. internal class PolicyAlternatives
  262. {
  263. public IEnumerable<IEnumerable<XmlElement>> EndpointAlternatives;
  264. public Dictionary<OperationDescription, IEnumerable<IEnumerable<XmlElement>>> OperationBindingAlternatives;
  265. public Dictionary<MessageDescription, IEnumerable<IEnumerable<XmlElement>>> MessageBindingAlternatives;
  266. public Dictionary<FaultDescription, IEnumerable<IEnumerable<XmlElement>>> FaultBindingAlternatives;
  267. }
  268. }
  269. }