Skip to content

Commit

Permalink
implemented a SubProcess handler into the engine.
Browse files Browse the repository at this point in the history
Improved speeds for loading of process definitions by ignoring elements that the system does not know about.
  • Loading branch information
roger-castaldo committed May 16, 2018
1 parent a3cfa4f commit 281114b
Show file tree
Hide file tree
Showing 19 changed files with 316 additions and 50 deletions.
4 changes: 3 additions & 1 deletion BpmEngine.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,16 @@
<TargetFrameworks>netstandard2.0;net452;net20</TargetFrameworks>
<RootNamespace>Org.Reddragonit.BpmEngine</RootNamespace>
<PackageId>Org.Reddragonit.BpmEngine</PackageId>
<Version>1.9.4</Version>
<Version>1.9.5</Version>
<Authors>Roger Castaldo</Authors>
<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>
<PackageProjectUrl>https://github.com/roger-castaldo/BPMEngine</PackageProjectUrl>
<PackageLicenseUrl>https://www.gnu.org/licenses/gpl-3.0.en.html</PackageLicenseUrl>
<RepositoryUrl>https://github.com/roger-castaldo/BPMEngine</RepositoryUrl>
<PackageTags>BPMN</PackageTags>
<PackageReleaseNotes>migrated begininvoke calls to await task calls for .netstandard and 452</PackageReleaseNotes>
<AssemblyVersion>1.9.5.0</AssemblyVersion>
<FileVersion>1.9.5.0</FileVersion>
</PropertyGroup>

<PropertyGroup Condition="'$(Configuration)'=='Debug'">
Expand Down
62 changes: 57 additions & 5 deletions BusinessProcess.cs
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,15 @@ internal string[] Keys
private OnGatewayError _onGatewayError;
public OnGatewayError OnGatewayError { get { return _onGatewayError; } set { _onGatewayError = value; } }

private OnSubProcessStarted _onSubProcessStarted;
public OnSubProcessStarted OnSubProcessStarted { get { return _onSubProcessStarted; } set { _onSubProcessStarted = value; } }

private OnSubProcessCompleted _onSubProcessCompleted;
public OnSubProcessCompleted OnSubProcessCompleted { get { return _onSubProcessCompleted; } set { _onSubProcessCompleted = value; } }

private OnSubProcessError _onSubProcessError;
public OnSubProcessError OnSubProcessError { get { return _onSubProcessError; } set { _onSubProcessError = value; } }

public OnStateChange OnStateChange { set { _state.OnStateChange = value; } }
#endregion

Expand Down Expand Up @@ -387,7 +396,8 @@ public BusinessProcess(XmlDocument doc, LogLevels stateLogLevel,sProcessRuntimeC
{
if (n.NodeType == XmlNodeType.Element)
{
map.Load((XmlElement)n);
if (map.Load((XmlElement)n))
_elementMapCache.MapIdeals(map);
IElement elem = Utility.ConstructElementType((XmlElement)n, map,null);
if (elem != null)
{
Expand Down Expand Up @@ -695,6 +705,9 @@ public BusinessProcess Clone(bool includeState,bool includeDelegates)
ret.OnProcessStarted = OnProcessStarted;
ret.OnProcessCompleted = OnProcessCompleted;
ret.OnProcessError = OnProcessError;
ret.OnSubProcessStarted = OnSubProcessStarted;
ret.OnSubProcessCompleted = OnSubProcessCompleted;
ret.OnSubProcessError = OnSubProcessError;
ret.OnSequenceFlowCompleted = OnSequenceFlowCompleted;
ret.OnMessageFlowCompleted = OnMessageFlowCompleted;
ret.IsEventStartValid = IsEventStartValid;
Expand Down Expand Up @@ -724,7 +737,7 @@ public bool BeginProcess(ProcessVariablesContainer variables)
{
if (elem is Elements.Process)
{
if (((Elements.Process)elem).IsProcessStartvalid(variables, _isProcessStartValid))
if (((Elements.Process)elem).IsStartValid(variables, _isProcessStartValid))
{
Elements.Process p = (Elements.Process)elem;
foreach (StartEvent se in p.StartEvents)
Expand Down Expand Up @@ -952,6 +965,12 @@ private void _ProcessElement(string sourceID,IElement elem)
else if (elem is AEvent)
{
AEvent evnt = (AEvent)elem;
if (evnt is IntermediateCatchEvent)
{
SubProcess sp = evnt.SubProcess;
if (sp != null)
_state.Path.StartSubProcess(sp, sourceID);
}
lock (_state)
{
_state.Path.StartEvent(evnt, sourceID);
Expand Down Expand Up @@ -999,9 +1018,19 @@ private void _ProcessElement(string sourceID,IElement elem)
{
if (((EndEvent)evnt).IsProcessEnd)
{
if (_onProcessCompleted != null)
_onProcessCompleted(((EndEvent)evnt).Process, new ReadOnlyProcessVariablesContainer(elem.id, _state, this));
_processLock.Set();
SubProcess sp = ((EndEvent)evnt).SubProcess;
if (sp != null)
{
lock (_state) { _state.Path.SucceedSubProcess(sp); }
if (_onSubProcessCompleted != null)
_onSubProcessCompleted(sp, new ReadOnlyProcessVariablesContainer(sp.id, _state, this));
}
else
{
if (_onProcessCompleted != null)
_onProcessCompleted(((EndEvent)evnt).Process, new ReadOnlyProcessVariablesContainer(elem.id, _state, this));
_processLock.Set();
}
}
}
}
Expand Down Expand Up @@ -1059,6 +1088,29 @@ private void _ProcessElement(string sourceID,IElement elem)
_onTaskError(tsk, new ReadOnlyProcessVariablesContainer(elem.id, _state,this,e));
lock (_state) { _state.Path.FailTask(tsk,e); }
}
}else if (elem is SubProcess)
{
SubProcess esp = (SubProcess)elem;
ProcessVariablesContainer variables = new ProcessVariablesContainer(elem.id, _state, this);
if (esp.IsStartValid(variables, _isProcessStartValid))
{
foreach (StartEvent se in esp.StartEvents)
{
if (se.IsEventStartValid(variables, _isEventStartValid))
{
WriteLogLine(LogLevels.Info, new StackFrame(1, true), DateTime.Now, string.Format("Valid Sub Process Start[{0}] located, beginning process", se.id));
lock (_state) { _state.Path.StartSubProcess(esp, sourceID); }
if (_onSubProcessStarted!= null)
_onSubProcessStarted(esp, new ReadOnlyProcessVariablesContainer(variables));
if (_onEventStarted != null)
_onEventStarted(se, new ReadOnlyProcessVariablesContainer(variables));
_state.Path.StartEvent(se, null);
_state.Path.SucceedEvent(se);
if (_onEventCompleted != null)
_onEventCompleted(se, new ReadOnlyProcessVariablesContainer(se.id, _state, this));
}
}
}
}
}
}
Expand Down
3 changes: 3 additions & 0 deletions Delegates.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ namespace Org.Reddragonit.BpmEngine
public delegate void OnGatewayStarted(IStepElement gateway, ReadOnlyProcessVariablesContainer variables);
public delegate void OnGatewayCompleted(IStepElement gateway, ReadOnlyProcessVariablesContainer variables);
public delegate void OnGatewayError(IStepElement gateway, ReadOnlyProcessVariablesContainer variables);
public delegate void OnSubProcessStarted(IStepElement SubProcess, ReadOnlyProcessVariablesContainer variables);
public delegate void OnSubProcessCompleted(IStepElement SubProcess, ReadOnlyProcessVariablesContainer variables);
public delegate void OnSubProcessError(IStepElement SubProcess, ReadOnlyProcessVariablesContainer variables);
public delegate void OnStateChange(XmlDocument stateDocument);
internal delegate void processStateChanged();
#endregion
Expand Down
20 changes: 20 additions & 0 deletions ElementTypeCache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,25 @@ public bool IsCached(string xmlTag)
{
return _cachedMaps.ContainsKey(xmlTag.ToLower());
}

public void MapIdeals(XmlPrefixMap map)
{
Dictionary<string, Dictionary<string, Type>> ideals = Utility.IdealMap;
foreach (string prefix in ideals.Keys)
{
List<string> tmp = map.Translate(prefix);
if (tmp.Count > 0)
{
foreach (string trans in tmp)
{
foreach (string tag in ideals[prefix].Keys)
{
if (!_cachedMaps.ContainsKey(string.Format("{0}:{1}", trans, tag)))
_cachedMaps.Add(string.Format("{0}:{1}", trans, tag), ideals[prefix][tag]);
}
}
}
}
}
}
}
2 changes: 1 addition & 1 deletion Elements/Collaborations/TextAnnotation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace Org.Reddragonit.BpmEngine.Elements.Collaborations
[XMLTag("bpmn","textAnnotation")]
[RequiredAttribute("id")]
[ValidParent(typeof(Collaboration))]
[ValidParent(typeof(Process))]
[ValidParent(typeof(IProcess))]
internal class TextAnnotation : AParentElement
{
public string Content
Expand Down
20 changes: 20 additions & 0 deletions Elements/Diagram.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Text;
using System.Xml;

Expand All @@ -17,6 +18,8 @@ namespace Org.Reddragonit.BpmEngine.Elements
[ValidParent(typeof(Definition))]
internal class Diagram : AParentElement
{
private const float _SUB_PROCESS_CORNER_RADIUS = 10f;

public Diagram(XmlElement elem, XmlPrefixMap map, AElement parent)
: base(elem, map, parent) { }

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

private GraphicsPath _GenerateRoundedRectangle(float XPosition, float YPosition, float Width, float Height)
{
GraphicsPath ret = new GraphicsPath();
ret.AddLine(XPosition + _SUB_PROCESS_CORNER_RADIUS, YPosition, XPosition + Width - (_SUB_PROCESS_CORNER_RADIUS * 2), YPosition);
ret.AddArc(XPosition + Width - (_SUB_PROCESS_CORNER_RADIUS * 2), YPosition, _SUB_PROCESS_CORNER_RADIUS * 2, _SUB_PROCESS_CORNER_RADIUS * 2, 270, 90);
ret.AddLine(XPosition + Width, YPosition + _SUB_PROCESS_CORNER_RADIUS, XPosition + Width, YPosition + Height - (_SUB_PROCESS_CORNER_RADIUS * 2));
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);
ret.AddLine(XPosition + Width - (_SUB_PROCESS_CORNER_RADIUS * 2), YPosition + Height, XPosition + _SUB_PROCESS_CORNER_RADIUS, YPosition + Height);
ret.AddArc(XPosition, YPosition + Height - (_SUB_PROCESS_CORNER_RADIUS * 2), _SUB_PROCESS_CORNER_RADIUS * 2, _SUB_PROCESS_CORNER_RADIUS * 2, 90, 90);
ret.AddLine(XPosition, YPosition + Height - (_SUB_PROCESS_CORNER_RADIUS * 2), XPosition, YPosition + _SUB_PROCESS_CORNER_RADIUS);
ret.AddArc(XPosition, YPosition, _SUB_PROCESS_CORNER_RADIUS * 2, _SUB_PROCESS_CORNER_RADIUS * 2, 180, 90);
ret.CloseFigure();
return ret;
}

private Brush _GetBrush(StepStatuses status)
{
Brush ret = Brushes.Black;
Expand Down
4 changes: 2 additions & 2 deletions Elements/Process.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ namespace Org.Reddragonit.BpmEngine.Elements
[XMLTag("bpmn","process")]
[RequiredAttribute("id")]
[ValidParent(typeof(Definition))]
internal class Process : AParentElement
internal class Process : AParentElement,IProcess
{
public bool isExecutable { get { return (this["isExecutable"] == null ? false : bool.Parse(this["isExecutable"])); } }

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

internal bool IsProcessStartvalid(ProcessVariablesContainer variables, IsProcessStartValid isProcessStartValid)
public bool IsStartValid(ProcessVariablesContainer variables, IsProcessStartValid isProcessStartValid)
{
if (ExtensionElement != null)
{
Expand Down
2 changes: 1 addition & 1 deletion Elements/Processes/Association.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ namespace Org.Reddragonit.BpmEngine.Elements.Processes
{
[XMLTag("bpmn","association")]
[RequiredAttribute("id")]
[ValidParent(typeof(Process))]
[ValidParent(typeof(IProcess))]
internal class Association : AElement
{
public Association(XmlElement elem, XmlPrefixMap map,AElement parent)
Expand Down
18 changes: 17 additions & 1 deletion Elements/Processes/Events/AEvent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

namespace Org.Reddragonit.BpmEngine.Elements.Processes.Events
{
[ValidParent(typeof(Process))]
[ValidParent(typeof(IProcess))]
internal abstract class AEvent : AFlowNode
{
public EventSubTypes? SubType
Expand Down Expand Up @@ -47,6 +47,22 @@ public EventSubTypes? SubType
}
}

public SubProcess SubProcess
{
get
{
IElement elem = Parent;
while (elem != null)
{
if (elem is SubProcess)
return (SubProcess)elem;
else if (elem is AElement)
elem = ((AElement)elem).Parent;
}
return null;
}
}

public AEvent(XmlElement elem, XmlPrefixMap map, AElement parent)
: base(elem, map, parent) { }

Expand Down
17 changes: 0 additions & 17 deletions Elements/Processes/Events/EndEvent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,23 +14,6 @@ internal class EndEvent : AEvent
public EndEvent(XmlElement elem, XmlPrefixMap map, AElement parent)
: base(elem, map, parent) { }

public IElement Process {
get
{
if (Parent == null)
return null;
else
{
AElement tmp = Parent;
while (!(tmp is Process))
tmp = tmp.Parent;
if (tmp is Process)
return tmp;
return null;
}
}
}

public bool IsProcessEnd
{
get
Expand Down
2 changes: 1 addition & 1 deletion Elements/Processes/Gateways/AGateway.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

namespace Org.Reddragonit.BpmEngine.Elements.Processes.Gateways
{
[ValidParent(typeof(Process))]
[ValidParent(typeof(IProcess))]
internal abstract class AGateway : AFlowNode
{
public AGateway(XmlElement elem, XmlPrefixMap map, AElement parent)
Expand Down
2 changes: 1 addition & 1 deletion Elements/Processes/LaneSet.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
namespace Org.Reddragonit.BpmEngine.Elements.Processes
{
[XMLTag("bpmn","laneSet")]
[ValidParent(typeof(Process))]
[ValidParent(typeof(IProcess))]
internal class LaneSet : AParentElement
{
public LaneSet(XmlElement elem, XmlPrefixMap map, AElement parent)
Expand Down
2 changes: 1 addition & 1 deletion Elements/Processes/SequenceFlow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace Org.Reddragonit.BpmEngine.Elements.Processes
{
[XMLTag("bpmn","sequenceFlow")]
[RequiredAttribute("id")]
[ValidParent(typeof(Process))]
[ValidParent(typeof(IProcess))]
internal class SequenceFlow : AElement
{
public string name { get { return this["Name"]; } }
Expand Down
2 changes: 1 addition & 1 deletion Elements/Processes/Tasks/ATask.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

namespace Org.Reddragonit.BpmEngine.Elements.Processes.Tasks
{
[ValidParent(typeof(Process))]
[ValidParent(typeof(IProcess))]
internal abstract class ATask : AFlowNode
{
public ATask(XmlElement elem, XmlPrefixMap map, AElement parent)
Expand Down
Loading

0 comments on commit 281114b

Please sign in to comment.