Skip to content

Commit

Permalink
Preserve same entity in nested pass-through (_elseNested).
Browse files Browse the repository at this point in the history
* Fixes #338 (see test `shouldHandleUnmatchedLiteralsAndEntitiesInElseNestedSource`; e4c6fe5).
* Doesn't work with partially handled entities (see test `shouldHandlePartiallyUnmatchedLiteralsAndEntitiesInElseNestedSource`).
  * It should either coordinate with `Entity` w.r.t. starting/ending entities.
  * Or separate pass-through entities from explicitly specified entities.
  • Loading branch information
blackwinter committed Nov 5, 2020
1 parent 226cf21 commit 9e865eb
Show file tree
Hide file tree
Showing 2 changed files with 233 additions and 29 deletions.
64 changes: 36 additions & 28 deletions metamorph/src/main/java/org/metafacture/metamorph/Metamorph.java
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,8 @@ public final class Metamorph implements StreamPipe<StreamReceiver>, NamedValuePi
private int recordCount;
private final List<FlushListener> recordEndListener = new ArrayList<>();
private boolean elseNested;
final private Pattern literalPatternOfEntityMarker = Pattern.compile(flattener.getEntityMarker(), Pattern.LITERAL);
private boolean elseNestedEntityStarted;
private String currentLiteralName;
private static final Logger LOG = LoggerFactory.getLogger(Metamorph.class);

protected Metamorph() {
Expand Down Expand Up @@ -202,7 +203,7 @@ private void init() {
flattener.setReceiver(new DefaultStreamReceiver() {
@Override
public void literal(final String name, final String value) {
dispatch(name, value, getElseSources());
dispatch(name, value, getElseSources(), false);
}
});
}
Expand Down Expand Up @@ -252,7 +253,7 @@ public void startRecord(final String identifier) {
final String identifierFinal = identifier;

outputStreamReceiver.startRecord(identifierFinal);
dispatch(StandardEventNames.ID, identifierFinal, null);
dispatch(StandardEventNames.ID, identifierFinal, null, false);
}

@Override
Expand Down Expand Up @@ -285,14 +286,15 @@ public void startEntity(final String name) {

@Override
public void endEntity() {
dispatch(flattener.getCurrentPath(), "", null);
dispatch(flattener.getCurrentPath(), "", getElseSources(), true);
currentEntityCount = entityCountStack.pop().intValue();
flattener.endEntity();
}


@Override
public void literal(final String name, final String value) {
currentLiteralName = name;
flattener.literal(name, value);
}

Expand All @@ -314,38 +316,44 @@ public void closeStream() {
outputStreamReceiver.closeStream();
}

protected void dispatch(final String path, final String value, final List<NamedValueReceiver> fallbackReceiver) {
List<NamedValueReceiver> matchingData = dataRegistry.get(path);
boolean fallback = false;
if (matchingData == null || matchingData.isEmpty()) {
fallback = true;
matchingData = fallbackReceiver;
private void dispatch(final String path, final String value, final List<NamedValueReceiver> fallbackReceiver, final boolean endEntity) {
final List<NamedValueReceiver> matchingData = dataRegistry.get(path);

if (matchingData != null && !matchingData.isEmpty()) {
send(path, value, matchingData);
}
if (null != matchingData) {
send(path, value, matchingData, fallback);
else if (fallbackReceiver != null) {
if (endEntity) {
if (elseNestedEntityStarted) {
outputStreamReceiver.endEntity();
elseNestedEntityStarted = false;
}
}
else {
final String entityName = elseNested ? flattener.getCurrentEntityName() : null;

if (entityName != null) {
if (!elseNestedEntityStarted) {
outputStreamReceiver.startEntity(entityName);
elseNestedEntityStarted = true;
}

send(currentLiteralName, value, fallbackReceiver);
}
else {
send(path, value, fallbackReceiver);
}
}
}
}

private void send(final String path, final String value, final List<NamedValueReceiver> dataList,
final boolean fallback) {
private void send(final String path, final String value, final List<NamedValueReceiver> dataList) {
for (final NamedValueReceiver data : dataList) {
String key = path;
if (fallback && elseNested) {
if (flattener.getCurrentEntityName() != null) {
outputStreamReceiver.startEntity(flattener.getCurrentEntityName());
key = literalPatternOfEntityMarker.split(path)[1];
}
}
try {
data.receive(key, value, null, recordCount, currentEntityCount);
data.receive(path, value, null, recordCount, currentEntityCount);
} catch (final RuntimeException e) {
errorHandler.error(e);
}
if (fallback && elseNested) {
if (flattener.getCurrentEntityName() != null) {
outputStreamReceiver.endEntity();
}
}
}
}

Expand Down Expand Up @@ -375,7 +383,7 @@ public void receive(final String name, final String value, final NamedValueSourc
}

if (name.length() != 0 && name.charAt(0) == FEEDBACK_CHAR) {
dispatch(name, value, null);
dispatch(name, value, null, false);
return;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,13 +98,19 @@ public void shouldHandleUnmatchedLiteralsAndEntitiesInElseFlattenedSource() {
private void testElseData(final String elseKeyword) {
assertMorph(receiver,
"<rules>" +
" <entity name='Germany'>" +
" <data source='Germany.Sylt' name='Hawaii' />" +
" <data source='Germany.Borkum' />" +
" </entity>" +
" <data source='" + elseKeyword + "'/>" +
"</rules>",
i -> {
i.startRecord("1");
i.literal("Shikotan", "Aekap");
i.startEntity("Germany");
i.literal("Langeoog", "Moin");
i.literal("Sylt", "Aloha");
i.literal("Borkum", "Tach");
i.endEntity();
i.startEntity("Germany");
i.literal("Baltrum", "Moin Moin");
Expand All @@ -115,12 +121,97 @@ private void testElseData(final String elseKeyword) {
o.get().startRecord("1");
o.get().literal("Shikotan", "Aekap");
o.get().literal("Germany.Langeoog", "Moin");
o.get().startEntity("Germany");
o.get().literal("Hawaii", "Aloha");
o.get().literal("Germany.Borkum", "Tach");
o.get().endEntity();
o.get().literal("Germany.Baltrum", "Moin Moin");
o.get().endRecord();
}
);
}

@Test
public void issue338_shouldPreserveSameEntitiesInElseNestedSource() {
assertMorph(receiver,
"<rules>" +
" <data source='_elseNested' />" +
"</rules>",
i -> {
i.startRecord("1");
i.literal("lit1", "val1");
i.startEntity("ent1");
i.literal("lit2", "val2");
i.literal("lit3", "val3");
i.endEntity();
i.literal("lit4", "val4");
i.startEntity("ent2");
i.literal("lit5", "val5");
i.literal("lit6", "val6");
i.literal("lit7", "val7");
i.endEntity();
i.startEntity("ent2"); // sic!
i.literal("lit8", "val8");
i.literal("lit9", "val9");
i.endEntity();
i.endRecord();
i.startRecord("2");
i.startEntity("ent1");
i.literal("lit1", "val1");
i.literal("lit2", "val2");
i.endEntity();
i.startEntity("ent2");
i.literal("lit3", "val3");
i.literal("lit4", "val4");
i.literal("lit5", "val5");
i.literal("lit6", "val6");
i.endEntity();
i.startEntity("ent3");
i.literal("lit7", "val7");
i.literal("lit8", "val8");
i.endEntity();
i.literal("lit9", "val9");
i.endRecord();
},
o -> {
o.get().startRecord("1");
o.get().literal("lit1", "val1");
o.get().startEntity("ent1");
o.get().literal("lit2", "val2");
o.get().literal("lit3", "val3");
o.get().endEntity();
o.get().literal("lit4", "val4");
o.get().startEntity("ent2");
o.get().literal("lit5", "val5");
o.get().literal("lit6", "val6");
o.get().literal("lit7", "val7");
o.get().endEntity();
o.get().startEntity("ent2");
o.get().literal("lit8", "val8");
o.get().literal("lit9", "val9");
o.get().endEntity();
o.get().endRecord();
o.get().startRecord("2");
o.get().startEntity("ent1");
o.get().literal("lit1", "val1");
o.get().literal("lit2", "val2");
o.get().endEntity();
o.get().startEntity("ent2");
o.get().literal("lit3", "val3");
o.get().literal("lit4", "val4");
o.get().literal("lit5", "val5");
o.get().literal("lit6", "val6");
o.get().endEntity();
o.get().startEntity("ent3");
o.get().literal("lit7", "val7");
o.get().literal("lit8", "val8");
o.get().endEntity();
o.get().literal("lit9", "val9");
o.get().endRecord();
}
);
}

@Test
public void shouldHandleUnmatchedLiteralsAndEntitiesInElseNestedSource() {
assertMorph(receiver,
Expand All @@ -147,13 +238,118 @@ public void shouldHandleUnmatchedLiteralsAndEntitiesInElseNestedSource() {
o.get().literal("Shikotan", "Aekap");
o.get().startEntity("Germany");
o.get().literal("Langeoog", "Moin");
o.get().literal("Baltrum", "Moin Moin");
o.get().endEntity();
o.get().startEntity("USA");
o.get().literal("Hawaii", "Aloha");
o.get().endEntity();
o.get().endRecord();
}
);
}

@Test
public void shouldHandlePartiallyUnmatchedLiteralsAndEntitiesInElseNestedSource() {
assertMorph(receiver,
"<rules>" +
" <entity name='USA1'>" +
" <data source='USA1.Sylt' name='Hawaii' />" +
" </entity>" +
" <entity name='USA2'>" +
" <data source='USA2.Sylt' name='Hawaii' />" +
" </entity>" +
" <entity name='USA3'>" +
" <data source='USA3.Sylt' name='Hawaii' />" +
" </entity>" +
" <entity name='USA4'>" +
" <data source='USA4.Sylt' name='Hawaii' />" +
" </entity>" +
" <data source='_elseNested' />" +
"</rules>",
i -> {
i.startRecord("1");
i.literal("Shikotan", "Aekap");
i.startEntity("Germany");
i.literal("Langeoog", "Moin");
i.literal("Baltrum", "Moin Moin");
i.endEntity();
i.startEntity("USA1");
i.literal("Sylt", "Aloha");
i.endEntity();
i.startEntity("USA2");
i.literal("Sylt", "Aloha");
i.literal("Langeoog", "Moin");
i.literal("Baltrum", "Moin Moin");
i.endEntity();
i.startEntity("USA3");
i.literal("Langeoog", "Moin");
i.literal("Sylt", "Aloha");
i.literal("Baltrum", "Moin Moin");
i.endEntity();
i.startEntity("USA4");
i.literal("Langeoog", "Moin");
i.literal("Baltrum", "Moin Moin");
i.literal("Sylt", "Aloha");
i.endEntity();
i.endRecord();
},
(o, f) -> {
final boolean coordinatesWithEntity = false;
final boolean separatesFromEntity = false;
o.get().startRecord("1");
o.get().literal("Shikotan", "Aekap");
o.get().startEntity("Germany");
o.get().literal("Langeoog", "Moin");
o.get().literal("Baltrum", "Moin Moin");
o.get().endEntity();
o.get().startEntity("USA");
o.get().startEntity("USA1");
o.get().literal("Hawaii", "Aloha");
o.get().endEntity();
o.get().startEntity("USA2");
o.get().literal("Hawaii", "Aloha");
if (!coordinatesWithEntity) {
o.get().endEntity();
o.get().startEntity("USA2");
}
o.get().literal("Langeoog", "Moin");
o.get().literal("Baltrum", "Moin Moin");
o.get().endEntity();
o.get().startEntity("USA3");
o.get().literal("Langeoog", "Moin");
if (!coordinatesWithEntity) {
o.get().startEntity("USA3");
}
else if (separatesFromEntity) {
o.get().endEntity();
o.get().startEntity("USA3");
}
o.get().literal("Hawaii", "Aloha");
if (!coordinatesWithEntity) {
o.get().endEntity();
}
else if (separatesFromEntity) {
o.get().endEntity();
o.get().startEntity("USA3");
}
o.get().literal("Baltrum", "Moin Moin");
o.get().endEntity();
o.get().startEntity("USA4");
o.get().literal("Langeoog", "Moin");
o.get().literal("Baltrum", "Moin Moin");
if (!coordinatesWithEntity) {
o.get().startEntity("USA4");
}
else if (separatesFromEntity) {
o.get().endEntity();
o.get().startEntity("USA4");
}
o.get().literal("Hawaii", "Aloha");
if (!coordinatesWithEntity) {
f.apply(2).endEntity();
}
else {
o.get().endEntity();
}
o.get().endRecord();
}
);
Expand Down

0 comments on commit 9e865eb

Please sign in to comment.