Skip to content

Commit 281114b

Browse files
implemented a SubProcess handler into the engine.
Improved speeds for loading of process definitions by ignoring elements that the system does not know about.
1 parent a3cfa4f commit 281114b

File tree

19 files changed

+316
-50
lines changed

19 files changed

+316
-50
lines changed

BpmEngine.csproj

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,16 @@
44
<TargetFrameworks>netstandard2.0;net452;net20</TargetFrameworks>
55
<RootNamespace>Org.Reddragonit.BpmEngine</RootNamespace>
66
<PackageId>Org.Reddragonit.BpmEngine</PackageId>
7-
<Version>1.9.4</Version>
7+
<Version>1.9.5</Version>
88
<Authors>Roger Castaldo</Authors>
99
<Description>A BPMN Engine written in .net. The engine attempts to read in a bpmn notation xml document defining both the process(s) as well as the diagrams. From here you can then load/unload the state, render the diagram in its current state or animated into a gif. Using the delegates for a process, you intercept and handle task and condition checking by reading additional xml held within flow and task objects.</Description>
1010
<PackageProjectUrl>https://github.com/roger-castaldo/BPMEngine</PackageProjectUrl>
1111
<PackageLicenseUrl>https://www.gnu.org/licenses/gpl-3.0.en.html</PackageLicenseUrl>
1212
<RepositoryUrl>https://github.com/roger-castaldo/BPMEngine</RepositoryUrl>
1313
<PackageTags>BPMN</PackageTags>
1414
<PackageReleaseNotes>migrated begininvoke calls to await task calls for .netstandard and 452</PackageReleaseNotes>
15+
<AssemblyVersion>1.9.5.0</AssemblyVersion>
16+
<FileVersion>1.9.5.0</FileVersion>
1517
</PropertyGroup>
1618

1719
<PropertyGroup Condition="'$(Configuration)'=='Debug'">

BusinessProcess.cs

Lines changed: 57 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,15 @@ internal string[] Keys
219219
private OnGatewayError _onGatewayError;
220220
public OnGatewayError OnGatewayError { get { return _onGatewayError; } set { _onGatewayError = value; } }
221221

222+
private OnSubProcessStarted _onSubProcessStarted;
223+
public OnSubProcessStarted OnSubProcessStarted { get { return _onSubProcessStarted; } set { _onSubProcessStarted = value; } }
224+
225+
private OnSubProcessCompleted _onSubProcessCompleted;
226+
public OnSubProcessCompleted OnSubProcessCompleted { get { return _onSubProcessCompleted; } set { _onSubProcessCompleted = value; } }
227+
228+
private OnSubProcessError _onSubProcessError;
229+
public OnSubProcessError OnSubProcessError { get { return _onSubProcessError; } set { _onSubProcessError = value; } }
230+
222231
public OnStateChange OnStateChange { set { _state.OnStateChange = value; } }
223232
#endregion
224233

@@ -387,7 +396,8 @@ public BusinessProcess(XmlDocument doc, LogLevels stateLogLevel,sProcessRuntimeC
387396
{
388397
if (n.NodeType == XmlNodeType.Element)
389398
{
390-
map.Load((XmlElement)n);
399+
if (map.Load((XmlElement)n))
400+
_elementMapCache.MapIdeals(map);
391401
IElement elem = Utility.ConstructElementType((XmlElement)n, map,null);
392402
if (elem != null)
393403
{
@@ -695,6 +705,9 @@ public BusinessProcess Clone(bool includeState,bool includeDelegates)
695705
ret.OnProcessStarted = OnProcessStarted;
696706
ret.OnProcessCompleted = OnProcessCompleted;
697707
ret.OnProcessError = OnProcessError;
708+
ret.OnSubProcessStarted = OnSubProcessStarted;
709+
ret.OnSubProcessCompleted = OnSubProcessCompleted;
710+
ret.OnSubProcessError = OnSubProcessError;
698711
ret.OnSequenceFlowCompleted = OnSequenceFlowCompleted;
699712
ret.OnMessageFlowCompleted = OnMessageFlowCompleted;
700713
ret.IsEventStartValid = IsEventStartValid;
@@ -724,7 +737,7 @@ public bool BeginProcess(ProcessVariablesContainer variables)
724737
{
725738
if (elem is Elements.Process)
726739
{
727-
if (((Elements.Process)elem).IsProcessStartvalid(variables, _isProcessStartValid))
740+
if (((Elements.Process)elem).IsStartValid(variables, _isProcessStartValid))
728741
{
729742
Elements.Process p = (Elements.Process)elem;
730743
foreach (StartEvent se in p.StartEvents)
@@ -952,6 +965,12 @@ private void _ProcessElement(string sourceID,IElement elem)
952965
else if (elem is AEvent)
953966
{
954967
AEvent evnt = (AEvent)elem;
968+
if (evnt is IntermediateCatchEvent)
969+
{
970+
SubProcess sp = evnt.SubProcess;
971+
if (sp != null)
972+
_state.Path.StartSubProcess(sp, sourceID);
973+
}
955974
lock (_state)
956975
{
957976
_state.Path.StartEvent(evnt, sourceID);
@@ -999,9 +1018,19 @@ private void _ProcessElement(string sourceID,IElement elem)
9991018
{
10001019
if (((EndEvent)evnt).IsProcessEnd)
10011020
{
1002-
if (_onProcessCompleted != null)
1003-
_onProcessCompleted(((EndEvent)evnt).Process, new ReadOnlyProcessVariablesContainer(elem.id, _state, this));
1004-
_processLock.Set();
1021+
SubProcess sp = ((EndEvent)evnt).SubProcess;
1022+
if (sp != null)
1023+
{
1024+
lock (_state) { _state.Path.SucceedSubProcess(sp); }
1025+
if (_onSubProcessCompleted != null)
1026+
_onSubProcessCompleted(sp, new ReadOnlyProcessVariablesContainer(sp.id, _state, this));
1027+
}
1028+
else
1029+
{
1030+
if (_onProcessCompleted != null)
1031+
_onProcessCompleted(((EndEvent)evnt).Process, new ReadOnlyProcessVariablesContainer(elem.id, _state, this));
1032+
_processLock.Set();
1033+
}
10051034
}
10061035
}
10071036
}
@@ -1059,6 +1088,29 @@ private void _ProcessElement(string sourceID,IElement elem)
10591088
_onTaskError(tsk, new ReadOnlyProcessVariablesContainer(elem.id, _state,this,e));
10601089
lock (_state) { _state.Path.FailTask(tsk,e); }
10611090
}
1091+
}else if (elem is SubProcess)
1092+
{
1093+
SubProcess esp = (SubProcess)elem;
1094+
ProcessVariablesContainer variables = new ProcessVariablesContainer(elem.id, _state, this);
1095+
if (esp.IsStartValid(variables, _isProcessStartValid))
1096+
{
1097+
foreach (StartEvent se in esp.StartEvents)
1098+
{
1099+
if (se.IsEventStartValid(variables, _isEventStartValid))
1100+
{
1101+
WriteLogLine(LogLevels.Info, new StackFrame(1, true), DateTime.Now, string.Format("Valid Sub Process Start[{0}] located, beginning process", se.id));
1102+
lock (_state) { _state.Path.StartSubProcess(esp, sourceID); }
1103+
if (_onSubProcessStarted!= null)
1104+
_onSubProcessStarted(esp, new ReadOnlyProcessVariablesContainer(variables));
1105+
if (_onEventStarted != null)
1106+
_onEventStarted(se, new ReadOnlyProcessVariablesContainer(variables));
1107+
_state.Path.StartEvent(se, null);
1108+
_state.Path.SucceedEvent(se);
1109+
if (_onEventCompleted != null)
1110+
_onEventCompleted(se, new ReadOnlyProcessVariablesContainer(se.id, _state, this));
1111+
}
1112+
}
1113+
}
10621114
}
10631115
}
10641116
}

Delegates.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ namespace Org.Reddragonit.BpmEngine
2222
public delegate void OnGatewayStarted(IStepElement gateway, ReadOnlyProcessVariablesContainer variables);
2323
public delegate void OnGatewayCompleted(IStepElement gateway, ReadOnlyProcessVariablesContainer variables);
2424
public delegate void OnGatewayError(IStepElement gateway, ReadOnlyProcessVariablesContainer variables);
25+
public delegate void OnSubProcessStarted(IStepElement SubProcess, ReadOnlyProcessVariablesContainer variables);
26+
public delegate void OnSubProcessCompleted(IStepElement SubProcess, ReadOnlyProcessVariablesContainer variables);
27+
public delegate void OnSubProcessError(IStepElement SubProcess, ReadOnlyProcessVariablesContainer variables);
2528
public delegate void OnStateChange(XmlDocument stateDocument);
2629
internal delegate void processStateChanged();
2730
#endregion

ElementTypeCache.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,5 +28,25 @@ public bool IsCached(string xmlTag)
2828
{
2929
return _cachedMaps.ContainsKey(xmlTag.ToLower());
3030
}
31+
32+
public void MapIdeals(XmlPrefixMap map)
33+
{
34+
Dictionary<string, Dictionary<string, Type>> ideals = Utility.IdealMap;
35+
foreach (string prefix in ideals.Keys)
36+
{
37+
List<string> tmp = map.Translate(prefix);
38+
if (tmp.Count > 0)
39+
{
40+
foreach (string trans in tmp)
41+
{
42+
foreach (string tag in ideals[prefix].Keys)
43+
{
44+
if (!_cachedMaps.ContainsKey(string.Format("{0}:{1}", trans, tag)))
45+
_cachedMaps.Add(string.Format("{0}:{1}", trans, tag), ideals[prefix][tag]);
46+
}
47+
}
48+
}
49+
}
50+
}
3151
}
3252
}

Elements/Collaborations/TextAnnotation.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ namespace Org.Reddragonit.BpmEngine.Elements.Collaborations
1010
[XMLTag("bpmn","textAnnotation")]
1111
[RequiredAttribute("id")]
1212
[ValidParent(typeof(Collaboration))]
13-
[ValidParent(typeof(Process))]
13+
[ValidParent(typeof(IProcess))]
1414
internal class TextAnnotation : AParentElement
1515
{
1616
public string Content

Elements/Diagram.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using System;
88
using System.Collections.Generic;
99
using System.Drawing;
10+
using System.Drawing.Drawing2D;
1011
using System.Text;
1112
using System.Xml;
1213

@@ -17,6 +18,8 @@ namespace Org.Reddragonit.BpmEngine.Elements
1718
[ValidParent(typeof(Definition))]
1819
internal class Diagram : AParentElement
1920
{
21+
private const float _SUB_PROCESS_CORNER_RADIUS = 10f;
22+
2023
public Diagram(XmlElement elem, XmlPrefixMap map, AElement parent)
2124
: base(elem, map, parent) { }
2225

@@ -294,6 +297,8 @@ private Image _Render(ProcessPath path, Definition definition, string elemid)
294297
});
295298
else if (elem is Lane || elem is Participant)
296299
gp.DrawRectangle(new Pen(_GetBrush(status), Constants.PEN_WIDTH), Rectangle.Round(shape.Rectangle));
300+
else if (elem is SubProcess)
301+
gp.DrawPath(new Pen(_GetBrush(status), Constants.PEN_WIDTH), _GenerateRoundedRectangle(shape.Rectangle.X, shape.Rectangle.Y, shape.Rectangle.Width, shape.Rectangle.Height));
297302
if (elem.ToString() != "")
298303
{
299304
if (shape.Label != null)
@@ -346,6 +351,21 @@ private Image _Render(ProcessPath path, Definition definition, string elemid)
346351
return bmp;
347352
}
348353

354+
private GraphicsPath _GenerateRoundedRectangle(float XPosition, float YPosition, float Width, float Height)
355+
{
356+
GraphicsPath ret = new GraphicsPath();
357+
ret.AddLine(XPosition + _SUB_PROCESS_CORNER_RADIUS, YPosition, XPosition + Width - (_SUB_PROCESS_CORNER_RADIUS * 2), YPosition);
358+
ret.AddArc(XPosition + Width - (_SUB_PROCESS_CORNER_RADIUS * 2), YPosition, _SUB_PROCESS_CORNER_RADIUS * 2, _SUB_PROCESS_CORNER_RADIUS * 2, 270, 90);
359+
ret.AddLine(XPosition + Width, YPosition + _SUB_PROCESS_CORNER_RADIUS, XPosition + Width, YPosition + Height - (_SUB_PROCESS_CORNER_RADIUS * 2));
360+
ret.AddArc(XPosition + Width - (_SUB_PROCESS_CORNER_RADIUS * 2), YPosition + Height - (_SUB_PROCESS_CORNER_RADIUS * 2), _SUB_PROCESS_CORNER_RADIUS * 2, _SUB_PROCESS_CORNER_RADIUS * 2, 0, 90);
361+
ret.AddLine(XPosition + Width - (_SUB_PROCESS_CORNER_RADIUS * 2), YPosition + Height, XPosition + _SUB_PROCESS_CORNER_RADIUS, YPosition + Height);
362+
ret.AddArc(XPosition, YPosition + Height - (_SUB_PROCESS_CORNER_RADIUS * 2), _SUB_PROCESS_CORNER_RADIUS * 2, _SUB_PROCESS_CORNER_RADIUS * 2, 90, 90);
363+
ret.AddLine(XPosition, YPosition + Height - (_SUB_PROCESS_CORNER_RADIUS * 2), XPosition, YPosition + _SUB_PROCESS_CORNER_RADIUS);
364+
ret.AddArc(XPosition, YPosition, _SUB_PROCESS_CORNER_RADIUS * 2, _SUB_PROCESS_CORNER_RADIUS * 2, 180, 90);
365+
ret.CloseFigure();
366+
return ret;
367+
}
368+
349369
private Brush _GetBrush(StepStatuses status)
350370
{
351371
Brush ret = Brushes.Black;

Elements/Process.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ namespace Org.Reddragonit.BpmEngine.Elements
1313
[XMLTag("bpmn","process")]
1414
[RequiredAttribute("id")]
1515
[ValidParent(typeof(Definition))]
16-
internal class Process : AParentElement
16+
internal class Process : AParentElement,IProcess
1717
{
1818
public bool isExecutable { get { return (this["isExecutable"] == null ? false : bool.Parse(this["isExecutable"])); } }
1919

@@ -34,7 +34,7 @@ public StartEvent[] StartEvents
3434
public Process(XmlElement elem, XmlPrefixMap map, AElement parent)
3535
: base(elem, map, parent) { }
3636

37-
internal bool IsProcessStartvalid(ProcessVariablesContainer variables, IsProcessStartValid isProcessStartValid)
37+
public bool IsStartValid(ProcessVariablesContainer variables, IsProcessStartValid isProcessStartValid)
3838
{
3939
if (ExtensionElement != null)
4040
{

Elements/Processes/Association.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ namespace Org.Reddragonit.BpmEngine.Elements.Processes
99
{
1010
[XMLTag("bpmn","association")]
1111
[RequiredAttribute("id")]
12-
[ValidParent(typeof(Process))]
12+
[ValidParent(typeof(IProcess))]
1313
internal class Association : AElement
1414
{
1515
public Association(XmlElement elem, XmlPrefixMap map,AElement parent)

Elements/Processes/Events/AEvent.cs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
namespace Org.Reddragonit.BpmEngine.Elements.Processes.Events
1010
{
11-
[ValidParent(typeof(Process))]
11+
[ValidParent(typeof(IProcess))]
1212
internal abstract class AEvent : AFlowNode
1313
{
1414
public EventSubTypes? SubType
@@ -47,6 +47,22 @@ public EventSubTypes? SubType
4747
}
4848
}
4949

50+
public SubProcess SubProcess
51+
{
52+
get
53+
{
54+
IElement elem = Parent;
55+
while (elem != null)
56+
{
57+
if (elem is SubProcess)
58+
return (SubProcess)elem;
59+
else if (elem is AElement)
60+
elem = ((AElement)elem).Parent;
61+
}
62+
return null;
63+
}
64+
}
65+
5066
public AEvent(XmlElement elem, XmlPrefixMap map, AElement parent)
5167
: base(elem, map, parent) { }
5268

Elements/Processes/Events/EndEvent.cs

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -14,23 +14,6 @@ internal class EndEvent : AEvent
1414
public EndEvent(XmlElement elem, XmlPrefixMap map, AElement parent)
1515
: base(elem, map, parent) { }
1616

17-
public IElement Process {
18-
get
19-
{
20-
if (Parent == null)
21-
return null;
22-
else
23-
{
24-
AElement tmp = Parent;
25-
while (!(tmp is Process))
26-
tmp = tmp.Parent;
27-
if (tmp is Process)
28-
return tmp;
29-
return null;
30-
}
31-
}
32-
}
33-
3417
public bool IsProcessEnd
3518
{
3619
get

0 commit comments

Comments
 (0)