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: Xslt functions used in XPath were called out of transaction scope. #938

Merged
merged 3 commits into from Sep 21, 2022
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
2 changes: 1 addition & 1 deletion backend/Origam.Rule/IXpathEvaluator.cs
Expand Up @@ -30,5 +30,5 @@ public interface IXpathEvaluator

object Evaluate(string xpath, bool isPathRelative,
OrigamDataType returnDataType, XPathNavigator nav,
XPathNodeIterator contextPosition);
XPathNodeIterator contextPosition, string transactionId);
}
7 changes: 5 additions & 2 deletions backend/Origam.Rule/RuleEngine.cs
Expand Up @@ -458,7 +458,8 @@ public object EvaluateContext(string xpath, object context, OrigamDataType dataT
return context;
}

OrigamXsltContext ctx = OrigamXsltContext.Create(new NameTable());
OrigamXsltContext ctx = OrigamXsltContext.Create(
new NameTable(), _transactionId);
XPathNavigator nav = ((XmlDocument)context).CreateNavigator();
XPathExpression expr = nav.Compile(xpath);
expr.SetContext(ctx);
Expand Down Expand Up @@ -2176,7 +2177,9 @@ private object EvaluateRule(XPathRule rule, IXmlContainer context, XPathNodeIter

XPathNavigator nav = context.Xml.CreateNavigator();

return XpathEvaluator.Instance.Evaluate(rule.XPath, rule.IsPathRelative, rule.DataType, nav, contextPosition);
return XpathEvaluator.Instance.Evaluate(
rule.XPath, rule.IsPathRelative, rule.DataType, nav,
contextPosition, _transactionId);
}

private object EvaluateRule(XslRule rule, IXmlContainer context)
Expand Down
9 changes: 5 additions & 4 deletions backend/Origam.Rule/XpathEvaluator.cs
Expand Up @@ -58,17 +58,18 @@ private string Evaluate(XPathNodeIterator iterator, string xpath)

private string Evaluate(XPathNavigator navigator, string xpath)
{
return (string)Evaluate(xpath, false, OrigamDataType.String, navigator, null);
return (string)Evaluate(xpath, false, OrigamDataType.String, navigator,
null, null);
}

public object Evaluate(string xpath, bool isPathRelative,
OrigamDataType returnDataType, XPathNavigator nav,
XPathNodeIterator contextPosition)
XPathNodeIterator contextPosition, string transactionId)
{
XPathExpression expr;
expr = nav.Compile(xpath);

OrigamXsltContext ctx = OrigamXsltContext.Create(new NameTable());
OrigamXsltContext ctx = OrigamXsltContext.Create(
new NameTable(), transactionId);
expr.SetContext(ctx);

object result;
Expand Down
10 changes: 6 additions & 4 deletions backend/Origam.Rule/Xslt/OrigamXsltContext.cs
Expand Up @@ -37,9 +37,11 @@ public class OrigamXsltContext : XsltContext
{
private Dictionary<string, object> _xslFunctionsDict;
private ExsltContext _exslt;
public static OrigamXsltContext Create(XmlNameTable nameTable)
public static OrigamXsltContext Create(
XmlNameTable nameTable, string transactionId)
{
var functionContainers = XsltFunctionContainerFactory.Create();
var functionContainers = XsltFunctionContainerFactory.Create(
transactionId);
return new OrigamXsltContext(
nameTable,
functionContainers
Expand Down Expand Up @@ -88,7 +90,7 @@ public override IXsltContextFunction ResolveFunction(string prefix, string name,
if (_xslFunctionsDict.TryGetValue(ns, out functionContainer))
{
IXsltContextFunction func = null;
func = GetExtentionMethod(ns, name, ArgTypes, functionContainer);
func = GetExtensionMethod(ns, name, ArgTypes, functionContainer);
if (func == null)
{
throw new XsltException(String.Format("Unknown Xslt function {0}", name));
Expand Down Expand Up @@ -206,7 +208,7 @@ private MethodInfo FindBestMethod(MethodInfo[] methods, bool ignoreCase, bool pu
}

private const BindingFlags bindingFlags = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static;
private IXsltContextFunction GetExtentionMethod(string ns, string name, XPathResultType[] argTypes, object extension)
private IXsltContextFunction GetExtensionMethod(string ns, string name, XPathResultType[] argTypes, object extension)
{
MethodInfo method = FindBestMethod(extension.GetType().GetMethods(bindingFlags), /*ignoreCase:*/false, /*publicOnly:*/true, name, argTypes);
if (method != null)
Expand Down
Expand Up @@ -33,7 +33,8 @@ namespace Origam.Rule.XsltFunctions;

public static class XsltFunctionContainerFactory
{
public static IEnumerable<XsltFunctionsDefinition> Create()
public static IEnumerable<XsltFunctionsDefinition> Create(
string transactionId = null)
{
return Create(
ServiceManager.Services.GetService<IBusinessServicesService>(),
Expand All @@ -50,9 +51,11 @@ public static IEnumerable<XsltFunctionsDefinition> Create()
SecurityManager.CurrentUserProfile,
XpathEvaluator.Instance,
HttpTools.Instance,
ResourceTools.Instance);
ResourceTools.Instance,
transactionId);
}

// the method is public because of tests
public static IEnumerable<XsltFunctionsDefinition> Create (
IBusinessServicesService businessService,
IXsltFunctionSchemaItemProvider xsltFunctionSchemaItemProvider,
Expand All @@ -61,7 +64,8 @@ public static IEnumerable<XsltFunctionsDefinition> Create()
ITracingService tracingService, IDocumentationService documentationService,
ICoreDataService dataService, IOrigamAuthorizationProvider authorizationProvider,
Func<UserProfile> userProfileGetter, IXpathEvaluator xpathEvaluator,
IHttpTools httpTools, IResourceTools resourceTools)
IHttpTools httpTools, IResourceTools resourceTools,
string transactionId)
{
return xsltFunctionSchemaItemProvider
.ChildItemsByType(XsltFunctionCollection.CategoryConst)
Expand All @@ -87,6 +91,7 @@ public static IEnumerable<XsltFunctionsDefinition> Create()
origamContainer.XpathEvaluator = xpathEvaluator;
origamContainer.HttpTools = httpTools;
origamContainer.ResourceTools = resourceTools;
origamContainer.TransactionId = transactionId;
}
return new XsltFunctionsDefinition(
Container: container,
Expand Down
3 changes: 2 additions & 1 deletion backend/Origam.RuleTests/XsltTests.cs
Expand Up @@ -132,7 +132,8 @@ public void Init()
userProfileGetterMock.Object,
xPathEvaluatorMock.Object,
httpToolsMock.Object,
resourceToolsMock.Object
resourceToolsMock.Object,
null
).ToList();
}

Expand Down
3 changes: 2 additions & 1 deletion backend/Origam.Workbench/Editors/XslEditor.cs
Expand Up @@ -1084,7 +1084,8 @@ private void ProcessXpath(string xpath, string xml)

XPathNavigator nav = doc.CreateNavigator();
XPathExpression expr = nav.Compile(xpath);
OrigamXsltContext ctx = OrigamXsltContext.Create(new NameTable());
OrigamXsltContext ctx = OrigamXsltContext.Create(
new NameTable(), null);
expr.SetContext(ctx);

object result = nav.Evaluate(expr);
Expand Down
3 changes: 2 additions & 1 deletion backend/Origam.Workflow/Tasks/ForEachBlockEngineTask.cs
Expand Up @@ -82,7 +82,8 @@ protected override void OnExecute()
ResourceUtils.GetString("ErrorSourceContextNotXmlDocument"));
}
XPathNavigator navigator = xmlContainer.Xml.CreateNavigator();
OrigamXsltContext ctx = OrigamXsltContext.Create(new NameTable());
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
Expand Down