File: RuleSet.cs

package info (click to toggle)
mono 6.12.0.199%2Bdfsg-6
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 1,296,836 kB
  • sloc: cs: 11,181,803; xml: 2,850,076; ansic: 699,709; cpp: 123,344; perl: 59,361; javascript: 30,841; asm: 21,853; makefile: 20,405; sh: 15,009; python: 4,839; pascal: 925; sql: 859; sed: 16; php: 1
file content (228 lines) | stat: -rw-r--r-- 7,614 bytes parent folder | download | duplicates (7)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
// ---------------------------------------------------------------------------
// Copyright (C) 2005 Microsoft Corporation All Rights Reserved
// ---------------------------------------------------------------------------

using System.Collections.Generic;
using System.ComponentModel;
using System.Workflow.ComponentModel;
using System.Workflow.ComponentModel.Compiler;
using System.Workflow.Activities.Common;

namespace System.Workflow.Activities.Rules
{
    public enum RuleChainingBehavior
    {
        None,
        UpdateOnly,
        Full
    };

    [Serializable]
    public class RuleSet
    {
        internal const string RuleSetTrackingKey = "RuleSet.";
        internal string name;
        internal string description;
        internal List<Rule> rules;
        internal RuleChainingBehavior behavior = RuleChainingBehavior.Full;
        private bool runtimeInitialized;
        private object syncLock = new object();

        // keep track of cached data
        [NonSerialized]
        private RuleEngine cachedEngine;
        [NonSerialized]
        private RuleValidation cachedValidation;

        public RuleSet()
        {
            this.rules = new List<Rule>();
        }

        public RuleSet(string name)
            : this()
        {
            this.name = name;
        }

        public RuleSet(string name, string description)
            : this(name)
        {
            this.description = description;
        }

        public string Name
        {
            get { return name; }
            set
            {
                if (runtimeInitialized)
                    throw new InvalidOperationException(SR.GetString(SR.Error_CanNotChangeAtRuntime));
                name = value;
            }
        }

        public string Description
        {
            get { return description; }
            set
            {
                if (runtimeInitialized)
                    throw new InvalidOperationException(SR.GetString(SR.Error_CanNotChangeAtRuntime));
                description = value;
            }
        }

        public RuleChainingBehavior ChainingBehavior
        {
            get { return behavior; }
            set
            {
                if (runtimeInitialized)
                    throw new InvalidOperationException(SR.GetString(SR.Error_CanNotChangeAtRuntime));
                behavior = value;
            }
        }

        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        public ICollection<Rule> Rules
        {
            get { return rules; }
        }

        public bool Validate(RuleValidation validation)
        {
            if (validation == null)
                throw new ArgumentNullException("validation");

            // Validate each rule.
            Dictionary<string, object> ruleNames = new Dictionary<string, object>();
            foreach (Rule r in rules)
            {
                if (!string.IsNullOrEmpty(r.Name))  // invalid names caught when validating the rule
                {
                    if (ruleNames.ContainsKey(r.Name))
                    {
                        // Duplicate rule name found.
                        ValidationError error = new ValidationError(Messages.Error_DuplicateRuleName, ErrorNumbers.Error_DuplicateConditions);
                        error.UserData[RuleUserDataKeys.ErrorObject] = r;
                        validation.AddError(error);
                    }
                    else
                    {
                        ruleNames.Add(r.Name, null);
                    }
                }

                r.Validate(validation);
            }

            if (validation.Errors == null || validation.Errors.Count == 0)
                return true;

            return false;
        }

        public void Execute(RuleExecution ruleExecution)
        {
            // we have no way of knowing if the ruleset has been changed, so no caching done
            if (ruleExecution == null)
                throw new ArgumentNullException("ruleExecution");
            if (ruleExecution.Validation == null)
                throw new ArgumentException(SR.GetString(SR.Error_MissingValidationProperty), "ruleExecution");

            RuleEngine engine = new RuleEngine(this, ruleExecution.Validation, ruleExecution.ActivityExecutionContext);
            engine.Execute(ruleExecution);
        }

        internal void Execute(Activity activity, ActivityExecutionContext executionContext)
        {
            // this can be called from multiple threads if multiple workflows are 
            // running at the same time (only a single workflow is single-threaded)
            // we want to only lock around the validation and preprocessing, so that
            // execution can run in parallel.

            if (activity == null)
                throw new ArgumentNullException("activity");

            Type activityType = activity.GetType();
            RuleEngine engine = null;
            lock (syncLock)
            {
                // do we have something useable cached?
                if ((cachedEngine == null) || (cachedValidation == null) || (cachedValidation.ThisType != activityType))
                {
                    // no cache (or its invalid)
                    RuleValidation validation = new RuleValidation(activityType, null);
                    engine = new RuleEngine(this, validation, executionContext);
                    cachedValidation = validation;
                    cachedEngine = engine;
                }
                else
                {
                    // this will happen if the ruleset has already been processed
                    // we can simply use the previously processed engine
                    engine = cachedEngine;
                }
            }

            // when we get here, we have a local RuleEngine all ready to go
            // we are outside the lock, so these can run in parallel
            engine.Execute(activity, executionContext);
        }

        public RuleSet Clone()
        {
            RuleSet newRuleSet = (RuleSet)this.MemberwiseClone();
            newRuleSet.runtimeInitialized = false;

            if (this.rules != null)
            {
                newRuleSet.rules = new List<Rule>();
                foreach (Rule r in this.rules)
                    newRuleSet.rules.Add(r.Clone());
            }

            return newRuleSet;
        }

        public override bool Equals(object obj)
        {
            RuleSet other = obj as RuleSet;
            if (other == null)
                return false;
            if ((this.Name != other.Name)
                || (this.Description != other.Description)
                || (this.ChainingBehavior != other.ChainingBehavior)
                || (this.Rules.Count != other.Rules.Count))
                return false;
            // look similar, compare each rule
            for (int i = 0; i < this.rules.Count; ++i)
            {
                if (!this.rules[i].Equals(other.rules[i]))
                    return false;
            }
            return true;
        }

        public override int GetHashCode()
        {
            return base.GetHashCode();
        }

        internal void OnRuntimeInitialized()
        {
            lock (syncLock)
            {
                if (runtimeInitialized)
                    return;

                foreach (Rule rule in rules)
                {
                    rule.OnRuntimeInitialized();
                }
                runtimeInitialized = true;
            }
        }
    }
}