Skip to content

Commit 3f421ed

Browse files
Ticket #3 : Support criterias (entry + exit)
1 parent 58834e0 commit 3f421ed

11 files changed

Lines changed: 160 additions & 86 deletions

File tree

Doc.docx

1.05 KB
Binary file not shown.

src/CaseManagement.CMMN/Builders/CMMNPlanItemBuilder.cs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,21 @@ public CMMNPlanItemBuilder(CMMNPlanItem planItem)
1212
_planItem = planItem;
1313
}
1414

15-
public CMMNPlanItemBuilder AddSEntry(string name, Action<CMMNSEntryBuilder> callback)
15+
public CMMNPlanItemBuilder AddEntryCriterion(string name, Action<CMMNSEntryBuilder> callback)
1616
{
1717
var sEntry = new CMMNSEntry(name);
18+
var entryCriterion = new CMMNCriterion(name) { SEntry = sEntry };
1819
callback(new CMMNSEntryBuilder(sEntry));
19-
_planItem.SEntries.Add(sEntry);
20+
_planItem.EntryCriterions.Add(entryCriterion);
21+
return this;
22+
}
23+
24+
public CMMNPlanItemBuilder AddExitCriterion(string name, Action<CMMNSEntryBuilder> callback)
25+
{
26+
var sEntry = new CMMNSEntry(name);
27+
var entryCriterion = new CMMNCriterion(name) { SEntry = sEntry };
28+
callback(new CMMNSEntryBuilder(sEntry));
29+
_planItem.ExitCriterions.Add(entryCriterion);
2030
return this;
2131
}
2232

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
namespace CaseManagement.CMMN.Domains
2+
{
3+
public class CMMNCriterion
4+
{
5+
public CMMNCriterion(string name)
6+
{
7+
Name = name;
8+
}
9+
10+
public string Name { get; set; }
11+
public CMMNSEntry SEntry { get; set; }
12+
}
13+
}

src/CaseManagement.CMMN/Domains/CMMNManualActivationRule.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,13 @@ public CMMNManualActivationRule(string name, CMMNExpression expression) : this(n
1212
Expression = expression;
1313
}
1414

15+
/// <summary>
16+
/// The name of the ManualActivationRule.
17+
/// </summary>
1518
public string Name { get; set; }
19+
/// <summary>
20+
/// An Expression that MUST evaluate to boolean. [1...1]
21+
/// </summary>
1622
public CMMNExpression Expression { get; set; }
1723
}
1824
}

src/CaseManagement.CMMN/Domains/CMMNPlanItem.cs

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ public class CMMNPlanItem : ProcessFlowInstanceElement
88
{
99
private CMMNPlanItem(string id, string name, CMMNPlanItemDefinition planItemDefinition) : base(id, name)
1010
{
11-
SEntries = new List<CMMNSEntry>();
11+
EntryCriterions = new List<CMMNCriterion>();
12+
ExitCriterions = new List<CMMNCriterion>();
1213
Events = new List<CMMNPlanItemTransitionEvent>();
1314
var evt = new CMMNPlanItemCreated();
1415
Events.Add(evt);
@@ -17,17 +18,22 @@ private CMMNPlanItem(string id, string name, CMMNPlanItemDefinition planItemDefi
1718
}
1819

1920
/// <summary>
20-
/// [0...1]
21+
/// The PlanItemControl controls aspects of the behavior of instances of the PlanItem object. [0...1]
2122
/// </summary>
2223
public CMMNPlanItemControl PlanItemControl { get; set; }
2324
/// <summary>
24-
/// [1...1]
25+
/// Reference to the corresponding PlanItemDefinition object. [1...1]
2526
/// </summary>
2627
public CMMNPlanItemDefinition PlanItemDefinition { get; set; }
2728
/// <summary>
28-
/// [0...*] // EntryCriterion TODO !!
29+
/// Zero or more EntryCriterion for that PlanItem. [0...*].
30+
/// An EntryCriterion represents the condition for a PlanItem to become available.
2931
/// </summary>
30-
public ICollection<CMMNSEntry> SEntries { get; set; }
32+
public ICollection<CMMNCriterion> EntryCriterions { get; set; }
33+
/// <summary>
34+
/// An ExitCriterion represents the condition for a PlanItem to terminate. [0...*]
35+
/// </summary>
36+
public ICollection<CMMNCriterion> ExitCriterions { get; set; }
3137
public ICollection<CMMNPlanItemTransitionEvent> Events { get; set; }
3238

3339
public void Enable()
@@ -63,6 +69,13 @@ public void Complete()
6369
PlanItemDefinition.Handle(evt);
6470
}
6571

72+
public void Terminate()
73+
{
74+
var evt = new CMMNPlanItemTerminated();
75+
Events.Add(evt);
76+
PlanItemDefinition.Handle(evt);
77+
}
78+
6679
public static CMMNPlanItem New(string id, string name, CMMNPlanItemDefinition planItemDef)
6780
{
6881
var result = new CMMNPlanItem(id, name, planItemDef);

src/CaseManagement.CMMN/Domains/CMMNTask.cs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,21 @@ public override void Handle(DomainEvent cmmnPlanItemEvent)
3131
{
3232
Handle((CMMNPlanItemManuallyStarted)cmmnPlanItemEvent);
3333
}
34+
35+
if (cmmnPlanItemEvent is CMMNPlanItemStarted)
36+
{
37+
Handle((CMMNPlanItemStarted)cmmnPlanItemEvent);
38+
}
39+
40+
if (cmmnPlanItemEvent is CMMNPlanItemTerminated)
41+
{
42+
Handle((CMMNPlanItemTerminated)cmmnPlanItemEvent);
43+
}
44+
45+
if (cmmnPlanItemEvent is CMMNPlanItemCompleted)
46+
{
47+
Handle((CMMNPlanItemCompleted)cmmnPlanItemEvent);
48+
}
3449
}
3550

3651
private void Handle(CMMNPlanItemCreated evt)
@@ -47,5 +62,20 @@ private void Handle(CMMNPlanItemManuallyStarted evt)
4762
{
4863
State = CMMNTaskStates.Active;
4964
}
65+
66+
private void Handle(CMMNPlanItemStarted evt)
67+
{
68+
State = CMMNTaskStates.Active;
69+
}
70+
71+
private void Handle(CMMNPlanItemTerminated evt)
72+
{
73+
State = CMMNTaskStates.Terminated;
74+
}
75+
76+
private void Handle(CMMNPlanItemCompleted evt)
77+
{
78+
State = CMMNTaskStates.Completed;
79+
}
5080
}
5181
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
namespace CaseManagement.CMMN.Domains.Events
2+
{
3+
public class CMMNPlanItemTerminated : CMMNPlanItemTransitionEvent
4+
{
5+
public CMMNPlanItemTerminated() : base(CMMNPlanItemTransitions.Terminate)
6+
{
7+
}
8+
}
9+
}

src/CaseManagement.CMMN/ProcessInstance/Processors/CMMNPlanItemProcessor.cs

Lines changed: 39 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -14,48 +14,60 @@ public class CMMNPlanItemProcessor : BaseProcessFlowElementProcessor
1414
protected override Task<bool> HandleProcessFlowInstance(ProcessFlowInstanceElement pfe, ProcessFlowInstanceExecutionContext context)
1515
{
1616
var planItem = (CMMNPlanItem)pfe;
17-
var processTask = (CMMNProcessTask)planItem.PlanItemDefinition;
18-
// TODO : check the plan definition status and execute the correct logic.
19-
if (processTask.State == CMMNTaskStates.Active)
17+
var processTask = planItem.PlanItemDefinition as CMMNProcessTask;
18+
if (processTask != null)
2019
{
21-
planItem.Complete();
22-
return Task.FromResult(true);
20+
return HandleProcessTask(planItem, processTask, context);
2321
}
2422

25-
if (!HandlePlanItemControl(planItem, context))
26-
{
27-
return Task.FromResult(false);
28-
}
29-
30-
// TODO : execute the plan item definition.
31-
planItem.Complete();
3223
return Task.FromResult(true);
3324
}
3425

35-
protected bool HandlePlanItemControl(CMMNPlanItem pfe, ProcessFlowInstanceExecutionContext context)
26+
protected Task<bool> HandleProcessTask(CMMNPlanItem planItem, CMMNProcessTask processTask, ProcessFlowInstanceExecutionContext context)
3627
{
37-
var planItem = (CMMNPlanItem)pfe;
38-
if (planItem.SEntries.Any() && !planItem.SEntries.Any(s => CheckSEntry(s, context)))
28+
if (planItem.ExitCriterions.Any() && planItem.ExitCriterions.Any(s => CheckCriterion(s, context)))
3929
{
40-
return false;
30+
planItem.Terminate();
31+
return Task.FromResult(true);
4132
}
42-
43-
if (planItem.PlanItemControl != null)
33+
34+
if (processTask.State == CMMNTaskStates.Available)
4435
{
45-
if (planItem.PlanItemControl is CMMNManualActivationRule)
36+
if (planItem.EntryCriterions.Any() && !planItem.EntryCriterions.Any(s => CheckCriterion(s, context)))
4637
{
47-
planItem.Enable();
48-
return false;
38+
return Task.FromResult(true);
4939
}
40+
41+
if (planItem.PlanItemControl != null)
42+
{
43+
var manualActivationRule = planItem.PlanItemControl as CMMNManualActivationRule;
44+
if (manualActivationRule != null)
45+
{
46+
// Note : at the moment the ContextRef is ignored.
47+
if (ExpressionParser.IsValid(manualActivationRule.Expression.Body, context))
48+
{
49+
planItem.Enable();
50+
return Task.FromResult(false);
51+
}
52+
}
53+
}
54+
55+
planItem.Start();
5056
}
5157

52-
planItem.Start();
53-
return true;
58+
if (processTask.State == CMMNTaskStates.Active)
59+
{
60+
// TODO : Execute the plan item definition.
61+
planItem.Complete();
62+
return Task.FromResult(true);
63+
}
64+
65+
return Task.FromResult(true);
5466
}
5567

56-
private bool CheckSEntry(CMMNSEntry sEntry, ProcessFlowInstanceExecutionContext context)
68+
private bool CheckCriterion(CMMNCriterion sCriterion, ProcessFlowInstanceExecutionContext context)
5769
{
58-
foreach (var onPart in sEntry.OnParts)
70+
foreach (var onPart in sCriterion.SEntry.OnParts)
5971
{
6072
if (onPart is CMMNPlanItemOnPart)
6173
{
@@ -70,9 +82,9 @@ private bool CheckSEntry(CMMNSEntry sEntry, ProcessFlowInstanceExecutionContext
7082
}
7183
}
7284

73-
if (sEntry.IfPart != null)
85+
if (sCriterion.SEntry.IfPart != null)
7486
{
75-
return ExpressionParser.IsValid(sEntry.IfPart.Condition, context);
87+
return ExpressionParser.IsValid(sCriterion.SEntry.IfPart.Condition, context);
7688
}
7789

7890
return true;
Lines changed: 5 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,14 @@
1-
using Microsoft.CodeAnalysis;
2-
using Microsoft.CodeAnalysis.CSharp;
3-
using System;
4-
using System.IO;
5-
using System.Linq;
6-
using System.Reflection;
1+
using DynamicExpresso;
72

83
namespace CaseManagement.Workflow.Engine
94
{
105
public static class ExpressionParser
116
{
12-
public static bool IsValid(string expression, ProcessFlowInstanceExecutionContext context)
7+
public static bool IsValid(string expressionBody, ProcessFlowInstanceExecutionContext context)
138
{
14-
var syntaxTree = CSharpSyntaxTree.ParseText(expression);
15-
var assemblyName = Path.GetRandomFileName();
16-
var references = new MetadataReference[]
17-
{
18-
MetadataReference.CreateFromFile(typeof(object).Assembly.Location),
19-
MetadataReference.CreateFromFile(typeof(Enumerable).Assembly.Location),
20-
MetadataReference.CreateFromFile(typeof(ProcessFlowInstanceExecutionContext).Assembly.Location)
21-
};
22-
23-
var compilation = CSharpCompilation.Create(
24-
assemblyName,
25-
syntaxTrees: new[] { syntaxTree },
26-
references: references,
27-
options: new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));
28-
using (var ms = new MemoryStream())
29-
{
30-
var result = compilation.Emit(ms);
31-
ms.Seek(0, SeekOrigin.Begin);
32-
var assembly = Assembly.Load(ms.ToArray());
33-
var type = assembly.GetType("CaseManagement.Conditions");
34-
var obj = Activator.CreateInstance(type);
35-
return bool.Parse(type.InvokeMember("Check", BindingFlags.Default | BindingFlags.InvokeMethod, null, obj, new object[]
36-
{
37-
context
38-
}).ToString());
39-
}
9+
var interpreter = new Interpreter().SetVariable("context", context);
10+
var parsedExpression = interpreter.Parse(expressionBody);
11+
return (bool)parsedExpression.Invoke();
4012
}
4113
}
4214
}

src/CaseManagement.Workflow/Engine/WorkflowEngine.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,12 +47,12 @@ private async Task<bool> Start(ProcessFlowInstance processFlowInstance, ProcessF
4747
return true;
4848
}
4949

50-
bool result = false;
50+
bool result = true;
5151
foreach (var nextElt in nextElts)
5252
{
53-
if (await Start(processFlowInstance, context, nextElt))
53+
if (!await Start(processFlowInstance, context, nextElt))
5454
{
55-
result = true;
55+
result = false;
5656
}
5757
}
5858

0 commit comments

Comments
 (0)