From a10bf9faea5789c683f81cdab565bb820a110f5f Mon Sep 17 00:00:00 2001 From: Fabian Steeg Date: Fri, 4 Sep 2020 15:16:47 +0200 Subject: [PATCH] Add generic options and flushing in Fix Binds --- .../main/java/org/metafacture/fix/Fix.xtext | 2 +- .../org/metafacture/metamorph/FixBuilder.java | 63 +++++++++++++------ .../metafacture/metamorph/MetafixDslTest.java | 24 +++++++ 3 files changed, 69 insertions(+), 20 deletions(-) diff --git a/org.metafacture.fix/src/main/java/org/metafacture/fix/Fix.xtext b/org.metafacture.fix/src/main/java/org/metafacture/fix/Fix.xtext index 2ff41a04..0da72b5d 100644 --- a/org.metafacture.fix/src/main/java/org/metafacture/fix/Fix.xtext +++ b/org.metafacture.fix/src/main/java/org/metafacture/fix/Fix.xtext @@ -36,7 +36,7 @@ Else: ; Do: - 'do' name = ValidID '(' ( params += (QualifiedName|STRING) ( ',' params += (QualifiedName|STRING) )* )? ')' BEGIN + 'do' name = ValidID '(' ( params += (QualifiedName|STRING) ( ',' params += (QualifiedName|STRING) )* ','? )? ( options = Options )? ')' BEGIN elements += Expression* END 'end' diff --git a/org.metafacture.fix/src/main/java/org/metafacture/metamorph/FixBuilder.java b/org.metafacture.fix/src/main/java/org/metafacture/metamorph/FixBuilder.java index b0bb6da2..728f9734 100644 --- a/org.metafacture.fix/src/main/java/org/metafacture/metamorph/FixBuilder.java +++ b/org.metafacture.fix/src/main/java/org/metafacture/metamorph/FixBuilder.java @@ -46,6 +46,7 @@ import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.regex.Pattern; /** * Builds a {@link Metafix} from a Fix DSL description @@ -56,7 +57,8 @@ * */ public class FixBuilder { // checkstyle-disable-line ClassDataAbstractionCoupling|ClassFanOutComplexity - private static final String FLUSH_WITH_RECORD = "record"; + private static final String FLUSH_WITH = "flushWith"; + private static final String RECORD = "record"; private final Deque stack = new LinkedList<>(); private final InterceptorFactory interceptorFactory; private final Metafix metafix; @@ -104,22 +106,37 @@ private void processBind(final Expression expression, final EList params // try generic no-args collectors, registered in collectFactory if (collect == null) { - final Map attributes = resolvedAttributeMap(expression, params); + if (!collectFactory.containsKey(expression.getName())) { + throw new IllegalArgumentException("Collector " + expression.getName() + + " not found"); + } + final Map attributes = resolvedAttributeMap(params, theDo.getOptions()); + // flushWith should not be passed to the headPipe object via a + // setter (see newInstance): + attributes.remove(FLUSH_WITH); collect = collectFactory.newInstance(expression.getName(), attributes); } - if (collect != null) { stack.push(new StackFrame(collect)); processSubexpressions(theDo.getElements(), firstParam); - exitCollectorAndFlushWith(null); + // must be set after recursive calls to flush descendants before parent + final String flushWith = resolvedAttribute(resolvedAttributeMap(params, theDo.getOptions()), FLUSH_WITH); + exitCollectorAndFlushWith(flushWith); } } - protected final Map resolvedAttributeMap(final Expression expression, final EList params) { + protected final Map resolvedAttributeMap(final EList params, final Options options) { final Map attributes = new HashMap(); - // TODO implement actual attributes for binds in the grammar attributes.put("name", resolvedAttribute(params, 1)); attributes.put("value", resolvedAttribute(params, 2)); + if (options == null) { + return attributes; + } + final EList keys = options.getKeys(); + final EList values = options.getValues(); + for (int i = 0; i < keys.size() && i < values.size(); i = i + 1) { + attributes.put(keys.get(i), values.get(i)); + } return attributes; } @@ -167,19 +184,22 @@ protected void exitCollectorAndFlushWith(final String flushWith) { } private void registerFlush(final String flushWith, final Collect flushListener) { - final FlushListener interceptor = interceptorFactory.createFlushInterceptor(flushListener); - final FlushListener delegate; - if (interceptor == null) { - delegate = flushListener; - } - else { - delegate = interceptor; - } - if (flushWith.equals(FLUSH_WITH_RECORD)) { - metafix.registerRecordEndFlush(delegate); - } - else { - metafix.registerNamedValueReceiver(flushWith, new Flush(delegate)); + final String[] keysSplit = Pattern.compile("|", Pattern.LITERAL).split(flushWith); + for (final String key : keysSplit) { + final FlushListener interceptor = interceptorFactory.createFlushInterceptor(flushListener); + final FlushListener delegate; + if (interceptor == null) { + delegate = flushListener; + } + else { + delegate = interceptor; + } + if (key.equals(RECORD)) { + metafix.registerRecordEndFlush(delegate); + } + else { + metafix.registerNamedValueReceiver(key, new Flush(delegate)); + } } } @@ -449,6 +469,11 @@ private String resolvedAttribute(final List params, final int i) { // TODO: resolve from vars/map/etc return params.size() < i ? null : params.get(i - 1); } + + private String resolvedAttribute(final Map attributes, final String string) { + // TODO: resolve from vars/map/etc + return attributes.get(string); + } private static class StackFrame { diff --git a/org.metafacture.fix/src/test/java/org/metafacture/metamorph/MetafixDslTest.java b/org.metafacture.fix/src/test/java/org/metafacture/metamorph/MetafixDslTest.java index 6bc87377..ed1dd461 100644 --- a/org.metafacture.fix/src/test/java/org/metafacture/metamorph/MetafixDslTest.java +++ b/org.metafacture.fix/src/test/java/org/metafacture/metamorph/MetafixDslTest.java @@ -628,6 +628,30 @@ public void shouldCombineToEntity() { ordered.verifyNoMoreInteractions(); } + @Test + public void shouldChooseFirstMapFlushWith() { + final Metafix metafix = fix( + "do choose(flushWith: 'd|record')", + " map(a, c)", + " map(b, c)", + "end", + "map(d,e)" // checkstyle-disable-line MultipleStringLiterals + ); + + metafix.startRecord("1"); + metafix.literal("b", LITERAL_B); + metafix.literal("a", LITERAL_A); + metafix.literal("d", LITERAL_B); + metafix.endRecord(); + + final InOrder ordered = Mockito.inOrder(streamReceiver); + ordered.verify(streamReceiver).startRecord("1"); + ordered.verify(streamReceiver).literal("c", LITERAL_A); + ordered.verify(streamReceiver).literal("e", LITERAL_B); + ordered.verify(streamReceiver).endRecord(); + ordered.verifyNoMoreInteractions(); + } + @Test @Disabled("Fix choose flushing") public void shouldChooseFirstMap() {