UriPrefixTable.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ WCF / WCF / 3.5.30729.1 / untmp / Orcas / SP / ndp / cdf / src / WCF / ServiceModel / System / ServiceModel / Channels / UriPrefixTable.cs / 1 / UriPrefixTable.cs

                            //---------------------------------------------------------------------------- 
// Copyright (c) Microsoft Corporation.  All rights reserved.
//---------------------------------------------------------------------------
namespace System.ServiceModel.Channels
{ 
    using System.Collections.Generic;
    using System.ServiceModel; 
    using System.ServiceModel.Dispatcher; 
    using System.Collections.ObjectModel;
    using System.Diagnostics; 
    using System.Globalization;
    using System.IO;
    using System.Net;
    using System.ServiceModel.Diagnostics; 
    using System.Text;
    using System.Threading; 
    using System.Web; 
    using System.Web.Hosting;
 
    sealed class UriPrefixTable
        where TItem : class
    {
        int count; 

        MruCache lookupCache; // cache matches, for lookup speed 
        // separate table for WeakReference usage 
        MruCache weakLookupCache;
 
        SegmentHierarchyNode root;
        bool useWeakReferences;
        bool includePortInComparison;
 
        public UriPrefixTable()
            : this(false) 
        { 
        }
 
        public UriPrefixTable(bool includePortInComparison)
            : this(includePortInComparison, false)
        {
        } 

        public UriPrefixTable(bool includePortInComparison, bool useWeakReferences) 
        { 
            const int mruWatermark = 128;
 
            this.includePortInComparison = includePortInComparison;
            this.useWeakReferences = useWeakReferences;
            this.root = new SegmentHierarchyNode(null, useWeakReferences);
            if (useWeakReferences) 
            {
                this.weakLookupCache = new MruCache(mruWatermark); 
            } 
            else
            { 
                this.lookupCache = new MruCache(mruWatermark);
            }
        }
 
        object ThisLock
        { 
            get 
            {
                return this; 
            }
        }

        public int Count 
        {
            get 
            { 
                return this.count;
            } 
        }

        public bool IsRegistered(BaseUriWithWildcard key)
        { 
            Uri uri = key.BaseAddress;
 
            // don't need to normalize path since SegmentHierarchyNode is 
            // already OrdinalIgnoreCase
            string[] paths = UriSegmenter.ToPath(uri, key.HostNameComparisonMode, this.includePortInComparison); 
            bool exactMatch;
            SegmentHierarchyNode node;
            lock (ThisLock)
            { 
                node = FindDataNode(paths, out exactMatch);
            } 
            return exactMatch && node != null && node.Data != null; 
        }
 
        public IEnumerable> GetAll()
        {
            lock (ThisLock)
            { 
                List> result = new List>();
                this.root.Collect(result); 
                return result; 
            }
        } 

        bool TryCacheLookup(BaseUriWithWildcard key, out TItem item)
        {
            if (useWeakReferences) 
            {
                WeakReference itemReference; 
                if (this.weakLookupCache.TryGetValue(key, out itemReference)) 
                {
                    item = itemReference.Target as TItem; 
                    if (item != null)
                    {
                        return true;
                    } 
                    else // dead link
                    { 
                        this.weakLookupCache.Remove(key); 
                    }
                } 
            }
            else
            {
                return this.lookupCache.TryGetValue(key, out item); 
            }
 
            item = null; 
            return false;
        } 

        void AddToCache(BaseUriWithWildcard key, TItem item)
        {
            if (useWeakReferences) 
            {
                this.weakLookupCache.Add(key, new WeakReference(item)); 
            } 
            else
            { 
                this.lookupCache.Add(key, item);
            }
        }
 
        void ClearCache()
        { 
            if (useWeakReferences) 
            {
                this.weakLookupCache.Clear(); 
            }
            else
            {
                this.lookupCache.Clear(); 
            }
        } 
 
        public bool TryLookupUri(Uri uri, HostNameComparisonMode hostNameComparisonMode, out TItem item)
        { 
            item = null;
            BaseUriWithWildcard key = new BaseUriWithWildcard(uri, hostNameComparisonMode);
            lock (ThisLock)
            { 
                bool isCached = TryCacheLookup(key, out item);
                if (!isCached) 
                { 
                    // exact match failed, perform the full lookup (which will also
                    // catch case-insensitive variations that aren't yet in our cache) 
                    bool dummy;
                    SegmentHierarchyNode node = FindDataNode(
                        UriSegmenter.ToPath(key.BaseAddress, hostNameComparisonMode, this.includePortInComparison), out dummy);
                    if (node != null) 
                    {
                        item = node.Data; 
                    } 
                    // We want to cache both positive AND negative results
                    AddToCache(key, item); 
                }
                return (item != null);
            }
        } 

        public void RegisterUri(Uri uri, HostNameComparisonMode hostNameComparisonMode, TItem item) 
        { 
            DiagnosticUtility.DebugAssert(HostNameComparisonModeHelper.IsDefined(hostNameComparisonMode), "RegisterUri: Invalid HostNameComparisonMode value passed in.");
 
            lock (ThisLock)
            {
                // Since every newly registered Uri could alter what Prefixes should have matched, we
                // should clear the cache of any existing results and start over 
                ClearCache();
                BaseUriWithWildcard key = new BaseUriWithWildcard(uri, hostNameComparisonMode); 
                SegmentHierarchyNode node = FindOrCreateNode(key); 
                if (node.Data != null)
                { 
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(
                        SR.DuplicateRegistration, uri)));
                }
                node.SetData(item, key); 
                count++;
            } 
        } 

        public void UnregisterUri(Uri uri, HostNameComparisonMode hostNameComparisonMode) 
        {
            lock (ThisLock)
            {
                // Since every removed Uri could alter what Prefixes should have matched, we 
                // should clear the cache of any existing results and start over
                ClearCache(); 
                string[] path = UriSegmenter.ToPath(uri, hostNameComparisonMode, this.includePortInComparison); 
                // Never remove the root
                if (path.Length == 0) 
                {
                    this.root.RemoveData();
                }
                else 
                {
                    this.root.RemovePath(path, 0); 
                } 
                count--;
            } 
        }

        SegmentHierarchyNode FindDataNode(string[] path, out bool exactMatch)
        { 
            DiagnosticUtility.DebugAssert(path != null, "FindDataNode: path is null");
 
            exactMatch = false; 
            SegmentHierarchyNode current = this.root;
            SegmentHierarchyNode result = null; 
            for (int i = 0; i < path.Length; ++i)
            {
                SegmentHierarchyNode next;
                if (!current.TryGetChild(path[i], out next)) 
                {
                    break; 
                } 
                else if (next.Data != null)
                { 
                    result = next;
                    exactMatch = (i == path.Length - 1);
                }
                current = next; 
            }
            return result; 
        } 

        SegmentHierarchyNode FindOrCreateNode(BaseUriWithWildcard baseUri) 
        {
            DiagnosticUtility.DebugAssert(baseUri != null, "FindOrCreateNode: baseUri is null");

            string[] path = UriSegmenter.ToPath(baseUri.BaseAddress, baseUri.HostNameComparisonMode, this.includePortInComparison); 
            SegmentHierarchyNode current = this.root;
            for (int i = 0; i < path.Length; ++i) 
            { 
                SegmentHierarchyNode next;
                if (!current.TryGetChild(path[i], out next)) 
                {
                    next = new SegmentHierarchyNode(path[i], useWeakReferences);
                    current.SetChildNode(path[i], next);
                } 
                current = next;
            } 
            return current; 
        }
 
        static class UriSegmenter
        {
            internal static string[] ToPath(Uri uriPath, HostNameComparisonMode hostNameComparisonMode,
                bool includePortInComparison) 
            {
                if (null == uriPath) 
                { 
                    return new string[0];
                } 
                UriSegmentEnum segmentEnum = new UriSegmentEnum(uriPath); // struct
                return segmentEnum.GetSegments(hostNameComparisonMode, includePortInComparison);
            }
 
            struct UriSegmentEnum
            { 
                string segment; 
                int segmentStartAt;
                int segmentLength; 
                UriSegmentType type;
                Uri uri;

                internal UriSegmentEnum(Uri uri) 
                {
                    DiagnosticUtility.DebugAssert(null != uri, "UreSegmentEnum: null uri"); 
                    this.uri = uri; 
                    this.type = UriSegmentType.Unknown;
                    this.segment = null; 
                    this.segmentStartAt = 0;
                    this.segmentLength = 0;
                }
 
                void ClearSegment()
                { 
                    this.type = UriSegmentType.None; 
                    this.segment = string.Empty;
                    this.segmentStartAt = 0; 
                    this.segmentLength = 0;
                }

                public string[] GetSegments(HostNameComparisonMode hostNameComparisonMode, 
                    bool includePortInComparison)
                { 
                    List segments = new List(); 
                    while (this.Next())
                    { 
                        switch (this.type)
                        {
                            case UriSegmentType.Path:
                                segments.Add(this.segment.Substring(this.segmentStartAt, this.segmentLength)); 
                                break;
 
                            case UriSegmentType.Host: 
                                if (hostNameComparisonMode == HostNameComparisonMode.StrongWildcard)
                                { 
                                    segments.Add("+");
                                }
                                else if (hostNameComparisonMode == HostNameComparisonMode.Exact)
                                { 
                                    segments.Add(this.segment);
                                } 
                                else 
                                {
                                    segments.Add("*"); 
                                }
                                break;

                            case UriSegmentType.Port: 
                                if (includePortInComparison || hostNameComparisonMode == HostNameComparisonMode.Exact)
                                { 
                                    segments.Add(this.segment); 
                                }
                                break; 

                            default:
                                segments.Add(this.segment);
                                break; 
                        }
                    } 
                    return segments.ToArray(); 
                }
 
                public bool Next()
                {
                    while (true)
                    { 
                        switch (this.type)
                        { 
                            case UriSegmentType.Unknown: 
                                this.type = UriSegmentType.Scheme;
                                this.SetSegment(this.uri.Scheme); 
                                return true;

                            case UriSegmentType.Scheme:
                                this.type = UriSegmentType.Host; 
                                string host = this.uri.Host;
                                // The userName+password also accompany... 
                                string userInfo = this.uri.UserInfo; 
                                if (null != userInfo && userInfo.Length > 0)
                                { 
                                    host = userInfo + '@' + host;
                                }
                                this.SetSegment(host);
                                return true; 

                            case UriSegmentType.Host: 
                                this.type = UriSegmentType.Port; 
                                int port = this.uri.Port;
                                this.SetSegment(port.ToString(CultureInfo.InvariantCulture)); 
                                return true;

                            case UriSegmentType.Port:
                                this.type = UriSegmentType.Path; 
                                string absPath = this.uri.AbsolutePath;
                                DiagnosticUtility.DebugAssert(null != absPath, "Next: nill absPath"); 
                                if (0 == absPath.Length) 
                                {
                                    this.ClearSegment(); 
                                    return false;
                                }
                                this.segment = absPath;
                                this.segmentStartAt = 0; 
                                this.segmentLength = 0;
                                return this.NextPathSegment(); 
 
                            case UriSegmentType.Path:
                                return this.NextPathSegment(); 

                            case UriSegmentType.None:
                                return false;
 
                            default:
                                DiagnosticUtility.DebugAssert("Next: unknown enum value"); 
                                return false; 
                        }
                    } 
                }

                public bool NextPathSegment()
                { 
                    this.segmentStartAt += this.segmentLength;
                    while (this.segmentStartAt < this.segment.Length && this.segment[this.segmentStartAt] == '/') 
                    { 
                        this.segmentStartAt++;
                    } 

                    if (this.segmentStartAt < this.segment.Length)
                    {
                        int next = this.segment.IndexOf('/', this.segmentStartAt); 
                        if (-1 == next)
                        { 
                            this.segmentLength = this.segment.Length - this.segmentStartAt; 
                        }
                        else 
                        {
                            this.segmentLength = next - this.segmentStartAt;
                        }
                        return true; 
                    }
                    this.ClearSegment(); 
                    return false; 
                }
 
                void SetSegment(string segment)
                {
                    this.segment = segment;
                    this.segmentStartAt = 0; 
                    this.segmentLength = segment.Length;
                } 
 
                enum UriSegmentType
                { 
                    Unknown,
                    Scheme,
                    Host,
                    Port, 
                    Path,
                    None 
                } 
            }
        } 
    }

    class SegmentHierarchyNode
        where TData : class 
    {
        BaseUriWithWildcard path; 
        TData data; 
        string name;
        Dictionary> children; 
        WeakReference weakData;
        bool useWeakReferences;

        public SegmentHierarchyNode(string name, bool useWeakReferences) 
        {
            this.name = name; 
            this.useWeakReferences = useWeakReferences; 
            this.children = new Dictionary>(StringComparer.OrdinalIgnoreCase);
        } 

        public TData Data
        {
            get 
            {
                if (useWeakReferences) 
                { 
                    if (this.weakData == null)
                    { 
                        return null;
                    }
                    else
                    { 
                        return this.weakData.Target as TData;
                    } 
                } 
                else
                { 
                    return this.data;
                }
            }
        } 

        public void SetData(TData data, BaseUriWithWildcard path) 
        { 
            this.path = path;
            if (useWeakReferences) 
            {
                if (data == null)
                {
                    this.weakData = null; 
                }
                else 
                { 
                    this.weakData = new WeakReference(data);
                } 
            }
            else
            {
                this.data = data; 
            }
        } 
 
        public void SetChildNode(string name, SegmentHierarchyNode node)
        { 
            this.children[name] = node;
        }

        public void Collect(List> result) 
        {
            TData localData = this.Data; 
            if (localData != null) 
            {
                result.Add(new KeyValuePair(path, localData)); 
            }

            foreach (SegmentHierarchyNode child in this.children.Values)
            { 
                child.Collect(result);
            } 
        } 

        public bool TryGetChild(string segment, out SegmentHierarchyNode value) 
        {
            return children.TryGetValue(segment, out value);
        }
 
        public void RemoveData()
        { 
            SetData(null, null); 
        }
 
        // bool is whether to remove this node
        public bool RemovePath(string[] path, int seg)
        {
            if (seg == path.Length) 
            {
                RemoveData(); 
                return this.children.Count == 0; 
            }
 
            SegmentHierarchyNode node;
            if (!TryGetChild(path[seg], out node))
            {
                return (this.children.Count == 0 && Data == null); 
            }
 
            if (node.RemovePath(path, seg + 1)) 
            {
                this.children.Remove(path[seg]); 
                return (this.children.Count == 0 && Data == null);
            }
            else
            { 
                return false;
            } 
        } 
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.


                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK