diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 098a49a0..ab48d691 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -12,8 +12,8 @@ jobs:
contents: read
packages: write
steps:
- - uses: actions/checkout@v3
- - uses: actions/setup-java@v3
+ - uses: actions/checkout@v4
+ - uses: actions/setup-java@v4
with:
java-version: '11'
distribution: 'adopt'
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
index 4c5c702d..9d15d2a3 100644
--- a/.github/workflows/publish.yml
+++ b/.github/workflows/publish.yml
@@ -19,14 +19,14 @@ jobs:
contents: read
packages: write
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: Import GPG Key
- uses: crazy-max/ghaction-import-gpg@v5
+ uses: crazy-max/ghaction-import-gpg@v6
with:
gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }}
passphrase: ${{ secrets.GPG_PASSPHRASE }}
- name: Set up Java for publishing to Maven Central Repository
- uses: actions/setup-java@v3
+ uses: actions/setup-java@v4
with:
java-version: '11'
distribution: 'adopt'
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b78fa146..802455aa 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,4 +1,4 @@
-# EFX Toolkit 2.0.0-alpha.3 Release Notes
+# EFX Toolkit 2.0.0-alpha.4 Release Notes
_The EFX Toolkit for Java developers is a library that enables the transpilation of [EFX](https://docs.ted.europa.eu/eforms/latest/efx) expressions and templates to different target languages. It also includes an implementation of an EFX-to-XPath transpiler._
@@ -6,8 +6,12 @@ _The EFX Toolkit for Java developers is a library that enables the transpilation
## In this release
-This release fixes an a bug that caused an exception to be thrown by XSLT processors when trying to format sequences of dates or times.
-This bug was reported by a user in [eForms Notice Viewer issue #88](https://github.com/OP-TED/eforms-notice-viewer/issues/88).
+This release fixes an a bug that caused variables and parameters to be in the wrong order in the generated XSL.
+
+A "qualifier" parameter was added in various methods, to allow the use of the corresponding new feature in the eForms Core Library 1.4.0.
+
+The dependency on ANTLR was updated to version 4.13.1.
+
## EFX-1 Support
@@ -22,7 +26,7 @@ The new version of EFX is still under development and will be released with SDK
## Breaking changes
-For users of the Toolkit that have implemented custom transpilers, this release contains a few breaking changes.
+For users of the Toolkit that have implemented custom transpilers, this release contains a few breaking changes from 1.3.0.
More specifically:
- Some additional methods have been added to the SymbolResolver, ScriptGenerator and MarkupGenerator API. As a guide for your implementations please look a the implementations included in the EFX Toolkit for use by the EFX-to-XPath transpilation.
@@ -33,7 +37,7 @@ Users of the Toolkit that only use the included EFX-to-XPath transpiler will not
## Future development
-Further alpha and beta releases of SDK 2 and EFX Toolkit 2 will be issued. While in "alpha" development stage, further braking changes may be introduced. SDK 2 and EFX 2 are expected to continue to be under development through the first quarter of 2024.
+Further alpha and beta releases of SDK 2 and EFX Toolkit 2 will be issued. While in "alpha" development stage, further breaking changes may be introduced.
---
@@ -49,4 +53,4 @@ This version of the EFX Toolkit has a compile-time dependency on the following v
- eForms SDK 1.x.x
- eForms SDK 2.0.0-alpha.1
-It also depends on the [eForms Core Java library](https://github.com/OP-TED/eforms-core-java) version 1.3.0.
+It also depends on the [eForms Core Java library](https://github.com/OP-TED/eforms-core-java) version 1.4.0.
diff --git a/pom.xml b/pom.xml
index d50786a3..a89daf04 100644
--- a/pom.xml
+++ b/pom.xml
@@ -3,7 +3,7 @@
eu.europa.ted.eforms
efx-toolkit-java
- 2.0.0-alpha.3
+ 2.0.0-alpha.4
jar
EFX Toolkit for Java
@@ -49,7 +49,7 @@
UTF-8
- 2023-07-28T16:03:53Z
+ 2024-08-02T09:53:37Z
s01.oss.sonatype.org
@@ -59,10 +59,10 @@
${project.build.directory}/eforms-sdk/antlr4
- 1.3.0
+ 1.4.0
- 4.9.3
+ 4.13.1
3.12.0
1.2.11
2.13.4
@@ -80,7 +80,7 @@
1.5
1.6.7
3.2.1
- 3.0.0-M7
+ 3.2.5
diff --git a/src/main/java/eu/europa/ted/eforms/sdk/ComponentFactory.java b/src/main/java/eu/europa/ted/eforms/sdk/ComponentFactory.java
index 65134e81..8f4c4da9 100644
--- a/src/main/java/eu/europa/ted/eforms/sdk/ComponentFactory.java
+++ b/src/main/java/eu/europa/ted/eforms/sdk/ComponentFactory.java
@@ -4,6 +4,7 @@
import java.text.MessageFormat;
import java.util.HashMap;
import java.util.Map;
+import java.util.Objects;
import eu.europa.ted.eforms.sdk.component.SdkComponentFactory;
import eu.europa.ted.eforms.sdk.component.SdkComponentType;
@@ -19,12 +20,45 @@ private ComponentFactory() {
super();
}
+ class VersionQualifier {
+ private final String sdkVersion;
+ private final String qualifier;
+
+ VersionQualifier(String sdkVersion, String qualifier) {
+ this.sdkVersion = sdkVersion;
+ this.qualifier = qualifier;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(sdkVersion, qualifier);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ VersionQualifier other = (VersionQualifier) obj;
+ if (!getEnclosingInstance().equals(other.getEnclosingInstance()))
+ return false;
+ return Objects.equals(sdkVersion, other.sdkVersion)
+ && Objects.equals(qualifier, other.qualifier);
+ }
+
+ private ComponentFactory getEnclosingInstance() {
+ return ComponentFactory.this;
+ }
+ }
/**
- * EfxToXpathSymbols is implemented as a "kind-of" singleton. One instance per version of the
- * eForms SDK.
+ * Symbol resolver is a "kind-of" singleton. One instance per version of the
+ * eForms SDK and per qualifier.
*/
- private static final Map instances = new HashMap<>();
+ private static final Map instances = new HashMap<>();
/**
* Gets the single instance containing the symbols defined in the given version of the eForms SDK.
@@ -37,10 +71,27 @@ private ComponentFactory() {
*/
public static SymbolResolver getSymbolResolver(final String sdkVersion, final Path sdkRootPath)
throws InstantiationException {
- return instances.computeIfAbsent(sdkVersion, k -> {
+ return getSymbolResolver(sdkVersion, "", sdkRootPath);
+ }
+
+ /**
+ * Gets the single instance containing the symbols defined in the given version of the eForms SDK.
+ *
+ * @param sdkVersion Version of the SDK
+ * @param qualifier Qualifier to choose between several implementations
+ * @param sdkRootPath Path to the root of the SDK
+ * @return The single instance containing the symbols defined in the given version of the eForms
+ * SDK.
+ * @throws InstantiationException If the SDK version is not supported.
+ */
+ public static SymbolResolver getSymbolResolver(final String sdkVersion, final String qualifier,
+ final Path sdkRootPath) throws InstantiationException {
+ VersionQualifier key = ComponentFactory.INSTANCE.new VersionQualifier(sdkVersion, qualifier);
+
+ return instances.computeIfAbsent(key, k -> {
try {
return ComponentFactory.INSTANCE.getComponentImpl(sdkVersion,
- SdkComponentType.SYMBOL_RESOLVER, SymbolResolver.class, sdkVersion,
+ SdkComponentType.SYMBOL_RESOLVER, qualifier, SymbolResolver.class, sdkVersion,
sdkRootPath);
} catch (InstantiationException e) {
throw new RuntimeException(MessageFormat.format(
@@ -51,13 +102,23 @@ public static SymbolResolver getSymbolResolver(final String sdkVersion, final Pa
public static MarkupGenerator getMarkupGenerator(final String sdkVersion, TranslatorOptions options)
throws InstantiationException {
+ return getMarkupGenerator(sdkVersion, "", options);
+ }
+
+ public static MarkupGenerator getMarkupGenerator(final String sdkVersion, final String qualifier,
+ TranslatorOptions options) throws InstantiationException {
return ComponentFactory.INSTANCE.getComponentImpl(sdkVersion,
- SdkComponentType.MARKUP_GENERATOR, MarkupGenerator.class, options);
+ SdkComponentType.MARKUP_GENERATOR, qualifier, MarkupGenerator.class, options);
}
public static ScriptGenerator getScriptGenerator(final String sdkVersion, TranslatorOptions options)
throws InstantiationException {
+ return getScriptGenerator(sdkVersion, "", options);
+ }
+
+ public static ScriptGenerator getScriptGenerator(final String sdkVersion, final String qualifier,
+ TranslatorOptions options) throws InstantiationException {
return ComponentFactory.INSTANCE.getComponentImpl(sdkVersion,
- SdkComponentType.SCRIPT_GENERATOR, ScriptGenerator.class, options);
+ SdkComponentType.SCRIPT_GENERATOR, qualifier, ScriptGenerator.class, options);
}
}
diff --git a/src/main/java/eu/europa/ted/efx/component/EfxTranslatorFactory.java b/src/main/java/eu/europa/ted/efx/component/EfxTranslatorFactory.java
index e40ae6bb..9bc54785 100644
--- a/src/main/java/eu/europa/ted/efx/component/EfxTranslatorFactory.java
+++ b/src/main/java/eu/europa/ted/efx/component/EfxTranslatorFactory.java
@@ -4,6 +4,9 @@
import eu.europa.ted.eforms.sdk.component.SdkComponentType;
import eu.europa.ted.efx.interfaces.EfxExpressionTranslator;
import eu.europa.ted.efx.interfaces.EfxTemplateTranslator;
+import eu.europa.ted.efx.interfaces.MarkupGenerator;
+import eu.europa.ted.efx.interfaces.ScriptGenerator;
+import eu.europa.ted.efx.interfaces.SymbolResolver;
import eu.europa.ted.efx.interfaces.TranslatorDependencyFactory;
import eu.europa.ted.efx.interfaces.TranslatorOptions;
@@ -16,17 +19,36 @@ private EfxTranslatorFactory() {
public static EfxExpressionTranslator getEfxExpressionTranslator(final String sdkVersion,
final TranslatorDependencyFactory factory, TranslatorOptions options) throws InstantiationException {
+ return getEfxExpressionTranslator(sdkVersion, "", factory, options);
+ }
+
+ public static EfxExpressionTranslator getEfxExpressionTranslator(final String sdkVersion,
+ final String qualifier, final TranslatorDependencyFactory factory, TranslatorOptions options)
+ throws InstantiationException {
+
+ SymbolResolver symbolResolver = factory.createSymbolResolver(sdkVersion, qualifier);
+ ScriptGenerator scriptGenerator = factory.createScriptGenerator(sdkVersion, qualifier, options);
+
return EfxTranslatorFactory.INSTANCE.getComponentImpl(sdkVersion,
- SdkComponentType.EFX_EXPRESSION_TRANSLATOR, EfxExpressionTranslator.class,
- factory.createSymbolResolver(sdkVersion), factory.createScriptGenerator(sdkVersion, options),
- factory.createErrorListener());
+ SdkComponentType.EFX_EXPRESSION_TRANSLATOR, qualifier, EfxExpressionTranslator.class,
+ symbolResolver, scriptGenerator, factory.createErrorListener());
}
public static EfxTemplateTranslator getEfxTemplateTranslator(final String sdkVersion,
final TranslatorDependencyFactory factory, TranslatorOptions options) throws InstantiationException {
+ return getEfxTemplateTranslator(sdkVersion, "", factory, options);
+ }
+
+ public static EfxTemplateTranslator getEfxTemplateTranslator(final String sdkVersion,
+ final String qualifier, final TranslatorDependencyFactory factory, TranslatorOptions options)
+ throws InstantiationException {
+
+ MarkupGenerator markupGenerator = factory.createMarkupGenerator(sdkVersion, qualifier, options);
+ SymbolResolver symbolResolver = factory.createSymbolResolver(sdkVersion, qualifier);
+ ScriptGenerator scriptGenerator = factory.createScriptGenerator(sdkVersion, qualifier, options);
+
return EfxTranslatorFactory.INSTANCE.getComponentImpl(sdkVersion,
- SdkComponentType.EFX_TEMPLATE_TRANSLATOR, EfxTemplateTranslator.class,
- factory.createMarkupGenerator(sdkVersion, options), factory.createSymbolResolver(sdkVersion),
- factory.createScriptGenerator(sdkVersion, options), factory.createErrorListener());
+ SdkComponentType.EFX_TEMPLATE_TRANSLATOR, qualifier, EfxTemplateTranslator.class,
+ markupGenerator, symbolResolver, scriptGenerator, factory.createErrorListener());
}
}
diff --git a/src/main/java/eu/europa/ted/efx/interfaces/TranslatorDependencyFactory.java b/src/main/java/eu/europa/ted/efx/interfaces/TranslatorDependencyFactory.java
index 69320ab2..59ad652d 100644
--- a/src/main/java/eu/europa/ted/efx/interfaces/TranslatorDependencyFactory.java
+++ b/src/main/java/eu/europa/ted/efx/interfaces/TranslatorDependencyFactory.java
@@ -37,9 +37,10 @@ public interface TranslatorDependencyFactory {
* @param sdkVersion The version of the SDK that contains the version of the EFX grammar that the
* EFX translator will attempt to translate. This is important as the symbols used in the
* EFX expression are defined in the specific version of the SDK.
+ * @param qualifier Qualifier to choose between several implementations.
* @return An instance of ScriptGenerator to be used by the EFX translator.
*/
- public SymbolResolver createSymbolResolver(String sdkVersion);
+ public SymbolResolver createSymbolResolver(String sdkVersion, String qualifier);
/**
* Creates a ScriptGenerator instance.
@@ -50,10 +51,11 @@ public interface TranslatorDependencyFactory {
* @param sdkVersion The version of the SDK that contains the version of the EFX grammar that the
* EFX translator will attempt to translate. This is important as it defines the EFX
* language features that ScriptGenerator instance should be able to handle.
+ * @param qualifier Qualifier to choose between several implementations.
* @param options The options to be used by the ScriptGenerator.
* @return An instance of ScriptGenerator to be used by the EFX translator.
*/
- public ScriptGenerator createScriptGenerator(String sdkVersion, TranslatorOptions options);
+ public ScriptGenerator createScriptGenerator(String sdkVersion, String qualifier, TranslatorOptions options);
/**
* Creates a MarkupGenerator instance.
@@ -64,10 +66,11 @@ public interface TranslatorDependencyFactory {
* @param sdkVersion The version of the SDK that contains the version of the EFX grammar that the
* EFX translator will attempt to translate. This is important as it defines the EFX
* language features that MarkupGenerator instance should be able to handle.
+ * @param qualifier Qualifier to choose between several implementations.
* @param options The options to be used by the MarkupGenerator.
* @return The instance of MarkupGenerator to be used by the EFX translator.
*/
- public MarkupGenerator createMarkupGenerator(String sdkVersion, TranslatorOptions options);
+ public MarkupGenerator createMarkupGenerator(String sdkVersion, String qualifier, TranslatorOptions options);
/**
* Creates an error listener instance.
diff --git a/src/main/java/eu/europa/ted/efx/model/templates/ContentBlock.java b/src/main/java/eu/europa/ted/efx/model/templates/ContentBlock.java
index b019ad1e..360d071a 100644
--- a/src/main/java/eu/europa/ted/efx/model/templates/ContentBlock.java
+++ b/src/main/java/eu/europa/ted/efx/model/templates/ContentBlock.java
@@ -122,9 +122,6 @@ public Context getParentContext() {
public Set getOwnVariables() {
Set variables = new LinkedHashSet<>();
- if (this.context != null && this.context.variable() != null) {
- variables.add(this.context.variable());
- }
variables.addAll(this.variables);
return variables;
}
@@ -140,7 +137,7 @@ public Set getAllVariables() {
}
public Set getTemplateParameters() {
- return this.getAllVariables().stream().map(v -> v.name).collect(Collectors.toSet());
+ return this.getAllVariables().stream().map(v -> v.name).collect(Collectors.toCollection(LinkedHashSet::new));
}
public Markup renderContent(MarkupGenerator markupGenerator) {
diff --git a/src/main/java/eu/europa/ted/efx/sdk2/EfxTemplateTranslatorV2.java b/src/main/java/eu/europa/ted/efx/sdk2/EfxTemplateTranslatorV2.java
index 8d87234f..510852c1 100644
--- a/src/main/java/eu/europa/ted/efx/sdk2/EfxTemplateTranslatorV2.java
+++ b/src/main/java/eu/europa/ted/efx/sdk2/EfxTemplateTranslatorV2.java
@@ -629,6 +629,11 @@ public void exitContextDeclaration(ContextDeclarationContext ctx) {
String fieldId = getFieldIdFromChildSimpleFieldReferenceContext(ctx);
if (fieldId != null) {
Variable contextVariable = this.getContextVariable(ctx, contextPath);
+ if (contextVariable != null) {
+ VariableList variables = this.stack.pop(VariableList.class);
+ variables.add(contextVariable);
+ this.stack.push(variables);
+ }
this.exitFieldContextDeclaration(fieldId, contextPath, contextVariable);
} else {
String nodeId = getNodeIdFromChildSimpleNodeReferenceContext(ctx);
@@ -694,11 +699,6 @@ private Variable getContextVariable(ContextDeclarationContext ctx,
}
- @Override
- public void enterTemplateVariableList(TemplateVariableListContext ctx) {
- this.stack.push(new VariableList());
- }
-
// #region Variable Initializers --------------------------------------------
@Override
@@ -740,7 +740,7 @@ private void exitVariableInitializer(
this.script.composeVariableDeclaration(variableName, expression.getClass()),
expression,
this.script.composeVariableReference(variableName, expression.getClass()));
- variables.push(variable);
+ variables.add(variable);
this.stack.push(variables);
this.stack.declareIdentifier(variable);
} catch (Exception e) {
@@ -752,20 +752,14 @@ private void exitVariableInitializer(
// #endregion New in EFX-2 --------------------------------------------------
- /**
- * This method changes the current EFX context.
- *
- * The EFX context is always assumed to be either a Field or a Node. Any predicate included in the
- * EFX context declaration is not relevant and is ignored.
- */
@Override
- public void exitContextDeclarationBlock(ContextDeclarationBlockContext ctx) {
- if (ctx.templateVariableList() == null) {
- this.stack.push(new VariableList());
- }
+ public void enterContextDeclarationBlock(ContextDeclarationBlockContext arg0) {
+ this.stack.push(new VariableList());
}
+
+
// #endregion Context Declaration Blocks {...} ------------------------------
// #region Template lines --------------------------------------------------
diff --git a/src/test/java/eu/europa/ted/efx/mock/DependencyFactoryMock.java b/src/test/java/eu/europa/ted/efx/mock/DependencyFactoryMock.java
index e05c038f..65070d76 100644
--- a/src/test/java/eu/europa/ted/efx/mock/DependencyFactoryMock.java
+++ b/src/test/java/eu/europa/ted/efx/mock/DependencyFactoryMock.java
@@ -26,18 +26,19 @@ private DependencyFactoryMock() {}
Map markupGenerators = new HashMap<>();
@Override
- public SymbolResolver createSymbolResolver(String sdkVersion) {
+ public SymbolResolver createSymbolResolver(String sdkVersion, String qualifier) {
+ // Ignore the qualifier for unit tests
return SymbolResolverMockFactory.getInstance(sdkVersion);
}
@Override
- public ScriptGenerator createScriptGenerator(String sdkVersion, TranslatorOptions options) {
+ public ScriptGenerator createScriptGenerator(String sdkVersion, String qualifier, TranslatorOptions options) {
// Default hashCode() implementation is OK here
// we just need to distinguish TranslatorOptions instances
- String key = sdkVersion + options.hashCode();
+ String key = sdkVersion + qualifier + options.hashCode();
if (!scriptGenerators.containsKey(key)) {
try {
- this.scriptGenerators.put(key, ComponentFactory.getScriptGenerator(sdkVersion, options));
+ this.scriptGenerators.put(key, ComponentFactory.getScriptGenerator(sdkVersion, qualifier, options));
} catch (InstantiationException e) {
throw new RuntimeException(e.getMessage(), e);
}
@@ -46,11 +47,9 @@ public ScriptGenerator createScriptGenerator(String sdkVersion, TranslatorOption
}
@Override
- public MarkupGenerator createMarkupGenerator(String sdkVersion, TranslatorOptions options) {
- if (!this.markupGenerators.containsKey(sdkVersion)) {
- this.markupGenerators.put(sdkVersion, new MarkupGeneratorMock());
- }
- return this.markupGenerators.get(sdkVersion);
+ public MarkupGenerator createMarkupGenerator(String sdkVersion, String qualifier, TranslatorOptions options) {
+ String key = sdkVersion + qualifier;
+ return this.markupGenerators.computeIfAbsent(key, k -> new MarkupGeneratorMock());
}
@Override
diff --git a/src/test/java/eu/europa/ted/efx/sdk2/EfxTemplateTranslatorV2Test.java b/src/test/java/eu/europa/ted/efx/sdk2/EfxTemplateTranslatorV2Test.java
index 127f911d..7ed9036b 100644
--- a/src/test/java/eu/europa/ted/efx/sdk2/EfxTemplateTranslatorV2Test.java
+++ b/src/test/java/eu/europa/ted/efx/sdk2/EfxTemplateTranslatorV2Test.java
@@ -176,15 +176,15 @@ void testTemplateLine_VariableScope() {
@Test
void testTemplateLine_ContextVariable() {
assertEquals(
- lines("let block01(t, ctx) -> { #1: eval(for $x in ./normalize-space(text()) return concat($x, $t))", //
+ lines("let block01(ctx, t) -> { #1: eval(for $x in ./normalize-space(text()) return concat($x, $t))", //
"for-each(.).call(block0101(ctx:$ctx, t:$t, t2:'test'))", //
"for-each(.).call(block0102(ctx:$ctx, t:$t, t2:'test3')) }", //
- "let block0101(t, ctx, t2) -> { #1.1: eval(for $y in ./normalize-space(text()) return concat($y, $t, $t2))", //
+ "let block0101(ctx, t, t2) -> { #1.1: eval(for $y in ./normalize-space(text()) return concat($y, $t, $t2))", //
"for-each(.).call(block010101(ctx:$ctx, t:$t, t2:$t2))", //
"for-each(.).call(block010102(ctx:$ctx, t:$t, t2:$t2)) }", //
- "let block010101(t, ctx, t2) -> { eval(for $z in ./normalize-space(text()) return concat($z, $t, $ctx)) }", //
- "let block010102(t, ctx, t2) -> { eval(for $z in ./normalize-space(text()) return concat($z, $t, $ctx)) }", //
- "let block0102(t, ctx, t2) -> { eval(for $z in ./normalize-space(text()) return concat($z, $t2, $ctx)) }", //
+ "let block010101(ctx, t, t2) -> { eval(for $z in ./normalize-space(text()) return concat($z, $t, $ctx)) }", //
+ "let block010102(ctx, t, t2) -> { eval(for $z in ./normalize-space(text()) return concat($z, $t, $ctx)) }", //
+ "let block0102(ctx, t, t2) -> { eval(for $z in ./normalize-space(text()) return concat($z, $t2, $ctx)) }", //
"for-each(/*/PathNode/TextField).call(block01(ctx:., t:./normalize-space(text())))"), //
translateTemplate(lines(
"{context:$ctx = BT-00-Text, text:$t = BT-00-Text} ${for text:$x in BT-00-Text return concat($x, $t)}",