Merge branch 'master' of github.com:mono/mono
[mono.git] / mcs / class / System.ServiceModel.Discovery / System.ServiceModel.Discovery / FindCriteria.cs
1 //
2 // Author: Atsushi Enomoto <atsushi@ximian.com>
3 //
4 // Copyright (C) 2009 Novell, Inc (http://www.novell.com)
5 //
6 // Permission is hereby granted, free of charge, to any person obtaining
7 // a copy of this software and associated documentation files (the
8 // "Software"), to deal in the Software without restriction, including
9 // without limitation the rights to use, copy, modify, merge, publish,
10 // distribute, sublicense, and/or sell copies of the Software, and to
11 // permit persons to whom the Software is furnished to do so, subject to
12 // the following conditions:
13 // 
14 // The above copyright notice and this permission notice shall be
15 // included in all copies or substantial portions of the Software.
16 // 
17 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 //
25 using System;
26 using System.Collections.Generic;
27 using System.Collections.ObjectModel;
28 using System.Linq;
29 using System.ServiceModel;
30 using System.ServiceModel.Channels;
31 using System.ServiceModel.Description;
32 using System.ServiceModel.Dispatcher;
33 using System.Xml;
34 using System.Xml.Schema;
35 using System.Xml.Linq;
36
37 namespace System.ServiceModel.Discovery
38 {
39         public class FindCriteria
40         {
41                 const string SerializationNS = "http://schemas.microsoft.com/ws/2008/06/discovery";
42                 const int default_max_results = int.MaxValue;
43
44                 public static readonly Uri ScopeMatchByExact = new Uri ("http://schemas.microsoft.com/ws/2008/06/discovery/strcmp0");
45                 public static readonly Uri ScopeMatchByLdap = new Uri ("http://schemas.microsoft.com/ws/2008/06/discovery/ldap");
46                 public static readonly Uri ScopeMatchByNone = new Uri ("http://schemas.microsoft.com/ws/2008/06/discovery/none");
47                 public static readonly Uri ScopeMatchByPrefix = new Uri ("http://schemas.microsoft.com/ws/2008/06/discovery/rfc3986");
48                 public static readonly Uri ScopeMatchByUuid = new Uri ("http://schemas.microsoft.com/ws/2008/06/discovery/uuid");
49
50                 public static FindCriteria CreateMetadataExchangeEndpointCriteria ()
51                 {
52                         return CreateMetadataExchangeEndpointCriteria (typeof (IMetadataExchange));
53                 }
54
55                 public static FindCriteria CreateMetadataExchangeEndpointCriteria (IEnumerable<XmlQualifiedName> contractTypeNames)
56                 {
57                         var fc = new FindCriteria ();
58                         foreach (var type in contractTypeNames)
59                                 fc.ContractTypeNames.Add (type);
60                         return fc;
61                 }
62
63                 public static FindCriteria CreateMetadataExchangeEndpointCriteria (Type contractType)
64                 {
65                         return new FindCriteria (contractType);
66                 }
67
68                 public FindCriteria ()
69                 {
70                         ContractTypeNames = new Collection<XmlQualifiedName> ();
71                         Extensions = new Collection<XElement> ();
72                         Scopes = new Collection<Uri> ();
73                         ScopeMatchBy = ScopeMatchByPrefix;
74                         MaxResults = default_max_results;
75                         Duration = TimeSpan.FromSeconds (20);
76                 }
77
78                 public FindCriteria (Type contractType)
79                         : this ()
80                 {
81                         var cd = ContractDescription.GetContract (contractType);
82                         ContractTypeNames.Add (new XmlQualifiedName (cd.Name, cd.Namespace));
83                 }
84
85                 public Collection<XmlQualifiedName> ContractTypeNames { get; private set; }
86                 public TimeSpan Duration { get; set; }
87                 public Collection<XElement> Extensions { get; private set; }
88                 public int MaxResults { get; set; }
89                 public Uri ScopeMatchBy { get; set; }
90                 public Collection<Uri> Scopes { get; private set; }
91
92                 [MonoTODO ("find out conformant behavior, and implement remaining bits")]
93                 public bool IsMatch (EndpointDiscoveryMetadata endpointDiscoveryMetadata)
94                 {
95                         var edm = endpointDiscoveryMetadata;
96                         if (edm == null)
97                                 throw new ArgumentNullException ("endpointDiscoveryMetadata");
98                         if (ContractTypeNames.Count > 0) {
99                                 bool match = false;
100                                 foreach (var qn in ContractTypeNames)
101                                         if (edm.ContractTypeNames.Contains (qn))
102                                                 match = true;
103                                 if (!match)
104                                         return false;
105                         }
106                         if (Scopes.Count > 0) {
107                                 bool match = false;
108                                 foreach (var scope in Scopes) {
109                                         if (ScopeMatchBy == null || ScopeMatchBy.Equals (ScopeMatchByPrefix)) {
110                                                 if (edm.Scopes.Contains (scope))
111                                                         match = true;
112                                         } else if (ScopeMatchBy.Equals (ScopeMatchByExact)) {
113                                                 if (edm.Scopes.Any (s => s.AbsoluteUri == scope.AbsoluteUri))
114                                                         match = true;
115                                         }
116                                         else if (ScopeMatchBy.Equals (ScopeMatchByUuid))
117                                                 throw new NotImplementedException ();
118                                         else if (ScopeMatchBy.Equals (ScopeMatchByNone))
119                                                 throw new NotImplementedException ();
120                                         else if (ScopeMatchBy.Equals (ScopeMatchByLdap))
121                                                 throw new NotImplementedException ();
122                                         else
123                                                 throw new InvalidOperationException (String.Format ("Unexpected ScopeMatchBy value: {0}", ScopeMatchBy));
124                                 }
125                                 if (!match)
126                                         return false;
127                         }
128                         if (Extensions.Count > 0)
129                                 throw new NotImplementedException (String.Format ("{0} extensions are found", Extensions.Count));
130
131                         return true;
132                 }
133
134                 internal static FindCriteria ReadXml (XmlReader reader, DiscoveryVersion version)
135                 {
136                         if (reader == null)
137                                 throw new ArgumentNullException ("reader");
138
139                         var ret = new FindCriteria ();
140
141                         reader.MoveToContent ();
142                         if (!reader.IsStartElement ("Probe", version.Namespace) || reader.IsEmptyElement)
143                                 throw new XmlException (String.Format ("Non-empty ProbeType element is expected. Got '{0}' {1} node in namespace '{2}' instead.", reader.LocalName, reader.NodeType, reader.NamespaceURI));
144                         reader.ReadStartElement ("Probe", version.Namespace);
145
146                         // standard members
147                         reader.MoveToContent ();
148                         if (reader.IsStartElement ("Types", version.Namespace))
149                                 ret.ContractTypeNames = new Collection<XmlQualifiedName> ((XmlQualifiedName []) reader.ReadElementContentAs (typeof (XmlQualifiedName []), null, "Types", version.Namespace));
150
151                         reader.MoveToContent ();
152                         if (reader.IsStartElement ("Types", version.Namespace)) {
153                                 if (reader.MoveToAttribute ("MatchBy")) {
154                                         ret.ScopeMatchBy = new Uri (reader.Value, UriKind.RelativeOrAbsolute);
155                                         reader.MoveToElement ();
156                                 }
157                         }
158                         if (reader.IsStartElement ("Scopes", version.Namespace))
159                                 ret.Scopes = new Collection<Uri> ((Uri []) reader.ReadElementContentAs (typeof (Uri []), null, "Scopes", version.Namespace));
160
161                         // non-standard members
162                         for (reader.MoveToContent (); !reader.EOF && reader.NodeType != XmlNodeType.EndElement; reader.MoveToContent ()) {
163                                 if (reader.NamespaceURI == SerializationNS) {
164                                         switch (reader.LocalName) {
165                                         case "MaxResults":
166                                                 ret.MaxResults = reader.ReadElementContentAsInt ();
167                                                 break;
168                                         case "Duration":
169                                                 ret.Duration = (TimeSpan) reader.ReadElementContentAs (typeof (TimeSpan), null);
170                                                 break;
171                                         }
172                                 }
173                                 else
174                                         ret.Extensions.Add (XElement.Load (reader));
175                         }
176
177                         reader.ReadEndElement ();
178
179                         return ret;
180                 }
181
182                 internal void WriteXml (XmlWriter writer, DiscoveryVersion version)
183                 {
184                         if (writer == null)
185                                 throw new ArgumentNullException ("writer");
186
187                         // standard members
188                         writer.WriteStartElement ("d", "Types", version.Namespace);
189                         int p = 0;
190                         foreach (var qname in ContractTypeNames)
191                                 if (writer.LookupPrefix (qname.Namespace) == null)
192                                         writer.WriteAttributeString ("xmlns", "p" + p++, "http://www.w3.org/2000/xmlns/", qname.Namespace);
193                         writer.WriteValue (ContractTypeNames);
194                         writer.WriteEndElement ();
195
196                         writer.WriteStartElement ("Scopes", version.Namespace);
197                         if (ScopeMatchBy != null) {
198                                 writer.WriteStartAttribute ("MatchBy");
199                                 writer.WriteValue (ScopeMatchBy);
200                                 writer.WriteEndAttribute ();
201                         }
202                         writer.WriteValue (Scopes);
203                         writer.WriteEndElement ();
204
205                         // non-standard members
206                         if (MaxResults != default_max_results) {
207                                 writer.WriteStartElement ("MaxResults", SerializationNS);
208                                 writer.WriteValue (MaxResults);
209                                 writer.WriteEndElement ();
210                         }
211                         writer.WriteStartElement ("Duration", SerializationNS);
212                         writer.WriteValue (Duration);
213                         writer.WriteEndElement ();
214                         
215                         foreach (var ext in Extensions)
216                                 ext.WriteTo (writer);
217                 }
218
219                 internal static XmlSchema BuildSchema (DiscoveryVersion version)
220                 {
221                         var schema = new XmlSchema () { TargetNamespace = version.Namespace };
222
223                         var anyAttr = new XmlSchemaAnyAttribute () { Namespace = "##other", ProcessContents = XmlSchemaContentProcessing.Lax };
224
225                         var probePart = new XmlSchemaSequence ();
226                         probePart.Items.Add (new XmlSchemaElement () { RefName = new XmlQualifiedName ("Types", version.Namespace), MinOccurs = 0 });
227                         probePart.Items.Add (new XmlSchemaElement () { RefName = new XmlQualifiedName ("Scopes", version.Namespace), MinOccurs = 0 });
228                         probePart.Items.Add (new XmlSchemaAny () { MinOccurs = 0, MaxOccursString = "unbounded", Namespace = "##other", ProcessContents = XmlSchemaContentProcessing.Lax });
229                         var ct = new XmlSchemaComplexType () { Name = "ProbeType", Particle = probePart, AnyAttribute = anyAttr };
230                         schema.Items.Add (ct);
231
232                         schema.Items.Add (new XmlSchemaSimpleType () { Name = "QNameListType", Content = new XmlSchemaSimpleTypeList () { ItemTypeName = new XmlQualifiedName ("QName", XmlSchema.Namespace) } });
233
234                         var scr = new XmlSchemaSimpleContentRestriction () { BaseTypeName = new XmlQualifiedName ("UriListType", version.Namespace), AnyAttribute = anyAttr };
235                         scr.Attributes.Add (new XmlSchemaAttribute () { Name = "matchBy", SchemaTypeName = new XmlQualifiedName ("anyURI", XmlSchema.Namespace) });
236                         schema.Items.Add (new XmlSchemaComplexType () { Name = "ScopesType", ContentModel = new XmlSchemaSimpleContent () { Content = scr } });
237
238                         schema.Items.Add (new XmlSchemaSimpleType () { Name = "UriListType", Content = new XmlSchemaSimpleTypeList () { ItemTypeName = new XmlQualifiedName ("anyURI", XmlSchema.Namespace) } });
239
240                         schema.Items.Add (new XmlSchemaElement () { Name = "Types", SchemaTypeName = new XmlQualifiedName ("QNameListType", version.Namespace) });
241                         schema.Items.Add (new XmlSchemaElement () { Name = "Scopes", SchemaTypeName = new XmlQualifiedName ("ScopesType", version.Namespace) });
242
243                         return schema;
244                 }
245         }
246 }