From f4f3adac869e64dedb2a1f124914175c0ac90b68 Mon Sep 17 00:00:00 2001 From: dsyer Date: Fri, 29 Feb 2008 10:40:54 +0000 Subject: [PATCH] OPEN - issue BATCH-385: Merge user attributes in StepContext with ExecutionContext http://jira.springframework.org/browse/BATCH-385 OPEN - issue BATCH-378: RepeatListener is confusing and too generic to use for 'intercepting' a step http://jira.springframework.org/browse/BATCH-378 Javadocs plus new setter. --- .../execution/step/ItemOrientedStep.java | 30 +++++++--- .../batch/execution/step/TaskletStep.java | 17 ++++++ .../step/support/ListenerMulticaster.java | 58 +++++++++++++++---- 3 files changed, 86 insertions(+), 19 deletions(-) diff --git a/spring-batch-execution/src/main/java/org/springframework/batch/execution/step/ItemOrientedStep.java b/spring-batch-execution/src/main/java/org/springframework/batch/execution/step/ItemOrientedStep.java index 23f9cf279..877112260 100644 --- a/spring-batch-execution/src/main/java/org/springframework/batch/execution/step/ItemOrientedStep.java +++ b/spring-batch-execution/src/main/java/org/springframework/batch/execution/step/ItemOrientedStep.java @@ -25,7 +25,6 @@ import org.springframework.batch.core.domain.JobInstance; import org.springframework.batch.core.domain.JobInterruptedException; import org.springframework.batch.core.domain.StepContribution; import org.springframework.batch.core.domain.StepExecution; -import org.springframework.batch.core.domain.StepListener; import org.springframework.batch.core.repository.JobRepository; import org.springframework.batch.core.runtime.ExitStatusExceptionClassifier; import org.springframework.batch.core.tasklet.Tasklet; @@ -102,8 +101,13 @@ public class ItemOrientedStep extends AbstractStep implements InitializingBean { /** * Register each of the objects as listeners. The {@link ItemOrientedStep} - * accepts listeners of type {@link ItemStream}, {@link StepListener}, - * TODO: complete the list. + * accepts listeners of type {@link ItemStream} and {@link BatchListener}. + * The {@link ItemReader} and {@link ItemWriter} are automatically + * registered, but it doesn't hurt to also register them here. Injected + * dependencies of the reader and writer are not automatically registered, + * so if you implement {@link ItemWriter} using delegation to another object + * which itself is a {@link BatchListener}, you need to register the + * delegate here. * * @param listeners an array of listener objects of known types. */ @@ -112,6 +116,15 @@ public class ItemOrientedStep extends AbstractStep implements InitializingBean { listener.register(listeners[i]); } } + + /** + * Register the objects as a listener. + * @see #setListeners(Object[]) + * @param listener the listener to set + */ + public void setListener(Object listener) { + this.listener.register(listener); + } /** * The {@link RepeatOperations} to use for the outer loop of the batch @@ -232,9 +245,10 @@ public class ItemOrientedStep extends AbstractStep implements InitializingBean { ExitStatus status = ExitStatus.FAILED; final ExceptionHolder fatalException = new ExceptionHolder(); - - // This could go in applyConfiguration(), but some unit tests do not call that - possiblyRegisterStreams(); + + // This could go in applyConfiguration(), but some unit tests do not + // call that + possiblyRegisterStreams(); try { @@ -300,7 +314,7 @@ public class ItemOrientedStep extends AbstractStep implements InitializingBean { } } - + try { result = result.and(listener.afterStep()); } @@ -334,7 +348,7 @@ public class ItemOrientedStep extends AbstractStep implements InitializingBean { synchronized (stepExecution) { stepExecution.rollback(); } - + try { itemReader.reset(); itemWriter.clear(); diff --git a/spring-batch-execution/src/main/java/org/springframework/batch/execution/step/TaskletStep.java b/spring-batch-execution/src/main/java/org/springframework/batch/execution/step/TaskletStep.java index 58aeb5fff..f9072be03 100644 --- a/spring-batch-execution/src/main/java/org/springframework/batch/execution/step/TaskletStep.java +++ b/spring-batch-execution/src/main/java/org/springframework/batch/execution/step/TaskletStep.java @@ -119,12 +119,26 @@ public class TaskletStep implements Step, InitializingBean, BeanNameAware { private CompositeStepListener listener = new CompositeStepListener(); + /** + * Register each of the objects as listeners. The {@link TaskletStep} + * accepts listeners of type {@link StepListener}. If the {@link Tasklet} + * itself implements this interface it will be registered automatically, but + * its injected dependencies will not be. This is a good way to get access + * to job parameters and execution context if the tasklet is parameterised. + * + * @param listeners an array of listener objects of known types. + */ public void setListeners(StepListener[] listeners) { for (int i = 0; i < listeners.length; i++) { this.listener.register(listeners[i]); } } + /** + * Register the objects as a listener. + * @see #setListeners(Object[]) + * @param listener the listener to set + */ public void setListener(StepListener listener) { this.listener.register(listener); } @@ -136,6 +150,9 @@ public class TaskletStep implements Step, InitializingBean, BeanNameAware { public void afterPropertiesSet() throws Exception { Assert.notNull(jobRepository, "JobRepository is mandatory for TaskletStep"); Assert.notNull(tasklet, "Tasklet is mandatory for TaskletStep"); + if (tasklet instanceof StepListener) { + listener.register((StepListener) tasklet); + } } /** diff --git a/spring-batch-execution/src/main/java/org/springframework/batch/execution/step/support/ListenerMulticaster.java b/spring-batch-execution/src/main/java/org/springframework/batch/execution/step/support/ListenerMulticaster.java index a5683dfe2..444ee3194 100644 --- a/spring-batch-execution/src/main/java/org/springframework/batch/execution/step/support/ListenerMulticaster.java +++ b/spring-batch-execution/src/main/java/org/springframework/batch/execution/step/support/ListenerMulticaster.java @@ -35,16 +35,17 @@ import org.springframework.batch.repeat.ExitStatus; * @author Dave Syer * */ -public class ListenerMulticaster implements ItemStream, StepListener, ChunkListener, ItemReadListener, ItemWriteListener { +public class ListenerMulticaster implements ItemStream, StepListener, ChunkListener, ItemReadListener, + ItemWriteListener { private CompositeItemStream stream = new CompositeItemStream(); private CompositeStepListener stepListener = new CompositeStepListener(); - + private CompositeChunkListener chunkListener = new CompositeChunkListener(); - + private CompositeItemReadListener itemReadListener = new CompositeItemReadListener(); - + private CompositeItemWriteListener itemWriteListener = new CompositeItemWriteListener(); /** @@ -62,7 +63,8 @@ public class ListenerMulticaster implements ItemStream, StepListener, ChunkListe /** * Register the listener for callbacks on the appropriate interfaces - * implemented. + * implemented. Any {@link BatchListener} can be provided, or an + * {@link ItemStream}. Other types will be ignored. */ public void register(Object listener) { if (listener instanceof StepListener) { @@ -71,14 +73,14 @@ public class ListenerMulticaster implements ItemStream, StepListener, ChunkListe if (listener instanceof ItemStream) { this.stream.register((ItemStream) listener); } - if(listener instanceof ChunkListener){ - this.chunkListener.register((ChunkListener)listener); + if (listener instanceof ChunkListener) { + this.chunkListener.register((ChunkListener) listener); } - if(listener instanceof ItemReadListener){ - this.itemReadListener.register((ItemReadListener)listener); + if (listener instanceof ItemReadListener) { + this.itemReadListener.register((ItemReadListener) listener); } - if(listener instanceof ItemWriteListener){ - this.itemWriteListener.register((ItemWriteListener)listener); + if (listener instanceof ItemWriteListener) { + this.itemWriteListener.register((ItemWriteListener) listener); } } @@ -133,34 +135,68 @@ public class ListenerMulticaster implements ItemStream, StepListener, ChunkListe stream.update(executionContext); } + /** + * + * @see org.springframework.batch.execution.listener.CompositeChunkListener#afterChunk() + */ public void afterChunk() { chunkListener.afterChunk(); } + /** + * + * @see org.springframework.batch.execution.listener.CompositeChunkListener#beforeChunk() + */ public void beforeChunk() { chunkListener.beforeChunk(); } + /** + * @param item + * @see org.springframework.batch.execution.listener.CompositeItemReadListener#afterRead(java.lang.Object) + */ public void afterRead(Object item) { itemReadListener.afterRead(item); } + /** + * + * @see org.springframework.batch.execution.listener.CompositeItemReadListener#beforeRead() + */ public void beforeRead() { itemReadListener.beforeRead(); } + /** + * @param ex + * @see org.springframework.batch.execution.listener.CompositeItemReadListener#onReadError(java.lang.Exception) + */ public void onReadError(Exception ex) { itemReadListener.onReadError(ex); } + /** + * + * @see org.springframework.batch.execution.listener.CompositeItemWriteListener#afterWrite() + */ public void afterWrite() { itemWriteListener.afterWrite(); } + /** + * @param item + * @see org.springframework.batch.execution.listener.CompositeItemWriteListener#beforeWrite(java.lang.Object) + */ public void beforeWrite(Object item) { itemWriteListener.beforeWrite(item); } + /** + * @param ex + * @param item + * @see org.springframework.batch.execution.listener.CompositeItemWriteListener#onWriteError(java.lang.Exception, + * java.lang.Object) + */ public void onWriteError(Exception ex, Object item) { itemWriteListener.onWriteError(ex, item); }