Skip to content
Permalink
Browse files

Spring batch configuration moved from Java to XML

  • Loading branch information...
cezarykluczynski committed Oct 21, 2016
1 parent 889628a commit 6a7f9c5f3c0e91f06cd275437885ba882367c587
@@ -4,11 +4,12 @@
import org.springframework.batch.core.ExitStatus;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.StepExecutionListener;
import org.springframework.batch.core.StepListener;
import org.springframework.stereotype.Service;

@Service
@Slf4j
public class CommonStepExecutionListener implements StepExecutionListener {
public class CommonStepExecutionListener implements StepExecutionListener, StepListener {

@Override
public void beforeStep(StepExecution stepExecution) {
@@ -1,35 +1,20 @@
package com.cezarykluczynski.stapi.etl.configuration;

import com.cezarykluczynski.stapi.etl.util.Steps;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.EnableBatchProcessing;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.launch.support.RunIdIncrementer;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.inject.Inject;
import org.springframework.context.annotation.ImportResource;
import org.springframework.core.task.SimpleAsyncTaskExecutor;
import org.springframework.core.task.TaskExecutor;

@Configuration
@EnableBatchProcessing
@ImportResource(locations = {"classpath:spring/batch/jobs/create.xml"})
public class EtlConfiguration {

@Inject
private JobBuilderFactory jobBuilderFactory;

@Inject
private ApplicationContext applicationContext;

@Bean
public Job job() {
return jobBuilderFactory.get("job")
.incrementer(new RunIdIncrementer())
.flow(applicationContext.getBean(Steps.STEP_001_CREATE_SERIES, Step.class))
.next(applicationContext.getBean(Steps.STEP_002_CREATE_PERFORMERS, Step.class))
.end()
.build();
public TaskExecutor taskExecutor() {
return new SimpleAsyncTaskExecutor();
}

}
@@ -1,12 +1,7 @@
package com.cezarykluczynski.stapi.etl.performer.creation.processor;

import com.cezarykluczynski.stapi.etl.common.listener.CommonStepExecutionListener;
import com.cezarykluczynski.stapi.etl.util.Steps;
import com.cezarykluczynski.stapi.model.performer.entity.Performer;
import com.cezarykluczynski.stapi.util.constants.CategoryName;
import com.cezarykluczynski.stapi.wiki.api.CategoryApi;
import com.cezarykluczynski.stapi.wiki.dto.PageHeader;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
@@ -31,18 +26,4 @@ public PerformerReader performerReader() {
return new PerformerReader(categoryApi.getPages(CategoryName.PERFORMERS));
}

@Bean(name = Steps.STEP_002_CREATE_PERFORMERS)
public Step step() {
return stepBuilderFactory.get(Steps.STEP_002_CREATE_PERFORMERS)
.<PageHeader, Performer> chunk(50)
.reader(applicationContext.getBean(PerformerReader.class))
.processor(applicationContext.getBean(PerformerProcessor.class))
.writer(applicationContext.getBean(PerformerWriter.class))
.listener(applicationContext.getBean(CommonStepExecutionListener.class))
.startLimit(1)
.allowStartIfComplete(false)
.build();
}


}
@@ -8,6 +8,8 @@
import org.springframework.batch.item.support.CompositeItemProcessor;
import org.springframework.stereotype.Service;

import javax.inject.Inject;

@Service
public class PerformerProcessor extends CompositeItemProcessor<PageHeader, Performer> {

@@ -17,6 +19,7 @@

private ActorTemplateProcessor actorTemplateProcessor;

@Inject
public PerformerProcessor(PageHeaderProcessor pageHeaderProcessor,
ActorTemplatePageProcessor actorTemplatePageProcessor, ActorTemplateProcessor actorTemplateProcessor) {
setDelegates(Lists.newArrayList(pageHeaderProcessor, actorTemplatePageProcessor, actorTemplateProcessor));
@@ -1,12 +1,7 @@
package com.cezarykluczynski.stapi.etl.series.creation.processor;

import com.cezarykluczynski.stapi.etl.common.listener.CommonStepExecutionListener;
import com.cezarykluczynski.stapi.etl.util.Steps;
import com.cezarykluczynski.stapi.model.series.entity.Series;
import com.cezarykluczynski.stapi.util.constants.CategoryName;
import com.cezarykluczynski.stapi.wiki.api.CategoryApi;
import com.cezarykluczynski.stapi.wiki.dto.PageHeader;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
@@ -31,17 +26,4 @@ public SeriesReader seriesReader() {
return new SeriesReader(categoryApi.getPages(CategoryName.STAR_TREK_SERIES));
}

@Bean(name = Steps.STEP_001_CREATE_SERIES)
public Step step() {
return stepBuilderFactory.get(Steps.STEP_001_CREATE_SERIES)
.<PageHeader, Series> chunk(10)
.reader(applicationContext.getBean(SeriesReader.class))
.processor(applicationContext.getBean(SeriesProcessor.class))
.writer(applicationContext.getBean(SeriesWriter.class))
.listener(applicationContext.getBean(CommonStepExecutionListener.class))
.startLimit(1)
.allowStartIfComplete(false)
.build();
}

}

This file was deleted.

Oops, something went wrong.
@@ -0,0 +1,45 @@
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:batch="http://www.springframework.org/schema/batch"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/batch
http://www.springframework.org/schema/batch/spring-batch-2.2.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
">
<batch:job id="CREATE">
<batch:listeners>
<batch:listener ref="commonStepExecutionListener"/>
</batch:listeners>
<batch:split id="CREATE_01" task-executor="taskExecutor">
<batch:flow>
<batch:step id="STEP_001_CREATE_SERIES" allow-start-if-complete="false">
<batch:tasklet>
<batch:chunk
commit-interval="50"
reader="seriesReader"
processor="seriesProcessor"
writer="seriesWriter"/>
</batch:tasklet>
<batch:listeners>
<batch:listener ref="commonStepExecutionListener"/>
</batch:listeners>
</batch:step>
</batch:flow>
<batch:flow>
<batch:step id="STEP_002_CREATE_PRODUCERS" allow-start-if-complete="false">
<batch:tasklet>
<batch:chunk
commit-interval="50"
reader="performerReader"
processor="performerProcessor"
writer="performerWriter" />
</batch:tasklet>
<batch:listeners>
<batch:listener ref="commonStepExecutionListener"/>
</batch:listeners>
</batch:step>
</batch:flow>
</batch:split>
</batch:job>
</beans>
@@ -1,62 +1,23 @@
package com.cezarykluczynski.stapi.etl.configuration

import com.cezarykluczynski.stapi.etl.util.Steps
import org.springframework.batch.core.Job
import org.springframework.batch.core.Step
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory
import org.springframework.batch.core.job.builder.FlowJobBuilder
import org.springframework.batch.core.job.builder.JobBuilder
import org.springframework.batch.core.job.builder.JobFlowBuilder
import org.springframework.batch.core.launch.support.RunIdIncrementer
import org.springframework.context.ApplicationContext
import org.springframework.core.task.SimpleAsyncTaskExecutor
import org.springframework.core.task.TaskExecutor
import spock.lang.Specification

class EtlConfigurationTest extends Specification {

private JobBuilderFactory jobBuilderFactoryMock

private ApplicationContext applicationContextMock

private EtlConfiguration etlConfiguration

def setup() {
jobBuilderFactoryMock = Mock(JobBuilderFactory)
applicationContextMock = Mock(ApplicationContext)
etlConfiguration = new EtlConfiguration(
jobBuilderFactory: jobBuilderFactoryMock,
applicationContext: applicationContextMock)
etlConfiguration = new EtlConfiguration()
}

def "Job is built"() {
given:
Step step1Mock = Mock(Step)
Step step2Mock = Mock(Step)
JobBuilder jobBuilderMock = Mock(JobBuilder)
JobFlowBuilder jobFlowBuilderMock = Mock(JobFlowBuilder)
FlowJobBuilder flowJobBuilderMock = Mock(FlowJobBuilder)
Job jobMock = Mock(Job)

def "task exeturor is created"() {
when:
Job job = etlConfiguration.job()

then: 'job builder is retrieved'
1 * jobBuilderFactoryMock.get("job") >> jobBuilderMock
1 * jobBuilderMock.incrementer(_ as RunIdIncrementer) >> jobBuilderMock

then: 'first step is retrieved from application context, then set'
1 * applicationContextMock.getBean(Steps.STEP_001_CREATE_SERIES, Step.class) >> step1Mock
1 * jobBuilderMock.flow(step1Mock) >> jobFlowBuilderMock

then: 'second step is retrieved from application context, then set'
1 * applicationContextMock.getBean(Steps.STEP_002_CREATE_PERFORMERS, Step.class) >> step2Mock
1 * jobFlowBuilderMock.next(step2Mock) >> jobFlowBuilderMock

then: 'job is built'
1 * jobFlowBuilderMock._() >> flowJobBuilderMock
1 * flowJobBuilderMock.build() >> jobMock
TaskExecutor taskExecutor = etlConfiguration.taskExecutor()

then: 'job is being returned'
job == jobMock
then:
taskExecutor instanceof SimpleAsyncTaskExecutor
}

}
@@ -1,21 +1,10 @@
package com.cezarykluczynski.stapi.etl.performer.creation.processor

import com.cezarykluczynski.stapi.etl.common.listener.CommonStepExecutionListener

import com.cezarykluczynski.stapi.etl.util.Steps
import com.cezarykluczynski.stapi.util.constants.CategoryName
import com.cezarykluczynski.stapi.wiki.api.CategoryApi
import com.cezarykluczynski.stapi.wiki.dto.PageHeader
import com.google.common.collect.Lists
import org.springframework.batch.core.Step
import org.springframework.batch.core.StepExecutionListener
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory
import org.springframework.batch.core.step.builder.SimpleStepBuilder
import org.springframework.batch.core.step.builder.StepBuilder
import org.springframework.batch.core.step.tasklet.TaskletStep
import org.springframework.batch.item.ItemProcessor
import org.springframework.batch.item.ItemReader
import org.springframework.batch.item.ItemWriter
import org.springframework.context.ApplicationContext
import spock.lang.Specification

@@ -54,42 +43,4 @@ class PerformerCreationConfigurationTest extends Specification {
performerReader.read() == null
}

def "Step is created"() {
given:
StepBuilder stepBuilderMock = Mock(StepBuilder)
SimpleStepBuilder simpleStepBuilderMock = Mock(SimpleStepBuilder)
ItemReader itemReaderMock = Mock(ItemReader)
ItemProcessor itemProcessorMock = Mock(ItemProcessor)
ItemWriter itemWriterMock = Mock(ItemWriter)
StepExecutionListener stepExecutionListenerMock = Mock(StepExecutionListener)
TaskletStep taskletStepMock = Mock(TaskletStep)

when:
Step step = performerCreationConfiguration.step()

then: 'StepBuilder is retrieved'
1 * stepBuilderMock.chunk(*_) >> simpleStepBuilderMock
1 * stepBuilderFactoryMock.get(Steps.STEP_002_CREATE_PERFORMERS) >> stepBuilderMock

then: 'beans are retrieved from application context, then passed to builder'
1 * applicationContextMock.getBean(PerformerReader.class) >> itemReaderMock
1 * simpleStepBuilderMock.reader(itemReaderMock) >> simpleStepBuilderMock
1 * applicationContextMock.getBean(PerformerProcessor.class) >> itemProcessorMock
1 * simpleStepBuilderMock.processor(itemProcessorMock) >> simpleStepBuilderMock
1 * applicationContextMock.getBean(PerformerWriter.class) >> itemWriterMock
1 * simpleStepBuilderMock.writer(itemWriterMock) >> simpleStepBuilderMock
1 * applicationContextMock.getBean(CommonStepExecutionListener.class) >> stepExecutionListenerMock
1 * simpleStepBuilderMock.listener(*_) >> simpleStepBuilderMock

then: 'step is configured to run only once'
1 * simpleStepBuilderMock.startLimit(1) >> simpleStepBuilderMock
1 * simpleStepBuilderMock.allowStartIfComplete(false) >> simpleStepBuilderMock

then: 'tasklet step is returned'
1 * simpleStepBuilderMock.build() >> taskletStepMock

then: 'step is being returned'
step == taskletStepMock
}

}
@@ -1,20 +1,10 @@
package com.cezarykluczynski.stapi.etl.series.creation.processor

import com.cezarykluczynski.stapi.etl.common.listener.CommonStepExecutionListener
import com.cezarykluczynski.stapi.etl.util.Steps
import com.cezarykluczynski.stapi.util.constants.CategoryName
import com.cezarykluczynski.stapi.wiki.api.CategoryApi
import com.cezarykluczynski.stapi.wiki.dto.PageHeader
import com.google.common.collect.Lists
import org.springframework.batch.core.Step
import org.springframework.batch.core.StepExecutionListener
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory
import org.springframework.batch.core.step.builder.SimpleStepBuilder
import org.springframework.batch.core.step.builder.StepBuilder
import org.springframework.batch.core.step.tasklet.TaskletStep
import org.springframework.batch.item.ItemProcessor
import org.springframework.batch.item.ItemReader
import org.springframework.batch.item.ItemWriter
import org.springframework.context.ApplicationContext
import spock.lang.Specification

@@ -53,42 +43,4 @@ class SeriesCreationConfigurationTest extends Specification {
seriesReader.read() == null
}

def "Step is created"() {
given:
StepBuilder stepBuilderMock = Mock(StepBuilder)
SimpleStepBuilder simpleStepBuilderMock = Mock(SimpleStepBuilder)
ItemReader itemReaderMock = Mock(ItemReader)
ItemProcessor itemProcessorMock = Mock(ItemProcessor)
ItemWriter itemWriterMock = Mock(ItemWriter)
StepExecutionListener stepExecutionListenerMock = Mock(StepExecutionListener)
TaskletStep taskletStepMock = Mock(TaskletStep)

when:
Step step = seriesCreationConfiguration.step()

then: 'StepBuilder is retrieved'
1 * stepBuilderMock.chunk(*_) >> simpleStepBuilderMock
1 * stepBuilderFactoryMock.get(Steps.STEP_001_CREATE_SERIES) >> stepBuilderMock

then: 'beans are retrieved from application context, then passed to builder'
1 * applicationContextMock.getBean(SeriesReader.class) >> itemReaderMock
1 * simpleStepBuilderMock.reader(itemReaderMock) >> simpleStepBuilderMock
1 * applicationContextMock.getBean(SeriesProcessor.class) >> itemProcessorMock
1 * simpleStepBuilderMock.processor(itemProcessorMock) >> simpleStepBuilderMock
1 * applicationContextMock.getBean(SeriesWriter.class) >> itemWriterMock
1 * simpleStepBuilderMock.writer(itemWriterMock) >> simpleStepBuilderMock
1 * applicationContextMock.getBean(CommonStepExecutionListener.class) >> stepExecutionListenerMock
1 * simpleStepBuilderMock.listener(*_) >> simpleStepBuilderMock

then: 'step is configured to run only once'
1 * simpleStepBuilderMock.startLimit(1) >> simpleStepBuilderMock
1 * simpleStepBuilderMock.allowStartIfComplete(false) >> simpleStepBuilderMock

then: 'tasklet step is returned'
1 * simpleStepBuilderMock.build() >> taskletStepMock

then: 'step is being returned'
step == taskletStepMock
}

}
}

0 comments on commit 6a7f9c5

Please sign in to comment.
You can’t perform that action at this time.