Click here to Skip to main content
15,880,469 members
Articles / Programming Languages / C#

Data-controlled Processes Application Design

Rate me:
Please Sign up or sign in to vote.
4.65/5 (7 votes)
23 Nov 2009CPOL10 min read 30.2K   376   34  
A ready-to-use process manager provided
using System.Collections;
using System.Collections.Generic;

namespace DataDriven
{
    public delegate bool InputPredicate(ProcessInput input);

    public class ProcessInputRequirements : IEnumerable<KeyValuePair<InputRequirement, int>>, IEnumerable<InputRequirement>
    {
        // requirement => number of inputs which must satisfy it;
        readonly Dictionary<InputRequirement, int> requirements = new Dictionary<InputRequirement, int>();
        private readonly List<InputRequirement> overAllRequirements = new List<InputRequirement>();
        //internal ProcessContainer Process;

        public ProcessInputRequirements(params InputPredicate[] predicates)
        {
            foreach (InputPredicate predicate in predicates)
                requirements.Add(new PredicateRequirement(predicate), 1);
        }
        public void AddOverAllRequirement(InputRequirement requirement)
        {
            overAllRequirements.Add(requirement);
        }
        public void Add(InputRequirement requirement, int quantity)
        {
            requirements.Add(requirement, quantity);
        }
        public void Add(InputRequirement requirement)
        {
            requirements.Add(requirement, 1);
        }

        public bool IsSatisfiedBy(InputSet inputSet)
        {
            var dataList = new LinkedList<DataContainer>(inputSet.AllData());
            foreach (var pair in requirements)
            {
                int quantity = pair.Value;
                InputRequirement requirement = pair.Key;
                for (LinkedListNode<DataContainer> node = dataList.First; node != null; node = node.Next)
                    if (node.Value != null && requirement.IsSatisfiedBy(new ProcessInput(node.Value)))
                    {
                        quantity--;
                        node.Value = null;
                        if (quantity == 0)
                            break;
                        //dataList.Remove(node);
                    }
                if (quantity != 0)
                    return false;
            }
            foreach (DataContainer o in inputSet.AllData())
                foreach (InputRequirement overAllRequirement in overAllRequirements)
                    if (!overAllRequirement.IsSatisfiedBy(new ProcessInput(o)))
                        return false;
            return true;
        }
        internal IEnumerable<InputRequirement> GetRequirementFor(DataContainer input)
        {
            if (SatisfiedByOverall(input))
                foreach (InputRequirement requirement in requirements.Keys)
                    if (requirement.IsSatisfiedBy(new ProcessInput(input)))
                        yield return requirement;
        }
        bool SatisfiedByOverall(DataContainer input)
        {
            foreach (InputRequirement requirement in overAllRequirements)
            {
                if (!requirement.IsSatisfiedBy(new ProcessInput(input)))
                    return false;
            }
            return true;
        }
        internal int NumberOfRequiedData(InputRequirement input)
        {
            return !requirements.ContainsKey(input)
                ? 0
                : requirements[input];
        }

        internal int MinInputCount
        {
            get
            {
                return requirements.Count;
            }
        }

        IEnumerator<InputRequirement> IEnumerable<InputRequirement>.GetEnumerator()
        {
            return requirements.Keys.GetEnumerator();
        }

        public IEnumerator<KeyValuePair<InputRequirement, int>> GetEnumerator()
        {
            return requirements.GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
    }
    public class InputRequirements
    {
        // predicate => quantity
        private readonly Dictionary<InputRequirement, int> requirements = new Dictionary<InputRequirement, int>();

        public Dictionary<InputRequirement, int> Requirements
        {
            get { return requirements; }
        }
    }

    public abstract class InputRequirement
    {
        public abstract bool IsSatisfiedBy(ProcessInput input);
    }

    public class TrackRestrictionRequirement : InputRequirement, IEnumerable<IDataProcess>
    {
        private readonly List<IDataProcess> affectedProcesses = new List<IDataProcess>();
        private RestrictionTypes restrictionType = RestrictionTypes.Forbid;

        public enum RestrictionTypes
        {
            /// <summary>None of affected processes can be in data's track.</summary>
            Forbid,
            /// <summary>All affected processes must be in data's track.</summary>
            Enforce
        }

        public List<IDataProcess> AffectedProcesses
        {
            get { return affectedProcesses; }
        }

        public RestrictionTypes RestrictionType
        {
            get { return restrictionType; }
            set { restrictionType = value; }
        }

        public override bool IsSatisfiedBy(ProcessInput input)
        {
            switch (restrictionType)
            {
                case RestrictionTypes.Forbid:
                    return !input.DataContainer.Track.Exists(pc => affectedProcesses.Contains(pc.Process));
                default://case RestrictionTypes.Enforce:
                    return !input.DataContainer.Track.Exists(pc => !affectedProcesses.Contains(pc.Process));
            }
        }

        public void Add(IDataProcess process)
        {
            affectedProcesses.Add(process);
        }
        public IEnumerator<IDataProcess> GetEnumerator()
        {
            return affectedProcesses.GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }

        public void AddRange(IEnumerable<IDataProcess> processes)
        {
            affectedProcesses.AddRange(processes);
        }
    }

    public class SequenceRequirement : InputRequirement, IEnumerable<IDataProcess>
    {
        private readonly List<IDataProcess> previousProcesses = new List<IDataProcess>();

        public SequenceRequirement(IEnumerable<IDataProcess> range)
        {
            previousProcesses.AddRange(range);
        }
        public void Add(IDataProcess process)
        {
            previousProcesses.Add(process);
        }
        public override bool IsSatisfiedBy(ProcessInput input)
        {
            return previousProcesses.Contains(input.Source);
        }

        public IEnumerator<IDataProcess> GetEnumerator()
        {
            return previousProcesses.GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
    }
    public class MultipleRequirement : InputRequirement
    {
        private readonly List<InputRequirement> partRequirements = new List<InputRequirement>();
        private Conjunctions conjunction = Conjunctions.And;
        public enum Conjunctions
        {
            And, Or, Neither, Single
        }

        public List<InputRequirement> PartRequirements
        {
            get { return partRequirements; }
        }

        public Conjunctions Conjunction
        {
            get { return conjunction; }
            set { conjunction = value; }
        }

        public override bool IsSatisfiedBy(ProcessInput input)
        {
            switch (conjunction)
            {
                case Conjunctions.Or:
                    foreach (InputRequirement partRequirement in PartRequirements)
                        if (partRequirement.IsSatisfiedBy(input))
                            return true;
                    return false;
                case Conjunctions.Neither:
                    foreach (InputRequirement partRequirement in PartRequirements)
                        if (partRequirement.IsSatisfiedBy(input))
                            return false;
                    return true;
                case Conjunctions.Single:
                    bool any = false;
                    foreach (InputRequirement partRequirement in PartRequirements)
                        if (partRequirement.IsSatisfiedBy(input))
                        {
                            if (any)
                                return false;
                            any = true;
                        }
                    return any;
                default: // Conjunctions.And:
                    foreach (InputRequirement partRequirement in PartRequirements)
                        if (!partRequirement.IsSatisfiedBy(input))
                            return false;
                    return true;
            }
        }

    }
    public class PredicateRequirement : InputRequirement
    {
        private InputPredicate predicate;

        public PredicateRequirement()
        {
        }
        public PredicateRequirement(InputPredicate predicate)
        {
            this.predicate = predicate;
        }


        public override bool IsSatisfiedBy(ProcessInput inputSet)
        {
            return predicate(inputSet);
        }
        public InputPredicate Predicate
        {
            get { return predicate; }
            set { predicate = value; }
        }
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer
Poland Poland
My name is Jacek. Currently, I am a Java/kotlin developer. I like C# and Monthy Python's sense of humour.

Comments and Discussions