Skip to content

Commit 6f871cc

Browse files
committed
Preserve same entity in nested pass-through (_elseNested).
* 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.
1 parent 226cf21 commit 6f871cc

File tree

2 files changed

+233
-29
lines changed

2 files changed

+233
-29
lines changed

metamorph/src/main/java/org/metafacture/metamorph/Metamorph.java

Lines changed: 36 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,8 @@ public final class Metamorph implements StreamPipe<StreamReceiver>, NamedValuePi
100100
private int recordCount;
101101
private final List<FlushListener> recordEndListener = new ArrayList<>();
102102
private boolean elseNested;
103-
final private Pattern literalPatternOfEntityMarker = Pattern.compile(flattener.getEntityMarker(), Pattern.LITERAL);
103+
private boolean elseNestedEntityStarted;
104+
private String currentLiteralName;
104105
private static final Logger LOG = LoggerFactory.getLogger(Metamorph.class);
105106

106107
protected Metamorph() {
@@ -202,7 +203,7 @@ private void init() {
202203
flattener.setReceiver(new DefaultStreamReceiver() {
203204
@Override
204205
public void literal(final String name, final String value) {
205-
dispatch(name, value, getElseSources());
206+
dispatch(name, value, getElseSources(), false);
206207
}
207208
});
208209
}
@@ -252,7 +253,7 @@ public void startRecord(final String identifier) {
252253
final String identifierFinal = identifier;
253254

254255
outputStreamReceiver.startRecord(identifierFinal);
255-
dispatch(StandardEventNames.ID, identifierFinal, null);
256+
dispatch(StandardEventNames.ID, identifierFinal, null, false);
256257
}
257258

258259
@Override
@@ -285,14 +286,15 @@ public void startEntity(final String name) {
285286

286287
@Override
287288
public void endEntity() {
288-
dispatch(flattener.getCurrentPath(), "", null);
289+
dispatch(flattener.getCurrentPath(), "", getElseSources(), true);
289290
currentEntityCount = entityCountStack.pop().intValue();
290291
flattener.endEntity();
291292
}
292293

293294

294295
@Override
295296
public void literal(final String name, final String value) {
297+
currentLiteralName = name;
296298
flattener.literal(name, value);
297299
}
298300

@@ -314,38 +316,44 @@ public void closeStream() {
314316
outputStreamReceiver.closeStream();
315317
}
316318

317-
protected void dispatch(final String path, final String value, final List<NamedValueReceiver> fallbackReceiver) {
318-
List<NamedValueReceiver> matchingData = dataRegistry.get(path);
319-
boolean fallback = false;
320-
if (matchingData == null || matchingData.isEmpty()) {
321-
fallback = true;
322-
matchingData = fallbackReceiver;
319+
private void dispatch(final String path, final String value, final List<NamedValueReceiver> fallbackReceiver, final boolean endEntity) {
320+
final List<NamedValueReceiver> matchingData = dataRegistry.get(path);
321+
322+
if (matchingData != null && !matchingData.isEmpty()) {
323+
send(path, value, matchingData);
323324
}
324-
if (null != matchingData) {
325-
send(path, value, matchingData, fallback);
325+
else if (fallbackReceiver != null) {
326+
if (endEntity) {
327+
if (elseNestedEntityStarted) {
328+
outputStreamReceiver.endEntity();
329+
elseNestedEntityStarted = false;
330+
}
331+
}
332+
else {
333+
final String entityName = elseNested ? flattener.getCurrentEntityName() : null;
334+
335+
if (entityName != null) {
336+
if (!elseNestedEntityStarted) {
337+
outputStreamReceiver.startEntity(entityName);
338+
elseNestedEntityStarted = true;
339+
}
340+
341+
send(currentLiteralName, value, fallbackReceiver);
342+
}
343+
else {
344+
send(path, value, fallbackReceiver);
345+
}
346+
}
326347
}
327348
}
328349

329-
private void send(final String path, final String value, final List<NamedValueReceiver> dataList,
330-
final boolean fallback) {
350+
private void send(final String path, final String value, final List<NamedValueReceiver> dataList) {
331351
for (final NamedValueReceiver data : dataList) {
332-
String key = path;
333-
if (fallback && elseNested) {
334-
if (flattener.getCurrentEntityName() != null) {
335-
outputStreamReceiver.startEntity(flattener.getCurrentEntityName());
336-
key = literalPatternOfEntityMarker.split(path)[1];
337-
}
338-
}
339352
try {
340-
data.receive(key, value, null, recordCount, currentEntityCount);
353+
data.receive(path, value, null, recordCount, currentEntityCount);
341354
} catch (final RuntimeException e) {
342355
errorHandler.error(e);
343356
}
344-
if (fallback && elseNested) {
345-
if (flattener.getCurrentEntityName() != null) {
346-
outputStreamReceiver.endEntity();
347-
}
348-
}
349357
}
350358
}
351359

@@ -375,7 +383,7 @@ public void receive(final String name, final String value, final NamedValueSourc
375383
}
376384

377385
if (name.length() != 0 && name.charAt(0) == FEEDBACK_CHAR) {
378-
dispatch(name, value, null);
386+
dispatch(name, value, null, false);
379387
return;
380388
}
381389

metamorph/src/test/java/org/metafacture/metamorph/TestMetamorphBasics.java

Lines changed: 197 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,13 +98,19 @@ public void shouldHandleUnmatchedLiteralsAndEntitiesInElseFlattenedSource() {
9898
private void testElseData(final String elseKeyword) {
9999
assertMorph(receiver,
100100
"<rules>" +
101+
" <entity name='Germany'>" +
102+
" <data source='Germany.Sylt' name='Hawaii' />" +
103+
" <data source='Germany.Borkum' />" +
104+
" </entity>" +
101105
" <data source='" + elseKeyword + "'/>" +
102106
"</rules>",
103107
i -> {
104108
i.startRecord("1");
105109
i.literal("Shikotan", "Aekap");
106110
i.startEntity("Germany");
107111
i.literal("Langeoog", "Moin");
112+
i.literal("Sylt", "Aloha");
113+
i.literal("Borkum", "Tach");
108114
i.endEntity();
109115
i.startEntity("Germany");
110116
i.literal("Baltrum", "Moin Moin");
@@ -115,12 +121,97 @@ private void testElseData(final String elseKeyword) {
115121
o.get().startRecord("1");
116122
o.get().literal("Shikotan", "Aekap");
117123
o.get().literal("Germany.Langeoog", "Moin");
124+
o.get().startEntity("Germany");
125+
o.get().literal("Hawaii", "Aloha");
126+
o.get().literal("Germany.Borkum", "Tach");
127+
o.get().endEntity();
118128
o.get().literal("Germany.Baltrum", "Moin Moin");
119129
o.get().endRecord();
120130
}
121131
);
122132
}
123133

134+
@Test
135+
public void issue338_shouldPreserveSameEntitiesInElseNestedSource() {
136+
assertMorph(receiver,
137+
"<rules>" +
138+
" <data source='_elseNested' />" +
139+
"</rules>",
140+
i -> {
141+
i.startRecord("1");
142+
i.literal("lit1", "val1");
143+
i.startEntity("ent1");
144+
i.literal("lit2", "val2");
145+
i.literal("lit3", "val3");
146+
i.endEntity();
147+
i.literal("lit4", "val4");
148+
i.startEntity("ent2");
149+
i.literal("lit5", "val5");
150+
i.literal("lit6", "val6");
151+
i.literal("lit7", "val7");
152+
i.endEntity();
153+
i.startEntity("ent2"); // sic!
154+
i.literal("lit8", "val8");
155+
i.literal("lit9", "val9");
156+
i.endEntity();
157+
i.endRecord();
158+
i.startRecord("2");
159+
i.startEntity("ent1");
160+
i.literal("lit1", "val1");
161+
i.literal("lit2", "val2");
162+
i.endEntity();
163+
i.startEntity("ent2");
164+
i.literal("lit3", "val3");
165+
i.literal("lit4", "val4");
166+
i.literal("lit5", "val5");
167+
i.literal("lit6", "val6");
168+
i.endEntity();
169+
i.startEntity("ent3");
170+
i.literal("lit7", "val7");
171+
i.literal("lit8", "val8");
172+
i.endEntity();
173+
i.literal("lit9", "val9");
174+
i.endRecord();
175+
},
176+
o -> {
177+
o.get().startRecord("1");
178+
o.get().literal("lit1", "val1");
179+
o.get().startEntity("ent1");
180+
o.get().literal("lit2", "val2");
181+
o.get().literal("lit3", "val3");
182+
o.get().endEntity();
183+
o.get().literal("lit4", "val4");
184+
o.get().startEntity("ent2");
185+
o.get().literal("lit5", "val5");
186+
o.get().literal("lit6", "val6");
187+
o.get().literal("lit7", "val7");
188+
o.get().endEntity();
189+
o.get().startEntity("ent2");
190+
o.get().literal("lit8", "val8");
191+
o.get().literal("lit9", "val9");
192+
o.get().endEntity();
193+
o.get().endRecord();
194+
o.get().startRecord("2");
195+
o.get().startEntity("ent1");
196+
o.get().literal("lit1", "val1");
197+
o.get().literal("lit2", "val2");
198+
o.get().endEntity();
199+
o.get().startEntity("ent2");
200+
o.get().literal("lit3", "val3");
201+
o.get().literal("lit4", "val4");
202+
o.get().literal("lit5", "val5");
203+
o.get().literal("lit6", "val6");
204+
o.get().endEntity();
205+
o.get().startEntity("ent3");
206+
o.get().literal("lit7", "val7");
207+
o.get().literal("lit8", "val8");
208+
o.get().endEntity();
209+
o.get().literal("lit9", "val9");
210+
o.get().endRecord();
211+
}
212+
);
213+
}
214+
124215
@Test
125216
public void shouldHandleUnmatchedLiteralsAndEntitiesInElseNestedSource() {
126217
assertMorph(receiver,
@@ -147,13 +238,118 @@ public void shouldHandleUnmatchedLiteralsAndEntitiesInElseNestedSource() {
147238
o.get().literal("Shikotan", "Aekap");
148239
o.get().startEntity("Germany");
149240
o.get().literal("Langeoog", "Moin");
241+
o.get().literal("Baltrum", "Moin Moin");
242+
o.get().endEntity();
243+
o.get().startEntity("USA");
244+
o.get().literal("Hawaii", "Aloha");
150245
o.get().endEntity();
246+
o.get().endRecord();
247+
}
248+
);
249+
}
250+
251+
@Test
252+
public void shouldHandlePartiallyUnmatchedLiteralsAndEntitiesInElseNestedSource() {
253+
assertMorph(receiver,
254+
"<rules>" +
255+
" <entity name='USA1'>" +
256+
" <data source='USA1.Sylt' name='Hawaii' />" +
257+
" </entity>" +
258+
" <entity name='USA2'>" +
259+
" <data source='USA2.Sylt' name='Hawaii' />" +
260+
" </entity>" +
261+
" <entity name='USA3'>" +
262+
" <data source='USA3.Sylt' name='Hawaii' />" +
263+
" </entity>" +
264+
" <entity name='USA4'>" +
265+
" <data source='USA4.Sylt' name='Hawaii' />" +
266+
" </entity>" +
267+
" <data source='_elseNested' />" +
268+
"</rules>",
269+
i -> {
270+
i.startRecord("1");
271+
i.literal("Shikotan", "Aekap");
272+
i.startEntity("Germany");
273+
i.literal("Langeoog", "Moin");
274+
i.literal("Baltrum", "Moin Moin");
275+
i.endEntity();
276+
i.startEntity("USA1");
277+
i.literal("Sylt", "Aloha");
278+
i.endEntity();
279+
i.startEntity("USA2");
280+
i.literal("Sylt", "Aloha");
281+
i.literal("Langeoog", "Moin");
282+
i.literal("Baltrum", "Moin Moin");
283+
i.endEntity();
284+
i.startEntity("USA3");
285+
i.literal("Langeoog", "Moin");
286+
i.literal("Sylt", "Aloha");
287+
i.literal("Baltrum", "Moin Moin");
288+
i.endEntity();
289+
i.startEntity("USA4");
290+
i.literal("Langeoog", "Moin");
291+
i.literal("Baltrum", "Moin Moin");
292+
i.literal("Sylt", "Aloha");
293+
i.endEntity();
294+
i.endRecord();
295+
},
296+
(o, f) -> {
297+
final boolean coordinatesWithEntity = false;
298+
final boolean separatesFromEntity = false;
299+
o.get().startRecord("1");
300+
o.get().literal("Shikotan", "Aekap");
151301
o.get().startEntity("Germany");
302+
o.get().literal("Langeoog", "Moin");
152303
o.get().literal("Baltrum", "Moin Moin");
153304
o.get().endEntity();
154-
o.get().startEntity("USA");
305+
o.get().startEntity("USA1");
306+
o.get().literal("Hawaii", "Aloha");
307+
o.get().endEntity();
308+
o.get().startEntity("USA2");
309+
o.get().literal("Hawaii", "Aloha");
310+
if (!coordinatesWithEntity) {
311+
o.get().endEntity();
312+
o.get().startEntity("USA2");
313+
}
314+
o.get().literal("Langeoog", "Moin");
315+
o.get().literal("Baltrum", "Moin Moin");
316+
o.get().endEntity();
317+
o.get().startEntity("USA3");
318+
o.get().literal("Langeoog", "Moin");
319+
if (!coordinatesWithEntity) {
320+
o.get().startEntity("USA3");
321+
}
322+
else if (separatesFromEntity) {
323+
o.get().endEntity();
324+
o.get().startEntity("USA3");
325+
}
326+
o.get().literal("Hawaii", "Aloha");
327+
if (!coordinatesWithEntity) {
328+
o.get().endEntity();
329+
}
330+
else if (separatesFromEntity) {
331+
o.get().endEntity();
332+
o.get().startEntity("USA3");
333+
}
334+
o.get().literal("Baltrum", "Moin Moin");
335+
o.get().endEntity();
336+
o.get().startEntity("USA4");
337+
o.get().literal("Langeoog", "Moin");
338+
o.get().literal("Baltrum", "Moin Moin");
339+
if (!coordinatesWithEntity) {
340+
o.get().startEntity("USA4");
341+
}
342+
else if (separatesFromEntity) {
343+
o.get().endEntity();
344+
o.get().startEntity("USA4");
345+
}
155346
o.get().literal("Hawaii", "Aloha");
347+
if (!coordinatesWithEntity) {
348+
f.apply(2).endEntity();
349+
}
350+
else {
156351
o.get().endEntity();
352+
}
157353
o.get().endRecord();
158354
}
159355
);

0 commit comments

Comments
 (0)