**** Merged from MCS ****
[mono-project.git] / mcs / class / System.Web.Services / System.Web.Services.Discovery / DiscoveryClientProtocol.cs
blobc24e50b0b68983f008b8af3759a8f22ea978d533
1 //
2 // System.Web.Services.Protocols.DiscoveryClientProtocol.cs
3 //
4 // Author:
5 // Dave Bettin (javabettin@yahoo.com)
6 // Lluis Sanchez Gual (lluis@ximian.com)
7 //
8 // Copyright (C) Dave Bettin, 2002
9 //
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:
19 //
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
22 //
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;
33 using System.IO;
34 using System.Web.Services.Protocols;
35 using System.Web.Services.Description;
36 using System.Xml;
37 using System.Xml.Schema;
38 using System.Xml.Serialization;
39 using System.Net;
40 using System.Text.RegularExpressions;
42 namespace System.Web.Services.Discovery {
43 public class DiscoveryClientProtocol : HttpWebClientProtocol {
45 #region Fields
47 private IList additionalInformation = new ArrayList ();
48 private DiscoveryClientDocumentCollection documents = new DiscoveryClientDocumentCollection();
49 private DiscoveryExceptionDictionary errors = new DiscoveryExceptionDictionary();
50 private DiscoveryClientReferenceCollection references = new DiscoveryClientReferenceCollection();
52 #endregion // Fields
54 #region Constructors
56 public DiscoveryClientProtocol ()
60 #endregion // Constructors
62 #region Properties
64 public IList AdditionalInformation {
65 get { return additionalInformation; }
68 public DiscoveryClientDocumentCollection Documents {
69 get { return documents; }
72 public DiscoveryExceptionDictionary Errors {
73 get { return errors; }
76 public DiscoveryClientReferenceCollection References {
77 get { return references; }
80 #endregion // Properties
82 #region Methods
84 public DiscoveryDocument Discover (string url)
86 Stream stream = Download (ref url);
87 XmlTextReader reader = new XmlTextReader (url, stream);
88 if (!DiscoveryDocument.CanRead (reader))
89 throw new InvalidOperationException ("The url '" + url + "' does not point to a valid discovery document");
91 DiscoveryDocument doc = DiscoveryDocument.Read (reader);
92 reader.Close ();
93 documents.Add (url, doc);
94 AddDiscoReferences (doc);
95 return doc;
98 public DiscoveryDocument DiscoverAny (string url)
102 string contentType = null;
103 Stream stream = Download (ref url, ref contentType);
105 if (contentType.IndexOf ("text/html") != -1)
107 // Look for an alternate url
109 StreamReader sr = new StreamReader (stream);
110 string str = sr.ReadToEnd ();
112 string rex = "link\\s*rel\\s*=\\s*[\"']?alternate[\"']?\\s*";
113 rex += "type\\s*=\\s*[\"']?text/xml[\"']?\\s*href\\s*=\\s*(?:\"(?<1>[^\"]*)\"|'(?<1>[^']*)'|(?<1>\\S+))";
114 Regex rob = new Regex (rex, RegexOptions.IgnoreCase);
115 Match m = rob.Match (str);
116 if (!m.Success)
117 throw new InvalidOperationException ("The HTML document does not contain Web service discovery information");
119 if (url.StartsWith ("/"))
121 Uri uri = new Uri (url);
122 url = uri.GetLeftPart (UriPartial.Authority) + m.Groups[1];
124 else
126 int i = url.LastIndexOf ('/');
127 if (i == -1)
128 throw new InvalidOperationException ("The HTML document does not contain Web service discovery information");
129 url = url.Substring (0,i+1) + m.Groups[1];
131 stream = Download (ref url);
134 XmlTextReader reader = new XmlTextReader (url, stream);
135 reader.MoveToContent ();
136 DiscoveryDocument doc;
137 DiscoveryReference refe = null;
139 if (DiscoveryDocument.CanRead (reader))
141 doc = DiscoveryDocument.Read (reader);
142 documents.Add (url, doc);
143 refe = new DiscoveryDocumentReference ();
144 AddDiscoReferences (doc);
146 else if (ServiceDescription.CanRead (reader))
148 ServiceDescription wsdl = ServiceDescription.Read (reader);
149 documents.Add (url, wsdl);
150 doc = new DiscoveryDocument ();
151 refe = new ContractReference ();
152 doc.References.Add (refe);
153 refe.Url = url;
154 ((ContractReference)refe).ResolveInternal (this, wsdl);
156 else
158 XmlSchema schema = XmlSchema.Read (reader, null);
159 documents.Add (url, schema);
160 doc = new DiscoveryDocument ();
161 refe = new SchemaReference ();
162 doc.References.Add (refe);
165 refe.ClientProtocol = this;
166 refe.Url = url;
167 references.Add (url, refe);
169 reader.Close ();
170 return doc;
172 catch (DiscoveryException ex) {
173 throw ex.Exception;
177 void AddDiscoReferences (DiscoveryDocument doc)
179 foreach (DiscoveryReference re in doc.References)
181 re.ClientProtocol = this;
182 references.Add (re.Url, re);
185 if (doc.AdditionalInfo != null) {
186 foreach (object info in doc.AdditionalInfo)
187 additionalInformation.Add (info);
191 public Stream Download (ref string url)
193 string contentType = null;
194 return Download (ref url, ref contentType);
197 public Stream Download (ref string url, ref string contentType)
199 if (url.StartsWith ("http://") || url.StartsWith ("https://"))
201 WebRequest request = GetWebRequest (new Uri(url));
202 WebResponse resp = request.GetResponse ();
203 contentType = resp.ContentType;
204 return resp.GetResponseStream ();
206 else if (url.StartsWith ("file://"))
208 WebRequest request = WebRequest.Create (new Uri (url));
209 WebResponse resp = request.GetResponse ();
210 contentType = resp.ContentType;
211 return resp.GetResponseStream ();
213 else
215 string ext = Path.GetExtension (url).ToLower();
216 if (ext == ".wsdl" || ext == ".xsd")
218 contentType = "text/xml";
219 return new FileStream (url, FileMode.Open, FileAccess.Read);
221 else
222 throw new InvalidOperationException ("Unrecognized file type '" + url + "'. Extension must be one of .wsdl or .xsd");
226 public DiscoveryClientResultCollection ReadAll (string topLevelFilename)
228 StreamReader sr = new StreamReader (topLevelFilename);
229 XmlSerializer ser = new XmlSerializer (typeof (DiscoveryClientResultsFile));
230 DiscoveryClientResultsFile resfile = (DiscoveryClientResultsFile) ser.Deserialize (sr);
231 sr.Close ();
233 foreach (DiscoveryClientResult dcr in resfile.Results)
235 Type type = Type.GetType (dcr.ReferenceTypeName);
236 DiscoveryReference dr = (DiscoveryReference) Activator.CreateInstance (type);
237 dr.Url = dcr.Url;
238 FileStream fs = new FileStream (dcr.Filename, FileMode.Open, FileAccess.Read);
239 Documents.Add (dr.Url, dr.ReadDocument (fs));
240 fs.Close ();
241 References.Add (dr.Url, dr);
243 return resfile.Results;
246 public void ResolveAll ()
248 ArrayList list = new ArrayList (References.Values);
249 foreach (DiscoveryReference re in list)
253 if (re is DiscoveryDocumentReference)
254 ((DiscoveryDocumentReference)re).ResolveAll ();
255 else
256 re.Resolve ();
258 catch (DiscoveryException ex)
260 Errors [ex.Url] = ex.Exception;
262 catch (Exception ex)
264 Errors [re.Url] = ex;
269 public void ResolveOneLevel ()
271 ArrayList list = new ArrayList (References.Values);
272 foreach (DiscoveryReference re in list)
273 re.Resolve ();
276 public DiscoveryClientResultCollection WriteAll (string directory, string topLevelFilename)
278 DiscoveryClientResultsFile resfile = new DiscoveryClientResultsFile();
280 foreach (DiscoveryReference re in References.Values)
282 object doc = Documents [re.Url];
283 if (doc == null) continue;
285 string fileName = FindValidName (resfile, re.DefaultFilename);
286 resfile.Results.Add (new DiscoveryClientResult (re.GetType(), re.Url, fileName));
288 string filepath = Path.Combine (directory, fileName);
289 FileStream fs = new FileStream (filepath, FileMode.Create, FileAccess.Write);
290 re.WriteDocument (doc, fs);
291 fs.Close ();
294 StreamWriter sw = new StreamWriter (Path.Combine (directory, topLevelFilename));
295 XmlSerializer ser = new XmlSerializer (typeof (DiscoveryClientResultsFile));
296 ser.Serialize (sw, resfile);
297 sw.Close ();
298 return resfile.Results;
301 string FindValidName (DiscoveryClientResultsFile resfile, string baseName)
303 string name = baseName;
304 int id = 0;
305 bool found;
308 found = false;
309 foreach (DiscoveryClientResult res in resfile.Results)
311 if (name == res.Filename) {
312 found = true; break;
315 if (found)
316 name = Path.GetFileNameWithoutExtension (baseName) + (++id) + Path.GetExtension (baseName);
318 while (found);
320 return name;
323 #endregion // Methods
325 #region Classes
327 public sealed class DiscoveryClientResultsFile {
329 #region Fields
331 private DiscoveryClientResultCollection results;
333 #endregion // Fields
335 #region Contructors
337 public DiscoveryClientResultsFile ()
339 results = new DiscoveryClientResultCollection ();
342 #endregion // Constructors
344 #region Properties
346 public DiscoveryClientResultCollection Results {
347 get { return results; }
350 #endregion // Properties
353 #endregion // Classes
356 internal class DiscoveryException : Exception
358 public string Url;
359 public Exception Exception;
361 public DiscoveryException (string url, Exception origin)
363 Url = url;
364 Exception = origin;