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
\r
13 // a copy of this software and associated documentation files (the
\r
14 // "Software"), to deal in the Software without restriction, including
\r
15 // without limitation the rights to use, copy, modify, merge, publish,
\r
16 // distribute, sublicense, and/or sell copies of the Software, and to
\r
17 // permit persons to whom the Software is furnished to do so, subject to
\r
18 // the following conditions:
\r
20 // The above copyright notice and this permission notice shall be
\r
21 // included in all copies or substantial portions of the Software.
\r
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
\r
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
\r
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
\r
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
\r
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
\r
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
\r
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\r
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
130 Uri tmp = new Uri (url);
\r
131 tmp = new Uri (tmp, m.Groups [1].ToString ());
\r
132 url = tmp.ToString ();
\r
134 stream = Download (ref url);
\r
137 XmlTextReader reader = new XmlTextReader (url, stream);
\r
138 reader.MoveToContent ();
\r
139 DiscoveryDocument doc;
\r
140 DiscoveryReference refe = null;
\r
142 if (DiscoveryDocument.CanRead (reader))
\r
144 doc = DiscoveryDocument.Read (reader);
\r
145 documents.Add (url, doc);
\r
146 refe = new DiscoveryDocumentReference ();
\r
147 AddDiscoReferences (doc);
\r
149 else if (ServiceDescription.CanRead (reader))
\r
151 ServiceDescription wsdl = ServiceDescription.Read (reader);
\r
152 documents.Add (url, wsdl);
\r
153 doc = new DiscoveryDocument ();
\r
154 refe = new ContractReference ();
\r
155 doc.References.Add (refe);
\r
157 ((ContractReference)refe).ResolveInternal (this, wsdl);
\r
161 XmlSchema schema = XmlSchema.Read (reader, null);
\r
162 documents.Add (url, schema);
\r
163 doc = new DiscoveryDocument ();
\r
164 refe = new SchemaReference ();
\r
165 doc.References.Add (refe);
\r
168 refe.ClientProtocol = this;
\r
170 references.Add (url, refe);
\r
175 catch (DiscoveryException ex) {
\r
176 throw ex.Exception;
\r
180 void AddDiscoReferences (DiscoveryDocument doc)
\r
182 foreach (DiscoveryReference re in doc.References)
\r
184 re.ClientProtocol = this;
\r
185 references.Add (re.Url, re);
\r
188 if (doc.AdditionalInfo != null) {
\r
189 foreach (object info in doc.AdditionalInfo)
\r
190 additionalInformation.Add (info);
\r
194 public Stream Download (ref string url)
\r
196 string contentType = null;
\r
197 return Download (ref url, ref contentType);
\r
200 public Stream Download (ref string url, ref string contentType)
\r
202 if (url.StartsWith ("http://") || url.StartsWith ("https://"))
\r
204 WebRequest request = GetWebRequest (new Uri(url));
\r
205 WebResponse resp = request.GetResponse ();
\r
206 contentType = resp.ContentType;
\r
207 return resp.GetResponseStream ();
\r
209 else if (url.StartsWith ("file://"))
\r
211 WebRequest request = WebRequest.Create (new Uri (url));
\r
212 WebResponse resp = request.GetResponse ();
\r
213 contentType = resp.ContentType;
\r
214 return resp.GetResponseStream ();
\r
218 string ext = Path.GetExtension (url).ToLower();
\r
219 if (ext == ".wsdl" || ext == ".xsd")
\r
221 contentType = "text/xml";
\r
222 return new FileStream (url, FileMode.Open, FileAccess.Read);
\r
225 throw new InvalidOperationException ("Unrecognized file type '" + url + "'. Extension must be one of .wsdl or .xsd");
\r
229 [Obsolete ("This method will be removed from a future version. The method call is no longer required for resource discovery", false)]
\r
230 public void LoadExternals ()
\r
234 public DiscoveryClientResultCollection ReadAll (string topLevelFilename)
\r
236 StreamReader sr = new StreamReader (topLevelFilename);
\r
237 XmlSerializer ser = new XmlSerializer (typeof (DiscoveryClientResultsFile));
\r
238 DiscoveryClientResultsFile resfile = (DiscoveryClientResultsFile) ser.Deserialize (sr);
\r
241 string basePath = Path.GetDirectoryName (topLevelFilename);
\r
243 foreach (DiscoveryClientResult dcr in resfile.Results)
\r
245 Type type = Type.GetType (dcr.ReferenceTypeName);
\r
246 DiscoveryReference dr = (DiscoveryReference) Activator.CreateInstance (type);
\r
248 FileStream fs = new FileStream (Path.Combine (basePath, dcr.Filename), FileMode.Open, FileAccess.Read);
\r
249 Documents.Add (dr.Url, dr.ReadDocument (fs));
\r
251 References.Add (dr.Url, dr);
\r
253 return resfile.Results;
\r
256 public void ResolveAll ()
\r
258 ArrayList list = new ArrayList (References.Values);
\r
259 foreach (DiscoveryReference re in list)
\r
263 if (re is DiscoveryDocumentReference)
\r
264 ((DiscoveryDocumentReference)re).ResolveAll ();
\r
268 catch (DiscoveryException ex)
\r
270 Errors [ex.Url] = ex.Exception;
\r
272 catch (Exception ex)
\r
274 Errors [re.Url] = ex;
\r
279 public void ResolveOneLevel ()
\r
281 ArrayList list = new ArrayList (References.Values);
\r
282 foreach (DiscoveryReference re in list)
\r
286 public DiscoveryClientResultCollection WriteAll (string directory, string topLevelFilename)
\r
288 DiscoveryClientResultsFile resfile = new DiscoveryClientResultsFile();
\r
290 foreach (DiscoveryReference re in References.Values)
\r
292 object doc = Documents [re.Url];
\r
293 if (doc == null) continue;
\r
295 string fileName = FindValidName (resfile, re.DefaultFilename);
\r
296 resfile.Results.Add (new DiscoveryClientResult (re.GetType(), re.Url, fileName));
\r
298 string filepath = Path.Combine (directory, fileName);
\r
299 FileStream fs = new FileStream (filepath, FileMode.Create, FileAccess.Write);
\r
300 re.WriteDocument (doc, fs);
\r
304 StreamWriter sw = new StreamWriter (Path.Combine (directory, topLevelFilename));
\r
305 XmlSerializer ser = new XmlSerializer (typeof (DiscoveryClientResultsFile));
\r
306 ser.Serialize (sw, resfile);
\r
308 return resfile.Results;
\r
311 string FindValidName (DiscoveryClientResultsFile resfile, string baseName)
\r
313 string name = baseName;
\r
319 foreach (DiscoveryClientResult res in resfile.Results)
\r
321 if (name == res.Filename) {
\r
322 found = true; break;
\r
326 name = Path.GetFileNameWithoutExtension (baseName) + (++id) + Path.GetExtension (baseName);
\r
333 #endregion // Methods
\r
337 public sealed class DiscoveryClientResultsFile {
\r
341 private DiscoveryClientResultCollection results;
\r
343 #endregion // Fields
\r
345 #region Contructors
\r
347 public DiscoveryClientResultsFile ()
\r
349 results = new DiscoveryClientResultCollection ();
\r
352 #endregion // Constructors
\r
356 public DiscoveryClientResultCollection Results {
\r
357 get { return results; }
\r
360 #endregion // Properties
\r
363 #endregion // Classes
\r
366 internal class DiscoveryException : Exception
\r
369 public Exception Exception;
\r
371 public DiscoveryException (string url, Exception origin)
\r
374 Exception = origin;
\r