From 1527c7ed4c96ecec7dc86b73f716f1bb94db4199 Mon Sep 17 00:00:00 2001 From: robokaso Date: Thu, 6 Nov 2008 14:10:39 +0000 Subject: [PATCH] REOPENED - BATCH-896: "DRY" FaultTolerantTasklet implementations added skip buffer cleaning and call skip listeners cautiously --- ...ringFaultTolerantChunkOrientedTasklet.java | 55 ++++++++++++++++++- 1 file changed, 54 insertions(+), 1 deletion(-) diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/step/item/NonbufferingFaultTolerantChunkOrientedTasklet.java b/spring-batch-core/src/main/java/org/springframework/batch/core/step/item/NonbufferingFaultTolerantChunkOrientedTasklet.java index 3bcfcb60d..aa70604a6 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/step/item/NonbufferingFaultTolerantChunkOrientedTasklet.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/step/item/NonbufferingFaultTolerantChunkOrientedTasklet.java @@ -1,11 +1,14 @@ package org.springframework.batch.core.step.item; import java.util.ArrayList; +import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Set; import org.springframework.batch.core.StepContribution; import org.springframework.batch.core.step.skip.ItemSkipPolicy; +import org.springframework.batch.core.step.skip.SkipListenerFailedException; import org.springframework.batch.item.ItemProcessor; import org.springframework.batch.item.ItemReader; import org.springframework.batch.item.ItemWriter; @@ -70,24 +73,74 @@ public class NonbufferingFaultTolerantChunkOrientedTasklet extends // filter inputs marked for skipping final Map skippedInputs = getBufferedSkips(attributes, SKIPPED_INPUTS_KEY); final Map skippedOutputs = getBufferedSkips(attributes, SKIPPED_OUTPUTS_KEY); + final Set inputsIncludingSkips = new HashSet(inputs.size()); + final Set outputsIncludingSkips = new HashSet(inputs.size()); if (!inputs.isEmpty()) { + inputsIncludingSkips.addAll(inputs); inputs.removeAll(skippedInputs.keySet()); final List outputs = new ArrayList(); process(contribution, inputs, outputs, skippedInputs); // filter outputs marked for skipping + outputsIncludingSkips.addAll(outputs); outputs.removeAll(skippedOutputs.keySet()); write(outputs, contribution, skippedOutputs); } - callSkipListeners(skippedReads, skippedInputs, skippedOutputs); + callSkipListenersAndCleanSkipsFromBuffer(skippedReads, skippedInputs, skippedOutputs, inputsIncludingSkips, + outputsIncludingSkips); return result; } + /** + * Identify items successfully skipped in this tasklet iteration, call skip + * listeners and remove skips from buffer. This requires care, because we + * might be processing a different chunk after rollback i.e. items marked + * for skipping from previous tasklet iteration may not have been + * encountered now. + */ + private void callSkipListenersAndCleanSkipsFromBuffer(final List skippedReads, + final Map skippedInputs, final Map skippedOutputs, + final Set inputsIncludingSkips, final Set outputsIncludingSkips) { + for (Exception skippedReadException : skippedReads) { + try { + listener.onSkipInRead(skippedReadException); + } + catch (RuntimeException e) { + throw new SkipListenerFailedException("Fatal exception in SkipListener.", e, skippedReadException); + } + } + skippedReads.clear(); + for (I input : inputsIncludingSkips) { + if (skippedInputs.containsKey(input)) { + try { + listener.onSkipInProcess(input, skippedInputs.get(input)); + } + catch (RuntimeException ex) { + throw new SkipListenerFailedException("Fatal exception in SkipListener.", ex, skippedInputs + .get(input)); + } + skippedInputs.remove(input); + } + } + for (O output : outputsIncludingSkips) { + if (skippedOutputs.containsKey(output)) { + try { + listener.onSkipInWrite(output, skippedOutputs.get(output)); + } + catch (RuntimeException ex) { + throw new SkipListenerFailedException("Fatal exception in skip listener", ex, skippedOutputs + .get(output)); + } + skippedOutputs.remove(output); + } + } + } + /** * Tries to read the item from the reader, in case of exception skip the * skip listener is called and exception is re-thrown (failed read causes