Skip to content

Commit 1c164e8

Browse files
committed
Implement "strict" mode. (#192)
Levels of strictness: - `PROCESS`: Abort process by throwing an exception. - `RECORD`: Ignore (skip) record and log an error. - `EXPRESSION`: Ignore (skip) expression and log a warning. Introduces `FixProcessException` to differentiate from `FixExecutionException`: The latter indicating potentially data-dependent issues that should be subject to strictness handling, while the former should only refer to static issues with the usage of Fix expressions.
1 parent b491cbb commit 1c164e8

File tree

17 files changed

+274
-18
lines changed

17 files changed

+274
-18
lines changed

metafix/src/main/java/org/metafacture/metafix/FixExecutionException.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,12 @@
1818

1919
import org.metafacture.framework.MetafactureException;
2020

21+
/**
22+
* Indicates dynamic (i.e., data-dependent) issues during Fix execution that
23+
* should be subject to {@link Metafix.Strictness strictness} handling.
24+
*
25+
* @see FixProcessException
26+
*/
2127
public class FixExecutionException extends MetafactureException {
2228

2329
public FixExecutionException(final String message) {
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
* Copyright 2022 hbz NRW
3+
*
4+
* Licensed under the Apache License, Version 2.0 the "License";
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.metafacture.metafix;
18+
19+
import org.metafacture.framework.MetafactureException;
20+
21+
/**
22+
* Indicates static (i.e., data-independent) issues with the usage of Fix
23+
* expressions.
24+
*
25+
* @see FixExecutionException
26+
*/
27+
public class FixProcessException extends MetafactureException {
28+
29+
public FixProcessException(final String message) {
30+
super(message);
31+
}
32+
33+
public FixProcessException(final String message, final Throwable cause) {
34+
super(message, cause);
35+
}
36+
37+
}

metafix/src/main/java/org/metafacture/metafix/Metafix.java

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
import java.util.LinkedList;
4646
import java.util.List;
4747
import java.util.Map;
48+
import java.util.function.BiConsumer;
4849

4950
/**
5051
* Transforms a data stream sent via the {@link StreamReceiver} interface. Use
@@ -61,6 +62,8 @@ public class Metafix implements StreamPipe<StreamReceiver>, Maps { // checkstyle
6162
public static final String VAR_END = "]";
6263
public static final String VAR_START = "$[";
6364

65+
public static final Strictness DEFAULT_STRICTNESS = Strictness.PROCESS;
66+
6467
public static final Map<String, String> NO_VARS = Collections.emptyMap();
6568

6669
private static final Logger LOG = LoggerFactory.getLogger(Metafix.class);
@@ -79,6 +82,7 @@ public class Metafix implements StreamPipe<StreamReceiver>, Maps { // checkstyle
7982
private List<Value> entities = new ArrayList<>();
8083
private Record currentRecord = new Record();
8184
private StreamReceiver outputStreamReceiver;
85+
private Strictness strictness = DEFAULT_STRICTNESS;
8286
private String fixFile;
8387
private String recordIdentifier;
8488
private int entityCount;
@@ -325,4 +329,58 @@ public String putValue(final String mapName, final String key, final String valu
325329
return maps.computeIfAbsent(mapName, k -> new HashMap<>()).put(key, value);
326330
}
327331

332+
public void setStrictness(final Strictness strictness) {
333+
this.strictness = strictness != null ? strictness : DEFAULT_STRICTNESS;
334+
}
335+
336+
public Strictness getStrictness() {
337+
return strictness;
338+
}
339+
340+
public enum Strictness {
341+
342+
/**
343+
* Aborts process by throwing an exception.
344+
*/
345+
PROCESS {
346+
@Override
347+
protected void handleInternal(final FixExecutionException exception, final Record record) {
348+
throw exception;
349+
}
350+
},
351+
352+
/**
353+
* Ignores (skips) record and logs an error.
354+
*/
355+
RECORD {
356+
@Override
357+
protected void handleInternal(final FixExecutionException exception, final Record record) {
358+
log(exception, LOG::error);
359+
record.setReject(true); // TODO: Skip remaining expressions?
360+
}
361+
},
362+
363+
/**
364+
* Ignores (skips) expression and logs a warning.
365+
*/
366+
EXPRESSION {
367+
@Override
368+
protected void handleInternal(final FixExecutionException exception, final Record record) {
369+
log(exception, LOG::warn);
370+
}
371+
};
372+
373+
public void handle(final FixExecutionException exception, final Record record) {
374+
LOG.debug("Current record: {}", record);
375+
handleInternal(exception, record);
376+
}
377+
378+
protected abstract void handleInternal(FixExecutionException exception, Record record);
379+
380+
protected void log(final FixExecutionException exception, final BiConsumer<String, Throwable> logger) {
381+
logger.accept(exception.getMessage(), exception.getCause());
382+
}
383+
384+
}
385+
328386
}

metafix/src/main/java/org/metafacture/metafix/RecordTransformer.java

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ else if (e instanceof MethodCall) {
9898
processFunction((MethodCall) e, params);
9999
}
100100
else {
101-
throw new FixExecutionException(executionExceptionMessage(e));
101+
throw new FixProcessException(executionExceptionMessage(e));
102102
}
103103
});
104104
}
@@ -173,15 +173,26 @@ private void processExpression(final Expression expression, final Consumer<Strin
173173
}
174174

175175
private void processFix(final Supplier<String> messageSupplier, final Runnable runnable) {
176+
final FixExecutionException exception;
177+
176178
try {
177179
runnable.run();
180+
return;
178181
}
179-
catch (final FixExecutionException e) {
182+
catch (final FixProcessException e) {
180183
throw e; // TODO: Add nesting information?
181184
}
185+
catch (final FixExecutionException e) {
186+
exception = e; // TODO: Add nesting information?
187+
}
188+
catch (final IllegalStateException | NumberFormatException e) {
189+
exception = new FixExecutionException(messageSupplier.get(), e);
190+
}
182191
catch (final RuntimeException e) { // checkstyle-disable-line IllegalCatch
183-
throw new FixExecutionException(messageSupplier.get(), e);
192+
throw new FixProcessException(messageSupplier.get(), e);
184193
}
194+
195+
metafix.getStrictness().handle(exception, record);
185196
}
186197

187198
private String executionExceptionMessage(final Expression expression) {

metafix/src/test/java/org/metafacture/metafix/MetafixLookupTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -159,7 +159,7 @@ public void shouldLookupInSeparateExternalFileMap() {
159159
public void shouldNotLookupInRelativeExternalFileMapFromInlineScript() {
160160
final String mapFile = "../maps/test.csv";
161161

162-
MetafixTestHelpers.assertThrowsCause(IllegalArgumentException.class, "Cannot resolve relative path: " + mapFile, () ->
162+
MetafixTestHelpers.assertProcessException(IllegalArgumentException.class, "Cannot resolve relative path: " + mapFile, () ->
163163
MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList(
164164
LOOKUP + " '" + mapFile + "')"
165165
),
@@ -299,7 +299,7 @@ public void shouldNotLookupInUnknownInternalMap() {
299299

300300
@Test
301301
public void shouldFailLookupInUnknownExternalMap() {
302-
MetafixTestHelpers.assertThrowsCause(MorphExecutionException.class, "File not found: testMap.csv", () ->
302+
MetafixTestHelpers.assertProcessException(MorphExecutionException.class, "File not found: testMap.csv", () ->
303303
MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList(
304304
LOOKUP + " 'testMap.csv')"
305305
),

metafix/src/test/java/org/metafacture/metafix/MetafixMethodTest.java

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ public void shouldCapitalizeStringsInArray() {
160160

161161
@Test
162162
public void shouldNotCapitalizeArray() {
163-
MetafixTestHelpers.assertThrowsCause(IllegalStateException.class, "Expected String, got Array", () ->
163+
MetafixTestHelpers.assertExecutionException(IllegalStateException.class, "Expected String, got Array", () ->
164164
MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList(
165165
"capitalize('title')"
166166
),
@@ -431,7 +431,7 @@ public void parseTextMixedGroups() {
431431

432432
@Test
433433
public void parseTextEscapedGroups() {
434-
MetafixTestHelpers.assertThrowsCause(IllegalArgumentException.class, "No group with name <c>", () ->
434+
MetafixTestHelpers.assertProcessException(IllegalArgumentException.class, "No group with name <c>", () ->
435435
MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList(
436436
"parse_text(data, '(?<a>.)(.)\\\\(?<c>.\\\\)')"
437437
),
@@ -448,7 +448,7 @@ public void parseTextEscapedGroups() {
448448

449449
@Test
450450
public void parseTextQuotedGroups() {
451-
MetafixTestHelpers.assertThrowsCause(IllegalArgumentException.class, "No group with name <c>", () ->
451+
MetafixTestHelpers.assertProcessException(IllegalArgumentException.class, "No group with name <c>", () ->
452452
MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList(
453453
"parse_text(data, '(?<a>.)(.)\\\\Q(?<c>.)\\\\E')"
454454
),
@@ -669,7 +669,7 @@ public void shouldAppendValueInEntireArray() {
669669
@Test
670670
// See https://github.com/metafacture/metafacture-fix/issues/100
671671
public void shouldNotAppendValueToArray() {
672-
MetafixTestHelpers.assertThrowsCause(IllegalStateException.class, "Expected String, got Array", () ->
672+
MetafixTestHelpers.assertExecutionException(IllegalStateException.class, "Expected String, got Array", () ->
673673
MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList(
674674
"append('animals[]', ' is cool')"
675675
),
@@ -691,7 +691,7 @@ public void shouldNotAppendValueToArray() {
691691
@Test
692692
// See https://github.com/metafacture/metafacture-fix/issues/100
693693
public void shouldNotAppendValueToHash() {
694-
MetafixTestHelpers.assertThrowsCause(IllegalStateException.class, "Expected String, got Hash", () ->
694+
MetafixTestHelpers.assertExecutionException(IllegalStateException.class, "Expected String, got Hash", () ->
695695
MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList(
696696
"append('animals', ' is cool')"
697697
),
@@ -1126,7 +1126,7 @@ public void shouldPrependValueInArraySubField() {
11261126
@Test
11271127
// See https://github.com/metafacture/metafacture-fix/issues/100
11281128
public void shouldNotPrependValueToArray() {
1129-
MetafixTestHelpers.assertThrowsCause(IllegalStateException.class, "Expected String, got Array", () ->
1129+
MetafixTestHelpers.assertExecutionException(IllegalStateException.class, "Expected String, got Array", () ->
11301130
MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList(
11311131
"prepend('animals[]', 'cool ')"
11321132
),
@@ -1592,7 +1592,7 @@ public void shouldSortFieldNumerically() {
15921592

15931593
@Test
15941594
public void shouldFailToSortNumericallyWithInvalidNumber() {
1595-
MetafixTestHelpers.assertThrowsCause(NumberFormatException.class, "For input string: \"x\"", () ->
1595+
MetafixTestHelpers.assertExecutionException(NumberFormatException.class, "For input string: \"x\"", () ->
15961596
MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList(
15971597
"sort_field(numbers, numeric: 'true')"
15981598
),

metafix/src/test/java/org/metafacture/metafix/MetafixRecordTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1083,7 +1083,7 @@ public void addFieldToObjectByIndexMissing() {
10831083
}
10841084

10851085
private void assertThrowsOnEmptyRecord(final String index) {
1086-
MetafixTestHelpers.assertThrowsCause(IllegalArgumentException.class, "Using ref, but can't find: " + index + " in: {}", () -> {
1086+
MetafixTestHelpers.assertProcessException(IllegalArgumentException.class, "Using ref, but can't find: " + index + " in: {}", () -> {
10871087
MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList(
10881088
"add_field('animals[]." + index + ".kind','nice')"
10891089
),
@@ -2150,7 +2150,7 @@ public void accessArrayByIndex() {
21502150

21512151
@Test
21522152
public void shouldNotAccessArrayImplicitly() {
2153-
MetafixTestHelpers.assertThrowsCause(IllegalStateException.class, "Expected String, got Array", () ->
2153+
MetafixTestHelpers.assertExecutionException(IllegalStateException.class, "Expected String, got Array", () ->
21542154
MetafixTestHelpers.assertFix(streamReceiver, Arrays.asList(
21552155
"upcase('name')"
21562156
),

0 commit comments

Comments
 (0)