Skip to content

Commit

Permalink
Refactored intital model parsing with XML Include to Document.
Browse files Browse the repository at this point in the history
Updated test scenarios.
  • Loading branch information
harmen-xb committed Nov 8, 2024
1 parent c109567 commit a83ce9a
Show file tree
Hide file tree
Showing 6 changed files with 62 additions and 36 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -117,10 +117,7 @@ public GenerationResult generateFromFiles(URI modelFileUri, URI templateFileUri,
// Create the model object from the model file.
Model model;
try {
boolean namespaceAware = false;
if (xGenConfig.getModelConfig() != null)
namespaceAware = xGenConfig.getModelConfig().isNamespaceAware();
model = Model.fromFile(modelFileUri, namespaceAware);
model = Model.fromFile(modelFileUri, xGenConfig.getModelConfig());
} catch (ModelException me) {
throw new GeneratorException(me);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,12 @@ else if (fileLogLevel != null) {
* @param debugMode Debug mode indicator.
*/
private void startGenerator(XGenAppConfig appConfig, ArrayList<ModelTemplateConfigCombination> modelTemplateConfigCombinations, boolean debugMode) {
try {
try
{
// Configure Java XML to use Saxon as the DOM and XPath implementation.
System.setProperty("javax.xml.parsers.DocumentBuilderFactory", "net.sf.saxon.om.DocumentBuilderFactoryImpl");
System.setProperty("javax.xml.xpath.XPathFactory", "net.sf.saxon.xpath.XPathFactoryImpl");

// Notify the generation observers the generation is starting.
this.notifyGenerationStarting(modelTemplateConfigCombinations.size(), LocalDateTime.now());
Generator generator = new Generator();
Expand Down
46 changes: 37 additions & 9 deletions XGenerate/src/main/java/com/xbreeze/xgenerate/model/Model.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,23 @@
*******************************************************************************/
package com.xbreeze.xgenerate.model;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.net.URI;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.logging.Logger;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.xml.sax.SAXException;

import com.xbreeze.xgenerate.config.model.ModelConfig;
import com.xbreeze.xgenerate.generator.GeneratorException;
import com.xbreeze.xgenerate.utils.FileUtils;
import com.xbreeze.xgenerate.utils.XMLUtils;
import com.xbreeze.xgenerate.utils.SaxonXMLUtils;
import com.xbreeze.xgenerate.utils.XmlException;

public class Model {
Expand Down Expand Up @@ -79,7 +87,7 @@ public String getModelFileContent() {
* @return The Model object.
* @throws GeneratorException
*/
public static Model fromFile(URI modelFileUri, boolean namespaceAware) throws ModelException {
public static Model fromFile(URI modelFileUri, ModelConfig modelConfig) throws ModelException {
logger.fine(String.format("Creating Model object from '%s'", modelFileUri));

// Read the model file content into a String.
Expand All @@ -90,22 +98,42 @@ public static Model fromFile(URI modelFileUri, boolean namespaceAware) throws Mo
throw new ModelException(String.format("Couldn't read the model file (%s): %s", modelFileUri, e.getMessage()));
}

return fromString(modelFileContent, modelFileUri, namespaceAware);
return fromString(modelFileContent, modelFileUri, modelConfig);
}

/**
* Statis function to construct a Model object from a string.
* Static function to construct a Model object from a string.
* @param modelFileUri
* @param modelFileContents
* @return
* @throws ModelException
*/
public static Model fromString(String modelFileContents, URI modelFileUri, boolean namespaceAware) throws ModelException {
public static Model fromString(String modelFileContents, URI modelFileUri, ModelConfig modelConfig) throws ModelException {
String resolvedModelFileContents;
try {
// Before constructing the model object, resolve any includes first
HashMap<URI, Integer> resolvedIncludes = new HashMap<>();
resolvedModelFileContents = XMLUtils.getXmlWithResolvedIncludes(modelFileContents, modelFileUri, 0, resolvedIncludes, namespaceAware);
// Parse the XML document using Saxon.
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
if (modelConfig != null)
factory.setNamespaceAware(modelConfig.isNamespaceAware());
factory.setXIncludeAware(true);
DocumentBuilder builder;

try {
builder = factory.newDocumentBuilder();
} catch (ParserConfigurationException exc) {
throw new ModelException(
String.format("Error while reading model XML file: %s", exc.getMessage()));
}
Document doc;

try {
// Set the system-id to the location of the model file, so it can resolve includes, if needed.
doc = builder.parse(new ByteArrayInputStream(modelFileContents.getBytes()), modelFileUri.toString());
} catch(SAXException | IOException exc) {
throw new ModelException(String.format("Error while reading model XML file: %s", exc.getMessage()), exc.getCause());
}

resolvedModelFileContents = SaxonXMLUtils.XmlDocumentToString(doc);
} catch (XmlException xec) {
throw new ModelException(String.format("Error while reading model: %s", xec.getMessage()), xec);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.URI;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.logging.ConsoleHandler;
import java.util.logging.Filter;
Expand Down Expand Up @@ -122,7 +121,7 @@ public boolean isLoggable(LogRecord record) {

// Set the feature support file location using the scenario location.
// The support file location is the same as the feature file location, but without the .feature extension and the directory 'features' is replaced with 'feature-support-files'.
String derivedFeatureSupportFileLocation = featureFileLocation.replaceFirst("features", "feature-support-files").replace(".feature", "");
String derivedFeatureSupportFileLocation = featureFileLocation.replaceFirst("features", "feature-support-files").replace(".feature", "/");
logger.info(String.format("The feature-support-file location will be set to '%s'.", derivedFeatureSupportFileLocation));
_featureSupportFilesLocation = URI.create(derivedFeatureSupportFileLocation);

Expand All @@ -149,11 +148,8 @@ private void RestoreSystemStreams() {

@Given("^I have the following model:$")
public void iHaveTheFollowingModel(String modelContent) throws Throwable {
boolean namespaceAware = false;
if (_xGenConfig != null)
namespaceAware = _xGenConfig.getModelConfig().isNamespaceAware();
try {
this._model = Model.fromString(modelContent, this._featureSupportFilesLocation, namespaceAware);
this._model = Model.fromString(modelContent, this._featureSupportFilesLocation.resolve("inline-model.xml"), (_xGenConfig != null) ? _xGenConfig.getModelConfig() : null);
} catch (ModelException mex) {
this.generatorException = mex;
}
Expand Down Expand Up @@ -204,7 +200,7 @@ else if (this._modelFileUri != null && this._templateFileUri != null && this._co
_generationResults = this._generator.generateFromFiles(this._modelFileUri, _templateFileUri, this._configFileUri, this._outputFolderUri, "");
}
else {
throw new GeneratorException ("Model ,template and config should all be specified as either content or file(URI) in the feature.");
throw new GeneratorException ("Model, template and config should all be specified as either content or file(URI) in the feature.");
}

if (_generationResults.getStatus().equals(GenerationStatus.ERROR)) {
Expand Down Expand Up @@ -279,7 +275,7 @@ private void compareActualAndExpectedOutput(String outputName, String expectedRe
}

private URI resolveSupportFile(String relativeFileLocation) {
return Path.of(this._featureSupportFilesLocation).resolve(relativeFileLocation).toUri();
return this._featureSupportFilesLocation.resolve(relativeFileLocation);
}

private String uriEncode(String uriPart) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,5 +76,5 @@ Feature: Unit_Config_Xml_Include
"""
Then I expect the following error message:
"""
com.xbreeze.xgenerate.utils.XmlException: XML include cycle detected at level 3, file {{support-file-location}}/entityBindingWithIncludeNested.xml is already included previously
com.xbreeze.xgenerate.utils.XmlException: XML include cycle detected at level 3, file {{support-file-location}}entityBindingWithIncludeNested.xml is already included previously
"""
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ Feature: Unit_Model_Xml_Include
Given the following config:
"""
<?xml version="1.0" encoding="UTF-8"?>
<XGenConfig xmlns:xi="http://www.w3.org/2001/XInclude">
<XGenConfig>
<Model namespaceAware="<NamespaceAware>" />
<TextTemplate rootSectionName="Template">
<FileFormat singleLineCommentPrefix="--" annotationPrefix="@XGen" annotationArgsPrefix="(" annotationArgsSuffix=")" />
Expand Down Expand Up @@ -43,22 +43,24 @@ Feature: Unit_Model_Xml_Include
Then I expect 1 generation result
And an output named "Unit_Config_Reuse_Partials.txt" with content:
"""
A
B
<expected-result>
"""

Examples:
| Scenario | NamespaceAware | Namespace |
| Namespace aware with namespace | true | xmlns:xi="http://www.w3.org/2001/XInclude" |
| Namespace unaware with namespace | false | xmlns:xi="http://www.w3.org/2001/XInclude" |
| Namespace unaware without namespace | false | |
| Scenario | NamespaceAware | Namespace | expected-result |
# When namespace aware is enabled and the namespace is in the model file, includes are resolved.
| Namespace aware with namespace | true | xmlns:xi="http://www.w3.org/2001/XInclude" | A\nB |
# When the namespace is not in the model file, model includes are not resolved.
| Namespace unaware with namespace | false | xmlns:xi="http://www.w3.org/2001/XInclude" | A |
# When parsing namespace unaware and the namespace is not in the the model file, includes are not resolved.
| Namespace unaware without namespace | false | | A |

Scenario Outline: Xml include in model file <Scenario>
Given the following config:
"""
<?xml version="1.0" encoding="UTF-8"?>
<XGenConfig xmlns:xi="http://www.w3.org/2001/XInclude">
<XGenConfig>
<Model namespaceAware="<NamespaceAware>" />
<TextTemplate rootSectionName="Template">
<FileFormat singleLineCommentPrefix="--" annotationPrefix="@XGen" annotationArgsPrefix="(" annotationArgsSuffix=")" />
Expand Down Expand Up @@ -87,11 +89,9 @@ Feature: Unit_Model_Xml_Include
"""
Then I expect the following error message:
"""
Error while reading model: Error while parsing file as XML document: Name space qualification Exception: Element not qualified
Line Number: 5 Offset: 4.
<ErrorMessage>
"""

Examples:
| Scenario | NamespaceAware | Namespace |
| Namespace aware without namespace | true | |
| Scenario | NamespaceAware | Namespace | ErrorMessage |
| Namespace aware without namespace | true | | Error while reading model XML file: The prefix "xi" for element "xi:include" is not bound. |

0 comments on commit a83ce9a

Please sign in to comment.