File: System\Web\Services\Discovery\DiscoveryReference.cs
Project: ndp\cdf\src\NetFx20\System.Web.Services\System.Web.Services.csproj (System.Web.Services)
//------------------------------------------------------------------------------
// <copyright file="DiscoveryReference.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>                                                                
//------------------------------------------------------------------------------
 
namespace System.Web.Services.Discovery {
 
    using System;
    using System.Xml.Serialization;
    using System.Text.RegularExpressions;
    using System.IO;
    using System.Text;
    using System.Threading;
    using System.Collections;
    using System.Diagnostics;
    using System.Web.Services.Diagnostics;
 
    /// <include file='doc\DiscoveryReference.uex' path='docs/doc[@for="DiscoveryReference"]/*' />
    /// <devdoc>
    ///    <para>[To be supplied.]</para>
    /// </devdoc>
    public abstract class DiscoveryReference {
 
        private DiscoveryClientProtocol clientProtocol;
 
        /// <include file='doc\DiscoveryReference.uex' path='docs/doc[@for="DiscoveryReference.ClientProtocol"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        [XmlIgnore]
        public DiscoveryClientProtocol ClientProtocol {
            get { return clientProtocol; }
            set { clientProtocol = value; }
        }
 
        /// <include file='doc\DiscoveryReference.uex' path='docs/doc[@for="DiscoveryReference.DefaultFilename"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        [XmlIgnore]
        public virtual string DefaultFilename {
            get {
                return FilenameFromUrl(Url);
            }
        }
 
        /// <include file='doc\DiscoveryReference.uex' path='docs/doc[@for="DiscoveryReference.WriteDocument"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        public abstract void WriteDocument(object document, Stream stream);
        /// <include file='doc\DiscoveryReference.uex' path='docs/doc[@for="DiscoveryReference.ReadDocument"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        public abstract object ReadDocument(Stream stream);
 
        /// <include file='doc\DiscoveryReference.uex' path='docs/doc[@for="DiscoveryReference.Url"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        [XmlIgnore]
        public abstract string Url {
            get;
            set;
        }
 
        internal virtual void LoadExternals(Hashtable loadedExternals) {
        }
 
        /// <include file='doc\DiscoveryReference.uex' path='docs/doc[@for="DiscoveryReference.FilenameFromUrl"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        public static string FilenameFromUrl(string url) {
            // get everything after the last /, not including the one at the end of the string
            int lastSlash = url.LastIndexOf('/', url.Length - 1);
            if (lastSlash >= 0) url = url.Substring(lastSlash + 1);
 
            // get everything up to the first dot (the filename)
            int firstDot = url.IndexOf('.');
            if (firstDot >= 0) url = url.Substring(0, firstDot);
 
            // make sure we don't include the question mark and stuff that follows it
            int question = url.IndexOf('?');
            if (question >= 0) url = url.Substring(0, question);
            if (url == null || url.Length == 0)
                return "item";
            return MakeValidFilename(url);
        }
 
        private static bool FindChar(char ch, char[] chars) {
            for (int i = 0; i < chars.Length; i++) {
                if (ch == chars[i])
                    return true;
            }
            return false;
        }
 
        internal static string MakeValidFilename(string filename) {
            if (filename == null)
                return null;
 
            StringBuilder sb = new StringBuilder(filename.Length);
            for (int i = 0; i < filename.Length; i++) {
                char c = filename[i];
                if (!FindChar(c, Path.InvalidPathChars))
                    sb.Append(c);
            }
            string name = sb.ToString();
            if (name.Length == 0)
                name = "item";
 
            return Path.GetFileName(name);
        }
 
        /// <include file='doc\DiscoveryReference.uex' path='docs/doc[@for="DiscoveryReference.Resolve"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        public void Resolve() {
            if (ClientProtocol == null)
                throw new InvalidOperationException(Res.GetString(Res.WebResolveMissingClientProtocol));
 
            if (ClientProtocol.Documents[Url] != null)
                return;
            if (ClientProtocol.InlinedSchemas[Url] != null)
                return;
 
            string newUrl = Url;
            string oldUrl = Url;
            string contentType = null;
            Stream stream = ClientProtocol.Download(ref newUrl, ref contentType);
            if (ClientProtocol.Documents[newUrl] != null) {
                Url = newUrl;
                return;
            }
            try {
                Url = newUrl;
                Resolve(contentType, stream);
            }
            catch {
                Url = oldUrl;
                throw;
            }
            finally {
                stream.Close();
            }
        }
 
        internal Exception AttemptResolve(string contentType, Stream stream) {
            try {
                Resolve(contentType, stream);
                return null;
            }
            catch (Exception e) {
                if (e is ThreadAbortException || e is StackOverflowException || e is OutOfMemoryException) {
                    throw;
                }
                if (Tracing.On) Tracing.ExceptionCatch(TraceEventType.Warning, this, "AttemptResolve", e);
                return e;
            }
        }
 
        /// <include file='doc\DiscoveryReference.uex' path='docs/doc[@for="DiscoveryReference.Resolve1"]/*' />
        /// <devdoc>
        ///    <para>[To be supplied.]</para>
        /// </devdoc>
        protected internal abstract void Resolve(string contentType, Stream stream);
 
        internal static string UriToString(string baseUrl, string relUrl) {
            return (new Uri(new Uri(baseUrl), relUrl)).GetComponents(UriComponents.AbsoluteUri, UriFormat.SafeUnescaped);
        }
    }
}