BATCHADM-49: added JMS integration test

This commit is contained in:
David Syer
2010-04-10 15:18:59 +00:00
committed by Michael Minella
parent c1616f0bbb
commit 6ca0512753
15 changed files with 329 additions and 116 deletions

View File

@@ -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

View File

@@ -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>

View File

@@ -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>

View File

@@ -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;
}

View File

@@ -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 ["

View File

@@ -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);
}
}

View File

@@ -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

View File

@@ -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();

View File

@@ -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());
}
}

View File

@@ -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());
}
}

View 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>

View File

@@ -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

View File

@@ -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>

View File

@@ -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>

View File

@@ -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" />