1 //------------------------------------------------------------
2 // Copyright (c) Microsoft Corporation.  All rights reserved.
3 //------------------------------------------------------------
4 
5 namespace System.ServiceModel.Security
6 {
7     using System.Collections.Generic;
8     using System.ServiceModel.Channels;
9     using System.ServiceModel;
10     using System.Runtime.Serialization;
11     using System.ServiceModel.Security;
12     using System.Xml;
13 
14     public class ScopedMessagePartSpecification
15     {
16         MessagePartSpecification channelParts;
17         Dictionary<string, MessagePartSpecification> actionParts;
18         Dictionary<string, MessagePartSpecification> readOnlyNormalizedActionParts;
19         bool isReadOnly;
20 
ScopedMessagePartSpecification()21         public ScopedMessagePartSpecification()
22         {
23             this.channelParts = new MessagePartSpecification();
24             this.actionParts = new Dictionary<string, MessagePartSpecification>();
25         }
26 
27         public ICollection<string> Actions
28         {
29             get
30             {
31                 return this.actionParts.Keys;
32             }
33         }
34 
35         public MessagePartSpecification ChannelParts
36         {
37             get
38             {
39                 return this.channelParts;
40             }
41         }
42 
43         public bool IsReadOnly
44         {
45             get
46             {
47                 return this.isReadOnly;
48             }
49         }
50 
ScopedMessagePartSpecification(ScopedMessagePartSpecification other)51         public ScopedMessagePartSpecification(ScopedMessagePartSpecification other)
52             : this()
53         {
54             if (other == null)
55                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("other"));
56 
57             this.channelParts.Union(other.channelParts);
58             if (other.actionParts != null)
59             {
60                 foreach (string action in other.actionParts.Keys)
61                 {
62                     MessagePartSpecification p = new MessagePartSpecification();
63                     p.Union(other.actionParts[action]);
64                     this.actionParts[action] = p;
65                 }
66             }
67         }
68 
ScopedMessagePartSpecification(ScopedMessagePartSpecification other, bool newIncludeBody)69         internal ScopedMessagePartSpecification(ScopedMessagePartSpecification other, bool newIncludeBody)
70             : this(other)
71         {
72             this.channelParts.IsBodyIncluded = newIncludeBody;
73             foreach (string action in this.actionParts.Keys)
74                 this.actionParts[action].IsBodyIncluded = newIncludeBody;
75         }
76 
AddParts(MessagePartSpecification parts)77         public void AddParts(MessagePartSpecification parts)
78         {
79             if (parts == null)
80                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("parts"));
81 
82             ThrowIfReadOnly();
83 
84             this.channelParts.Union(parts);
85         }
86 
AddParts(MessagePartSpecification parts, string action)87         public void AddParts(MessagePartSpecification parts, string action)
88         {
89             if (action == null)
90                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("action"));
91             if (parts == null)
92                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("parts"));
93 
94             ThrowIfReadOnly();
95 
96             if (!this.actionParts.ContainsKey(action))
97                 this.actionParts[action] = new MessagePartSpecification();
98             this.actionParts[action].Union(parts);
99         }
100 
AddParts(MessagePartSpecification parts, XmlDictionaryString action)101         internal void AddParts(MessagePartSpecification parts, XmlDictionaryString action)
102         {
103             if (action == null)
104                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException("action"));
105             AddParts(parts, action.Value);
106         }
107 
IsEmpty()108         internal bool IsEmpty()
109         {
110             bool result;
111             if (!channelParts.IsEmpty())
112             {
113                 result = false;
114             }
115             else
116             {
117                 result = true;
118                 foreach (string action in this.Actions)
119                 {
120                     MessagePartSpecification parts;
121                     if (TryGetParts(action, true, out parts))
122                     {
123                         if (!parts.IsEmpty())
124                         {
125                             result = false;
126                             break;
127                         }
128                     }
129                 }
130             }
131 
132             return result;
133         }
134 
TryGetParts(string action, bool excludeChannelScope, out MessagePartSpecification parts)135         public bool TryGetParts(string action, bool excludeChannelScope, out MessagePartSpecification parts)
136         {
137             if (action == null)
138                 action = MessageHeaders.WildcardAction;
139             parts = null;
140 
141             if (this.isReadOnly)
142             {
143                 if (this.readOnlyNormalizedActionParts.ContainsKey(action))
144                     if (excludeChannelScope)
145                         parts = this.actionParts[action];
146                     else
147                         parts = this.readOnlyNormalizedActionParts[action];
148             }
149             else if (this.actionParts.ContainsKey(action))
150             {
151                 MessagePartSpecification p = new MessagePartSpecification();
152                 p.Union(this.actionParts[action]);
153                 if (!excludeChannelScope)
154                     p.Union(this.channelParts);
155                 parts = p;
156             }
157 
158             return parts != null;
159         }
160 
CopyTo(ScopedMessagePartSpecification target)161         internal void CopyTo(ScopedMessagePartSpecification target)
162         {
163             if (target == null)
164             {
165                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("target");
166             }
167             target.ChannelParts.IsBodyIncluded = this.ChannelParts.IsBodyIncluded;
168             foreach (XmlQualifiedName headerType in ChannelParts.HeaderTypes)
169             {
170                 if (!target.channelParts.IsHeaderIncluded(headerType.Name, headerType.Namespace))
171                 {
172                     target.ChannelParts.HeaderTypes.Add(headerType);
173                 }
174             }
175             foreach (string action in this.actionParts.Keys)
176             {
177                 target.AddParts(this.actionParts[action], action);
178             }
179         }
180 
TryGetParts(string action, out MessagePartSpecification parts)181         public bool TryGetParts(string action, out MessagePartSpecification parts)
182         {
183             return this.TryGetParts(action, false, out parts);
184         }
185 
MakeReadOnly()186         public void MakeReadOnly()
187         {
188             if (!this.isReadOnly)
189             {
190                 this.readOnlyNormalizedActionParts = new Dictionary<string, MessagePartSpecification>();
191                 foreach (string action in this.actionParts.Keys)
192                 {
193                     MessagePartSpecification p = new MessagePartSpecification();
194                     p.Union(this.actionParts[action]);
195                     p.Union(this.channelParts);
196                     p.MakeReadOnly();
197                     this.readOnlyNormalizedActionParts[action] = p;
198                 }
199                 this.isReadOnly = true;
200             }
201         }
202 
ThrowIfReadOnly()203         void ThrowIfReadOnly()
204         {
205             if (this.isReadOnly)
206                 throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ObjectIsReadOnly)));
207         }
208     }
209 }
210