Skip to content

Commit

Permalink
FEATURE: validate step listeners
Browse files Browse the repository at this point in the history
  • Loading branch information
hosuaby committed May 8, 2020
1 parent 10fd371 commit d7e5bf7
Show file tree
Hide file tree
Showing 6 changed files with 124 additions and 102 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@
*/
package org.springframework.batch.core.listener;

import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.springframework.batch.core.StepListener;

/**
Expand All @@ -23,11 +26,22 @@
*
* @author Lucas Ward
* @author Dan Garrette
* @author Alexei KLENIN
* @since 2.0
* @see AbstractListenerFactoryBean
* @see StepListenerMetaData
*/
public class StepListenerFactoryBean extends AbstractListenerFactoryBean<StepListener> {
private static final String STR_STEP_LISTENER_ANNOTATIONS_LIST = Stream
.of(StepListenerMetaData.values())
.map(StepListenerMetaData::getAnnotation)
.map(Class::getSimpleName)
.map(annotation -> String.format("\t- @%s\n", annotation))
.collect(Collectors.joining());
private static final String ERR_OBJECT_NOT_STEP_LISTENER_TEMPLATE =
"Object of type [%s] is not a valid step listener. " +
"It must ether implement StepListener interface or have methods annotated with any of:\n" +
STR_STEP_LISTENER_ANNOTATIONS_LIST;

@Override
protected ListenerMetaData getMetaDataFromPropertyName(String propertyName) {
Expand Down Expand Up @@ -74,4 +88,19 @@ public static StepListener getListener(Object delegate) {
public static boolean isListener(Object delegate) {
return AbstractListenerFactoryBean.isListener(delegate, StepListener.class, StepListenerMetaData.values());
}

/**
* Asserts that {@code delegate} is a valid step listener. If this is not a case, throws an
* {@link IllegalArgumentException} with message detailing the problem. Object is a valid
* step listener is it ether implements interface {@link StepListener} or has any method
* annotated with one of marker annotations.
*
* @param delegate the object to check
*/
public static void assertListener(Object delegate) {
if (!isListener(delegate)) {
throw new IllegalArgumentException(String.format(
ERR_OBJECT_NOT_STEP_LISTENER_TEMPLATE, delegate.getClass().getName()));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import org.springframework.batch.core.ChunkListener;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.StepExecutionListener;
import org.springframework.batch.core.StepListener;
import org.springframework.batch.core.annotation.AfterChunk;
import org.springframework.batch.core.annotation.AfterChunkError;
import org.springframework.batch.core.annotation.BeforeChunk;
Expand All @@ -47,6 +48,7 @@
* @author Dave Syer
* @author Michael Minella
* @author Mahmoud Ben Hassine
* @author Alexei Klenin
*
* @since 2.2
*
Expand Down Expand Up @@ -159,10 +161,9 @@ public B listener(Object listener) {
chunkListenerMethods.addAll(ReflectionUtils.findMethod(listener.getClass(), AfterChunk.class));
chunkListenerMethods.addAll(ReflectionUtils.findMethod(listener.getClass(), AfterChunkError.class));

if(chunkListenerMethods.size() > 0) {
StepListenerFactoryBean factory = new StepListenerFactoryBean();
factory.setDelegate(listener);
this.listener((ChunkListener) factory.getObject());
if (!chunkListenerMethods.isEmpty()) {
StepListener stepListener = StepListenerFactoryBean.getListener(listener);
this.listener((ChunkListener) stepListener);
}

@SuppressWarnings("unchecked")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@
* @author Chris Schaefer
* @author Michael Minella
* @author Mahmoud Ben Hassine
* @author Alexei Klenin
*
* @since 2.2
*/
Expand Down Expand Up @@ -204,18 +205,14 @@ public SimpleStepBuilder<I, O> listener(Object listener) {
skipListenerMethods.addAll(ReflectionUtils.findMethod(listener.getClass(), OnSkipInProcess.class));
skipListenerMethods.addAll(ReflectionUtils.findMethod(listener.getClass(), OnSkipInWrite.class));

if(skipListenerMethods.size() > 0) {
StepListenerFactoryBean factory = new StepListenerFactoryBean();
factory.setDelegate(listener);
skipListeners.add((SkipListener) factory.getObject());
if (!skipListenerMethods.isEmpty()) {
StepListener stepListener = StepListenerFactoryBean.getListener(listener);
skipListeners.add((SkipListener<I, O>) stepListener);
}

@SuppressWarnings("unchecked")
SimpleStepBuilder<I, O> result = this;
return result;
return this;
}


/**
* Register a skip listener.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
*
* @author Dave Syer
* @author Mahmoud Ben Hassine
* @author Alexei Klenin
*
* @since 2.2
*/
Expand Down Expand Up @@ -265,7 +266,6 @@ public SimpleStepBuilder<I, O> readerIsTransactionalQueue() {
* @param listener the object that has a method configured with listener annotation
* @return this for fluent chaining
*/
@SuppressWarnings("unchecked")
@Override
public SimpleStepBuilder<I, O> listener(Object listener) {
super.listener(listener);
Expand All @@ -281,18 +281,14 @@ public SimpleStepBuilder<I, O> listener(Object listener) {
itemListenerMethods.addAll(ReflectionUtils.findMethod(listener.getClass(), OnProcessError.class));
itemListenerMethods.addAll(ReflectionUtils.findMethod(listener.getClass(), OnWriteError.class));

if(itemListenerMethods.size() > 0) {
StepListenerFactoryBean factory = new StepListenerFactoryBean();
factory.setDelegate(listener);
itemListeners.add((StepListener) factory.getObject());
if (!itemListenerMethods.isEmpty()) {
StepListener stepListener = StepListenerFactoryBean.getListener(listener);
itemListeners.add(stepListener);
}

@SuppressWarnings("unchecked")
SimpleStepBuilder<I, O> result = this;
return result;
return this;
}


/**
* Register an item reader listener.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,10 @@

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.springframework.batch.core.Step;
import org.springframework.batch.core.StepExecutionListener;
import org.springframework.batch.core.StepListener;
import org.springframework.batch.core.annotation.AfterStep;
import org.springframework.batch.core.annotation.BeforeStep;
import org.springframework.batch.core.listener.StepListenerFactoryBean;
Expand All @@ -40,6 +42,7 @@
*
* @author Dave Syer
* @author Michael Minella
* @author Alexei Klenin
*
* @since 2.2
*/
Expand Down Expand Up @@ -91,14 +94,15 @@ public B startLimit(int startLimit) {
* @return this for fluent chaining
*/
public B listener(Object listener) {
StepListenerFactoryBean.assertListener(listener);

Set<Method> stepExecutionListenerMethods = new HashSet<>();
stepExecutionListenerMethods.addAll(ReflectionUtils.findMethod(listener.getClass(), BeforeStep.class));
stepExecutionListenerMethods.addAll(ReflectionUtils.findMethod(listener.getClass(), AfterStep.class));

if(stepExecutionListenerMethods.size() > 0) {
StepListenerFactoryBean factory = new StepListenerFactoryBean();
factory.setDelegate(listener);
properties.addStepExecutionListener((StepExecutionListener) factory.getObject());
if (!stepExecutionListenerMethods.isEmpty()) {
StepListener stepListener = StepListenerFactoryBean.getListener(listener);
properties.addStepExecutionListener((StepExecutionListener) stepListener);
}

@SuppressWarnings("unchecked")
Expand Down
Loading

0 comments on commit d7e5bf7

Please sign in to comment.