Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FIX: Foreach workflow block task doesn't ignore source context store … #2196

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 4 additions & 3 deletions backend/Origam.Workflow/Engine.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1064,9 +1064,9 @@ internal OrigamDataType ContextStoreType(Key key)
return cs.DataType;
}

internal void MergeContext(Key resultContextKey, object inputContext, IWorkflowStep step, string contextName, ServiceOutputMethod method)
internal bool MergeContext(Key resultContextKey, object inputContext, IWorkflowStep step, string contextName, ServiceOutputMethod method)
{
if(method == ServiceOutputMethod.Ignore) return;
if(method == ServiceOutputMethod.Ignore) return false;

object resultContext = this.RuleEngine.GetContext(resultContextKey);
bool changed = false;
Expand Down Expand Up @@ -1104,7 +1104,7 @@ internal void MergeContext(Key resultContextKey, object inputContext, IWorkflowS

if (inputContext == null || inputContext == DBNull.Value)
{
return;
return changed;
}
else if(inputDataDoc != null
&& resultDataDoc != null)
Expand Down Expand Up @@ -1336,6 +1336,7 @@ internal void MergeContext(Key resultContextKey, object inputContext, IWorkflowS
if(step != null) stepNameLog = ", Step '" + (step as AbstractSchemaItem)?.Path + "'";
log.Info("Finished merging context '" + contextName + "'" + stepNameLog);
}
return changed;
}

private void ProcessRulesTimed(Key resultContextKey,
Expand Down
90 changes: 68 additions & 22 deletions backend/Origam.Workflow/Tasks/ForEachBlockEngineTask.cs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
using Origam.Schema.WorkflowModel;
using Origam.Service.Core;
using Origam.Workbench.Services;
using System.Xml.Linq;
using System.Windows.Input;

namespace Origam.Workflow.Tasks
{
Expand All @@ -42,6 +44,7 @@ public class ForEachBlockEngineTask : BlockEngineTask
private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
XPathNodeIterator _iter;
WorkflowEngine _call;
bool sourceContextChanged;

public ForEachBlockEngineTask() : base()
{
Expand All @@ -64,30 +67,22 @@ protected override void MeasuredExecution()
CleanUp();
}

protected override void OnExecute()
{
if(log.IsInfoEnabled)
{
log.Info("ForEach Block started.");
}
this.Engine.Host.WorkflowFinished += Host_WorkflowFinished;
ForeachWorkflowBlock block = this.Step as ForeachWorkflowBlock;
IXmlContainer xmlContainer = this.Engine.RuleEngine.GetContext(
block.SourceContextStore) as IXmlContainer;
if(xmlContainer == null)
{
throw new ArgumentOutOfRangeException(
"SourceContextStore",
block.SourceContextStore,
ResourceUtils.GetString("ErrorSourceContextNotXmlDocument"));
}
protected override void OnExecute()
{
if (log.IsInfoEnabled)
{
log.Info("ForEach Block started.");
}
this.Engine.Host.WorkflowFinished += Host_WorkflowFinished;
ForeachWorkflowBlock block = this.Step as ForeachWorkflowBlock;
IXmlContainer xmlContainer = GetSourceContextXmlContainer(block);
XPathNavigator navigator = xmlContainer.Xml.CreateNavigator();
OrigamXsltContext ctx = OrigamXsltContext.Create(
new NameTable(), Engine.TransactionId);
XPathExpression expr = navigator.Compile(block.IteratorXPath);
expr.SetContext(ctx);
// code might fail and this handler doesn't get cleared
// and will interfer with other workflow invocations
// code might fail and this handler doesn't get cleared
// and will interfer with other workflow invocations
this.Engine.Host.WorkflowMessage += Host_WorkflowMessage;
_iter = navigator.Select(expr);
ResumeIteration();
Expand All @@ -99,9 +94,33 @@ private void ResumeIteration()
_call = this.Engine.GetSubEngine(block, Engine.TransactionBehavior);
_call.IterationTotal = _iter.Count;

while (_iter.MoveNext())
for (int currentPosition = 1; currentPosition <= _call.IterationTotal;
currentPosition++)
{
if(_iter.CurrentPosition > _iter.Count) break;
if (!block.IgnoreSourceContextChanges && this.sourceContextChanged)
{
// reinitialize _iter to updated context store and wind up
// to current position
IXmlContainer updatedSourceContextStore = GetSourceContextXmlContainer(block);
XPathNavigator navigator = updatedSourceContextStore.Xml.CreateNavigator();
OrigamXsltContext ctx = OrigamXsltContext.Create(
new NameTable(), Engine.TransactionId);
XPathExpression expr = navigator.Compile(block.IteratorXPath);
expr.SetContext(ctx);
_iter = navigator.Select(expr);
if (!WindUpTo(currentPosition))
{
break;
}
}
else
{
bool moved = _iter.MoveNext();
if (!moved || _iter.CurrentPosition > _iter.Count)
{
break;
}
}

// if workflow finished with an exception, we don't proceed
if(this.Engine == null) return;
Expand Down Expand Up @@ -149,6 +168,33 @@ private void ResumeIteration()
}
}

private bool WindUpTo(int currentPosition)
{
for (int i = currentPosition; i > 0; i--)
{
bool moved = _iter.MoveNext();
if (!moved || _iter.CurrentPosition > _iter.Count)
{
return false;
}
}
return true;
}

private IXmlContainer GetSourceContextXmlContainer(ForeachWorkflowBlock block)
{
IXmlContainer xmlContainer = this.Engine.RuleEngine.GetContext(
block.SourceContextStore) as IXmlContainer;
if (xmlContainer == null)
{
throw new ArgumentOutOfRangeException(
"SourceContextStore",
block.SourceContextStore,
ResourceUtils.GetString("ErrorSourceContextNotXmlDocument"));
}
return xmlContainer;
}

private void CleanUp()
{
// there is no other iteration, we finish
Expand Down Expand Up @@ -183,7 +229,7 @@ private void Host_WorkflowFinished(object sender, WorkflowHostEventArgs e)
if(entry.Key.Equals(block.SourceContextStore.PrimaryKey))
{
bool fullMerge = (! entry.Key.Equals(block.SourceContextStore.PrimaryKey));
this.Engine.MergeContext(
sourceContextChanged = Engine.MergeContext(
(Key)entry.Key,
_call.RuleEngine.GetContext(entry.Key as Key),
block,
Expand Down