WorkflowDefinitionDispenser.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 / WF / RunTime / WorkflowDefinitionDispenser.cs / 1407647 / WorkflowDefinitionDispenser.cs

                            #region Imports 

using System;
using System.ComponentModel;
using System.ComponentModel.Design; 
using System.ComponentModel.Design.Serialization;
using System.Diagnostics; 
using System.Collections; 
using System.Collections.Generic;
using System.Collections.Specialized; 
using System.Collections.ObjectModel;
using System.Configuration;
using System.Reflection;
using System.Threading; 
using System.Globalization;
using System.IO; 
using System.Xml; 
using System.Text;
using System.Workflow.Runtime.Hosting; 
using System.Workflow.Runtime.Configuration;
using System.Workflow.ComponentModel;
using System.Workflow.Runtime.Tracking;
using System.Workflow.ComponentModel.Compiler; 
using System.Workflow.ComponentModel.Serialization;
using System.Security.Cryptography; 
using System.Workflow.ComponentModel.Design; 

#endregion 


namespace System.Workflow.Runtime
{ 
    internal sealed class WorkflowDefinitionDispenser : IDisposable
    { 
        private MruCache workflowTypes; 
        private MruCache xomlFragments;
        private Dictionary> workflowOutParameters; 
        private WorkflowRuntime                 workflowRuntime;
        private bool                            validateOnCreate = true;
        internal static DependencyProperty WorkflowDefinitionHashCodeProperty = DependencyProperty.RegisterAttached("WorkflowDefinitionHashCode", typeof(byte[]), typeof(WorkflowDefinitionDispenser));
        internal event EventHandler WorkflowDefinitionLoaded; 

        private ReaderWriterLock parametersLock; 
 
        internal WorkflowDefinitionDispenser(WorkflowRuntime runtime, bool validateOnCreate, int capacity)
        { 
            if (capacity <= 0)
            {
                capacity = 2000;
            } 
            this.workflowRuntime = runtime;
            this.workflowTypes = new MruCache(capacity, this, CacheType.Type); 
            this.xomlFragments = new MruCache(capacity, this, CacheType.Xoml); 
            this.workflowOutParameters = new Dictionary>();
            this.parametersLock = new ReaderWriterLock(); 
            this.validateOnCreate = validateOnCreate;
        }

        internal ReadOnlyCollection GetOutputParameters(Activity rootActivity) 
        {
            Type workflowType = rootActivity.GetType(); 
            this.parametersLock.AcquireReaderLock(-1); 
            try
            { 
                if (this.workflowOutParameters.ContainsKey(workflowType))
                    return new ReadOnlyCollection(this.workflowOutParameters[workflowType]);
            }
            finally 
            {
                this.parametersLock.ReleaseLock(); 
            } 

            // We will recurse at most once because CacheOutputParameters() will perform negative caching. 
            CacheOutputParameters(rootActivity);
            return GetOutputParameters(rootActivity);
        }
 
        internal void GetWorkflowTypes(out ReadOnlyCollection keys, out ReadOnlyCollection values)
        { 
            this.workflowTypes.GetWorkflowDefinitions(out keys, out values); 
        }
 
        internal void GetWorkflowDefinitions(out ReadOnlyCollection keys, out ReadOnlyCollection values)
        {
            this.xomlFragments.GetWorkflowDefinitions(out keys, out values);
        } 

        internal Activity GetWorkflowDefinition(byte[] xomlHashCode) 
        { 
            Activity workflowDefinition = null;
            if (xomlHashCode == null) 
                throw new ArgumentNullException("xomlHashCode");

            workflowDefinition = xomlFragments.GetDefinition(xomlHashCode);
 
            if(workflowDefinition == null)
                throw new ArgumentException("xomlHashCode"); 
 
            return workflowDefinition;
        } 

        internal Activity GetWorkflowDefinition(Type workflowType)
        {
            if (workflowType == null) 
                throw new ArgumentNullException("workflowType");
 
            return this.GetRootActivity(workflowType, false, true); 
        }
 
        internal Activity GetRootActivity(Type workflowType, bool createNew, bool initForRuntime)
        {
            Activity root = null;
 
            if (createNew)
                return LoadRootActivity(workflowType, false, initForRuntime); 
            bool exist; 
            root = workflowTypes.GetOrGenerateDefinition(workflowType, null, null, null, initForRuntime, out exist);
            if (exist) 
            {
                return root;
            }
            // Set the locking object used for cloning the definition 
            // for non-internal use (WorkflowInstance.GetWorkflowDefinition
            // and WorkflowCompletedEventArgs.WorkflowDefinition) 
            WorkflowDefinitionLock.SetWorkflowDefinitionLockObject(root, new object()); 

            EventHandler localWorkflowDefinitionLoaded = WorkflowDefinitionLoaded; 
            if (localWorkflowDefinitionLoaded != null)
                localWorkflowDefinitionLoaded(this.workflowRuntime, new WorkflowDefinitionEventArgs(workflowType));

            return root; 
        }
 
        // This function will create a new root activity definition tree by deserializing the xoml and the rules file. 
        // The last parameter createNew should be true when the caller is asking for a new definition for performing
        // dynamic updates instead of a cached definition. 
        internal Activity GetRootActivity(string xomlText, string rulesText, bool createNew, bool initForRuntime)
        {
            if (string.IsNullOrEmpty(xomlText))
                throw new ArgumentNullException("xomlText"); 

            //calculate the "hash". Think 60s! 
            byte[] xomlHashCode = null; 
            MemoryStream xomlBytesStream = new MemoryStream();
            using (StreamWriter streamWriter = new StreamWriter(xomlBytesStream)) 
            {
                streamWriter.Write(xomlText);

                //consider rules, if they exist 
                if (!string.IsNullOrEmpty(rulesText))
                    streamWriter.Write(rulesText); 
 
                streamWriter.Flush();
                xomlBytesStream.Position = 0; 

                xomlHashCode = MD5HashHelper.ComputeHash(xomlBytesStream.GetBuffer());
            }
 
            if (createNew)
                return LoadRootActivity(xomlText, rulesText, xomlHashCode, false, initForRuntime); 
 
            bool exist;
            Activity root = xomlFragments.GetOrGenerateDefinition(null, xomlText, rulesText, xomlHashCode, initForRuntime, out exist); 
            if (exist)
            {
                return root;
            } 
            // Set the locking object used for cloning the definition
            // for non-internal use (WorkflowInstance.GetWorkflowDefinition 
            // and WorkflowCompletedEventArgs.WorkflowDefinition) 
            WorkflowDefinitionLock.SetWorkflowDefinitionLockObject(root, new object());
 
            EventHandler localWorkflowDefinitionLoaded = WorkflowDefinitionLoaded;
            if (localWorkflowDefinitionLoaded != null)
                localWorkflowDefinitionLoaded(this.workflowRuntime, new WorkflowDefinitionEventArgs(xomlHashCode));
 
            return root;
        } 
 
        internal void ValidateDefinition(Activity root, bool isNewType, ITypeProvider typeProvider)
        { 
            if (!this.validateOnCreate)
                return;

            ValidationErrorCollection errors = new ValidationErrorCollection(); 

            // For validation purposes, create a type provider in the type case if the 
            // host did not push one. 
            if (typeProvider == null)
                typeProvider = WorkflowRuntime.CreateTypeProvider(root); 

            // Validate that we are purely XAML.
            if (!isNewType)
            { 
                if (!string.IsNullOrEmpty(root.GetValue(WorkflowMarkupSerializer.XClassProperty) as string))
                    errors.Add(new ValidationError(ExecutionStringManager.XomlWorkflowHasClassName, ErrorNumbers.Error_XomlWorkflowHasClassName)); 
 
                Queue compositeActivities = new Queue();
                compositeActivities.Enqueue(root); 
                while (compositeActivities.Count > 0)
                {
                    Activity activity = compositeActivities.Dequeue() as Activity;
 
                    if (activity.GetValue(WorkflowMarkupSerializer.XCodeProperty) != null)
                        errors.Add(new ValidationError(ExecutionStringManager.XomlWorkflowHasCode, ErrorNumbers.Error_XomlWorkflowHasCode)); 
 
                    CompositeActivity compositeActivity = activity as CompositeActivity;
                    if (compositeActivity != null) 
                    {
                        foreach (Activity childActivity in compositeActivity.EnabledActivities)
                            compositeActivities.Enqueue(childActivity);
                    } 
                }
            } 
 
            ServiceContainer serviceContainer = new ServiceContainer();
            serviceContainer.AddService(typeof(ITypeProvider), typeProvider); 

            ValidationManager validationManager = new ValidationManager(serviceContainer);
            using (WorkflowCompilationContext.CreateScope(validationManager))
            { 
                foreach (Validator validator in validationManager.GetValidators(root.GetType()))
                { 
                    foreach (ValidationError error in validator.Validate(validationManager, root)) 
                    {
                        if (!error.UserData.Contains(typeof(Activity))) 
                            error.UserData[typeof(Activity)] = root;

                        errors.Add(error);
                    } 
                }
            } 
            if (errors.HasErrors) 
                throw new WorkflowValidationFailedException(ExecutionStringManager.WorkflowValidationFailure, errors);
        } 

        public void Dispose()
        {
            xomlFragments.Dispose(); 
            workflowTypes.Dispose();
        } 
 
        private Activity LoadRootActivity(Type workflowType, bool createDefinition, bool initForRuntime)
        { 
            WorkflowLoaderService loader = workflowRuntime.GetService();
            Activity root = loader.CreateInstance(workflowType);
            if (root == null)
                throw new InvalidOperationException(ExecutionStringManager.CannotCreateRootActivity); 
            if (root.GetType() != workflowType)
                throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, ExecutionStringManager.WorkflowTypeMismatch, workflowType.FullName)); 
 
            if (createDefinition)
                ValidateDefinition(root, true, workflowRuntime.GetService()); 

            if (initForRuntime)
                ((IDependencyObjectAccessor)root).InitializeDefinitionForRuntime(null);
 
            root.SetValue(Activity.WorkflowRuntimeProperty, workflowRuntime);
 
            return root; 
        }
 
        private Activity LoadRootActivity(string xomlText, string rulesText, byte[] xomlHashCode, bool createDefinition, bool initForRuntime)
        {
            Activity root = null;
            WorkflowLoaderService loader = workflowRuntime.GetService(); 

            using (StringReader xomlTextReader = new StringReader(xomlText)) 
            { 
                using (XmlReader xomlReader = XmlReader.Create(xomlTextReader))
                { 
                    XmlReader rulesReader = null;
                    StringReader rulesTextReader = null;
                    try
                    { 
                        if (!string.IsNullOrEmpty(rulesText))
                        { 
                            rulesTextReader = new StringReader(rulesText); 
                            rulesReader = XmlReader.Create(rulesTextReader);
                        } 
                        root = loader.CreateInstance(xomlReader, rulesReader);
                    }
                    finally
                    { 
                        if (rulesReader != null)
                            rulesReader.Close(); 
                        if (rulesTextReader != null) 
                            rulesTextReader.Close();
                    } 
                }
            }

            if (root == null) 
                throw new InvalidOperationException(ExecutionStringManager.CannotCreateRootActivity);
 
            if (createDefinition) 
            {
                ITypeProvider typeProvider = workflowRuntime.GetService(); 
                ValidateDefinition(root, false, typeProvider);
            }

            if (initForRuntime) 
                ((IDependencyObjectAccessor)root).InitializeDefinitionForRuntime(null);
 
            // Save the original markup. 
            root.SetValue(Activity.WorkflowXamlMarkupProperty, xomlText);
            root.SetValue(Activity.WorkflowRulesMarkupProperty, rulesText); 
            root.SetValue(WorkflowDefinitionHashCodeProperty, xomlHashCode);
            root.SetValue(Activity.WorkflowRuntimeProperty, workflowRuntime);

            return root; 
        }
 
        private void CacheOutputParameters(Activity rootActivity) 
        {
            Type workflowType = rootActivity.GetType(); 
            List outputParameters = null;

            this.parametersLock.AcquireWriterLock(-1);
 
            try
            { 
                if (this.workflowOutParameters.ContainsKey(workflowType)) 
                    return;
 
                // Cache negative and positive cases!
                outputParameters = new List();
                this.workflowOutParameters.Add(workflowType, outputParameters);
 
                PropertyInfo[] properties = workflowType.GetProperties();
                foreach (PropertyInfo property in properties) 
                { 
                    if (!property.CanRead || property.DeclaringType == typeof(DependencyObject) || property.DeclaringType == typeof(Activity) || property.DeclaringType == typeof(CompositeActivity))
                        continue; 

                    bool ignoreProperty = false;
                    foreach (DependencyProperty dependencyProperty in rootActivity.MetaDependencyProperties)
                    { 
                        if (dependencyProperty.Name == property.Name && dependencyProperty.DefaultMetadata.IsMetaProperty)
                        { 
                            ignoreProperty = true; 
                            break;
                        } 
                    }

                    if (!ignoreProperty)
                        outputParameters.Add(property); 
                }
            } 
            finally 
            {
                Thread.MemoryBarrier(); 
                this.parametersLock.ReleaseLock();
            }
        }
 
        private enum CacheType
        { 
            Type = 0, 
            Xoml = 1,
        } 

        private class MruCache : IDisposable
        {
            Hashtable hashtable; 
            LinkedList mruList;
            int size; 
            int capacity; 
            WorkflowDefinitionDispenser dispenser;
            CacheType type; 

            internal MruCache(int capacity, WorkflowDefinitionDispenser dispenser, CacheType type)
            {
                if (type == CacheType.Xoml) 
                {
                    this.hashtable = new Hashtable((IEqualityComparer)new DigestComparerWrapper()); 
                } 
                else
                { 
                    this.hashtable = new Hashtable();
                }
                this.mruList = new LinkedList();
                this.capacity = capacity; 
                this.dispenser = dispenser;
                this.type = type; 
            } 

            private void RemoveFromDictionary(Activity activity) 
            {
                byte[] key = activity.GetValue(WorkflowDefinitionHashCodeProperty) as byte[];
                if (key != null)
                { 
                    this.hashtable.Remove(key);
                } 
                else 
                {
                    Type type = activity.GetType(); 
                    this.hashtable.Remove(type);
                }
            }
 
            private void AddToDictionary(LinkedListNode node)
            { 
                byte[] key = node.Value.GetValue(WorkflowDefinitionHashCodeProperty) as byte[]; 
                if (key != null)
                { 
                    this.hashtable.Add(key, node);
                }
                else
                { 
                    Type type = node.Value.GetType();
                    this.hashtable.Add(type, node); 
                } 
            }
 
            internal Activity GetDefinition(byte[] md5Codes)
            {
                LinkedListNode node;
                node = this.hashtable[md5Codes] as LinkedListNode; 
                if (node != null)
                { 
                    return node.Value; 
                }
                else 
                {
                    return null;
                }
            } 

            internal Activity GetOrGenerateDefinition(Type type, string xomlText, string rulesText, byte[] md5Codes, bool initForRuntime, out bool exist) 
            { 
                LinkedListNode node;
                object key; 

                if (type != null)
                {
                    key = type; 
                }
                else 
                { 
                    key = md5Codes;
                } 
                try
                {
                    exist = false;
                    node = this.hashtable[key] as LinkedListNode; 

                    if (node != null) 
                    { 
                        lock (this.mruList)
                        { 
                            node = this.hashtable[key] as LinkedListNode;
                            if (node != null)
                            {
                                exist = true; 
                                this.mruList.Remove(node);
                                this.mruList.AddFirst(node); 
                            } 
                            else
                            { 
                                exist = false;
                            }
                        }
                    } 

                    if (!exist) 
                    { 
                        lock (this.hashtable)
                        { 
                            node = this.hashtable[key] as LinkedListNode;
                            if (node != null)
                            {
                                exist = true; 
                                lock (this.mruList)
                                { 
                                    this.mruList.Remove(node); 
                                    this.mruList.AddFirst(node);
                                } 
                            }
                            else
                            {
                                exist = false; 
                                Activity activity;
                                if (type != null) 
                                { 
                                    activity = this.dispenser.LoadRootActivity(type, true, initForRuntime);
                                } 
                                else
                                {
                                    activity = this.dispenser.LoadRootActivity(xomlText, rulesText, key as byte[], true, initForRuntime);
                                } 
                                lock (this.mruList)
                                { 
                                    if (this.size < this.capacity) 
                                    {
                                        this.size++; 
                                    }
                                    else
                                    {
                                        RemoveFromDictionary(this.mruList.Last.Value); 
                                        this.mruList.RemoveLast();
                                    } 
                                    node = new LinkedListNode(activity); 
                                    AddToDictionary(node);
                                    this.mruList.AddFirst(node); 
                                }
                            }
                        }
                    } 
                }
                finally 
                { 
                    Thread.MemoryBarrier();
                } 
                return node.Value;
            }

            internal void GetWorkflowDefinitions(out ReadOnlyCollection keys, out ReadOnlyCollection values) 
            {
                lock (this.hashtable) 
                { 
                    if (((typeof(K) == typeof(Type)) && (this.type == CacheType.Type)) || ((typeof(K) == typeof(byte[])) && (this.type == CacheType.Xoml)))
                    { 
                        List keyList = new List();
                        foreach (K key in this.hashtable.Keys)
                        {
                            keyList.Add(key); 
                        }
                        keys = new ReadOnlyCollection(keyList); 
                        List list = new List(); 
                        foreach (LinkedListNode node in this.hashtable.Values)
                        { 
                            list.Add(node.Value);
                        }
                        values = new ReadOnlyCollection(list);
                    } 
                    else
                    { 
                        keys = null; 
                        values = null;
                    } 
                }
            }

            public void Dispose() 
            {
                foreach (LinkedListNode node in hashtable.Values) 
                { 
                    try
                    { 
                        node.Value.Dispose();
                    }
                    catch (Exception)//ignore any dispose exception.
                    { 
                    }
                } 
            } 
        }
 
        private class DigestComparerWrapper : IEqualityComparer
        {
            IEqualityComparer comparer = (IEqualityComparer)new DigestComparer();
            bool IEqualityComparer.Equals(object object1, object object2) 
            {
                return comparer.Equals((byte[])object1, (byte[])object2); 
            } 

            int IEqualityComparer.GetHashCode(object obj) 
            {
                return comparer.GetHashCode((byte[]) obj);
            }
        } 

    } 
 
    internal class WorkflowDefinitionLock : IDisposable
    { 
        internal static readonly DependencyProperty WorkflowDefinitionLockObjectProperty = DependencyProperty.RegisterAttached("WorkflowDefinitionLockObject", typeof(object), typeof(WorkflowDefinitionLock), new PropertyMetadata(DependencyPropertyOptions.NonSerialized));

        internal static object GetWorkflowDefinitionLockObject(DependencyObject dependencyObject)
        { 
            // The Dependency Properties are kept in a Dictionary<>, which is not thread safe between
            // "getters" and "setters", so lock around the "getter", too. 
            lock (dependencyObject) 
            {
                return dependencyObject.GetValue(WorkflowDefinitionLockObjectProperty); 
            }
        }

        internal static void SetWorkflowDefinitionLockObject(DependencyObject dependencyObject, object value) 
        {
            lock (dependencyObject) 
            { 
                if (dependencyObject.GetValue(WorkflowDefinitionLockObjectProperty) == null)
                { 
                    dependencyObject.SetValue(WorkflowDefinitionLockObjectProperty, value);
                }
            }
        } 

        private object _syncObj; 
 
        public WorkflowDefinitionLock(Activity definition)
        { 
            this._syncObj = GetWorkflowDefinitionLockObject(definition);

            Debug.Assert(this._syncObj != null, "Definition's synchronization object was null.  This should always be set.");
 
#pragma warning disable 0618
//@ 
            Monitor.Enter(this._syncObj); 
#pragma warning restore 0618
        } 

        #region IDisposable Members

        public void Dispose() 
        {
            Monitor.Exit(this._syncObj); 
        } 

        #endregion 
    }
}

// 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