From 63e210937062ff6af4d1f25aba680e0641c898cd Mon Sep 17 00:00:00 2001 From: Morten Jacobsen Date: Wed, 1 Feb 2023 12:02:43 +0100 Subject: [PATCH] NH-3566: Fix caching threadsafety issue --- .../xml/schematron/CompiledXslt.cs | 36 ++----- .../xml/schematron/SchematronValidator.cs | 99 ++++++++++--------- src/dk.gov.oiosi/xml/xslt/XsltUtility.cs | 58 +++++------ 3 files changed, 88 insertions(+), 105 deletions(-) diff --git a/src/dk.gov.oiosi/xml/schematron/CompiledXslt.cs b/src/dk.gov.oiosi/xml/schematron/CompiledXslt.cs index 2599e389..02a580af 100644 --- a/src/dk.gov.oiosi/xml/schematron/CompiledXslt.cs +++ b/src/dk.gov.oiosi/xml/schematron/CompiledXslt.cs @@ -16,13 +16,7 @@ namespace dk.gov.oiosi.xml.schematron { public class CompiledXslt { - /// - /// The compiles cache entry, if xslt 1.0, and not to complex - /// The compiles cache entry, if xslt 2.0, and not to complex - /// - private XsltTransformer saxonXsltTransform; - - private byte[] memoryStreamBytes; + private XsltExecutable xlstExecutable; private Processor mainProcessor; @@ -60,10 +54,7 @@ namespace dk.gov.oiosi.xml.schematron Uri uri = new Uri("file://" + FileInfo.Directory.FullName); xsltCompiler.BaseUri = uri; - XsltExecutable xsltExecutable = xsltCompiler.Compile(new Uri(xslt.FullName)); - saxonXsltTransform = xsltExecutable.Load(); - - memoryStreamBytes = LoadXsltFromFile(); + this.xlstExecutable = xsltCompiler.Compile(new Uri(xslt.FullName)); } catch (System.Xml.Xsl.XsltException ex) { @@ -71,19 +62,19 @@ namespace dk.gov.oiosi.xml.schematron { // To complex - normally behavior // using saxon - this.saxonXsltTransform = null; + this.xlstExecutable = null; } else if (ex.Message.Equals("XSLT compile error.")) { // To complex - normally behavior // using saxon - this.saxonXsltTransform = null; + this.xlstExecutable = null; } else if (ex.Message.Contains("is an unknown XSLT function")) { // To complex - normally behavior // using saxon - this.saxonXsltTransform = null; + this.xlstExecutable = null; } else { @@ -99,32 +90,19 @@ namespace dk.gov.oiosi.xml.schematron } } - public XsltTransformer GetSaxonXsltTransformer + public XsltExecutable XlstExecutable { - get { return this.saxonXsltTransform; } + get { return this.xlstExecutable; } } public Processor GetSaxonProcessor { get { return this.mainProcessor; } } - public MemoryStream GetCachedXsltMemoryStream - { - get { return new MemoryStream(memoryStreamBytes); } - } public FileInfo FileInfo { get { return this.fileInfo; } } - - public byte[] LoadXsltFromFile() - { - FileStream fileStream = this.fileInfo.Open(FileMode.Open, FileAccess.Read, FileShare.Read); - var b = new byte[fileStream.Length]; - fileStream.Read(b, 0, (int)b.Length); - fileStream.Close(); - return b; - } } } diff --git a/src/dk.gov.oiosi/xml/schematron/SchematronValidator.cs b/src/dk.gov.oiosi/xml/schematron/SchematronValidator.cs index f8dc3592..7d37cc17 100644 --- a/src/dk.gov.oiosi/xml/schematron/SchematronValidator.cs +++ b/src/dk.gov.oiosi/xml/schematron/SchematronValidator.cs @@ -153,39 +153,39 @@ namespace dk.gov.oiosi.xml.schematron { if (compiledXslt != null) { - using (MemoryStream xmlSchematronStylesheetMemoryStream = compiledXslt.GetCachedXsltMemoryStream) - { - xmlSchematronStylesheetMemoryStream.Flush();//Adjust this if you want read your data - xmlSchematronStylesheetMemoryStream.Position = 0; - - Processor processor = compiledXslt.GetSaxonProcessor; - Serializer serializer = processor.NewSerializer(); + Processor processor = compiledXslt.GetSaxonProcessor; + Serializer serializer = processor.NewSerializer(); - try - { - // Set the root node of the source document to be the initial - // context node - compiledXslt.GetSaxonXsltTransformer.InitialContextNode = processor.NewDocumentBuilder().Build(xmlDocument); + XsltTransformer transformer = null; + try + { + transformer = compiledXslt.XlstExecutable.Load(); + // Set the root node of the source document to be the initial + // context node + transformer.InitialContextNode = processor.NewDocumentBuilder().Build(xmlDocument); - // Init. the result object - serializer.SetOutputProperty(Serializer.INDENT, "yes"); - serializer.SetOutputProperty(Serializer.ENCODING, Encoding.UTF8.BodyName); + // Init. the result object + serializer.SetOutputProperty(Serializer.INDENT, "yes"); + serializer.SetOutputProperty(Serializer.ENCODING, Encoding.UTF8.BodyName); - serializer.SetOutputStream(schematronResultMemoryStream); + serializer.SetOutputStream(schematronResultMemoryStream); - // Run the transformation with result object as input param. - compiledXslt.GetSaxonXsltTransformer.Run(serializer); - } - catch (Exception) - { - // easy debugging - throw; - } - finally + // Run the transformation with result object as input param. + transformer.Run(serializer); + } + catch (Exception) + { + // easy debugging + throw; + } + finally + { + if(transformer != null) { - // close/dispose - serializer.Close(); + transformer.Close(); } + // close/dispose + serializer.Close(); } } else @@ -287,7 +287,7 @@ namespace dk.gov.oiosi.xml.schematron XmlDocument schematronResultXmlDocument = null; PrefixedNamespace[] prefixedNamespaces = null; - if (compiledXslt == null || compiledXslt.GetSaxonXsltTransformer == null) + if (compiledXslt == null || compiledXslt.XlstExecutable == null) { throw new Exception("compiledXslt is null."); } @@ -296,27 +296,25 @@ namespace dk.gov.oiosi.xml.schematron { using (MemoryStream schematronResultMemoryStream = new MemoryStream()) { + Processor processor = compiledXslt.GetSaxonProcessor; + Uri uri = new Uri("file://" + compiledXslt.FileInfo.Directory.FullName); - using (MemoryStream xmlSchematronStylesheetMemoryStream = compiledXslt.GetCachedXsltMemoryStream) - { - xmlSchematronStylesheetMemoryStream.Flush(); - xmlSchematronStylesheetMemoryStream.Position = 0; + serializer = processor.NewSerializer(); - Processor processor = compiledXslt.GetSaxonProcessor; - Uri uri = new Uri("file://" + compiledXslt.FileInfo.Directory.FullName); - - serializer = processor.NewSerializer(); - - // Load the XML document. Input to the build method is the document. - DocumentBuilder docBuilder = processor.NewDocumentBuilder(); - if (docBuilder.BaseUri == null) - { - docBuilder.BaseUri = new Uri("file://" + compiledXslt.FileInfo.Directory.FullName); - } + // Load the XML document. Input to the build method is the document. + DocumentBuilder docBuilder = processor.NewDocumentBuilder(); + if (docBuilder.BaseUri == null) + { + docBuilder.BaseUri = new Uri("file://" + compiledXslt.FileInfo.Directory.FullName); + } - // Set the root node of the source document to be the initial - // context node - compiledXslt.GetSaxonXsltTransformer.InitialContextNode = docBuilder.Build(documentAsString.ToStream()); + // Set the root node of the source document to be the initial + // context node + XsltTransformer transformer = null; + try + { + transformer = compiledXslt.XlstExecutable.Load(); + transformer.InitialContextNode = docBuilder.Build(documentAsString.ToStream()); // Init. the result object serializer.SetOutputProperty(Serializer.INDENT, "yes"); @@ -326,7 +324,14 @@ namespace dk.gov.oiosi.xml.schematron // Run the transformation with result object as input param. - compiledXslt.GetSaxonXsltTransformer.Run(serializer); + transformer.Run(serializer); + } + finally + { + if(transformer != null) + { + transformer.Close(); + } } // convert the schematronResultMemoryStream, into a xmlDocument diff --git a/src/dk.gov.oiosi/xml/xslt/XsltUtility.cs b/src/dk.gov.oiosi/xml/xslt/XsltUtility.cs index d2cc6475..8968d722 100644 --- a/src/dk.gov.oiosi/xml/xslt/XsltUtility.cs +++ b/src/dk.gov.oiosi/xml/xslt/XsltUtility.cs @@ -67,7 +67,7 @@ namespace dk.gov.oiosi.xml.xslt { XmlDocument xmlDocument = null; //XslCompiledTransform transform = PrecompiledStyleSheet(stylesheet); - if (stylesheet != null && stylesheet.GetSaxonXsltTransformer != null) + if (stylesheet != null && stylesheet.XlstExecutable != null) { xmlDocument = this.SaxonTransformXml(xmlDoc, stylesheet); } @@ -160,40 +160,40 @@ namespace dk.gov.oiosi.xml.xslt { if (compiledXslt != null) { - using (MemoryStream xmlSchematronStylesheetMemoryStream = compiledXslt.GetCachedXsltMemoryStream) - { - xmlSchematronStylesheetMemoryStream.Flush();//Adjust this if you want read your data - xmlSchematronStylesheetMemoryStream.Position = 0; - - Processor processor = compiledXslt.GetSaxonProcessor; - Serializer serializer = processor.NewSerializer(); + Processor processor = compiledXslt.GetSaxonProcessor; + Serializer serializer = processor.NewSerializer(); - try - { - // Set the root node of the source document to be the initial - // context node - compiledXslt.GetSaxonXsltTransformer.InitialContextNode = processor.NewDocumentBuilder().Build(document); + XsltTransformer transformer = null; + try + { + transformer = compiledXslt.XlstExecutable.Load(); + // Set the root node of the source document to be the initial + // context node + transformer.InitialContextNode = processor.NewDocumentBuilder().Build(document); - // Init. the result object - serializer.SetOutputProperty(Serializer.INDENT, "yes"); - serializer.SetOutputProperty(Serializer.ENCODING, Encoding.UTF8.BodyName); - serializer.SetOutputProperty(Serializer.OMIT_XML_DECLARATION, "no"); + // Init. the result object + serializer.SetOutputProperty(Serializer.INDENT, "yes"); + serializer.SetOutputProperty(Serializer.ENCODING, Encoding.UTF8.BodyName); + serializer.SetOutputProperty(Serializer.OMIT_XML_DECLARATION, "no"); - serializer.SetOutputStream(schematronResultMemoryStream); + serializer.SetOutputStream(schematronResultMemoryStream); - // Run the transformation with result object as input param. - compiledXslt.GetSaxonXsltTransformer.Run(serializer); - } - catch (Exception) - { - // easy debugging - throw; - } - finally + // Run the transformation with result object as input param. + transformer.Run(serializer); + } + catch (Exception) + { + // easy debugging + throw; + } + finally + { + if(transformer != null) { - // close/dispose - serializer.Close(); + transformer.Close(); } + // close/dispose + serializer.Close(); } } else -- GitLab