RESOLVED - issue BATCH-205: support for processing chain
http://opensource.atlassian.com/projects/spring/browse/BATCH-205 Patch applied.
This commit is contained in:
@@ -0,0 +1,42 @@
|
||||
package org.springframework.batch.item.processor;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Composite {@link ItemTransformer} that passes the item through a sequence
|
||||
* of injected <code>ItemTransformer</code>s (return value of previous transformation
|
||||
* is the entry value of the next).
|
||||
*
|
||||
* @author Robert Kasanicky
|
||||
*/
|
||||
public class CompositeItemTransformer implements ItemTransformer, InitializingBean {
|
||||
|
||||
private List itemTransformers;
|
||||
|
||||
public Object transform(Object item) {
|
||||
Object result = item;
|
||||
for (Iterator iterator = itemTransformers.listIterator(); iterator.hasNext();) {
|
||||
result = ((ItemTransformer)iterator.next()).transform(result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.notEmpty(itemTransformers);
|
||||
for (Iterator iterator = itemTransformers.iterator(); iterator.hasNext();) {
|
||||
Assert.isInstanceOf(ItemTransformer.class, iterator.next());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param itemTransformers will be chained to produce a composite transformation.
|
||||
*/
|
||||
public void setItemTransformers(List itemTransformers) {
|
||||
this.itemTransformers = itemTransformers;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package org.springframework.batch.item.processor;
|
||||
|
||||
/**
|
||||
* Interface for item transformations during processing phase.
|
||||
*
|
||||
* @author Robert Kasanicky
|
||||
*/
|
||||
public interface ItemTransformer {
|
||||
|
||||
Object transform(Object item);
|
||||
}
|
||||
@@ -9,6 +9,7 @@ import org.springframework.batch.restart.GenericRestartData;
|
||||
import org.springframework.batch.restart.RestartData;
|
||||
import org.springframework.batch.restart.Restartable;
|
||||
import org.springframework.batch.statistics.StatisticsProvider;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -16,23 +17,33 @@ import org.springframework.util.Assert;
|
||||
* {@link StatisticsProvider} where the {@link OutputSource} does.
|
||||
*
|
||||
* @author Dave Syer
|
||||
* @author Robert Kasanicky
|
||||
*/
|
||||
public class OutputSourceItemProcessor implements ItemProcessor, Restartable, Skippable,
|
||||
StatisticsProvider {
|
||||
StatisticsProvider, InitializingBean {
|
||||
|
||||
private OutputSource source;
|
||||
|
||||
/* (non-Javadoc)
|
||||
/**
|
||||
* Calls {@link #doProcess(Object)} and then writes the result to the output source.
|
||||
*
|
||||
* @see org.springframework.batch.item.ItemProcessor#process(java.lang.Object)
|
||||
*/
|
||||
public void process(Object data) throws Exception {
|
||||
source.write(data);
|
||||
final public void process(Object item) throws Exception {
|
||||
Object result = doProcess(item);
|
||||
source.write(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* By default returns the argument. This method is an extension point
|
||||
* meant to be overridden by subclasses that implement processing logic.
|
||||
*/
|
||||
protected Object doProcess(Object item) {
|
||||
return item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for output source.
|
||||
*
|
||||
* @param source
|
||||
*/
|
||||
public void setOutputSource(OutputSource source) {
|
||||
this.source = source;
|
||||
@@ -85,4 +96,9 @@ public class OutputSourceItemProcessor implements ItemProcessor, Restartable, Sk
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.notNull(source);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
package org.springframework.batch.item.processor;
|
||||
|
||||
import org.springframework.batch.io.OutputSource;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Transforms the item using injected {@link ItemTransformer}
|
||||
* before it is written to output by {@link OutputSource}.
|
||||
*
|
||||
* @author Robert Kasanicky
|
||||
*/
|
||||
public class TransformerOutputSourceItemProcessor extends OutputSourceItemProcessor {
|
||||
|
||||
private ItemTransformer itemTransformer;
|
||||
|
||||
/**
|
||||
* Transform the item using the {@link #itemTransformer}.
|
||||
*/
|
||||
protected Object doProcess(Object item) {
|
||||
return itemTransformer.transform(item);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param itemTransformer will transform the item before
|
||||
* it is passed to {@link OutputSource}.
|
||||
*/
|
||||
public void setItemTransformer(ItemTransformer itemTransformer) {
|
||||
this.itemTransformer = itemTransformer;
|
||||
}
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
super.afterPropertiesSet();
|
||||
Assert.notNull(itemTransformer);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
package org.springframework.batch.item.processor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.easymock.MockControl;
|
||||
|
||||
/**
|
||||
* Tests for {@link CompositeItemTransformer}.
|
||||
*
|
||||
* @author Robert Kasanicky
|
||||
*/
|
||||
public class CompositeItemTransformerTests extends TestCase {
|
||||
|
||||
private CompositeItemTransformer composite = new CompositeItemTransformer();
|
||||
|
||||
private ItemTransformer transformer1;
|
||||
private ItemTransformer transformer2;
|
||||
|
||||
private MockControl tControl1 = MockControl.createControl(ItemTransformer.class);
|
||||
private MockControl tControl2 = MockControl.createControl(ItemTransformer.class);
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
transformer1 = (ItemTransformer) tControl1.getMock();
|
||||
transformer2 = (ItemTransformer) tControl2 .getMock();
|
||||
|
||||
composite.setItemTransformers(new ArrayList() {{
|
||||
add(transformer1); add(transformer2);
|
||||
}});
|
||||
|
||||
composite.afterPropertiesSet();
|
||||
}
|
||||
|
||||
/**
|
||||
* Regular usage scenario - item is passed through the processing chain,
|
||||
* return value of the of the last transformation is returned by the composite.
|
||||
*/
|
||||
public void testTransform() throws Exception {
|
||||
Object item = new Object();
|
||||
Object itemAfterFirstTransfromation = new Object();
|
||||
Object itemAfterSecondTransformation = new Object();
|
||||
|
||||
transformer1.transform(item);
|
||||
tControl1.setReturnValue(itemAfterFirstTransfromation);
|
||||
|
||||
transformer2.transform(itemAfterFirstTransfromation);
|
||||
tControl2.setReturnValue(itemAfterSecondTransformation);
|
||||
|
||||
tControl1.replay();
|
||||
tControl2.replay();
|
||||
|
||||
assertSame(itemAfterSecondTransformation, composite.transform(item));
|
||||
|
||||
tControl1.verify();
|
||||
tControl2.verify();
|
||||
}
|
||||
|
||||
/**
|
||||
* The list of transformers must not be null or empty and
|
||||
* can contain only instances of {@link ItemTransformer}.
|
||||
*/
|
||||
public void testAfterPropertiesSet() throws Exception {
|
||||
|
||||
// value not set
|
||||
composite.setItemTransformers(null);
|
||||
try {
|
||||
composite.afterPropertiesSet();
|
||||
fail();
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
// expected
|
||||
}
|
||||
|
||||
// empty list
|
||||
composite.setItemTransformers(new ArrayList());
|
||||
try {
|
||||
composite.afterPropertiesSet();
|
||||
fail();
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
// expected
|
||||
}
|
||||
|
||||
// invalid list member
|
||||
composite.setItemTransformers(new ArrayList() {{ add(new Object()); }});
|
||||
try {
|
||||
composite.afterPropertiesSet();
|
||||
fail();
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
// expected
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -47,6 +47,7 @@ public class OutputSourceItemProcessorTests extends TestCase {
|
||||
protected void setUp() throws Exception {
|
||||
source = new MockOutputSource("test");
|
||||
processor.setOutputSource(source);
|
||||
processor.afterPropertiesSet();
|
||||
}
|
||||
|
||||
public void testProcess() throws Exception {
|
||||
@@ -126,6 +127,20 @@ public class OutputSourceItemProcessorTests extends TestCase {
|
||||
assertEquals("after skip", list.get(0));
|
||||
}
|
||||
|
||||
/**
|
||||
* Output source property must be set.
|
||||
*/
|
||||
public void testAfterPropertiesSet() throws Exception {
|
||||
processor.setOutputSource(null);
|
||||
try {
|
||||
processor.afterPropertiesSet();
|
||||
fail();
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
// expected
|
||||
}
|
||||
}
|
||||
|
||||
private List list = new ArrayList();
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
package org.springframework.batch.item.processor;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.easymock.MockControl;
|
||||
import org.springframework.batch.io.OutputSource;
|
||||
|
||||
/**
|
||||
* Tests for {@link TransformerOutputSourceItemProcessor}.
|
||||
*
|
||||
* @author Robert Kasanicky
|
||||
*/
|
||||
public class TransformerOutputSourceItemProcessorTests extends TestCase {
|
||||
|
||||
private TransformerOutputSourceItemProcessor processor = new TransformerOutputSourceItemProcessor();
|
||||
|
||||
private ItemTransformer transformer;
|
||||
private OutputSource outputSource;
|
||||
|
||||
private MockControl tControl = MockControl.createControl(ItemTransformer.class);
|
||||
private MockControl outControl = MockControl.createControl(OutputSource.class);
|
||||
|
||||
protected void setUp() throws Exception {
|
||||
transformer = (ItemTransformer) tControl.getMock();
|
||||
outputSource = (OutputSource) outControl.getMock();
|
||||
|
||||
processor.setItemTransformer(transformer);
|
||||
processor.setOutputSource(outputSource);
|
||||
|
||||
processor.afterPropertiesSet();
|
||||
}
|
||||
|
||||
/**
|
||||
* Regular usage scenario - item is passed to transformer
|
||||
* and the result of transformation is passed to output source.
|
||||
*/
|
||||
public void testProcess() throws Exception {
|
||||
Object item = new Object();
|
||||
Object itemAfterTransformation = new Object();
|
||||
|
||||
transformer.transform(item);
|
||||
tControl.setReturnValue(itemAfterTransformation);
|
||||
|
||||
outputSource.write(itemAfterTransformation);
|
||||
outControl.setVoidCallable();
|
||||
|
||||
tControl.replay();
|
||||
outControl.replay();
|
||||
|
||||
processor.process(item);
|
||||
|
||||
tControl.verify();
|
||||
outControl.verify();
|
||||
}
|
||||
|
||||
/**
|
||||
* Item transformer must be set.
|
||||
*/
|
||||
public void testAfterPropertiesSet() throws Exception {
|
||||
|
||||
// value not set
|
||||
processor.setItemTransformer(null);
|
||||
try {
|
||||
processor.afterPropertiesSet();
|
||||
fail();
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
// expected
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user