BATCHADM-49: added JMS integration test
This commit is contained in:
committed by
Michael Minella
parent
c1616f0bbb
commit
6ca0512753
@@ -1,8 +1,9 @@
|
||||
#Fri Apr 09 09:28:44 BST 2010
|
||||
//com.springsource.sts.config.flow.coordinates\:http\://www.springframework.org/schema/batch\:/spring-batch-integration/src/test/resources/org/springframework/batch/integration/chunk/ChunkStepIntegrationTests-context.xml=<?xml version\="1.0" encoding\="UTF-8"?>\n<graph>\n<element type\="job">\n<structure end\="1102" endstart\="1096" start\="901" startend\="967"/>\n<bounds height\="118" width\="79" x\="15" y\="17"/>\n</element>\n<element type\="job">\n<structure end\="1473" endstart\="1467" start\="1107" startend\="1182"/>\n<bounds height\="118" width\="127" x\="106" y\="17"/>\n</element>\n</graph>
|
||||
//com.springsource.sts.config.flow.coordinates\:http\://www.springframework.org/schema/batch\:/spring-batch-integration/src/test/resources/org/springframework/batch/integration/chunk/RemoteChunkFaultTolerantStepIntegrationTests-context.xml=<?xml version\="1.0" encoding\="UTF-8"?>\n<graph>\n<element type\="job">\n<structure end\="1279" endstart\="1273" start\="901" startend\="976"/>\n<bounds height\="118" width\="127" x\="15" y\="17"/>\n</element>\n</graph>
|
||||
//com.springsource.sts.config.flow.coordinates\:http\://www.springframework.org/schema/batch\:/spring-batch-integration/src/test/resources/org/springframework/batch/integration/chunk/RemoteChunkStepIntegrationTests-context.xml=<?xml version\="1.0" encoding\="UTF-8"?>\r\n<graph>\r\n<element type\="job">\r\n<structure end\="1101" endstart\="1095" start\="899" startend\="965"/>\r\n<bounds height\="118" width\="75" x\="15" y\="17"/>\r\n</element>\r\n</graph>
|
||||
//com.springsource.sts.config.flow.coordinates\:http\://www.springframework.org/schema/batch\:/spring-batch-integration/src/test/resources/org/springframework/batch/integration/file/FileToMessagesJobIntegrationTests-context.xml=<?xml version\="1.0" encoding\="UTF-8"?>\r\n<graph>\r\n<element type\="job">\r\n<structure end\="972" endstart\="966" start\="771" startend\="837"/>\r\n<bounds height\="118" width\="75" x\="15" y\="17"/>\r\n</element>\r\n</graph>
|
||||
//com.springsource.sts.config.flow.coordinates\:http\://www.springframework.org/schema/batch\:/spring-batch-integration/src/test/resources/org/springframework/batch/integration/step/StepGatewayIntegrationTests-context.xml=<?xml version\="1.0" encoding\="UTF-8"?>\n<graph>\n<element type\="job">\n<structure end\="1419" endstart\="1413" start\="1302" startend\="1368"/>\n<bounds height\="128" width\="79" x\="109" y\="19"/>\n</element>\n<element type\="step">\n<structure end\="1953" endstart\="1946" start\="1846" startend\="1916"/>\n<bounds height\="34" width\="74" x\="17" y\="19"/>\n</element>\n</graph>
|
||||
//com.springsource.sts.config.flow.coordinates\:http\://www.springframework.org/schema/batch\:/spring-batch-integration/src/test/resources/org/springframework/batch/integration/tasklet/StepGatewayIntegrationTests-context.xml=<?xml version\="1.0" encoding\="UTF-8"?>\n<graph>\n<element type\="job">\n<structure end\="1421" endstart\="1415" start\="1302" startend\="1368"/>\n<bounds height\="128" width\="79" x\="109" y\="19"/>\n</element>\n<element type\="step">\n<structure end\="1962" endstart\="1955" start\="1855" startend\="1925"/>\n<bounds height\="34" width\="74" x\="17" y\="19"/>\n</element>\n</graph>
|
||||
eclipse.preferences.version=1
|
||||
#Fri Apr 09 18:01:26 BST 2010
|
||||
//com.springsource.sts.config.flow.coordinates\:http\://www.springframework.org/schema/batch\:/spring-batch-integration/src/test/resources/org/springframework/batch/integration/chunk/ChunkStepIntegrationTests-context.xml=<?xml version\="1.0" encoding\="UTF-8"?>\n<graph>\n<element type\="job">\n<structure end\="1102" endstart\="1096" start\="901" startend\="967"/>\n<bounds height\="118" width\="79" x\="15" y\="17"/>\n</element>\n<element type\="job">\n<structure end\="1473" endstart\="1467" start\="1107" startend\="1182"/>\n<bounds height\="118" width\="127" x\="106" y\="17"/>\n</element>\n</graph>
|
||||
//com.springsource.sts.config.flow.coordinates\:http\://www.springframework.org/schema/batch\:/spring-batch-integration/src/test/resources/org/springframework/batch/integration/chunk/RemoteChunkFaultTolerantStepIntegrationTests-context.xml=<?xml version\="1.0" encoding\="UTF-8"?>\n<graph>\n<element type\="job">\n<structure end\="1667" endstart\="1661" start\="1306" startend\="1372"/>\n<bounds height\="118" width\="79" x\="15" y\="17"/>\n</element>\n</graph>
|
||||
//com.springsource.sts.config.flow.coordinates\:http\://www.springframework.org/schema/batch\:/spring-batch-integration/src/test/resources/org/springframework/batch/integration/chunk/RemoteChunkFaultTolerantStepJmsIntegrationTests-context.xml=<?xml version\="1.0" encoding\="UTF-8"?>\n<graph>\n<element type\="job">\n<structure end\="1608" endstart\="1602" start\="1257" startend\="1323"/>\n<bounds height\="118" width\="79" x\="15" y\="17"/>\n</element>\n</graph>
|
||||
//com.springsource.sts.config.flow.coordinates\:http\://www.springframework.org/schema/batch\:/spring-batch-integration/src/test/resources/org/springframework/batch/integration/chunk/RemoteChunkStepIntegrationTests-context.xml=<?xml version\="1.0" encoding\="UTF-8"?>\n<graph>\n<element type\="job">\n<structure end\="1269" endstart\="1263" start\="1067" startend\="1133"/>\n<bounds height\="118" width\="79" x\="15" y\="17"/>\n</element>\n</graph>
|
||||
//com.springsource.sts.config.flow.coordinates\:http\://www.springframework.org/schema/batch\:/spring-batch-integration/src/test/resources/org/springframework/batch/integration/file/FileToMessagesJobIntegrationTests-context.xml=<?xml version\="1.0" encoding\="UTF-8"?>\r\n<graph>\r\n<element type\="job">\r\n<structure end\="972" endstart\="966" start\="771" startend\="837"/>\r\n<bounds height\="118" width\="75" x\="15" y\="17"/>\r\n</element>\r\n</graph>
|
||||
//com.springsource.sts.config.flow.coordinates\:http\://www.springframework.org/schema/batch\:/spring-batch-integration/src/test/resources/org/springframework/batch/integration/step/StepGatewayIntegrationTests-context.xml=<?xml version\="1.0" encoding\="UTF-8"?>\n<graph>\n<element type\="job">\n<structure end\="1419" endstart\="1413" start\="1302" startend\="1368"/>\n<bounds height\="128" width\="79" x\="109" y\="19"/>\n</element>\n<element type\="step">\n<structure end\="1953" endstart\="1946" start\="1846" startend\="1916"/>\n<bounds height\="34" width\="74" x\="17" y\="19"/>\n</element>\n</graph>
|
||||
//com.springsource.sts.config.flow.coordinates\:http\://www.springframework.org/schema/batch\:/spring-batch-integration/src/test/resources/org/springframework/batch/integration/tasklet/StepGatewayIntegrationTests-context.xml=<?xml version\="1.0" encoding\="UTF-8"?>\n<graph>\n<element type\="job">\n<structure end\="1421" endstart\="1415" start\="1302" startend\="1368"/>\n<bounds height\="128" width\="79" x\="109" y\="19"/>\n</element>\n<element type\="step">\n<structure end\="1962" endstart\="1955" start\="1855" startend\="1925"/>\n<bounds height\="34" width\="74" x\="17" y\="19"/>\n</element>\n</graph>
|
||||
eclipse.preferences.version=1
|
||||
|
||||
@@ -23,6 +23,9 @@
|
||||
<config>src/test/resources/org/springframework/batch/integration/file/FileToMessagesJobIntegrationTests-context.xml</config>
|
||||
<config>src/test/resources/org/springframework/batch/integration/step/StepGatewayIntegrationTests-context.xml</config>
|
||||
<config>src/test/resources/org/springframework/batch/integration/chunk/RemoteChunkFaultTolerantStepIntegrationTests-context.xml</config>
|
||||
<config>src/test/resources/jms-context.xml</config>
|
||||
<config>src/test/resources/org/springframework/batch/integration/chunk/RemoteChunkFaultTolerantStepJmsIntegrationTests-context.xml</config>
|
||||
<config>src/test/resources/org/springframework/batch/integration/chunk/RemoteChunkStepIntegrationTests-context.xml</config>
|
||||
</configs>
|
||||
<configSets>
|
||||
</configSets>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>spring-batch-integration</artifactId>
|
||||
<name>Spring Batch Integration</name>
|
||||
@@ -10,36 +11,6 @@
|
||||
<version>1.0.0.BUILD-SNAPSHOT</version>
|
||||
<relativePath>../spring-batch-admin-parent</relativePath>
|
||||
</parent>
|
||||
<profiles>
|
||||
<profile>
|
||||
<activation>
|
||||
<activeByDefault>true</activeByDefault>
|
||||
</activation>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
<profile>
|
||||
<id>test</id>
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<skip>false</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</profile>
|
||||
</profiles>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.batch</groupId>
|
||||
@@ -58,6 +29,12 @@
|
||||
<artifactId>geronimo-jms_1.1_spec</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.activemq</groupId>
|
||||
<artifactId>activemq-core</artifactId>
|
||||
<version>5.3.0</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
@@ -93,6 +70,12 @@
|
||||
<version>${spring.integration.version}</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.integration</groupId>
|
||||
<artifactId>spring-integration-jms</artifactId>
|
||||
<version>${spring.integration.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.integration</groupId>
|
||||
<artifactId>spring-integration-adapter</artifactId>
|
||||
@@ -135,6 +118,21 @@
|
||||
<groupId>com.springsource.bundlor</groupId>
|
||||
<artifactId>com.springsource.bundlor.maven</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-clean-plugin</artifactId>
|
||||
<configuration>
|
||||
<filesets>
|
||||
<fileset>
|
||||
<directory>activemq-data</directory>
|
||||
<includes>
|
||||
<include>**</include>
|
||||
<include>*</include>
|
||||
</includes>
|
||||
</fileset>
|
||||
</filesets>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
|
||||
@@ -18,6 +18,6 @@ package org.springframework.batch.integration.chunk;
|
||||
|
||||
public interface ChunkHandler<T> {
|
||||
|
||||
ChunkResponse handleChunk(ChunkRequest<T> chunk);
|
||||
ChunkResponse handleChunk(ChunkRequest<T> chunk) throws Exception;
|
||||
|
||||
}
|
||||
@@ -195,9 +195,12 @@ public class ChunkMessageChannelItemWriter<T> extends StepExecutionListenerSuppo
|
||||
* @throws IllegalStateException if the result contains the wrong job
|
||||
* instance id (maybe we are sharing a channel and we shouldn't be)
|
||||
*/
|
||||
private void getNextResult() {
|
||||
private void getNextResult() throws AsynchronousFailureException {
|
||||
ChunkResponse payload = (ChunkResponse) messagingGateway.receive();
|
||||
if (payload != null) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Found result: "+payload);
|
||||
}
|
||||
Long jobInstanceId = payload.getJobId();
|
||||
Assert.state(jobInstanceId != null, "Message did not contain job instance id.");
|
||||
Assert.state(jobInstanceId.equals(localState.getJobId()), "Message contained wrong job instance id ["
|
||||
|
||||
@@ -22,7 +22,6 @@ import org.springframework.batch.core.JobInterruptedException;
|
||||
import org.springframework.batch.core.StepContribution;
|
||||
import org.springframework.batch.core.step.item.Chunk;
|
||||
import org.springframework.batch.core.step.item.ChunkProcessor;
|
||||
import org.springframework.batch.core.step.item.FaultTolerantChunkProcessor;
|
||||
import org.springframework.batch.core.step.skip.NonSkippableReadException;
|
||||
import org.springframework.batch.core.step.skip.SkipLimitExceededException;
|
||||
import org.springframework.batch.core.step.skip.SkipListenerFailedException;
|
||||
@@ -63,23 +62,39 @@ public class ChunkProcessorChunkHandler<S> implements ChunkHandler<S>, Initializ
|
||||
* @see ChunkHandler#handleChunk(ChunkRequest)
|
||||
*/
|
||||
@ServiceActivator
|
||||
public ChunkResponse handleChunk(ChunkRequest<S> chunkRequest) {
|
||||
public ChunkResponse handleChunk(ChunkRequest<S> chunkRequest) throws Exception {
|
||||
|
||||
logger.debug("Handling chunk: " + chunkRequest);
|
||||
|
||||
StepContribution stepContribution = chunkRequest.getStepContribution();
|
||||
Throwable failure = null;
|
||||
try {
|
||||
process(chunkRequest, stepContribution);
|
||||
}
|
||||
catch (SkipLimitExceededException e) {
|
||||
failure = e;
|
||||
}
|
||||
catch (NonSkippableReadException e) {
|
||||
failure = e;
|
||||
}
|
||||
catch (SkipListenerFailedException e) {
|
||||
failure = e;
|
||||
}
|
||||
catch (RetryException e) {
|
||||
failure = e;
|
||||
}
|
||||
catch (JobInterruptedException e) {
|
||||
failure = e;
|
||||
}
|
||||
catch (Exception e) {
|
||||
logger.debug("Failed chunk", e);
|
||||
return new ChunkResponse(false, chunkRequest.getJobId(), stepContribution, e.getClass().getName() + ": "
|
||||
+ e.getMessage());
|
||||
} catch (Throwable e) {
|
||||
// The handler might throw an Error or other non-exception
|
||||
logger.debug("Failed chunk with non-exception", e);
|
||||
return new ChunkResponse(false, chunkRequest.getJobId(), stepContribution, e.getClass().getName() + ": "
|
||||
+ e.getMessage());
|
||||
// try again...
|
||||
throw e;
|
||||
}
|
||||
|
||||
if (failure != null) {
|
||||
logger.debug("Failed chunk", failure);
|
||||
return new ChunkResponse(false, chunkRequest.getJobId(), stepContribution, failure.getClass().getName()
|
||||
+ ": " + failure.getMessage());
|
||||
}
|
||||
|
||||
logger.debug("Completed chunk handling with " + stepContribution);
|
||||
@@ -95,40 +110,7 @@ public class ChunkProcessorChunkHandler<S> implements ChunkHandler<S>, Initializ
|
||||
private void process(ChunkRequest<S> chunkRequest, StepContribution stepContribution) throws Exception {
|
||||
|
||||
Chunk<S> chunk = new Chunk<S>(chunkRequest.getItems());
|
||||
|
||||
if (chunkProcessor instanceof FaultTolerantChunkProcessor<?, ?>) {
|
||||
|
||||
boolean processed = false;
|
||||
|
||||
while (!processed) {
|
||||
try {
|
||||
chunkProcessor.process(stepContribution, chunk);
|
||||
processed = true;
|
||||
}
|
||||
catch (SkipLimitExceededException e) {
|
||||
throw e;
|
||||
}
|
||||
catch (NonSkippableReadException e) {
|
||||
throw e;
|
||||
}
|
||||
catch (SkipListenerFailedException e) {
|
||||
throw e;
|
||||
}
|
||||
catch (RetryException e) {
|
||||
throw e;
|
||||
}
|
||||
catch (JobInterruptedException e) {
|
||||
throw e;
|
||||
}
|
||||
catch (Exception e) {
|
||||
// try again...
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
chunkProcessor.process(stepContribution, chunk);
|
||||
}
|
||||
chunkProcessor.process(stepContribution, chunk);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ import org.springframework.batch.core.StepExecutionListener;
|
||||
import org.springframework.batch.core.step.item.Chunk;
|
||||
import org.springframework.batch.core.step.item.ChunkOrientedTasklet;
|
||||
import org.springframework.batch.core.step.item.ChunkProcessor;
|
||||
import org.springframework.batch.core.step.item.FaultTolerantChunkProcessor;
|
||||
import org.springframework.batch.core.step.item.SimpleChunkProcessor;
|
||||
import org.springframework.batch.core.step.tasklet.Tasklet;
|
||||
import org.springframework.batch.core.step.tasklet.TaskletStep;
|
||||
@@ -114,6 +115,7 @@ public class RemoteChunkHandlerFactoryBean<T> implements FactoryBean<ChunkHandle
|
||||
}
|
||||
|
||||
ChunkProcessorChunkHandler<T> handler = new ChunkProcessorChunkHandler<T>();
|
||||
setNonBuffering(chunkProcessor);
|
||||
handler.setChunkProcessor(chunkProcessor);
|
||||
// TODO: create step context for the processor in case it has scope="step" dependencies
|
||||
handler.afterPropertiesSet();
|
||||
@@ -122,6 +124,15 @@ public class RemoteChunkHandlerFactoryBean<T> implements FactoryBean<ChunkHandle
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param chunkProcessor
|
||||
*/
|
||||
private void setNonBuffering(ChunkProcessor<T> chunkProcessor) {
|
||||
if (chunkProcessor instanceof FaultTolerantChunkProcessor<?, ?>) {
|
||||
((FaultTolerantChunkProcessor<?, ?>)chunkProcessor).setBuffering(false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param tasklet
|
||||
* @param chunkWriter
|
||||
|
||||
@@ -17,7 +17,7 @@ public class ChunkProcessorChunkHandlerTests {
|
||||
protected int count = 0;
|
||||
|
||||
@Test
|
||||
public void testVanillaHandleChunk() {
|
||||
public void testVanillaHandleChunk() throws Exception {
|
||||
handler.setChunkProcessor(new ChunkProcessor<Object>() {
|
||||
public void process(StepContribution contribution, Chunk<Object> chunk) throws Exception {
|
||||
count += chunk.size();
|
||||
|
||||
@@ -4,7 +4,6 @@ import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.batch.core.BatchStatus;
|
||||
@@ -41,7 +40,6 @@ public class RemoteChunkFaultTolerantStepIntegrationTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void testFailedStepOnError() throws Exception {
|
||||
JobExecution jobExecution = jobLauncher.run(job, new JobParameters(Collections.singletonMap("item.three",
|
||||
new JobParameter("error"))));
|
||||
@@ -69,7 +67,8 @@ public class RemoteChunkFaultTolerantStepIntegrationTests {
|
||||
assertEquals(BatchStatus.COMPLETED, jobExecution.getStatus());
|
||||
StepExecution stepExecution = jobExecution.getStepExecutions().iterator().next();
|
||||
assertEquals(9, stepExecution.getReadCount());
|
||||
assertEquals(8, stepExecution.getWriteCount());
|
||||
assertEquals(1, stepExecution.getWriteSkipCount());
|
||||
assertEquals(7, stepExecution.getWriteCount());
|
||||
// The whole chunk gets skipped...
|
||||
assertEquals(2, stepExecution.getWriteSkipCount());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
package org.springframework.batch.integration.chunk;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.batch.core.BatchStatus;
|
||||
import org.springframework.batch.core.Job;
|
||||
import org.springframework.batch.core.JobExecution;
|
||||
import org.springframework.batch.core.JobParameter;
|
||||
import org.springframework.batch.core.JobParameters;
|
||||
import org.springframework.batch.core.JobParametersBuilder;
|
||||
import org.springframework.batch.core.StepExecution;
|
||||
import org.springframework.batch.core.launch.JobLauncher;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
@ContextConfiguration
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
public class RemoteChunkFaultTolerantStepJmsIntegrationTests {
|
||||
|
||||
@Autowired
|
||||
private JobLauncher jobLauncher;
|
||||
|
||||
@Autowired
|
||||
private Job job;
|
||||
|
||||
@Test
|
||||
public void testFailedStep() throws Exception {
|
||||
JobExecution jobExecution = jobLauncher.run(job, new JobParameters(Collections.singletonMap("item.three",
|
||||
new JobParameter("unsupported"))));
|
||||
assertEquals(BatchStatus.FAILED, jobExecution.getStatus());
|
||||
StepExecution stepExecution = jobExecution.getStepExecutions().iterator().next();
|
||||
assertEquals(9, stepExecution.getReadCount());
|
||||
// In principle the write count could be more than 2 and less than 9...
|
||||
assertEquals(7, stepExecution.getWriteCount());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailedStepOnError() throws Exception {
|
||||
JobExecution jobExecution = jobLauncher.run(job, new JobParameters(Collections.singletonMap("item.three",
|
||||
new JobParameter("error"))));
|
||||
assertEquals(BatchStatus.FAILED, jobExecution.getStatus());
|
||||
StepExecution stepExecution = jobExecution.getStepExecutions().iterator().next();
|
||||
assertEquals(9, stepExecution.getReadCount());
|
||||
// In principle the write count could be more than 2 and less than 9...
|
||||
assertEquals(7, stepExecution.getWriteCount());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSunnyDayFaultTolerant() throws Exception {
|
||||
JobExecution jobExecution = jobLauncher.run(job, new JobParameters(Collections.singletonMap("item.three",
|
||||
new JobParameter("3"))));
|
||||
assertEquals(BatchStatus.COMPLETED, jobExecution.getStatus());
|
||||
StepExecution stepExecution = jobExecution.getStepExecutions().iterator().next();
|
||||
assertEquals(9, stepExecution.getReadCount());
|
||||
assertEquals(9, stepExecution.getWriteCount());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSkipsInWriter() throws Exception {
|
||||
JobExecution jobExecution = jobLauncher.run(job, new JobParametersBuilder().addString("item.three", "fail")
|
||||
.addLong("run.id", 1L).toJobParameters());
|
||||
assertEquals(BatchStatus.COMPLETED, jobExecution.getStatus());
|
||||
StepExecution stepExecution = jobExecution.getStepExecutions().iterator().next();
|
||||
assertEquals(9, stepExecution.getReadCount());
|
||||
assertEquals(7, stepExecution.getWriteCount());
|
||||
assertEquals(2, stepExecution.getWriteSkipCount());
|
||||
}
|
||||
}
|
||||
41
spring-batch-integration/src/test/resources/jms-context.xml
Normal file
41
spring-batch-integration/src/test/resources/jms-context.xml
Normal file
@@ -0,0 +1,41 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:aop="http://www.springframework.org/schema/aop"
|
||||
xmlns:p="http://www.springframework.org/schema/p" xmlns:tx="http://www.springframework.org/schema/tx"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="
|
||||
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
|
||||
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
|
||||
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">
|
||||
|
||||
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
|
||||
<property name="connectionFactory" ref="connectionFactory" />
|
||||
<property name="receiveTimeout" value="100" />
|
||||
<!-- This is important... -->
|
||||
<property name="sessionTransacted" value="true" />
|
||||
</bean>
|
||||
|
||||
<bean id="connectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory" depends-on="brokerService">
|
||||
<property name="brokerURL">
|
||||
<value>vm://localhost</value>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="brokerService" class="org.apache.activemq.broker.BrokerService" init-method="start"
|
||||
destroy-method="stop">
|
||||
<property name="brokerName" value="localhost" />
|
||||
<property name="useJmx" value="false"/>
|
||||
<property name="transportConnectorURIs">
|
||||
<list>
|
||||
<value>vm://localhost</value>
|
||||
</list>
|
||||
</property>
|
||||
<property name="persistenceAdapter">
|
||||
<bean class="org.apache.activemq.store.memory.MemoryPersistenceAdapter"/>
|
||||
<!-- bean class="org.apache.activemq.store.jdbc.JDBCPersistenceAdapter">
|
||||
<property name="dataSource" ref="dataSource"/>
|
||||
<property name="createTablesOnStartup" value="true" />
|
||||
</bean-->
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
@@ -6,6 +6,7 @@ log4j.appender.stdout.layout.ConversionPattern=%d %5p %t [%c] - <%m>%n
|
||||
|
||||
log4j.category.org.springframework.context=INFO
|
||||
log4j.category.org.springframework.beans=INFO
|
||||
log4j.category.org.springframework.batch.retry=DEBUG
|
||||
log4j.category.org.springframework.batch.core=DEBUG
|
||||
log4j.category.org.springframework.batch.integration=DEBUG
|
||||
log4j.category.org.springframework.transaction=INFO
|
||||
@@ -1,19 +1,22 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:beans="http://www.springframework.org/schema/beans"
|
||||
xmlns:integration="http://www.springframework.org/schema/integration"
|
||||
xmlns:beans="http://www.springframework.org/schema/beans" xmlns:integration="http://www.springframework.org/schema/integration"
|
||||
xmlns:batch="http://www.springframework.org/schema/batch" xmlns:context="http://www.springframework.org/schema/context"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration-1.0.xsd
|
||||
xmlns:aop="http://www.springframework.org/schema/aop"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
|
||||
http://www.springframework.org/schema/jms http://www.springframework.org/schema/jms/spring-jms-3.0.xsd
|
||||
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration-1.0.xsd
|
||||
http://www.springframework.org/schema/integration/jms http://www.springframework.org/schema/integration/jms/spring-integration-jms-1.0.xsd
|
||||
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
|
||||
http://www.springframework.org/schema/batch http://www.springframework.org/schema/batch/spring-batch-2.1.xsd
|
||||
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
|
||||
|
||||
<job id="tolerant-job" xmlns="http://www.springframework.org/schema/batch">
|
||||
<step id="tolerant-step">
|
||||
<job id="job" xmlns="http://www.springframework.org/schema/batch">
|
||||
<step id="step">
|
||||
<tasklet>
|
||||
<chunk reader="reader" writer="writer" commit-interval="2" skip-limit="2">
|
||||
<skippable-exception-classes>
|
||||
<include class="java.lang.IllegalStateException"/>
|
||||
<include class="java.lang.IllegalStateException" />
|
||||
</skippable-exception-classes>
|
||||
</chunk>
|
||||
</tasklet>
|
||||
@@ -43,20 +46,19 @@
|
||||
</bean>
|
||||
|
||||
<bean id="messagingGateway" class="org.springframework.integration.gateway.SimpleMessagingGateway">
|
||||
<property name="requestChannel" ref="tolerant-requests" />
|
||||
<property name="replyChannel" ref="tolerant-replies" />
|
||||
<property name="requestChannel" ref="requests" />
|
||||
<property name="replyChannel" ref="replies" />
|
||||
<property name="replyTimeout" value="1000" />
|
||||
</bean>
|
||||
|
||||
<integration:channel id="tolerant-requests" />
|
||||
<integration:channel id="tolerant-replies">
|
||||
<integration:queue />
|
||||
</integration:channel>
|
||||
<integration:service-activator input-channel="tolerant-requests" output-channel="tolerant-replies" ref="tolerant-chunkHandler" />
|
||||
<integration:channel id="requests" />
|
||||
<!-- If we use a direct channel for requests then the replies can come in on a thread-local -->
|
||||
<integration:thread-local-channel id="replies"/>
|
||||
<integration:service-activator input-channel="requests" output-channel="replies" ref="chunkHandler" />
|
||||
|
||||
<bean id="tolerant-chunkHandler" class="org.springframework.batch.integration.chunk.RemoteChunkHandlerFactoryBean">
|
||||
<bean id="chunkHandler" class="org.springframework.batch.integration.chunk.RemoteChunkHandlerFactoryBean">
|
||||
<property name="chunkWriter" ref="chunkWriter" />
|
||||
<property name="step" ref="tolerant-step" />
|
||||
<property name="step" ref="step" />
|
||||
</bean>
|
||||
|
||||
<bean id="transactionManager" class="org.springframework.batch.support.transaction.ResourcelessTransactionManager" />
|
||||
@@ -68,5 +70,23 @@
|
||||
<bean id="jobLauncher" class="org.springframework.batch.core.launch.support.SimpleJobLauncher">
|
||||
<property name="jobRepository" ref="jobRepository" />
|
||||
</bean>
|
||||
|
||||
|
||||
<bean id="retryAdvice" class="org.springframework.batch.retry.interceptor.RetryOperationsInterceptor">
|
||||
<property name="retryOperations">
|
||||
<bean class="org.springframework.batch.retry.support.RetryTemplate">
|
||||
<property name="retryPolicy">
|
||||
<bean class="org.springframework.batch.retry.policy.SimpleRetryPolicy">
|
||||
<property name="maxAttempts" value="10" />
|
||||
</bean>
|
||||
</property>
|
||||
</bean>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<!-- Simulate JMS rollback and redelivery using a direct channel and a retry -->
|
||||
<aop:config>
|
||||
<aop:advisor advice-ref="retryAdvice"
|
||||
pointcut="execution(* org.springframework.integration.core.MessageChannel+.send(..)) and bean(requests)" />
|
||||
</aop:config>
|
||||
|
||||
</beans>
|
||||
@@ -0,0 +1,83 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:integration="http://www.springframework.org/schema/integration" xmlns:batch="http://www.springframework.org/schema/batch"
|
||||
xmlns:context="http://www.springframework.org/schema/context" xmlns:int-jms="http://www.springframework.org/schema/integration/jms"
|
||||
xmlns:jms="http://www.springframework.org/schema/jms"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/jms http://www.springframework.org/schema/jms/spring-jms-3.0.xsd
|
||||
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration-1.0.xsd
|
||||
http://www.springframework.org/schema/integration/jms http://www.springframework.org/schema/integration/jms/spring-integration-jms-1.0.xsd
|
||||
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
|
||||
http://www.springframework.org/schema/batch http://www.springframework.org/schema/batch/spring-batch-2.1.xsd
|
||||
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
|
||||
|
||||
<import resource="classpath:/jms-context.xml" />
|
||||
|
||||
<job id="job" xmlns="http://www.springframework.org/schema/batch">
|
||||
<step id="step">
|
||||
<tasklet>
|
||||
<chunk reader="reader" writer="writer" commit-interval="2" skip-limit="2">
|
||||
<skippable-exception-classes>
|
||||
<include class="java.lang.IllegalStateException" />
|
||||
</skippable-exception-classes>
|
||||
</chunk>
|
||||
</tasklet>
|
||||
</step>
|
||||
</job>
|
||||
|
||||
<bean id="reader" class="org.springframework.batch.integration.chunk.TestItemReader" scope="step">
|
||||
<property name="items">
|
||||
<list>
|
||||
<value>1</value>
|
||||
<value>2</value>
|
||||
<value>#{jobParameters['item.three']}</value>
|
||||
<value>4</value>
|
||||
<value>5</value>
|
||||
<value>6</value>
|
||||
<value>7</value>
|
||||
<value>8</value>
|
||||
<value>9</value>
|
||||
</list>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
<bean id="writer" class="org.springframework.batch.integration.chunk.TestItemWriter" />
|
||||
|
||||
<bean id="chunkWriter" class="org.springframework.batch.integration.chunk.ChunkMessageChannelItemWriter" scope="step">
|
||||
<property name="messagingGateway" ref="messagingGateway" />
|
||||
</bean>
|
||||
|
||||
<bean id="messagingGateway" class="org.springframework.integration.gateway.SimpleMessagingGateway">
|
||||
<property name="requestChannel" ref="requests" />
|
||||
<property name="replyChannel" ref="replies" />
|
||||
<property name="replyTimeout" value="1000" />
|
||||
</bean>
|
||||
|
||||
<int-jms:outbound-channel-adapter connection-factory="connectionFactory" channel="requests"
|
||||
destination-name="requests" />
|
||||
<int-jms:message-driven-channel-adapter connection-factory="connectionFactory"
|
||||
channel="replies" destination-name="replies" transaction-manager="transactionManager" acknowledge="transacted"/>
|
||||
<integration:channel id="requests" />
|
||||
<integration:channel id="replies">
|
||||
<integration:queue />
|
||||
</integration:channel>
|
||||
|
||||
<jms:listener-container connection-factory="connectionFactory" transaction-manager="transactionManager" acknowledge="transacted">
|
||||
<jms:listener destination="requests" response-destination="replies" ref="chunkHandler" method="handleChunk" />
|
||||
</jms:listener-container>
|
||||
|
||||
<bean id="chunkHandler" class="org.springframework.batch.integration.chunk.RemoteChunkHandlerFactoryBean">
|
||||
<property name="chunkWriter" ref="chunkWriter" />
|
||||
<property name="step" ref="step" />
|
||||
</bean>
|
||||
|
||||
<bean id="transactionManager" class="org.springframework.batch.support.transaction.ResourcelessTransactionManager" />
|
||||
|
||||
<bean id="jobRepository" class="org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean">
|
||||
<property name="transactionManager" ref="transactionManager" />
|
||||
</bean>
|
||||
|
||||
<bean id="jobLauncher" class="org.springframework.batch.core.launch.support.SimpleJobLauncher">
|
||||
<property name="jobRepository" ref="jobRepository" />
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
@@ -1,8 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:beans="http://www.springframework.org/schema/beans" xmlns:integration="http://www.springframework.org/schema/integration"
|
||||
xmlns:beans="http://www.springframework.org/schema/beans"
|
||||
xmlns:integration="http://www.springframework.org/schema/integration"
|
||||
xmlns:batch="http://www.springframework.org/schema/batch" xmlns:context="http://www.springframework.org/schema/context"
|
||||
xmlns:task="http://www.springframework.org/schema/task"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration-1.0.xsd
|
||||
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd
|
||||
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
|
||||
http://www.springframework.org/schema/batch http://www.springframework.org/schema/batch/spring-batch-2.1.xsd
|
||||
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
|
||||
@@ -43,19 +46,14 @@
|
||||
<property name="replyTimeout" value="1000" />
|
||||
</bean>
|
||||
|
||||
<integration:poller default="true">
|
||||
<integration:interval-trigger interval="50" />
|
||||
<integration:transactional/>
|
||||
</integration:poller>
|
||||
<task:executor id="poolExecutor" pool-size="5-10" queue-capacity="0"/>
|
||||
|
||||
<integration:channel id="requests">
|
||||
<integration:queue />
|
||||
</integration:channel>
|
||||
<!-- A pub-sub channel with task executor is a decent approximation to a JMS outbound adapter -->
|
||||
<integration:publish-subscribe-channel id="requests" task-executor="poolExecutor"/>
|
||||
<integration:channel id="replies">
|
||||
<integration:queue />
|
||||
</integration:channel>
|
||||
|
||||
<integration:service-activator input-channel="requests" output-channel="replies" ref="chunkHandler"/>
|
||||
<integration:service-activator input-channel="requests" output-channel="replies" ref="chunkHandler" />
|
||||
|
||||
<bean id="chunkHandler" class="org.springframework.batch.integration.chunk.RemoteChunkHandlerFactoryBean">
|
||||
<property name="chunkWriter" ref="chunkWriter" />
|
||||
|
||||
Reference in New Issue
Block a user