CorrelationKeyCalculator.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / cdf / src / NetFx40 / System.ServiceModel.Activities / System / ServiceModel / Activities / Dispatcher / CorrelationKeyCalculator.cs / 1305376 / CorrelationKeyCalculator.cs

                            //---------------------------------------------------------------- 
// Copyright (c) Microsoft Corporation.  All rights reserved.
//---------------------------------------------------------------
namespace System.ServiceModel.Activities.Dispatcher
{ 
    using System.Collections.Generic;
    using System.Diagnostics; 
    using System.Diagnostics.CodeAnalysis; 
    using System.Runtime;
    using System.Runtime.Collections; 
    using System.Runtime.Diagnostics;
    using System.Runtime.DurableInstancing;
    using System.ServiceModel;
    using System.ServiceModel.Channels; 
    using System.ServiceModel.Diagnostics;
    using System.ServiceModel.Dispatcher; 
    using System.Xml.Linq; 
    using System.Text;
    using SR2 = System.ServiceModel.Activities.SR; 

    class CorrelationKeyCalculator
    {
        MessageBufferCalculator bufferCalculator; 
        MessageCalculator messageCalculator;
        XName scopeName; 
        MessageFilterTable whereRuntime; 
        CorrelationKeyCache keyCache;
 
        public CorrelationKeyCalculator(XName scopeName)
        {
            this.whereRuntime = new MessageFilterTable();
            this.scopeName = scopeName; 
            this.keyCache = new CorrelationKeyCache();
        } 
 
        public void AddQuery(MessageFilter where, MessageQueryTable select,
            IDictionary> selectAdditional, bool isContextQuery) 
        {
            SelectRuntime selectRuntime = new SelectRuntime { Select = select, SelectAdditional = selectAdditional, IsContextQuery = isContextQuery };
            this.whereRuntime.Add(where, selectRuntime);
        } 

        public bool CalculateKeys(Message message, out InstanceKey instanceKey, 
            out ICollection additionalKeys) 
        {
            MessageCalculator calculator = this.messageCalculator; 

            if (calculator == null)
            {
                calculator = this.messageCalculator = new MessageCalculator(this); 
            }
 
            return calculator.CalculateKeys(message, null, out instanceKey, out additionalKeys); 
        }
 
        public bool CalculateKeys(MessageBuffer buffer, Message messageToReadHeaders, out InstanceKey instanceKey,
          out ICollection additionalKeys)
        {
            MessageBufferCalculator calculator = this.bufferCalculator; 

            if (calculator == null) 
            { 
                calculator = this.bufferCalculator = new MessageBufferCalculator(this);
            } 

            return calculator.CalculateKeys(buffer, messageToReadHeaders, out instanceKey, out additionalKeys);
        }
 
        abstract class Calculator
        { 
            CorrelationKeyCalculator parent; 

            public Calculator(CorrelationKeyCalculator parent) 
            {
                this.parent = parent;
            }
 
            public bool CalculateKeys(T target, Message messageToReadHeaders, out InstanceKey instanceKey,
                out ICollection additionalKeys) 
            { 
                SelectRuntime select;
 
                instanceKey = InstanceKey.InvalidKey;
                additionalKeys = null;

                // this is a query on the serverside, either Receive or SendReply 
                // Where
                if (!this.ExecuteWhere(target, messageToReadHeaders, this.parent.whereRuntime, out select)) 
                { 
                    return false;
                } 

                Dictionary values = new Dictionary();

                // Select 
                if (select.Select.Count > 0)
                { 
                    bool allOptional = true; 

                    foreach (KeyValuePair result in this.ExecuteSelect(target, messageToReadHeaders, select.Select, select.IsContextQuery)) 
                    {
                        if (!(result.Key is OptionalMessageQuery))
                        {
                            allOptional = false; 
                        }
 
                        if (!string.IsNullOrEmpty(result.Value)) 
                        {
                            values.Add(select.Select[result.Key], result.Value); 
                        }
                    }

                    if (values.Count == 0) 
                    {
                        if (!allOptional) 
                        { 
                            throw FxTrace.Exception.AsError(new ProtocolException(SR2.EmptyCorrelationQueryResults));
                        } 
                    }
                    else
                    {
                        instanceKey = this.GetInstanceKey(values); 
                        if (TD.TraceCorrelationKeysIsEnabled())
                        { 
                            TraceCorrelationKeys(instanceKey, values); 
                        }
                    } 
                }

                // SelectAdditional
                foreach (KeyValuePair> item in select.SelectAdditional) 
                {
                    if (additionalKeys == null) 
                    { 
                        additionalKeys = new List();
                    } 

                    values.Clear();

                    InstanceKey additionalKey = InstanceKey.InvalidKey; 
                    bool allOptional = true;
 
                    foreach (KeyValuePair result in this.ExecuteSelect(target, messageToReadHeaders, item.Value, select.IsContextQuery)) 
                    {
                        if (!(result.Key is OptionalMessageQuery)) 
                        {
                            allOptional = false;
                        }
 
                        if (!string.IsNullOrEmpty(result.Value))
                        { 
                            values.Add(item.Value[result.Key], result.Value); 
                        }
                    } 

                    if (values.Count == 0)
                    {
                        if (!allOptional) 
                        {
                            throw FxTrace.Exception.AsError(new ProtocolException(SR2.EmptyCorrelationQueryResults)); 
                        } 
                    }
                    else 
                    {
                        additionalKey = new CorrelationKey(values, this.parent.scopeName.ToString(), null) { Name = item.Key };
                        if (TD.TraceCorrelationKeysIsEnabled())
                        { 
                            TraceCorrelationKeys(additionalKey, values);
                        } 
                    } 

                    additionalKeys.Add(additionalKey); 
                }

                return true;
            } 

            CorrelationKey GetInstanceKey(Dictionary values) 
            { 
                // We only optimize for upto 3 keys
                if (values.Count <= 3) 
                {
                    CorrelationKey correlationKey;
                    CorrelationCacheKey cacheKey = CorrelationCacheKey.CreateKey(values);
                    if (this.parent.keyCache.TryGetValue(cacheKey, out correlationKey)) 
                    {
                        return correlationKey; 
                    } 

                    correlationKey = new CorrelationKey(values, this.parent.scopeName.ToString(), null); 
                    this.parent.keyCache.Add(cacheKey, correlationKey);
                    return correlationKey;
                }
 
                return new CorrelationKey(values, this.parent.scopeName.ToString(), null);
            } 
 
            protected abstract IEnumerable> ExecuteSelect(T target, Message messageToReadHeaders,
                MessageQueryTable select, bool IsContextQuery); 

            protected abstract bool ExecuteWhere(T target, Message messageToReadHeaders, MessageFilterTable whereRuntime,
                out SelectRuntime select);
 
            void TraceCorrelationKeys(InstanceKey instanceKey, Dictionary values)
            { 
                StringBuilder keyValueAsString = new StringBuilder(); 
                foreach (KeyValuePair pair in values)
                { 
                    keyValueAsString.Append(pair.Key).Append(":").Append(pair.Value).Append(',');
                }
                TD.TraceCorrelationKeys(instanceKey.Value, keyValueAsString.ToString(), this.parent.scopeName.ToString());
            } 

        } 
 
        class MessageBufferCalculator : Calculator
        { 

            public MessageBufferCalculator(CorrelationKeyCalculator parent)
                : base(parent)
            { 

            } 
 
            protected override IEnumerable> ExecuteSelect(MessageBuffer target, Message messageToReadHeaders,
                MessageQueryTable select, bool isContextQuery) 
            {
                if (isContextQuery && messageToReadHeaders != null)
                {
                    //we can pass in the message directly in this case since we know it is a context query that will read from the header 
                    return select.Evaluate(messageToReadHeaders);
                } 
                else 
                {
                    return select.Evaluate(target); 
                }
            }

            protected override bool ExecuteWhere(MessageBuffer target, Message messageToReadHeaders, MessageFilterTable whereRuntime, 
                out SelectRuntime select)
            { 
                return whereRuntime.GetMatchingValue(target, messageToReadHeaders, out select); 
            }
        } 

        [SuppressMessage(FxCop.Category.Performance, FxCop.Rule.AvoidUncalledPrivateCode,
            Justification = "Will use this once correlation with streaming is fixed")]
        class MessageCalculator : Calculator 
        {
            [SuppressMessage(FxCop.Category.Performance, FxCop.Rule.AvoidUncalledPrivateCode, 
                Justification = "Will use this once correlation with streaming is fixed")] 
            public MessageCalculator(CorrelationKeyCalculator parent)
                : base(parent) 
            {
            }

            protected override IEnumerable> ExecuteSelect(Message target, Message messageToReadHeaders, 
                MessageQueryTable select, bool isContextQuery)
            { 
                return select.Evaluate(target); 
            }
 
            protected override bool ExecuteWhere(Message target, Message messageToReadHeaders, MessageFilterTable whereRuntime,
                out SelectRuntime select)
            {
                // messageToReadHeaders is not used in case of MessageCalculator 
                return whereRuntime.GetMatchingValue(target, out select);
            } 
        } 

        class SelectRuntime 
        {
            public MessageQueryTable Select { get; set; }
            public IDictionary> SelectAdditional { get; set; }
            internal bool IsContextQuery { get; set; } 
        }
 
        // Needs to seperate from the generic calculator as all jitted types 
        // should share the same cache.
        class CorrelationKeyCache 
        {
            HopperCache cache;
            object cacheLock;
 
            internal CorrelationKeyCache()
            { 
                this.cache = new HopperCache(128, false); 
                this.cacheLock = new object();
            } 

            internal void Add(CorrelationCacheKey key, CorrelationKey value)
            {
                Fx.Assert(key != null, "Cannot add a null CorrelationCacheKey to the cache."); 
                lock (this.cacheLock)
                { 
                    this.cache.Add(key, value); 
                }
            } 

            internal bool TryGetValue(CorrelationCacheKey key, out CorrelationKey value)
            {
                value = (CorrelationKey)this.cache.GetValue(this.cacheLock, key); 
                return (value != null);
            } 
        } 

        abstract class CorrelationCacheKey 
        {
            static internal CorrelationCacheKey CreateKey(Dictionary keys)
            {
                if (keys.Count == 1) 
                {
                    return new SingleCacheKey(keys); 
                } 
                else
                { 
                    return new MultipleCacheKey(keys);
                }
            }
 
            static int CombineHashCodes(int h1, int h2)
            { 
                return (((h1 << 5) + h1) ^ h2); 
            }
 
            class SingleCacheKey : CorrelationCacheKey
            {
                int hashCode;
                string key; 
                string value;
 
                public SingleCacheKey(Dictionary keys) 
                {
                    Fx.Assert(keys.Count == 1, "Cannot intialize CorrelationCacheSingleKey with multiple key values."); 
                    foreach (KeyValuePair keyValue in keys)
                    {
                        this.key = keyValue.Key;
                        this.value = keyValue.Value; 
                        this.hashCode = CombineHashCodes(this.key.GetHashCode(), this.value.GetHashCode());
                        return; 
                    } 
                }
 
                public override bool Equals(object obj)
                {
                    SingleCacheKey target = obj as SingleCacheKey;
                    return (target != null && 
                        (this.hashCode == target.hashCode) &&
                        ((this.key == target.key) && (this.value == target.value))); 
                } 

                public override int GetHashCode() 
                {
                    return this.hashCode;
                }
            } 

            class MultipleCacheKey : CorrelationCacheKey 
            { 
                Dictionary keyValues;
                int hashCode; 

                public MultipleCacheKey(Dictionary keys)
                {
                    this.keyValues = keys; 

                    foreach (KeyValuePair keyValue in this.keyValues) 
                    { 
                        int hash1 = CombineHashCodes(this.hashCode, keyValue.Key.GetHashCode());
                        this.hashCode = CombineHashCodes(hash1, keyValue.Value.GetHashCode()); 
                    }
                }

                public override bool Equals(object obj) 
                {
                    MultipleCacheKey target = obj as MultipleCacheKey; 
                    if (target != null) 
                    {
                        if ((this.hashCode == target.hashCode) && 
                            (this.keyValues.Count == target.keyValues.Count))
                        {
                            string sourceValue;
                            foreach (KeyValuePair targetKeyValue in target.keyValues) 
                            {
                                if (!this.keyValues.TryGetValue(targetKeyValue.Key, out sourceValue) || 
                                    sourceValue != targetKeyValue.Value) 
                                {
                                    return false; 
                                }
                            }

                            //All keys and values are the same 
                            return true;
                        } 
                    } 

                    return false; 
                }

                public override int GetHashCode()
                { 
                    return this.hashCode;
                } 
            } 
        }
 
    }
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
                        

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