2 // System.Web.Services.Protocols.DiscoveryClientProtocol.cs
\r
5 // Dave Bettin (javabettin@yahoo.com)
\r
6 // Lluis Sanchez Gual (lluis@ximian.com)
\r
8 // Copyright (C) Dave Bettin, 2002
\r
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 using System.Collections;
\r
34 using System.Web.Services.Protocols;
\r
35 using System.Web.Services.Description;
\r
37 using System.Xml.Schema;
\r
38 using System.Xml.Serialization;
\r
40 using System.Text.RegularExpressions;
\r
42 namespace System.Web.Services.Discovery {
\r
43 public class DiscoveryClientProtocol : HttpWebClientProtocol {
\r
47 private IList additionalInformation = new ArrayList ();
\r
48 private DiscoveryClientDocumentCollection documents = new DiscoveryClientDocumentCollection();
\r
49 private DiscoveryExceptionDictionary errors = new DiscoveryExceptionDictionary();
\r
50 private DiscoveryClientReferenceCollection references = new DiscoveryClientReferenceCollection();
\r
52 #endregion // Fields
\r
54 #region Constructors
\r
56 public DiscoveryClientProtocol ()
\r
60 #endregion // Constructors
\r
64 public IList AdditionalInformation {
\r
65 get { return additionalInformation; }
\r
68 public DiscoveryClientDocumentCollection Documents {
\r
69 get { return documents; }
\r
72 public DiscoveryExceptionDictionary Errors {
\r
73 get { return errors; }
\r
76 public DiscoveryClientReferenceCollection References {
\r
77 get { return references; }
\r
80 #endregion // Properties
\r
84 public DiscoveryDocument Discover (string url)
\r
86 Stream stream = Download (ref url);
\r
87 XmlTextReader reader = new XmlTextReader (url, stream);
\r
88 if (!DiscoveryDocument.CanRead (reader))
\r
89 throw new InvalidOperationException ("The url '" + url + "' does not point to a valid discovery document");
\r
91 DiscoveryDocument doc = DiscoveryDocument.Read (reader);
\r
93 documents.Add (url, doc);
\r
94 AddDiscoReferences (doc);
\r
98 public DiscoveryDocument DiscoverAny (string url)
\r
102 string contentType = null;
\r
103 Stream stream = Download (ref url, ref contentType);
\r
105 if (contentType.IndexOf ("text/html") != -1)
\r
107 // Look for an alternate url
\r
109 StreamReader sr = new StreamReader (stream);
\r
110 string str = sr.ReadToEnd ();
\r
112 string rex = "link\\s*rel\\s*=\\s*[\"']?alternate[\"']?\\s*";
\r
113 rex += "type\\s*=\\s*[\"']?text/xml[\"']?\\s*href\\s*=\\s*(?:\"(?<1>[^\"]*)\"|'(?<1>[^']*)'|(?<1>\\S+))";
\r
114 Regex rob = new Regex (rex, RegexOptions.IgnoreCase);
\r
115 Match m = rob.Match (str);
\r
117 throw new InvalidOperationException ("The HTML document does not contain Web service discovery information");
\r
119 if (url.StartsWith ("/"))
\r
121 Uri uri = new Uri (url);
\r
122 url = uri.GetLeftPart (UriPartial.Authority) + m.Groups[1];
\r
126 int i = url.LastIndexOf ('/');
\r
128 throw new InvalidOperationException ("The HTML document does not contain Web service discovery information");
\r
129 url = url.Substring (0,i+1) + m.Groups[1];
\r
131 stream = Download (ref url);
\r
134 XmlTextReader reader = new XmlTextReader (url, stream);
\r
135 reader.MoveToContent ();
\r
136 DiscoveryDocument doc;
\r
137 DiscoveryReference refe = null;
\r
139 if (DiscoveryDocument.CanRead (reader))
\r
141 doc = DiscoveryDocument.Read (reader);
\r
142 documents.Add (url, doc);
\r
143 refe = new DiscoveryDocumentReference ();
\r
144 AddDiscoReferences (doc);
\r
146 else if (ServiceDescription.CanRead (reader))
\r
148 ServiceDescription wsdl = ServiceDescription.Read (reader);
\r
149 documents.Add (url, wsdl);
\r
150 doc = new DiscoveryDocument ();
\r
151 refe = new ContractReference ();
\r
152 doc.References.Add (refe);
\r
154 ((ContractReference)refe).ResolveInternal (this, wsdl);
\r
158 XmlSchema schema = XmlSchema.Read (reader, null);
\r
159 documents.Add (url, schema);
\r
160 doc = new DiscoveryDocument ();
\r
161 refe = new SchemaReference ();
\r
162 doc.References.Add (refe);
\r
165 refe.ClientProtocol = this;
\r
167 references.Add (url, refe);
\r
172 catch (DiscoveryException ex) {
\r
173 throw ex.Exception;
\r
177 void AddDiscoReferences (DiscoveryDocument doc)
\r
179 foreach (DiscoveryReference re in doc.References)
\r
181 re.ClientProtocol = this;
\r
182 references.Add (re.Url, re);
\r
185 if (doc.AdditionalInfo != null) {
\r
186 foreach (object info in doc.AdditionalInfo)
\r
187 additionalInformation.Add (info);
\r
191 public Stream Download (ref string url)
\r
193 string contentType = null;
\r
194 return Download (ref url, ref contentType);
\r
197 public Stream Download (ref string url, ref string contentType)
\r
199 if (url.StartsWith ("http://") || url.StartsWith ("https://"))
\r
201 WebRequest request = GetWebRequest (new Uri(url));
\r
202 WebResponse resp = request.GetResponse ();
\r
203 contentType = resp.ContentType;
\r
204 return resp.GetResponseStream ();
\r
208 string ext = Path.GetExtension (url).ToLower();
\r
209 if (ext == ".wsdl" || ext == ".xsd")
\r
211 contentType = "text/xml";
\r
212 return new FileStream (url, FileMode.Open, FileAccess.Read);
\r
215 throw new InvalidOperationException ("Unrecognized file type '" + url + "'. Extension must be one of .wsdl or .xsd");
\r
219 public DiscoveryClientResultCollection ReadAll (string topLevelFilename)
\r
221 StreamReader sr = new StreamReader (topLevelFilename);
\r
222 XmlSerializer ser = new XmlSerializer (typeof (DiscoveryClientResultsFile));
\r
223 DiscoveryClientResultsFile resfile = (DiscoveryClientResultsFile) ser.Deserialize (sr);
\r
226 foreach (DiscoveryClientResult dcr in resfile.Results)
\r
228 Type type = Type.GetType (dcr.ReferenceTypeName);
\r
229 DiscoveryReference dr = (DiscoveryReference) Activator.CreateInstance (type);
\r
231 FileStream fs = new FileStream (dcr.Filename, FileMode.Open, FileAccess.Read);
\r
232 Documents.Add (dr.Url, dr.ReadDocument (fs));
\r
234 References.Add (dr.Url, dr);
\r
236 return resfile.Results;
\r
239 public void ResolveAll ()
\r
241 ArrayList list = new ArrayList (References.Values);
\r
242 foreach (DiscoveryReference re in list)
\r
246 if (re is DiscoveryDocumentReference)
\r
247 ((DiscoveryDocumentReference)re).ResolveAll ();
\r
251 catch (DiscoveryException ex)
\r
253 Errors [ex.Url] = ex.Exception;
\r
255 catch (Exception ex)
\r
257 Errors [re.Url] = ex;
\r
262 public void ResolveOneLevel ()
\r
264 ArrayList list = new ArrayList (References.Values);
\r
265 foreach (DiscoveryReference re in list)
\r
269 public DiscoveryClientResultCollection WriteAll (string directory, string topLevelFilename)
\r
271 DiscoveryClientResultsFile resfile = new DiscoveryClientResultsFile();
\r
273 foreach (DiscoveryReference re in References.Values)
\r
275 object doc = Documents [re.Url];
\r
276 if (doc == null) continue;
\r
278 string fileName = FindValidName (resfile, re.DefaultFilename);
\r
279 resfile.Results.Add (new DiscoveryClientResult (re.GetType(), re.Url, fileName));
\r
281 string filepath = Path.Combine (directory, fileName);
\r
282 FileStream fs = new FileStream (filepath, FileMode.Create, FileAccess.Write);
\r
283 re.WriteDocument (doc, fs);
\r
287 StreamWriter sw = new StreamWriter (Path.Combine (directory, topLevelFilename));
\r
288 XmlSerializer ser = new XmlSerializer (typeof (DiscoveryClientResultsFile));
\r
289 ser.Serialize (sw, resfile);
\r
291 return resfile.Results;
\r
294 string FindValidName (DiscoveryClientResultsFile resfile, string baseName)
\r
296 string name = baseName;
\r
302 foreach (DiscoveryClientResult res in resfile.Results)
\r
304 if (name == res.Filename) {
\r
305 found = true; break;
\r
309 name = Path.GetFileNameWithoutExtension (baseName) + (++id) + Path.GetExtension (baseName);
\r
316 #endregion // Methods
\r
320 public sealed class DiscoveryClientResultsFile {
\r
324 private DiscoveryClientResultCollection results;
\r
326 #endregion // Fields
\r
328 #region Contructors
\r
330 public DiscoveryClientResultsFile ()
\r
332 results = new DiscoveryClientResultCollection ();
\r
335 #endregion // Constructors
\r
339 public DiscoveryClientResultCollection Results {
\r
340 get { return results; }
\r
343 #endregion // Properties
\r
346 #endregion // Classes
\r
349 internal class DiscoveryException : Exception
\r
352 public Exception Exception;
\r
354 public DiscoveryException (string url, Exception origin)
\r
357 Exception = origin;
\r