diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/MultiResourceItemReader.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/MultiResourceItemReader.java index 7cbfb4df7..125fc0c38 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/MultiResourceItemReader.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/MultiResourceItemReader.java @@ -16,8 +16,7 @@ import org.springframework.util.Assert; * Reset (rollback) capability is implemented by item buffering. To restart * correctly resource ordering needs to be preserved between runs. * - * TODO more robust restart e.g. sort resources alphabetically and store - * filename instead of resource array index. + * @see SortedMultiResourceItemReader * * @author Robert Kasanicky */ diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/SortedMultiResourceItemReader.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/SortedMultiResourceItemReader.java new file mode 100644 index 000000000..a39c648c7 --- /dev/null +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/SortedMultiResourceItemReader.java @@ -0,0 +1,49 @@ +package org.springframework.batch.item; + +import java.util.Arrays; +import java.util.Comparator; + +import org.springframework.core.io.Resource; + +/** + * {@link MultiResourceItemReader} which orders the injected resources using + * {@link #setComparator(Comparator)} to avoid potential problems caused by + * resource re-ordering on restart. + * + * @see MultiResourceItemReader + * + * @author Robert Kasanicky + */ +public class SortedMultiResourceItemReader extends MultiResourceItemReader { + + private Comparator comparator = new Comparator() { + + /** + * Compares resource filenames. + */ + public int compare(Object o1, Object o2) { + Resource r1 = (Resource) o1; + Resource r2 = (Resource) o2; + return r1.getFilename().compareTo(r2.getFilename()); + } + + }; + + /** + * @param comparator used to order the injected resources, by default + * compares {@link Resource#getFilename()} values. + */ + public void setComparator(Comparator comparator) { + this.comparator = comparator; + } + + /** + * Orders the resources using {@link #setComparator(Comparator)} before + * setting them. + */ + public void setResources(Resource[] resources) { + Arrays.sort(resources, comparator); + super.setResources(resources); + } + +} diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/SortedMultiResourceItemReaderTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/SortedMultiResourceItemReaderTests.java new file mode 100644 index 000000000..e94785f8c --- /dev/null +++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/item/SortedMultiResourceItemReaderTests.java @@ -0,0 +1,62 @@ +package org.springframework.batch.item; + +import java.util.Comparator; + +import junit.framework.TestCase; + +import org.springframework.core.io.FileSystemResource; +import org.springframework.core.io.Resource; + +/** + * Tests for {@link SortedMultiResourceItemReader}. + */ +public class SortedMultiResourceItemReaderTests extends TestCase { + + private SortedMultiResourceItemReader tested = new SortedMultiResourceItemReader(); + + private Resource r1 = new FileSystemResource("b"); + + private Resource r2 = new FileSystemResource("a"); + + private Resource r3 = new FileSystemResource("c"); + + private Resource[] resources = { r1, r2, r3 }; + + /** + * Resources are ordered according to filename by default. + */ + public void testResourceOrdering() { + + tested.setResources(resources); + + assertSame(r2, resources[0]); + assertSame(r1, resources[1]); + assertSame(r3, resources[2]); + + } + + /** + * Resources are ordered according to injected comparator. + */ + public void testResourceOrderingWithCustomComparator() { + Comparator comp = new Comparator() { + + /** + * Reversed ordering by filename. + */ + public int compare(Object o1, Object o2) { + Resource r1 = (Resource) o1; + Resource r2 = (Resource) o2; + return -r1.getFilename().compareTo(r2.getFilename()); + } + + }; + + tested.setComparator(comp); + tested.setResources(resources); + + assertSame(r3, resources[0]); + assertSame(r1, resources[1]); + assertSame(r2, resources[2]); + } +}