From 51a0c2952723a5faeb9c9878bec879748187d026 Mon Sep 17 00:00:00 2001 From: dsyer Date: Fri, 5 Oct 2007 15:02:48 +0000 Subject: [PATCH] IN PROGRESS - issue BATCH-145: Move CollectionItemProvider to infrastructure from samples http://opensource.atlassian.com/projects/spring/browse/BATCH-145 --- .../item/provider/CollectionItemProvider.java | 134 ++++++++++-------- ....java => CollectionItemProviderTests.java} | 14 +- 2 files changed, 82 insertions(+), 66 deletions(-) rename samples/src/test/java/org/springframework/batch/sample/item/provider/{CollectionItemProviderTest.java => CollectionItemProviderTests.java} (77%) diff --git a/samples/src/main/java/org/springframework/batch/sample/item/provider/CollectionItemProvider.java b/samples/src/main/java/org/springframework/batch/sample/item/provider/CollectionItemProvider.java index 28e27dfbd..2edd91ba4 100644 --- a/samples/src/main/java/org/springframework/batch/sample/item/provider/CollectionItemProvider.java +++ b/samples/src/main/java/org/springframework/batch/sample/item/provider/CollectionItemProvider.java @@ -21,81 +21,101 @@ import java.util.Collection; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.springframework.batch.io.InputSource; import org.springframework.batch.io.file.FieldSet; import org.springframework.batch.io.file.FieldSetInputSource; import org.springframework.batch.io.file.FieldSetMapper; +import org.springframework.batch.item.ItemProvider; import org.springframework.batch.item.provider.AbstractItemProvider; - +/** + * An {@link ItemProvider} that delivers a list as its item, storing up objects + * from the injected {@link InputSource} until they are ready to be packed out + * as a collection.
+ * + * This class is thread safe (it can be used concurrently by multiple threads) as + * long as the {@link InputSource} is also thread safe. + * + * @author Dave Syer + * + */ public class CollectionItemProvider extends AbstractItemProvider { - - private static final Log log = LogFactory.getLog(CollectionItemProvider.class); - - private FieldSetInputSource inputSource; - //collects simple records - private Collection multiRecord; + private static final Log log = LogFactory + .getLog(CollectionItemProvider.class); - //marks we have finished reading one whole multiRecord - private boolean recordFinished; + private FieldSetInputSource inputSource; - //mapps a sigle line to a simple record - private FieldSetMapper fieldSetMapper; + // maps a single line to a simple record + private FieldSetMapper fieldSetMapper; - public Object next() { - recordFinished = false; + /** + * Get the next list of records. + * + * @see org.springframework.batch.item.ItemProvider#next() + */ + public Object next() { + ResultHolder holder = new ResultHolder(); - while (!recordFinished) { - process(inputSource.readFieldSet()); - } + while (process(inputSource.readFieldSet(), holder)) { + continue; + } - if (multiRecord != null) { - Collection result = new ArrayList(multiRecord); - multiRecord = null; + if (!holder.exhausted) { + return holder.records; + } else { + return null; + } + } - return result; - } else { - return null; - } - } + private boolean process(FieldSet fieldSet, ResultHolder holder) { + // finish processing if we hit the end of file + if (fieldSet == null) { + log.debug("Exhausted InputSource"); + holder.exhausted = true; + return false; + } - private void process(FieldSet fieldSet) { - //finish processing if we hit the end of file - if (fieldSet == null) { - log.debug("FINISHED"); - recordFinished = true; - multiRecord = null; + // start a new collection + if (fieldSet.readString(0).equals("BEGIN")) { + log.debug("Start of new record detected"); + return true; + } - return; - } + // mark we are finished with current collection + if (fieldSet.readString(0).equals("END")) { + log.debug("End of record detected"); + return false; + } - //start a new collection - if (fieldSet.readString(0).equals("BEGIN")) { - log.debug("STARTING NEW RECORD"); - multiRecord = new ArrayList(); + // add a simple record to the current collection + log.debug("Mapping: " + fieldSet); + holder.records.add(fieldSetMapper.mapLine(fieldSet)); + return true; + } - return; - } + /** + * Injection setter for {@link InputSource}. + * @param inputSource an {@link InputSource}. + */ + public void setInputSource(FieldSetInputSource inputSource) { + this.inputSource = inputSource; + } - //mark we are finished with current collection - if (fieldSet.readString(0).equals("END")) { - log.debug("END OF RECORD"); - recordFinished = true; + public void setFieldSetMapper(FieldSetMapper mapper) { + this.fieldSetMapper = mapper; + } - return; - } - - //add a simple record to the current collection - log.debug("MAPPING: " + fieldSet); - multiRecord.add(fieldSetMapper.mapLine(fieldSet)); - } - - public void setInputSource(FieldSetInputSource inputTemplate) { - this.inputSource = inputTemplate; - } - - public void setFieldSetMapper(FieldSetMapper mapper) { - this.fieldSetMapper = mapper; - } + /** + * Private class for temporary state management while item is being + * collected. + * + * @author Dave Syer + * + */ + private class ResultHolder { + Collection records = new ArrayList(); + boolean exhausted = false; + } } diff --git a/samples/src/test/java/org/springframework/batch/sample/item/provider/CollectionItemProviderTest.java b/samples/src/test/java/org/springframework/batch/sample/item/provider/CollectionItemProviderTests.java similarity index 77% rename from samples/src/test/java/org/springframework/batch/sample/item/provider/CollectionItemProviderTest.java rename to samples/src/test/java/org/springframework/batch/sample/item/provider/CollectionItemProviderTests.java index a2b5e45fd..cb515c705 100644 --- a/samples/src/test/java/org/springframework/batch/sample/item/provider/CollectionItemProviderTest.java +++ b/samples/src/test/java/org/springframework/batch/sample/item/provider/CollectionItemProviderTests.java @@ -11,11 +11,10 @@ import org.springframework.batch.io.file.FieldSetInputSource; import org.springframework.batch.io.file.FieldSetMapper; import org.springframework.batch.sample.item.provider.CollectionItemProvider; -public class CollectionItemProviderTest extends TestCase { +public class CollectionItemProviderTests extends TestCase { private MockControl inputControl; private FieldSetInputSource input; - private MockControl mapperControl; private FieldSetMapper mapper; private CollectionItemProvider provider; @@ -26,12 +25,9 @@ public class CollectionItemProviderTest extends TestCase { input = (FieldSetInputSource) inputControl.getMock(); //create mock for mapper - mapperControl = MockControl.createControl(FieldSetMapper.class); - mapper = (FieldSetMapper) mapperControl.getMock(); - mapperControl.setDefaultMatcher(MockControl.ALWAYS_MATCHER); - mapper.mapLine(null); - mapperControl.setDefaultReturnValue("line"); - mapperControl.replay(); + mapper = new FieldSetMapper() { + public Object mapLine(FieldSet fs) { return fs.readString(0); } + }; //create provider provider = new CollectionItemProvider(); @@ -55,7 +51,7 @@ public class CollectionItemProviderTest extends TestCase { //read object Object result = provider.next(); - //it should be collection od 3 strings "line" + //it should be collection of 3 strings "line" assertTrue(result instanceof Collection); Collection lines = (Collection)result; assertEquals(3, lines.size());