Add MessageChannelPartitionHandler

This commit is contained in:
dsyer
2009-05-06 12:22:21 +00:00
parent 11deb78a44
commit 91cf3c83c3
14 changed files with 687 additions and 3 deletions

View File

@@ -0,0 +1,59 @@
package org.springframework.batch.integration.partition;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import org.junit.Test;
import org.springframework.batch.core.JobInterruptedException;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.StepExecution;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
public class BeanFactoryStepLocatorTests {
private BeanFactoryStepLocator stepLocator = new BeanFactoryStepLocator();
private DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
@Test
public void testGetStep() throws Exception {
beanFactory.registerSingleton("foo", new StubStep("foo"));
stepLocator.setBeanFactory(beanFactory);
assertNotNull(stepLocator.getStep("foo"));
}
@Test
public void testGetStepNames() throws Exception {
beanFactory.registerSingleton("foo", new StubStep("foo"));
beanFactory.registerSingleton("bar", new StubStep("bar"));
stepLocator.setBeanFactory(beanFactory);
assertEquals(2, stepLocator.getStepNames().size());
}
private static final class StubStep implements Step {
private String name;
public StubStep(String name) {
this.name = name;
}
public void execute(StepExecution stepExecution) throws JobInterruptedException {
}
public String getName() {
return name;
}
public int getStartLimit() {
// TODO Auto-generated method stub
return 0;
}
public boolean isAllowStartIfComplete() {
// TODO Auto-generated method stub
return false;
}
}
}

View File

@@ -0,0 +1,57 @@
package org.springframework.batch.integration.partition;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.batch.item.ExecutionContext;
import org.springframework.batch.item.ItemReader;
import org.springframework.batch.item.ItemStream;
import org.springframework.batch.item.ItemStreamException;
/**
* {@link ItemReader} with hard-coded input data.
*/
public class ExampleItemReader implements ItemReader<String>, ItemStream {
private Log logger = LogFactory.getLog(getClass());
private String[] input = { "Hello", "world!", "Go", "on", "punk", "make", "my", "day!" };
private int index = 0;
public static volatile boolean fail = false;
/**
* Reads next record from input
*/
public String read() throws Exception {
if (index >= input.length) {
return null;
}
logger.info(String.format("Processing input index=%s, item=%s, in (%s)", index, input[index], this));
if (fail && index == 4) {
synchronized (ExampleItemReader.class) {
if (fail) {
// Only fail once per flag setting...
fail = false;
logger.info(String.format("Throwing exception index=%s, item=%s, in (%s)", index, input[index],
this));
index++;
throw new RuntimeException("Planned failure");
}
}
}
return input[index++];
}
public void close() throws ItemStreamException {
}
public void open(ExecutionContext executionContext) throws ItemStreamException {
index = (int) executionContext.getLong("POSITION", 0);
}
public void update(ExecutionContext executionContext) throws ItemStreamException {
executionContext.putLong("POSITION", index);
}
}

View File

@@ -0,0 +1,70 @@
package org.springframework.batch.integration.partition;
import static org.junit.Assert.*;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.batch.item.ExecutionContext;
public class ExampleItemReaderTests {
private ExampleItemReader reader = new ExampleItemReader();
@Before
@After
public void ensureFailFlagUnset() {
ExampleItemReader.fail = false;
}
@Test
public void testRead() throws Exception {
int count = 0;
while (reader.read()!=null) {
count++;
}
assertEquals(8, count);
}
@Test
public void testOpen() throws Exception {
ExecutionContext context = new ExecutionContext();
for (int i=0; i<4; i++) {
reader.read();
}
reader.update(context);
reader.open(context);
int count = 0;
while (reader.read()!=null) {
count++;
}
assertEquals(4, count);
}
@Test
public void testFailAndRestart() throws Exception {
ExecutionContext context = new ExecutionContext();
ExampleItemReader.fail = true;
for (int i=0; i<4; i++) {
reader.read();
reader.update(context);
}
try {
reader.read();
reader.update(context);
fail("Expected Exception");
}
catch (Exception e) {
// expected
assertEquals("Planned failure", e.getMessage());
}
assertFalse(ExampleItemReader.fail);
reader.open(context);
int count = 0;
while (reader.read()!=null) {
count++;
}
assertEquals(4, count);
}
}

View File

@@ -0,0 +1,23 @@
package org.springframework.batch.integration.partition;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.batch.item.ItemWriter;
/**
* Dummy {@link ItemWriter} which only logs data it receives.
*/
public class ExampleItemWriter implements ItemWriter<Object> {
private static final Log log = LogFactory.getLog(ExampleItemWriter.class);
/**
* @see ItemWriter#write(List)
*/
public void write(List<? extends Object> data) throws Exception {
log.info(data);
}
}

View File

@@ -0,0 +1,70 @@
/*
* Copyright 2006-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.batch.integration.partition;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import java.util.List;
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.JobInstance;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.explore.JobExplorer;
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;
/**
* @author Dave Syer
*
*/
@ContextConfiguration
@RunWith(SpringJUnit4ClassRunner.class)
public class VanillaIntegrationTests {
@Autowired
private JobLauncher jobLauncher;
@Autowired
private Job job;
@Autowired
private JobExplorer jobExplorer;
@Test
public void testSimpleProperties() throws Exception {
assertNotNull(jobLauncher);
}
@Test
public void testLaunchJob() throws Exception {
int before = jobExplorer.getJobInstances(job.getName(), 0, 100).size();
assertNotNull(jobLauncher.run(job, new JobParameters()));
List<JobInstance> jobInstances = jobExplorer.getJobInstances(job.getName(), 0, 100);
int after = jobInstances.size();
assertEquals(1, after-before);
JobExecution jobExecution = jobExplorer.getJobExecutions(jobInstances.get(jobInstances.size()-1)).get(0);
assertEquals(BatchStatus.COMPLETED, jobExecution.getStatus());
assertEquals(3, jobExecution.getStepExecutions().size());
}
}

View File

@@ -4,6 +4,6 @@ log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %5p %t [%c] - <%m>%n
log4j.logger.org.springframework.batch=DEBUG
log4j.logger.org.springframework.batch.core=DEBUG
log4j.category.org.springframework.integration=DEBUG
log4j.category.org.springframework.transaction=DEBUG

View File

@@ -10,10 +10,11 @@
http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
<annotation-config/>
<channel id="smokein"/>
<channel id="smokeout">
<queue/>
</channel>
</beans:beans>

View File

@@ -0,0 +1,96 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p" xmlns:integration="http://www.springframework.org/schema/integration"
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.xsd
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration-1.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<import resource="classpath:/simple-job-launcher-context.xml" />
<integration:channel id="requests">
<integration:queue />
</integration:channel>
<integration:channel id="staging">
<integration:queue />
</integration:channel>
<integration:channel id="replies">
<integration:queue />
</integration:channel>
<integration:service-activator ref="stepExecutionRequestHandler"
input-channel="requests" output-channel="staging">
<integration:poller>
<integration:interval-trigger interval="10"/>
</integration:poller>
</integration:service-activator>
<integration:aggregator ref="partitionHandler"
timeout="10000" input-channel="staging" output-channel="replies">
<integration:poller>
<integration:interval-trigger interval="10"/>
</integration:poller>
</integration:aggregator>
<!-- This is the "remote" worker (which in this case is local) -->
<bean id="stepExecutionRequestHandler"
class="org.springframework.batch.integration.partition.StepExecutionRequestHandler"
p:jobExplorer-ref="jobExplorer" p:stepLocator-ref="stepLocator" />
<bean id="stepLocator"
class="org.springframework.batch.integration.partition.BeanFactoryStepLocator" />
<bean id="jobExplorer"
class="org.springframework.batch.core.explore.support.MapJobExplorerFactoryBean" />
<bean id="partitionHandler"
class="org.springframework.batch.integration.partition.MessageChannelPartitionHandler">
<property name="messagingGateway">
<bean
class="org.springframework.integration.gateway.SimpleMessagingGateway">
<property name="requestChannel" ref="requests" />
<property name="replyChannel" ref="replies" />
<property name="replyTimeout" value="10000" />
</bean>
</property>
<property name="stepName" value="step1" />
<property name="gridSize" value="2" />
</bean>
<bean id="job1" parent="simpleJob">
<property name="steps">
<bean name="step1:master"
class="org.springframework.batch.core.partition.support.PartitionStep">
<property name="partitionHandler" ref="partitionHandler" />
<property name="stepExecutionSplitter">
<bean
class="org.springframework.batch.core.partition.support.SimpleStepExecutionSplitter">
<constructor-arg ref="jobRepository" />
<constructor-arg ref="step1" />
</bean>
</property>
<property name="jobRepository" ref="jobRepository" />
</bean>
</property>
</bean>
<bean id="step1" parent="simpleStep">
<property name="itemReader">
<bean
class="org.springframework.batch.integration.partition.ExampleItemReader"
scope="step">
<!--
<property name="resource"
value="#{stepAttributes[jobParameters['resource']]}"/>
-->
</bean>
</property>
<property name="itemWriter">
<bean
class="org.springframework.batch.integration.partition.ExampleItemWriter" />
</property>
</bean>
<bean class="org.springframework.batch.core.scope.StepScope" />
</beans>