Add Spring Integration prototype code
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* 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.integration.batch;
|
||||
|
||||
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.Step;
|
||||
import org.springframework.batch.core.StepExecution;
|
||||
import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException;
|
||||
import org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException;
|
||||
import org.springframework.batch.core.repository.JobRepository;
|
||||
import org.springframework.batch.core.repository.JobRestartException;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public class JobRepositorySupport implements JobRepository {
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.batch.core.repository.JobRepository#createJobExecution(org.springframework.batch.core.Job, org.springframework.batch.core.JobParameters)
|
||||
*/
|
||||
public JobExecution createJobExecution(Job job, JobParameters jobParameters)
|
||||
throws JobExecutionAlreadyRunningException, JobRestartException, JobInstanceAlreadyCompleteException {
|
||||
return new JobExecution(new JobInstance(0L, jobParameters, job.getName()));
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.batch.core.repository.JobRepository#getLastStepExecution(org.springframework.batch.core.JobInstance, org.springframework.batch.core.Step)
|
||||
*/
|
||||
public StepExecution getLastStepExecution(JobInstance jobInstance, Step step) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.batch.core.repository.JobRepository#getStepExecutionCount(org.springframework.batch.core.JobInstance, org.springframework.batch.core.Step)
|
||||
*/
|
||||
public int getStepExecutionCount(JobInstance jobInstance, Step step) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.batch.core.repository.JobRepository#saveOrUpdate(org.springframework.batch.core.JobExecution)
|
||||
*/
|
||||
public void saveOrUpdate(JobExecution jobExecution) {
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.batch.core.repository.JobRepository#saveOrUpdate(org.springframework.batch.core.StepExecution)
|
||||
*/
|
||||
public void saveOrUpdate(StepExecution stepExecution) {
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.batch.core.repository.JobRepository#saveOrUpdateExecutionContext(org.springframework.batch.core.StepExecution)
|
||||
*/
|
||||
public void saveOrUpdateExecutionContext(StepExecution stepExecution) {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package org.springframework.integration.batch;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.batch.core.Job;
|
||||
import org.springframework.batch.core.JobExecution;
|
||||
import org.springframework.batch.core.JobExecutionException;
|
||||
|
||||
public class JobSupport implements Job {
|
||||
|
||||
String name;
|
||||
|
||||
public JobSupport(String name){
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public void execute(JobExecution execution) throws JobExecutionException {
|
||||
// TODO Auto-generated method stub
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public List getSteps() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean isRestartable() {
|
||||
// TODO Auto-generated method stub
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package org.springframework.integration.batch;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.integration.annotation.Handler;
|
||||
import org.springframework.integration.annotation.MessageEndpoint;
|
||||
import org.springframework.integration.channel.MessageChannel;
|
||||
import org.springframework.integration.message.GenericMessage;
|
||||
import org.springframework.integration.message.Message;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
@ContextConfiguration(locations = "/integration-context.xml")
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@MessageEndpoint(input = "smokein", output = "smokeout")
|
||||
public class SmokeTests {
|
||||
|
||||
@Autowired
|
||||
@Qualifier("smokein")
|
||||
private MessageChannel smokein;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("smokeout")
|
||||
private MessageChannel smokeout;
|
||||
|
||||
// This has to be static because the MessageBus registers the handler
|
||||
// more than once (every time a test instance is created), but only one of
|
||||
// them will get the message.
|
||||
private volatile static int count = 0;
|
||||
|
||||
@Handler
|
||||
public String process(String message) {
|
||||
count++;
|
||||
String result = message + ": " + count;
|
||||
return result;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDummyWithSimpleAssert() throws Exception {
|
||||
assertTrue(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVanillaSendAndReceive() throws Exception {
|
||||
smokein.send(new GenericMessage<String>("foo"));
|
||||
Message<?> message = smokeout.receive(100);
|
||||
String result = (String) (message == null ? null : message.getPayload());
|
||||
assertEquals("foo: 1", result);
|
||||
assertEquals(1, count);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* 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.integration.batch;
|
||||
|
||||
import org.springframework.batch.core.JobInterruptedException;
|
||||
import org.springframework.batch.core.Step;
|
||||
import org.springframework.batch.core.StepExecution;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public class StepSupport implements Step {
|
||||
|
||||
private String name;
|
||||
private int startLimit;
|
||||
|
||||
/**
|
||||
* @param name
|
||||
*/
|
||||
public StepSupport(String name) {
|
||||
super();
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.batch.core.Step#execute(org.springframework.batch.core.StepExecution)
|
||||
*/
|
||||
public void execute(StepExecution stepExecution) throws JobInterruptedException {
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.batch.core.Step#getName()
|
||||
*/
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.batch.core.Step#getStartLimit()
|
||||
*/
|
||||
public int getStartLimit() {
|
||||
return startLimit;
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.batch.core.Step#isAllowStartIfComplete()
|
||||
*/
|
||||
public boolean isAllowStartIfComplete() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Public setter for the startLimit.
|
||||
* @param startLimit the startLimit to set
|
||||
*/
|
||||
public void setStartLimit(int startLimit) {
|
||||
this.startLimit = startLimit;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,330 @@
|
||||
package org.springframework.integration.batch.chunk;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.batch.core.BatchStatus;
|
||||
import org.springframework.batch.core.JobExecution;
|
||||
import org.springframework.batch.core.JobParametersBuilder;
|
||||
import org.springframework.batch.core.Step;
|
||||
import org.springframework.batch.core.StepExecution;
|
||||
import org.springframework.batch.core.UnexpectedJobExecutionException;
|
||||
import org.springframework.batch.core.job.SimpleJob;
|
||||
import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException;
|
||||
import org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException;
|
||||
import org.springframework.batch.core.repository.JobRestartException;
|
||||
import org.springframework.batch.core.repository.dao.MapJobExecutionDao;
|
||||
import org.springframework.batch.core.repository.dao.MapJobInstanceDao;
|
||||
import org.springframework.batch.core.repository.dao.MapStepExecutionDao;
|
||||
import org.springframework.batch.core.repository.support.SimpleJobRepository;
|
||||
import org.springframework.batch.core.step.item.SimpleStepFactoryBean;
|
||||
import org.springframework.batch.item.ExecutionContext;
|
||||
import org.springframework.batch.item.support.ListItemReader;
|
||||
import org.springframework.batch.repeat.ExitStatus;
|
||||
import org.springframework.batch.support.transaction.ResourcelessTransactionManager;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.integration.channel.MessageChannel;
|
||||
import org.springframework.integration.message.GenericMessage;
|
||||
import org.springframework.integration.message.Message;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@ContextConfiguration
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
public class ChunkMessageItemWriterIntegrationTests {
|
||||
|
||||
private ChunkMessageChannelItemWriter writer = new ChunkMessageChannelItemWriter();
|
||||
|
||||
@Autowired
|
||||
@Qualifier("requests")
|
||||
private MessageChannel requests;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("replies")
|
||||
private MessageChannel replies;
|
||||
|
||||
private SimpleStepFactoryBean factory;
|
||||
|
||||
private SimpleJobRepository jobRepository;
|
||||
|
||||
private static long jobCounter;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
|
||||
factory = new SimpleStepFactoryBean();
|
||||
jobRepository = new SimpleJobRepository(new MapJobInstanceDao(),
|
||||
new MapJobExecutionDao(), new MapStepExecutionDao());
|
||||
factory.setJobRepository(jobRepository);
|
||||
factory.setTransactionManager(new ResourcelessTransactionManager());
|
||||
factory.setBeanName("step");
|
||||
factory.setItemWriter(writer);
|
||||
factory.setCommitInterval(4);
|
||||
|
||||
writer.setReplyChannel(replies);
|
||||
writer.setRequestChannel(requests);
|
||||
|
||||
TestItemWriter.count = 0;
|
||||
|
||||
// Drain queues
|
||||
Message<?> message = requests.receive(10);
|
||||
while (message!=null) {
|
||||
System.err.println(message);
|
||||
message = requests.receive(10);
|
||||
}
|
||||
message = replies.receive(10);
|
||||
while (message!=null) {
|
||||
System.err.println(message);
|
||||
message = replies.receive(10);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
while(requests.receive(10L)!=null) {}
|
||||
while(replies.receive(10L)!=null) {}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOpenWithNoState() throws Exception {
|
||||
writer.open(new ExecutionContext());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateAndOpenWithState() throws Exception {
|
||||
ExecutionContext executionContext = new ExecutionContext();
|
||||
writer.update(executionContext);
|
||||
writer.open(executionContext);
|
||||
assertEquals(0, executionContext
|
||||
.getLong(ChunkMessageChannelItemWriter.EXPECTED));
|
||||
assertEquals(0, executionContext
|
||||
.getLong(ChunkMessageChannelItemWriter.ACTUAL));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVanillaIteration() throws Exception {
|
||||
|
||||
factory.setItemReader(new ListItemReader(Arrays.asList(StringUtils
|
||||
.commaDelimitedListToStringArray("1,2,3,4,5,6"))));
|
||||
|
||||
Step step = (Step) factory.getObject();
|
||||
|
||||
StepExecution stepExecution = getStepExecution(step);
|
||||
step.execute(stepExecution);
|
||||
|
||||
waitForResults(6, 10);
|
||||
|
||||
assertEquals(6, TestItemWriter.count);
|
||||
assertEquals(6, stepExecution.getItemCount().intValue());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSimulatedRestart() throws Exception {
|
||||
|
||||
factory.setItemReader(new ListItemReader(Arrays.asList(StringUtils
|
||||
.commaDelimitedListToStringArray("1,2,3,4,5,6"))));
|
||||
|
||||
Step step = (Step) factory.getObject();
|
||||
|
||||
StepExecution stepExecution = getStepExecution(step);
|
||||
|
||||
// Set up context with two messages (chunks) in the backlog
|
||||
stepExecution.getExecutionContext().putLong(
|
||||
ChunkMessageChannelItemWriter.EXPECTED, 6);
|
||||
stepExecution.getExecutionContext().putLong(
|
||||
ChunkMessageChannelItemWriter.ACTUAL, 4);
|
||||
// And make the back log real
|
||||
requests.send(getSimpleMessage("foo", stepExecution.getJobExecution().getJobId()));
|
||||
requests.send(getSimpleMessage("bar", stepExecution.getJobExecution().getJobId()));
|
||||
step.execute(stepExecution);
|
||||
|
||||
waitForResults(8, 10);
|
||||
|
||||
assertEquals(8, TestItemWriter.count);
|
||||
assertEquals(6, stepExecution.getItemCount().intValue());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSimulatedRestartWithBadMessagesFromAnotherJob() throws Exception {
|
||||
|
||||
factory.setItemReader(new ListItemReader(Arrays.asList(StringUtils
|
||||
.commaDelimitedListToStringArray("1,2,3,4,5,6"))));
|
||||
|
||||
Step step = (Step) factory.getObject();
|
||||
|
||||
StepExecution stepExecution = getStepExecution(step);
|
||||
|
||||
// Set up context with two messages (chunks) in the backlog
|
||||
stepExecution.getExecutionContext().putLong(
|
||||
ChunkMessageChannelItemWriter.EXPECTED, 3);
|
||||
stepExecution.getExecutionContext().putLong(
|
||||
ChunkMessageChannelItemWriter.ACTUAL, 2);
|
||||
// And make the back log real
|
||||
requests.send(getSimpleMessage("foo", new Long(4321)));
|
||||
try {
|
||||
step.execute(stepExecution);
|
||||
fail("Expected UnexpectedJobExecutionException");
|
||||
} catch (UnexpectedJobExecutionException e) {
|
||||
String message = e.getCause().getMessage();
|
||||
assertTrue("Message does not contain 'wrong job': "+message, message.contains("wrong job"));
|
||||
}
|
||||
|
||||
waitForResults(1, 10);
|
||||
|
||||
assertEquals(1, TestItemWriter.count);
|
||||
assertEquals(0, stepExecution.getItemCount().intValue());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param jobId
|
||||
* @param string
|
||||
* @return
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private GenericMessage<ChunkRequest> getSimpleMessage(String string, Long jobId) {
|
||||
ChunkRequest chunk = new ChunkRequest(StringUtils
|
||||
.commaDelimitedListToSet(string), jobId, 0);
|
||||
GenericMessage<ChunkRequest> message = new GenericMessage<ChunkRequest>(chunk);
|
||||
return message;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEarlyCompletionSignalledInHandler() throws Exception {
|
||||
|
||||
factory.setItemReader(new ListItemReader(Arrays.asList(StringUtils
|
||||
.commaDelimitedListToStringArray("1,bad,3,4,5,6"))));
|
||||
factory.setCommitInterval(2);
|
||||
|
||||
Step step = (Step) factory.getObject();
|
||||
|
||||
StepExecution stepExecution = getStepExecution(step);
|
||||
try {
|
||||
step.execute(stepExecution);
|
||||
fail("Expected AsynchronousFailureException");
|
||||
} catch (AsynchronousFailureException e) {
|
||||
assertTrue(e.getMessage().contains("bad"));
|
||||
}
|
||||
|
||||
waitForResults(2, 10);
|
||||
|
||||
// The number of items processed is actually between 1 and 6, because
|
||||
// the one that failed might have been processed out of order.
|
||||
assertTrue(1 <= TestItemWriter.count);
|
||||
assertTrue(6 >= TestItemWriter.count);
|
||||
// But it should fail the step in any case
|
||||
assertEquals(BatchStatus.FAILED, stepExecution.getStatus());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSimulatedRestartWithNoBacklog() throws Exception {
|
||||
|
||||
factory.setItemReader(new ListItemReader(Arrays.asList(StringUtils
|
||||
.commaDelimitedListToStringArray("1,2,3,4,5,6"))));
|
||||
|
||||
Step step = (Step) factory.getObject();
|
||||
|
||||
StepExecution stepExecution = getStepExecution(step);
|
||||
|
||||
// Set up expectation of three messages (chunks) in the backlog
|
||||
stepExecution.getExecutionContext().putLong(
|
||||
ChunkMessageChannelItemWriter.EXPECTED, 6);
|
||||
stepExecution.getExecutionContext().putLong(
|
||||
ChunkMessageChannelItemWriter.ACTUAL, 3);
|
||||
/*
|
||||
* With no backlog we process all the items, but the listener can't
|
||||
* reconcile the expected number of items with the actual. An infinite
|
||||
* loop would be bad, so the best we can do is fail as fast as possible.
|
||||
*/
|
||||
try {
|
||||
step.execute(stepExecution);
|
||||
fail("Expected UnexpectedJobExecutionException");
|
||||
} catch (UnexpectedJobExecutionException e) {
|
||||
String message = e.getCause().getMessage();
|
||||
assertTrue("Message did not contain 'timed out': " + message,
|
||||
message.toLowerCase().contains("timed out"));
|
||||
}
|
||||
|
||||
assertEquals(0, TestItemWriter.count);
|
||||
assertEquals(0, stepExecution.getItemCount().intValue());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This one is flakey - we try to force it to wait until after the step to
|
||||
* finish processing just by waiting for long enough.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void testFailureInStepListener() throws Exception {
|
||||
|
||||
factory.setItemReader(new ListItemReader(Arrays.asList(StringUtils
|
||||
.commaDelimitedListToStringArray("wait,bad,3,4,5,6"))));
|
||||
|
||||
Step step = (Step) factory.getObject();
|
||||
|
||||
StepExecution stepExecution = getStepExecution(step);
|
||||
step.execute(stepExecution);
|
||||
|
||||
waitForResults(2, 10);
|
||||
|
||||
// The number of items processed is actually between 1 and 6, because
|
||||
// the one that failed might have been processed out of order.
|
||||
assertTrue(1 <= TestItemWriter.count);
|
||||
assertTrue(6 >= TestItemWriter.count);
|
||||
|
||||
assertEquals(BatchStatus.FAILED, stepExecution.getStatus());
|
||||
assertEquals(ExitStatus.FAILED.getExitCode(), stepExecution
|
||||
.getExitStatus().getExitCode());
|
||||
|
||||
String exitDescription = stepExecution.getExitStatus()
|
||||
.getExitDescription();
|
||||
assertTrue("Exit description does not contain exception type name: "
|
||||
+ exitDescription, exitDescription
|
||||
.contains(AsynchronousFailureException.class.getName()));
|
||||
|
||||
}
|
||||
|
||||
// TODO: test failure in chunk handler
|
||||
// TODO : test non-dispatch of empty chunk
|
||||
|
||||
/**
|
||||
* @param expected
|
||||
* @param maxWait
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
private void waitForResults(int expected, int maxWait) throws InterruptedException {
|
||||
int count = 0;
|
||||
while (TestItemWriter.count<expected && count<maxWait) {
|
||||
count++;
|
||||
Thread.sleep(10);
|
||||
}
|
||||
}
|
||||
|
||||
private StepExecution getStepExecution(Step step)
|
||||
throws JobExecutionAlreadyRunningException, JobRestartException,
|
||||
JobInstanceAlreadyCompleteException {
|
||||
SimpleJob job = new SimpleJob();
|
||||
job.setName("job");
|
||||
JobExecution jobExecution = jobRepository.createJobExecution(job,
|
||||
new JobParametersBuilder().addLong("job.counter", jobCounter++)
|
||||
.toJobParameters());
|
||||
StepExecution stepExecution = jobExecution.createStepExecution(step);
|
||||
return stepExecution;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
package org.springframework.integration.batch.chunk;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.batch.core.SkipListener;
|
||||
import org.springframework.batch.core.listener.SkipListenerSupport;
|
||||
import org.springframework.batch.core.step.skip.AlwaysSkipItemSkipPolicy;
|
||||
import org.springframework.batch.item.AbstractItemWriter;
|
||||
import org.springframework.batch.repeat.ExitStatus;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
public class ItemWriterChunkHandlerTests {
|
||||
|
||||
private ItemWriterChunkHandler handler = new ItemWriterChunkHandler();
|
||||
|
||||
protected int count = 0;
|
||||
|
||||
private SkipListenerSupport listener = new SkipListenerSupport() {
|
||||
@Override
|
||||
public void onSkipInWrite(Object item, Throwable t) {
|
||||
count++;
|
||||
}
|
||||
};
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void testVanillaHandleChunk() {
|
||||
handler.setItemWriter(new AbstractItemWriter() {
|
||||
public void write(Object item) throws Exception {
|
||||
count++;
|
||||
}
|
||||
});
|
||||
ChunkResponse response = handler.handleChunk(new ChunkRequest(StringUtils.commaDelimitedListToSet("foo,bar"),
|
||||
12L, 10));
|
||||
assertEquals(0, response.getSkipCount());
|
||||
assertEquals(new Long(12L), response.getJobId());
|
||||
assertEquals(ExitStatus.CONTINUABLE, response.getExitStatus());
|
||||
assertEquals(2, count);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void testSetItemSkipPolicy() {
|
||||
handler.setItemWriter(new AbstractItemWriter() {
|
||||
public void write(Object item) throws Exception {
|
||||
count++;
|
||||
throw new RuntimeException("Planned failure");
|
||||
}
|
||||
});
|
||||
handler.setItemSkipPolicy(new AlwaysSkipItemSkipPolicy());
|
||||
ChunkResponse response = handler.handleChunk(new ChunkRequest(StringUtils.commaDelimitedListToSet("foo,bar"),
|
||||
12L, 10));
|
||||
assertEquals(2, response.getSkipCount());
|
||||
assertEquals(new Long(12L), response.getJobId());
|
||||
assertEquals(ExitStatus.CONTINUABLE, response.getExitStatus());
|
||||
assertEquals(2, count);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void testRegisterSkipListener() {
|
||||
handler.setItemWriter(new AbstractItemWriter() {
|
||||
public void write(Object item) throws Exception {
|
||||
count++;
|
||||
throw new RuntimeException("Planned failure");
|
||||
}
|
||||
});
|
||||
handler.setItemSkipPolicy(new AlwaysSkipItemSkipPolicy());
|
||||
handler.registerSkipListener(listener);
|
||||
ChunkResponse response = handler.handleChunk(new ChunkRequest(StringUtils.commaDelimitedListToSet("foo,bar"),
|
||||
12L, 10));
|
||||
assertEquals(2, response.getSkipCount());
|
||||
assertEquals(4, count);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSetSkipListeners() {
|
||||
handler.setSkipListeners(new SkipListener[] { listener });
|
||||
testRegisterSkipListener();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package org.springframework.integration.batch.chunk;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.batch.item.AbstractItemWriter;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class TestItemWriter extends AbstractItemWriter {
|
||||
|
||||
private static final Log logger = LogFactory.getLog(TestItemWriter.class);
|
||||
|
||||
/**
|
||||
* Counts the number of chunks processed in the handler.
|
||||
*/
|
||||
public volatile static int count = 0;
|
||||
|
||||
/**
|
||||
* Item that causes failure in handler.
|
||||
*/
|
||||
public final static String FAIL_ON = "bad";
|
||||
|
||||
/**
|
||||
* Item that causes handler to wait to simulate delayed processing.
|
||||
*/
|
||||
public static final String WAIT_ON = "wait";
|
||||
|
||||
public void write(Object item) throws Exception {
|
||||
|
||||
count++;
|
||||
|
||||
logger.debug("Writing: "+item);
|
||||
|
||||
if (item.equals(WAIT_ON)) {
|
||||
try {
|
||||
Thread.sleep(200);
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
throw new RuntimeException("Unexpected interruption.", e);
|
||||
}
|
||||
}
|
||||
|
||||
if (item.equals(FAIL_ON)) {
|
||||
throw new IllegalStateException("Planned failure on: " + FAIL_ON);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
* 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.integration.batch.file;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.batch.core.BatchStatus;
|
||||
import org.springframework.batch.core.Job;
|
||||
import org.springframework.batch.core.JobExecution;
|
||||
import org.springframework.batch.core.JobParameters;
|
||||
import org.springframework.batch.core.JobParametersBuilder;
|
||||
import org.springframework.batch.core.repository.JobRepository;
|
||||
import org.springframework.batch.item.ItemReader;
|
||||
import org.springframework.batch.item.file.FlatFileItemReader;
|
||||
import org.springframework.batch.item.file.mapping.FieldSet;
|
||||
import org.springframework.batch.item.file.mapping.PassThroughFieldSetMapper;
|
||||
import org.springframework.batch.support.transaction.ResourcelessTransactionManager;
|
||||
import org.springframework.beans.factory.annotation.Required;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.integration.batch.JobRepositorySupport;
|
||||
import org.springframework.integration.channel.MessageChannel;
|
||||
import org.springframework.integration.channel.ThreadLocalChannel;
|
||||
import org.springframework.integration.dispatcher.DirectChannel;
|
||||
import org.springframework.integration.message.Message;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public class FileToMessagesJobFactoryBeanTests {
|
||||
|
||||
private static final String FILE_INPUT_PATH = ResourcePayloadAsJobParameterStrategy.FILE_INPUT_PATH;
|
||||
private FileToMessagesJobFactoryBean factory = new FileToMessagesJobFactoryBean();
|
||||
private ThreadLocalChannel receiver = new ThreadLocalChannel();
|
||||
private JobRepositorySupport jobRepository;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
jobRepository = new JobRepositorySupport();
|
||||
factory.setJobRepository(jobRepository);
|
||||
factory.setTransactionManager(new ResourcelessTransactionManager());
|
||||
FlatFileItemReader itemReader = new FlatFileItemReader();
|
||||
itemReader.setFieldSetMapper(new PassThroughFieldSetMapper());
|
||||
factory.setItemReader(itemReader);
|
||||
DirectChannel channel = new DirectChannel();
|
||||
factory.setChannel(channel);
|
||||
channel.subscribe(this.receiver);
|
||||
}
|
||||
|
||||
@After
|
||||
public void tearDown() {
|
||||
while(receiver.receive(10L)!=null) {}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for
|
||||
* {@link org.springframework.integration.batch.file.FileToMessagesJobFactoryBean#setBeanName(java.lang.String)}.
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void testSetBeanName() throws Exception {
|
||||
assertNotNull(((Job) factory.getObject()).getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for
|
||||
* {@link org.springframework.integration.batch.file.FileToMessagesJobFactoryBean#setItemReader(org.springframework.batch.item.ItemReader)}.
|
||||
*/
|
||||
@Test
|
||||
public void testSetItemReader() {
|
||||
Method method = ReflectionUtils.findMethod(FileToMessagesJobFactoryBean.class, "setItemReader",
|
||||
new Class<?>[] { ItemReader.class });
|
||||
assertNotNull(method);
|
||||
Annotation[] annotations = AnnotationUtils.getAnnotations(method);
|
||||
assertEquals(1, annotations.length);
|
||||
assertEquals(Required.class, annotations[0].annotationType());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for
|
||||
* {@link org.springframework.integration.batch.file.FileToMessagesJobFactoryBean#setChannel(org.springframework.integration.channel.MessageChannel)}.
|
||||
*/
|
||||
@Test
|
||||
public void testSetChannel() {
|
||||
Method method = ReflectionUtils.findMethod(FileToMessagesJobFactoryBean.class, "setChannel",
|
||||
new Class<?>[] { MessageChannel.class });
|
||||
assertNotNull(method);
|
||||
Annotation[] annotations = AnnotationUtils.getAnnotations(method);
|
||||
assertEquals(1, annotations.length);
|
||||
assertEquals(Required.class, annotations[0].annotationType());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for
|
||||
* {@link org.springframework.integration.batch.file.FileToMessagesJobFactoryBean#setJobRepository(org.springframework.batch.core.repository.JobRepository)}.
|
||||
*/
|
||||
@Test
|
||||
public void testSetJobRepository() {
|
||||
Method method = ReflectionUtils.findMethod(FileToMessagesJobFactoryBean.class, "setJobRepository",
|
||||
new Class<?>[] { JobRepository.class });
|
||||
assertNotNull(method);
|
||||
Annotation[] annotations = AnnotationUtils.getAnnotations(method);
|
||||
assertEquals(1, annotations.length);
|
||||
assertEquals(Required.class, annotations[0].annotationType());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for
|
||||
* {@link org.springframework.integration.batch.file.FileToMessagesJobFactoryBean#setTransactionManager(org.springframework.transaction.PlatformTransactionManager)}.
|
||||
*/
|
||||
@Test
|
||||
public void testSetTransactionManager() {
|
||||
Method method = ReflectionUtils.findMethod(FileToMessagesJobFactoryBean.class, "setTransactionManager",
|
||||
new Class<?>[] { PlatformTransactionManager.class });
|
||||
assertNotNull(method);
|
||||
Annotation[] annotations = AnnotationUtils.getAnnotations(method);
|
||||
assertEquals(1, annotations.length);
|
||||
assertEquals(Required.class, annotations[0].annotationType());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for
|
||||
* {@link org.springframework.integration.batch.file.FileToMessagesJobFactoryBean#getObject()}.
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void testGetObjectNotBroken() throws Exception {
|
||||
assertNotNull(factory.getObject());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for
|
||||
* {@link org.springframework.integration.batch.file.FileToMessagesJobFactoryBean#getObjectType()}.
|
||||
*/
|
||||
@Test
|
||||
public void testGetObjectType() {
|
||||
FileToMessagesJobFactoryBean factory = new FileToMessagesJobFactoryBean();
|
||||
assertEquals(Job.class, factory.getObjectType());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for
|
||||
* {@link org.springframework.integration.batch.file.FileToMessagesJobFactoryBean#isSingleton()}.
|
||||
*/
|
||||
@Test
|
||||
public void testIsSingleton() {
|
||||
FileToMessagesJobFactoryBean factory = new FileToMessagesJobFactoryBean();
|
||||
assertEquals(true, factory.isSingleton());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void testVanillaJobExecution() throws Exception {
|
||||
|
||||
Job job = (Job) factory.getObject();
|
||||
JobParameters jobParameters = new JobParametersBuilder().addString(FILE_INPUT_PATH, "classpath:/log4j.properties").toJobParameters();
|
||||
JobExecution jobExecution = jobRepository.createJobExecution(job, jobParameters);
|
||||
|
||||
job.execute(jobExecution);
|
||||
assertNotNull(jobExecution);
|
||||
assertEquals(BatchStatus.COMPLETED, jobExecution.getStatus());
|
||||
|
||||
FieldSet payload;
|
||||
Message<FieldSet> message;
|
||||
|
||||
// first line from properties file
|
||||
message = (Message<FieldSet>) receiver.receive(100L);
|
||||
assertNotNull(message);
|
||||
payload = message.getPayload();
|
||||
assertNotNull(payload);
|
||||
// second line from properties file
|
||||
message = (Message<FieldSet>) receiver.receive(100L);
|
||||
assertNotNull(message);
|
||||
payload = message.getPayload();
|
||||
assertNotNull(payload);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* 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.integration.batch.file;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.batch.core.JobParameters;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.integration.batch.file.ResourcePayloadAsJobParameterStrategy;
|
||||
import org.springframework.integration.message.GenericMessage;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public class ResourcePayloadAsJobParameterStrategyTests {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final String INPUT_FILE_PATH = ResourcePayloadAsJobParameterStrategy.FILE_INPUT_PATH;
|
||||
|
||||
/**
|
||||
* Test method for {@link org.springframework.integration.batch.file.ResourcePayloadAsJobParameterStrategy#getJobParameters(org.springframework.integration.message.Message)}.
|
||||
*/
|
||||
@Test
|
||||
public void testGetJobParameters() {
|
||||
ResourcePayloadAsJobParameterStrategy strategy = new ResourcePayloadAsJobParameterStrategy();
|
||||
JobParameters parameters = strategy.getJobParameters(new GenericMessage<Resource>(new ClassPathResource("log4j.properties")));
|
||||
assertTrue(parameters.getParameters().containsKey(INPUT_FILE_PATH));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link org.springframework.integration.batch.file.ResourcePayloadAsJobParameterStrategy#getJobParameters(org.springframework.integration.message.Message)}.
|
||||
*/
|
||||
@Test
|
||||
public void testGetJobParametersWithWrongPayload() {
|
||||
ResourcePayloadAsJobParameterStrategy strategy = new ResourcePayloadAsJobParameterStrategy();
|
||||
try {
|
||||
strategy.getJobParameters(new GenericMessage<String>("log4j.properties"));
|
||||
fail("Expected ClassCastException");
|
||||
} catch (ClassCastException e) {
|
||||
String message = e.getMessage();
|
||||
assertTrue("Wrong message: "+message, message.contains("String cannot be cast"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* 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.integration.batch.file;
|
||||
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.integration.annotation.MessageEndpoint;
|
||||
import org.springframework.integration.annotation.Splitter;
|
||||
import org.springframework.integration.channel.MessageChannel;
|
||||
import org.springframework.integration.message.GenericMessage;
|
||||
import org.springframework.integration.message.Message;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
@ContextConfiguration()
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@MessageEndpoint(input = "resources", output = "requests")
|
||||
public class ResourceSplitterIntegrationTests {
|
||||
|
||||
@Autowired
|
||||
@Qualifier("resources")
|
||||
private MessageChannel resources;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("requests")
|
||||
private MessageChannel requests;
|
||||
|
||||
/*
|
||||
* This is so cool (but see INT-190)...<br/>
|
||||
*
|
||||
* The incoming message is a Resource pattern, and it is converted to the
|
||||
* correct payload type with Spring's default strategy
|
||||
*/
|
||||
@Splitter
|
||||
public Resource[] handle(Resource[] message) {
|
||||
List<Resource> list = Arrays.asList(message);
|
||||
System.err.println(list);
|
||||
return message;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void testVanillaConversion() throws Exception {
|
||||
resources.send(new GenericMessage<String>("classpath:*-context.xml"));
|
||||
Message<Resource> message = (Message<Resource>) requests.receive(100L);
|
||||
assertNotNull(message);
|
||||
message = (Message<Resource>) requests.receive(100L);
|
||||
assertNotNull(message);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* 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.integration.batch.item;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.batch.item.ItemWriter;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.integration.channel.MessageChannel;
|
||||
import org.springframework.integration.message.Message;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
@ContextConfiguration()
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
public class MessageChannelItemWriterIntegrationTests {
|
||||
|
||||
@Autowired
|
||||
private MessageChannel channel;
|
||||
|
||||
@Autowired
|
||||
private ItemWriter itemWriter;
|
||||
|
||||
@Test
|
||||
public void testSend() throws Exception {
|
||||
itemWriter.write("foo");
|
||||
Message<?> message = channel.receive(10);
|
||||
assertNotNull(message);
|
||||
assertEquals("foo", message.getPayload());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* 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.integration.batch.item;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.annotation.Required;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.integration.channel.MessageChannel;
|
||||
import org.springframework.integration.channel.ThreadLocalChannel;
|
||||
import org.springframework.integration.dispatcher.DirectChannel;
|
||||
import org.springframework.integration.endpoint.HandlerEndpoint;
|
||||
import org.springframework.integration.handler.MessageHandler;
|
||||
import org.springframework.integration.message.Message;
|
||||
import org.springframework.integration.message.Target;
|
||||
import org.springframework.integration.util.ErrorHandler;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public class MessageChannelItemWriterTests {
|
||||
|
||||
/**
|
||||
* Test method for {@link org.springframework.integration.batch.item.MessageChannelItemWriter#setChannel(org.springframework.integration.channel.MessageChannel)}.
|
||||
*/
|
||||
@Test
|
||||
public void testSetChannel() {
|
||||
Method method = ReflectionUtils.findMethod(MessageChannelItemWriter.class, "setChannel", new Class<?>[] {MessageChannel.class});
|
||||
assertNotNull(method);
|
||||
Annotation[] annotations = AnnotationUtils.getAnnotations(method);
|
||||
assertEquals(1, annotations.length);
|
||||
assertEquals(Required.class, annotations[0].annotationType());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link org.springframework.integration.batch.item.MessageChannelItemWriter#write(java.lang.Object)}.
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void testWrite() throws Exception {
|
||||
DirectChannel channel = new DirectChannel();
|
||||
ThreadLocalChannel receiver = new ThreadLocalChannel();
|
||||
channel.subscribe(receiver);
|
||||
MessageChannelItemWriter writer = new MessageChannelItemWriter();
|
||||
writer.setChannel(channel);
|
||||
writer.write("foo");
|
||||
Message<?> message = receiver.receive(10);
|
||||
assertNotNull(message);
|
||||
assertEquals("foo", message.getPayload());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link org.springframework.integration.batch.item.MessageChannelItemWriter#write(java.lang.Object)}.
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void testWriteWithRollback() throws Exception {
|
||||
DirectChannel channel = new DirectChannel();
|
||||
channel.subscribe(new Target() {
|
||||
public boolean send(Message<?> message) {
|
||||
throw new RuntimeException("Planned failure");
|
||||
}
|
||||
});
|
||||
MessageChannelItemWriter writer = new MessageChannelItemWriter();
|
||||
writer.setChannel(channel);
|
||||
try {
|
||||
writer.write("foo");
|
||||
fail("Expected RuntimeException");
|
||||
}
|
||||
catch (RuntimeException e) {
|
||||
assertEquals("Planned failure", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for {@link org.springframework.integration.batch.item.MessageChannelItemWriter#write(java.lang.Object)}.
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void testWriteWithRollbackOnEndpoint() throws Exception {
|
||||
DirectChannel channel = new DirectChannel();
|
||||
HandlerEndpoint endpoint = new HandlerEndpoint(new MessageHandler() {
|
||||
public Message<?> handle(Message<?> message) {
|
||||
throw new RuntimeException("Planned failure");
|
||||
}
|
||||
});
|
||||
// INT-184: this shouldn't be necessary?
|
||||
endpoint.setErrorHandler(new ErrorHandler() {
|
||||
public void handle(Throwable t) {
|
||||
throw (RuntimeException)t;
|
||||
}
|
||||
});
|
||||
channel.subscribe(endpoint);
|
||||
endpoint.start();
|
||||
MessageChannelItemWriter writer = new MessageChannelItemWriter();
|
||||
writer.setChannel(channel);
|
||||
try {
|
||||
writer.write("foo");
|
||||
fail("Expected RuntimeException");
|
||||
}
|
||||
catch (RuntimeException e) {
|
||||
assertEquals("Planned failure", e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* 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.integration.batch.job;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.batch.core.BatchStatus;
|
||||
import org.springframework.batch.core.JobExecution;
|
||||
import org.springframework.batch.core.JobParameters;
|
||||
import org.springframework.batch.core.configuration.JobLocator;
|
||||
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 MessageOrientedStepIntegrationTests {
|
||||
|
||||
@Autowired
|
||||
private JobLauncher jobLauncher;
|
||||
|
||||
@Autowired
|
||||
private JobLocator jobLocator;
|
||||
|
||||
@Test
|
||||
public void testLaunchJob() throws Exception {
|
||||
JobExecution jobExecution = jobLauncher.run(jobLocator.getJob("job"), new JobParameters());
|
||||
assertEquals(BatchStatus.COMPLETED, jobExecution.getStatus());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
* 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.integration.batch.job;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.batch.core.BatchStatus;
|
||||
import org.springframework.batch.core.JobExecution;
|
||||
import org.springframework.batch.core.JobInstance;
|
||||
import org.springframework.batch.core.JobParameters;
|
||||
import org.springframework.batch.core.StepExecution;
|
||||
import org.springframework.beans.factory.annotation.Required;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.integration.batch.JobRepositorySupport;
|
||||
import org.springframework.integration.channel.MessageChannel;
|
||||
import org.springframework.integration.channel.ThreadLocalChannel;
|
||||
import org.springframework.integration.dispatcher.DirectChannel;
|
||||
import org.springframework.integration.message.GenericMessage;
|
||||
import org.springframework.integration.message.Message;
|
||||
import org.springframework.integration.message.Target;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public class MessageOrientedStepTests {
|
||||
|
||||
private MessageOrientedStep step = new MessageOrientedStep();
|
||||
|
||||
private JobExecution jobExecution;
|
||||
|
||||
private DirectChannel requestChannel;
|
||||
|
||||
private MessageChannel replyChannel;
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
@Before
|
||||
public void createStep() {
|
||||
replyChannel = new ThreadLocalChannel();
|
||||
requestChannel = new DirectChannel();
|
||||
step.setName("step");
|
||||
step.setRequestChannel(requestChannel);
|
||||
step.setReplyChannel(replyChannel);
|
||||
step.setStartLimit(10);
|
||||
step.setJobRepository(new JobRepositorySupport());
|
||||
JobInstance jobInstance = new JobInstance(0L, new JobParameters(), "job");
|
||||
jobExecution = new JobExecution(jobInstance);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for
|
||||
* {@link org.springframework.integration.batch.job.MessageOrientedStep#setRequestChannel(org.springframework.integration.channel.MessageChannel)}.
|
||||
*/
|
||||
@Test
|
||||
public void testSetRequestChannel() {
|
||||
Method method = ReflectionUtils.findMethod(MessageOrientedStep.class, "setRequestChannel",
|
||||
new Class<?>[] { MessageChannel.class });
|
||||
assertNotNull(method);
|
||||
Annotation[] annotations = AnnotationUtils.getAnnotations(method);
|
||||
assertEquals(1, annotations.length);
|
||||
assertEquals(Required.class, annotations[0].annotationType());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for
|
||||
* {@link org.springframework.integration.batch.job.MessageOrientedStep#setReplyChannel(org.springframework.integration.channel.MessageChannel)}.
|
||||
*/
|
||||
@Test
|
||||
public void testSetReplyChannel() {
|
||||
Method method = ReflectionUtils.findMethod(MessageOrientedStep.class, "setReplyChannel",
|
||||
new Class<?>[] { MessageChannel.class });
|
||||
assertNotNull(method);
|
||||
Annotation[] annotations = AnnotationUtils.getAnnotations(method);
|
||||
assertEquals(1, annotations.length);
|
||||
assertEquals(Required.class, annotations[0].annotationType());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for
|
||||
* {@link org.springframework.integration.batch.job.MessageOrientedStep#execute(org.springframework.batch.core.StepExecution)}.
|
||||
* @throws Exception
|
||||
* @throws
|
||||
*/
|
||||
@Test
|
||||
public void testExecuteWithTimeout() throws Exception {
|
||||
try {
|
||||
step.execute(jobExecution.createStepExecution(step));
|
||||
fail("Expected StepExecutionTimeoutException");
|
||||
}
|
||||
catch (StepExecutionTimeoutException e) {
|
||||
// expected
|
||||
String message = e.getMessage();
|
||||
assertTrue("Wrong message: " + message, message.contains("waiting for steps"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testVanillaExecute() throws Exception {
|
||||
requestChannel.subscribe(new Target() {
|
||||
public boolean send(Message<?> message) {
|
||||
JobExecutionRequest jobExecution = (JobExecutionRequest) message.getPayload();
|
||||
jobExecution.setStatus(BatchStatus.COMPLETED);
|
||||
return replyChannel.send(message);
|
||||
}
|
||||
});
|
||||
step.execute(jobExecution.createStepExecution(step));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExecuteWithFailure() throws Exception {
|
||||
requestChannel.subscribe(new Target() {
|
||||
public boolean send(Message<?> message) {
|
||||
JobExecutionRequest jobExecution = (JobExecutionRequest) message.getPayload();
|
||||
jobExecution.registerThrowable(new RuntimeException("Planned failure"));
|
||||
return replyChannel.send(message);
|
||||
}
|
||||
});
|
||||
try {
|
||||
step.execute(jobExecution.createStepExecution(step));
|
||||
fail("Expected RuntimeException");
|
||||
}
|
||||
catch (RuntimeException e) {
|
||||
// expected
|
||||
String message = e.getMessage();
|
||||
assertEquals("Wrong message: " + message, "Planned failure", message);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testExecuteOnRestart() throws Exception {
|
||||
JobExecutionRequest jobExecutionRequest = new JobExecutionRequest(jobExecution);
|
||||
jobExecutionRequest.setStatus(BatchStatus.COMPLETED);
|
||||
// Send a message to the reply channel to simulate step that we were
|
||||
// waiting for when we failed on the last execution.
|
||||
replyChannel.send(new GenericMessage<JobExecutionRequest>(jobExecutionRequest));
|
||||
StepExecution stepExecution = jobExecution.createStepExecution(step);
|
||||
stepExecution.getExecutionContext().putString(MessageOrientedStep.WAITING, "true");
|
||||
step.execute(stepExecution);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,247 @@
|
||||
/*
|
||||
* 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.integration.batch.job;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.batch.core.BatchStatus;
|
||||
import org.springframework.batch.core.JobExecution;
|
||||
import org.springframework.batch.core.JobInstance;
|
||||
import org.springframework.batch.core.JobInterruptedException;
|
||||
import org.springframework.batch.core.JobParameters;
|
||||
import org.springframework.batch.core.StartLimitExceededException;
|
||||
import org.springframework.batch.core.Step;
|
||||
import org.springframework.batch.core.StepExecution;
|
||||
import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException;
|
||||
import org.springframework.batch.core.repository.JobRepository;
|
||||
import org.springframework.batch.core.repository.JobRestartException;
|
||||
import org.springframework.batch.item.ExecutionContext;
|
||||
import org.springframework.batch.support.PropertiesConverter;
|
||||
import org.springframework.beans.factory.annotation.Required;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.integration.batch.JobRepositorySupport;
|
||||
import org.springframework.integration.batch.JobSupport;
|
||||
import org.springframework.integration.batch.StepSupport;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public class StepExecutionMessageHandlerTests {
|
||||
|
||||
/**
|
||||
* Test method for
|
||||
* {@link org.springframework.integration.batch.job.StepExecutionMessageHandler#setStep(org.springframework.batch.core.Step)}.
|
||||
*/
|
||||
@Test
|
||||
public void testSetStep() {
|
||||
Method method = ReflectionUtils.findMethod(StepExecutionMessageHandler.class, "setStep",
|
||||
new Class<?>[] { Step.class });
|
||||
assertNotNull(method);
|
||||
Annotation[] annotations = AnnotationUtils.getAnnotations(method);
|
||||
assertEquals(1, annotations.length);
|
||||
assertEquals(Required.class, annotations[0].annotationType());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for
|
||||
* {@link org.springframework.integration.batch.job.StepExecutionMessageHandler#setJobRepository(org.springframework.batch.core.repository.JobRepository)}.
|
||||
*/
|
||||
@Test
|
||||
public void testSetJobRepository() {
|
||||
Method method = ReflectionUtils.findMethod(StepExecutionMessageHandler.class, "setJobRepository",
|
||||
new Class<?>[] { JobRepository.class });
|
||||
assertNotNull(method);
|
||||
Annotation[] annotations = AnnotationUtils.getAnnotations(method);
|
||||
assertEquals(1, annotations.length);
|
||||
assertEquals(Required.class, annotations[0].annotationType());
|
||||
}
|
||||
|
||||
/**
|
||||
* Test method for
|
||||
* {@link org.springframework.integration.batch.job.StepExecutionMessageHandler#handle(org.springframework.integration.message.Message)}.
|
||||
* @throws Exception
|
||||
* @throws JobRestartException
|
||||
* @throws JobExecutionAlreadyRunningException
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void testVanillaHandle() throws Exception {
|
||||
JobRepositorySupport jobRepository = new JobRepositorySupport();
|
||||
StepExecutionMessageHandler handler = createHandler(jobRepository);
|
||||
JobExecutionRequest message = handler.handle(new JobExecutionRequest(jobRepository.createJobExecution(
|
||||
new JobSupport("job"), new JobParameters())));
|
||||
assertEquals(1, message.getJobExecution().getStepExecutions().size());
|
||||
assertEquals(BatchStatus.COMPLETED, message.getStatus());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void testHandleWithInputs() throws Exception {
|
||||
JobRepositorySupport jobRepository = new JobRepositorySupport();
|
||||
StepExecutionMessageHandler handler = createHandler(jobRepository);
|
||||
handler.setInputKeys(new String[] { "foo" });
|
||||
JobExecutionRequest jobExecutionRequest = new JobExecutionRequest(jobRepository.createJobExecution(
|
||||
new JobSupport("job"), new JobParameters()));
|
||||
jobExecutionRequest.setAttribute("foo", "bar");
|
||||
JobExecutionRequest message = handler.handle(jobExecutionRequest);
|
||||
assertEquals(1, message.getJobExecution().getStepExecutions().size());
|
||||
StepExecution stepExecution = (StepExecution) message.getJobExecution().getStepExecutions().iterator().next();
|
||||
assertTrue(stepExecution.getExecutionContext().containsKey("foo"));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void testHandleWithInputsAndOutputs() throws Exception {
|
||||
JobRepositorySupport jobRepository = new JobRepositorySupport();
|
||||
StepExecutionMessageHandler handler = createHandler(jobRepository);
|
||||
handler.setInputKeys(new String[] { "foo" });
|
||||
handler.setOutputKeys(new String[] { "bar" });
|
||||
JobExecutionRequest jobExecutionRequest = new JobExecutionRequest(jobRepository.createJobExecution(
|
||||
new JobSupport("job"), new JobParameters()));
|
||||
jobExecutionRequest.setAttribute("foo", "bar");
|
||||
// The step has to add the output attribute to the context
|
||||
handler.setStep(new StepSupport("step") {
|
||||
@Override
|
||||
public void execute(StepExecution stepExecution) throws JobInterruptedException {
|
||||
stepExecution.getExecutionContext().putString("bar", "spam");
|
||||
}
|
||||
});
|
||||
handler.handle(jobExecutionRequest);
|
||||
assertFalse(jobExecutionRequest.hasAttribute("foo"));
|
||||
assertTrue(jobExecutionRequest.hasAttribute("bar"));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void testHandleFailedJob() throws Exception {
|
||||
JobRepositorySupport jobRepository = new JobRepositorySupport();
|
||||
StepExecutionMessageHandler handler = createHandler(jobRepository);
|
||||
JobExecution jobExecution = jobRepository.createJobExecution(new JobSupport("job"), new JobParameters());
|
||||
jobExecution.setStatus(BatchStatus.FAILED);
|
||||
JobExecutionRequest message = handler.handle(new JobExecutionRequest(jobExecution));
|
||||
assertEquals(0, message.getJobExecution().getStepExecutions().size());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void testHandleRestart() throws Exception {
|
||||
JobRepositorySupport jobRepository = new JobRepositorySupport() {
|
||||
@Override
|
||||
public StepExecution getLastStepExecution(JobInstance jobInstance, Step step) {
|
||||
StepExecution stepExecution = new StepExecution(step.getName(), new JobExecution(jobInstance));
|
||||
stepExecution.setStatus(BatchStatus.FAILED);
|
||||
stepExecution.setExecutionContext(new ExecutionContext(PropertiesConverter
|
||||
.stringToProperties("foo=bar")));
|
||||
return stepExecution;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.integration.batch.JobRepositorySupport#getStepExecutionCount(org.springframework.batch.core.JobInstance,
|
||||
* org.springframework.batch.core.Step)
|
||||
*/
|
||||
@Override
|
||||
public int getStepExecutionCount(JobInstance jobInstance, Step step) {
|
||||
return 1;
|
||||
}
|
||||
};
|
||||
StepExecutionMessageHandler handler = createHandler(jobRepository);
|
||||
JobExecution jobExecution = jobRepository.createJobExecution(new JobSupport("job"), new JobParameters());
|
||||
JobExecutionRequest message = handler.handle(new JobExecutionRequest(jobExecution));
|
||||
assertNotNull(message);
|
||||
assertEquals(1, jobExecution.getStepExecutions().size());
|
||||
StepExecution stepExecution = (StepExecution) jobExecution.getStepExecutions().iterator().next();
|
||||
assertTrue(stepExecution.getExecutionContext().containsKey("foo"));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void testHandleRestartAlreadyComplete() throws Exception {
|
||||
JobRepositorySupport jobRepository = new JobRepositorySupport() {
|
||||
@Override
|
||||
public StepExecution getLastStepExecution(JobInstance jobInstance, Step step) {
|
||||
StepExecution stepExecution = new StepExecution(step.getName(), new JobExecution(jobInstance));
|
||||
stepExecution.setStatus(BatchStatus.COMPLETED);
|
||||
stepExecution.setExecutionContext(new ExecutionContext(PropertiesConverter
|
||||
.stringToProperties("foo=bar")));
|
||||
return stepExecution;
|
||||
}
|
||||
};
|
||||
StepExecutionMessageHandler handler = createHandler(jobRepository);
|
||||
JobExecution jobExecution = jobRepository.createJobExecution(new JobSupport("job"), new JobParameters());
|
||||
JobExecutionRequest message = handler.handle(new JobExecutionRequest(jobExecution));
|
||||
assertNotNull(message);
|
||||
assertEquals(1, jobExecution.getStepExecutions().size());
|
||||
StepExecution stepExecution = (StepExecution) jobExecution.getStepExecutions().iterator().next();
|
||||
assertEquals(BatchStatus.STARTING, stepExecution.getStatus());
|
||||
// We expect to get the context from the previous execution, even if we
|
||||
// do not execute
|
||||
assertTrue(stepExecution.getExecutionContext().containsKey("foo"));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void testHandleRestartStartLimitExceeded() throws Exception {
|
||||
JobRepositorySupport jobRepository = new JobRepositorySupport() {
|
||||
@Override
|
||||
public StepExecution getLastStepExecution(JobInstance jobInstance, Step step) {
|
||||
return new StepExecution(step.getName(), new JobExecution(jobInstance));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStepExecutionCount(JobInstance jobInstance, Step step) {
|
||||
// sufficiently high restart count
|
||||
return 100;
|
||||
}
|
||||
};
|
||||
StepExecutionMessageHandler handler = createHandler(jobRepository);
|
||||
JobExecution jobExecution = jobRepository.createJobExecution(new JobSupport("job"), new JobParameters());
|
||||
JobExecutionRequest message = handler.handle(new JobExecutionRequest(jobExecution));
|
||||
assertNotNull(message);
|
||||
assertEquals(1, jobExecution.getStepExecutions().size());
|
||||
JobExecutionRequest payload = message;
|
||||
assertEquals(BatchStatus.FAILED, payload.getStatus());
|
||||
assertTrue(payload.hasErrors());
|
||||
Throwable error = payload.getLastThrowable();
|
||||
assertTrue(error instanceof StartLimitExceededException);
|
||||
String text = error.getMessage();
|
||||
assertTrue("Wrong exit description: " + text, text.toLowerCase().contains("start limit"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param jobRepository
|
||||
* @return
|
||||
*
|
||||
*/
|
||||
public StepExecutionMessageHandler createHandler(JobRepositorySupport jobRepository) {
|
||||
StepExecutionMessageHandler handler = new StepExecutionMessageHandler();
|
||||
StepSupport step = new StepSupport("step");
|
||||
step.setStartLimit(10);
|
||||
handler.setStep(step);
|
||||
handler.setJobRepository(jobRepository);
|
||||
return handler;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* 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.integration.batch.job;
|
||||
|
||||
import org.springframework.batch.core.step.tasklet.Tasklet;
|
||||
import org.springframework.batch.repeat.ExitStatus;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public class TestTasklet implements Tasklet {
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.batch.core.step.tasklet.Tasklet#execute()
|
||||
*/
|
||||
public ExitStatus execute() throws Exception {
|
||||
return ExitStatus.FINISHED;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package org.springframework.integration.batch.launch;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.batch.core.JobExecution;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.integration.channel.MessageChannel;
|
||||
import org.springframework.integration.message.Message;
|
||||
import org.springframework.integration.message.StringMessage;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
@ContextConfiguration()
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
public class JobLaunchingMessageHandlerIntegrationTests {
|
||||
|
||||
@Autowired @Qualifier("requests")
|
||||
private MessageChannel requestChannel;
|
||||
|
||||
@Autowired @Qualifier("response")
|
||||
private MessageChannel responseChannel;
|
||||
|
||||
@Before
|
||||
public void setUp(){
|
||||
requestChannel.purge(null);
|
||||
responseChannel.purge(null);
|
||||
}
|
||||
|
||||
|
||||
@Test @DirtiesContext @SuppressWarnings("unchecked")
|
||||
public void testNoReply(){
|
||||
requestChannel.send(new StringMessage("testJob"));
|
||||
Message<JobExecution> executionMessage = (Message<JobExecution>)responseChannel.receive(1000);
|
||||
|
||||
assertNull("JobExecution message received when no return address set", executionMessage);
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test @DirtiesContext
|
||||
public void testReply(){
|
||||
StringMessage trigger = new StringMessage("testJob");
|
||||
trigger.getHeader().setProperty("dontclash", "12");
|
||||
trigger.getHeader().setReturnAddress("response");
|
||||
requestChannel.send(trigger);
|
||||
Message<JobExecution> executionMessage = (Message<JobExecution>)responseChannel.receive(1000);
|
||||
|
||||
assertNotNull("No response received", executionMessage);
|
||||
JobExecution execution = executionMessage.getPayload();
|
||||
assertNotNull("JobExectuion not returned", execution);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
package org.springframework.integration.batch.launch;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
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.launch.JobLauncher;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.integration.batch.JobSupport;
|
||||
import org.springframework.integration.bus.MessageBus;
|
||||
import org.springframework.integration.channel.AbstractMessageChannel;
|
||||
import org.springframework.integration.message.Message;
|
||||
import org.springframework.integration.message.StringMessage;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests;
|
||||
|
||||
@ContextConfiguration(locations = { "/job-execution-context.xml" })
|
||||
public class JobLaunchingMessageHandlerTests extends AbstractJUnit4SpringContextTests {
|
||||
|
||||
JobLaunchingMessageHandler messageHandler;
|
||||
|
||||
StubJobLauncher jobLauncher;
|
||||
|
||||
|
||||
|
||||
// @Autowired
|
||||
// @Qualifier("jobs") TODO: Qualifier seems to be broken here why ?????
|
||||
public AbstractMessageChannel jobsChannel;
|
||||
|
||||
@Autowired
|
||||
public MessageBus messageBus;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
jobLauncher = new StubJobLauncher();
|
||||
messageHandler = new JobLaunchingMessageHandler(jobLauncher, new StubMessageToJobStrategy());
|
||||
jobsChannel = (AbstractMessageChannel) applicationContext.getBean("jobs");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSimpleDelivery() throws Exception{
|
||||
messageHandler.handle(new StringMessage("testjob"));
|
||||
|
||||
assertEquals("Wrong job count", 1, jobLauncher.jobs.size());
|
||||
assertEquals("Wrong job name", jobLauncher.jobs.get(0).getName(), "testjob");
|
||||
|
||||
}
|
||||
|
||||
private static class StubJobLauncher implements JobLauncher {
|
||||
|
||||
List<Job> jobs = new ArrayList<Job>();
|
||||
|
||||
List<JobParameters> parameters = new ArrayList<JobParameters>();
|
||||
|
||||
AtomicLong jobId = new AtomicLong();
|
||||
|
||||
public JobExecution run(Job job, JobParameters jobParameters){
|
||||
jobs.add(job);
|
||||
parameters.add(jobParameters);
|
||||
return new JobExecution(new JobInstance(jobId.getAndIncrement(), jobParameters, job.getName()));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static class StubMessageToJobStrategy implements MessageToJobStrategy {
|
||||
|
||||
public Job getJob(Message<?> message) {
|
||||
String name = (String) message.getPayload();
|
||||
return new JobSupport(name);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
package org.springframework.integration.batch.launch;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.batch.core.Job;
|
||||
import org.springframework.batch.core.JobExecution;
|
||||
import org.springframework.batch.core.JobParameters;
|
||||
import org.springframework.batch.core.launch.JobLauncher;
|
||||
import org.springframework.integration.batch.JobSupport;
|
||||
import org.springframework.integration.channel.AbstractMessageChannel;
|
||||
import org.springframework.integration.message.StringMessage;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
@ContextConfiguration(locations = { "/job-execution-context.xml" })
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
public class JobLaunchingPostReceiveChannelAdapterTests extends AbstractJUnit4SpringContextTests {
|
||||
|
||||
JobLaunchingPostReceiveChannelInterceptor interceptor;
|
||||
|
||||
StubJobLauncher jobLauncher;
|
||||
|
||||
JobSupport job;
|
||||
|
||||
// @Autowired
|
||||
// @Qualifier("jobs") TODO: Qualifier seems to be broken here why ?????
|
||||
public AbstractMessageChannel jobsChannel;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
job = new JobSupport(getClass().getName());
|
||||
jobLauncher = new StubJobLauncher();
|
||||
interceptor = new JobLaunchingPostReceiveChannelInterceptor(job, jobLauncher);
|
||||
jobsChannel = (AbstractMessageChannel) applicationContext.getBean("jobs");
|
||||
jobsChannel.addInterceptor(interceptor);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJobPassedToLauncherCalled() {
|
||||
StringMessage message = new StringMessage("test payload");
|
||||
jobsChannel.send(message);
|
||||
assertTrue("Job launcher called before recevie", (jobLauncher.jobs.size() == 0));
|
||||
jobsChannel.receive();
|
||||
assertEquals(job, jobLauncher.jobs.get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMessagePropertiesPassedAsJobParameters() {
|
||||
StringMessage message = new StringMessage("test payload");
|
||||
message.getHeader().setProperty("testOne", "a");
|
||||
message.getHeader().setProperty("testTwo", "b");
|
||||
jobsChannel.send(message);
|
||||
jobsChannel.receive();
|
||||
JobParameters parameters = jobLauncher.parameters.get(0);
|
||||
assertEquals("a", parameters.getString("testOne"));
|
||||
assertEquals("b", parameters.getString("testTwo"));
|
||||
|
||||
}
|
||||
|
||||
private static class StubJobLauncher implements JobLauncher {
|
||||
|
||||
List<Job> jobs = new ArrayList<Job>();
|
||||
|
||||
List<JobParameters> parameters = new ArrayList<JobParameters>();
|
||||
|
||||
|
||||
public JobExecution run(Job job, JobParameters jobParameters){
|
||||
jobs.add(job);
|
||||
parameters.add(jobParameters);
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,462 @@
|
||||
package org.springframework.integration.batch.retry;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
import org.aopalliance.aop.Advice;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.junit.Test;
|
||||
import org.springframework.batch.item.ItemKeyGenerator;
|
||||
import org.springframework.batch.item.ItemReader;
|
||||
import org.springframework.batch.item.ItemRecoverer;
|
||||
import org.springframework.batch.item.support.ListItemReader;
|
||||
import org.springframework.batch.repeat.interceptor.RepeatOperationsInterceptor;
|
||||
import org.springframework.batch.repeat.policy.SimpleCompletionPolicy;
|
||||
import org.springframework.batch.repeat.support.RepeatTemplate;
|
||||
import org.springframework.batch.retry.interceptor.StatefulRetryOperationsInterceptor;
|
||||
import org.springframework.batch.support.PropertiesConverter;
|
||||
import org.springframework.batch.support.transaction.ResourcelessTransactionManager;
|
||||
import org.springframework.batch.support.transaction.TransactionAwareProxyFactory;
|
||||
import org.springframework.context.Lifecycle;
|
||||
import org.springframework.integration.channel.MessageChannel;
|
||||
import org.springframework.integration.dispatcher.DirectChannel;
|
||||
import org.springframework.integration.endpoint.SourceEndpoint;
|
||||
import org.springframework.integration.message.GenericMessage;
|
||||
import org.springframework.integration.message.Message;
|
||||
import org.springframework.integration.message.Source;
|
||||
import org.springframework.integration.message.Target;
|
||||
import org.springframework.integration.scheduling.MessagingTaskScheduler;
|
||||
import org.springframework.integration.scheduling.PollingSchedule;
|
||||
import org.springframework.integration.scheduling.SimpleMessagingTaskScheduler;
|
||||
import org.springframework.integration.util.ErrorHandler;
|
||||
import org.springframework.transaction.interceptor.TransactionInterceptor;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
public class PollableSourceRetryTests {
|
||||
|
||||
private Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private List<String> processed = new ArrayList<String>();
|
||||
|
||||
protected List<String> recovered = new ArrayList<String>();
|
||||
|
||||
public void add(String str) {
|
||||
logger.debug("Adding: " + str);
|
||||
processed.add(str);
|
||||
}
|
||||
|
||||
ItemKeyGenerator itemKeyGenerator = new ItemKeyGenerator() {
|
||||
@SuppressWarnings("unchecked")
|
||||
public Object getKey(Object item) {
|
||||
if (item == null) {
|
||||
return "NULL";
|
||||
}
|
||||
if (item.getClass().isArray()) {
|
||||
item = ((Object[]) item)[0];
|
||||
}
|
||||
return ((Message<Object>) item).getPayload();
|
||||
}
|
||||
};
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void testSimpleTransactionalPolling() throws Exception {
|
||||
|
||||
List<String> list = TransactionAwareProxyFactory.createTransactionalList();
|
||||
list.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray("a,b,c,d,e,f,g,h,j,k")));
|
||||
int beforeCount = list.size();
|
||||
|
||||
Target handler = new Target() {
|
||||
public boolean send(Message<?> message) {
|
||||
Object payload = message.getPayload();
|
||||
logger.debug("Handling: " + payload);
|
||||
return processed.add((String) payload);
|
||||
}
|
||||
};
|
||||
Source<Object> source = getPollableSource(list);
|
||||
DirectChannel channel = getChannel(handler, source);
|
||||
SourceEndpoint endpoint = getSourceEndpoint(source, channel);
|
||||
endpoint.setDispatchAdviceChain(Arrays.asList(new Advice[] { getTransactionInterceptor() }));
|
||||
endpoint.initializeTask();
|
||||
MessagingTaskScheduler scheduler = getSchedulerWithErrorHandler(endpoint);
|
||||
|
||||
waitForResults(scheduler, 2, 40);
|
||||
|
||||
assertEquals(2, processed.size());
|
||||
|
||||
assertEquals(beforeCount - list.size(), processed.size());
|
||||
assertEquals("a", processed.get(0));
|
||||
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void testNonTransactionalPollingWithRollback() throws Exception {
|
||||
|
||||
List<String> list = TransactionAwareProxyFactory.createTransactionalList();
|
||||
list.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray("a,b,c,d,e,f,g,h,j,k")));
|
||||
int beforeCount = list.size();
|
||||
|
||||
Target handler = new Target() {
|
||||
public boolean send(Message<?> message) {
|
||||
Object payload = message.getPayload();
|
||||
logger.debug("Handling: " + payload);
|
||||
processed.add((String) payload);
|
||||
throw new RuntimeException("Planned failure: " + payload);
|
||||
}
|
||||
};
|
||||
Source<Object> source = getPollableSource(list);
|
||||
DirectChannel channel = getChannel(handler, source);
|
||||
SourceEndpoint endpoint = getSourceEndpoint(source, channel);
|
||||
MessagingTaskScheduler scheduler = getSchedulerWithErrorHandler(endpoint);
|
||||
|
||||
waitForResults(scheduler, 2, 20);
|
||||
|
||||
assertEquals(2, processed.size());
|
||||
|
||||
// None rolled back because there was no transaction
|
||||
assertEquals(beforeCount - list.size(), 2);
|
||||
assertEquals("a", processed.get(0));
|
||||
assertEquals("b", processed.get(1));
|
||||
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void testTransactionalHandlingWithUnconditionalRollback() throws Exception {
|
||||
|
||||
List<String> list = TransactionAwareProxyFactory.createTransactionalList();
|
||||
list.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray("a,b,c,d,e,f,g,h,j,k")));
|
||||
int beforeCount = list.size();
|
||||
|
||||
Target handler = new Target() {
|
||||
public boolean send(Message<?> message) {
|
||||
Object payload = message.getPayload();
|
||||
logger.debug("Handling: " + payload);
|
||||
processed.add((String) payload);
|
||||
throw new RuntimeException("Planned failure: " + payload);
|
||||
}
|
||||
};
|
||||
Source<Object> source = getPollableSource(list);
|
||||
DirectChannel channel = getChannel(handler, source);
|
||||
SourceEndpoint endpoint = getSourceEndpoint(source, channel);
|
||||
endpoint.setTaskAdviceChain(Arrays.asList(new Advice[] { getTransactionInterceptor() }));
|
||||
endpoint.initializeTask();
|
||||
MessagingTaskScheduler scheduler = getSchedulerWithErrorHandler(endpoint);
|
||||
|
||||
waitForResults(scheduler, 2, 20);
|
||||
|
||||
assertEquals(2, processed.size());
|
||||
|
||||
// TODO: this would fail if exception not propagated: INT-184.
|
||||
// All rolled back
|
||||
assertEquals(beforeCount - list.size(), 0);
|
||||
assertEquals("a", processed.get(0));
|
||||
// processed twice and rolled back both times
|
||||
assertEquals("a", processed.get(1));
|
||||
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void testTransactionalHandlingWithRollback() throws Exception {
|
||||
|
||||
List<String> list = TransactionAwareProxyFactory.createTransactionalList();
|
||||
list.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray("a,b,fail,d,e,f,g,h,j,k")));
|
||||
int beforeCount = list.size();
|
||||
|
||||
Target handler = new Target() {
|
||||
public boolean send(Message<?> message) {
|
||||
Object payload = message.getPayload();
|
||||
logger.debug("Handling: " + payload);
|
||||
boolean result = processed.add((String) payload);
|
||||
if ("fail".equals(payload)) {
|
||||
throw new RuntimeException("Planned failure: " + payload);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
Source<Object> source = getPollableSource(list);
|
||||
DirectChannel channel = getChannel(handler, source);
|
||||
SourceEndpoint endpoint = getSourceEndpoint(source, channel);
|
||||
endpoint.setTaskAdviceChain(Arrays.asList(new Advice[] { getTransactionInterceptor() }));
|
||||
endpoint.initializeTask();
|
||||
MessagingTaskScheduler scheduler = getSchedulerWithErrorHandler(endpoint);
|
||||
|
||||
waitForResults(scheduler, 5, 20);
|
||||
|
||||
assertEquals(5, processed.size());
|
||||
assertFalse("No messages got to processor", processed.isEmpty());
|
||||
// First two TX succeed, and the rest rolled back so list has had two
|
||||
// elements popped off
|
||||
assertEquals(beforeCount - 2, list.size());
|
||||
assertEquals("a", processed.get(0));
|
||||
assertEquals("b", processed.get(1));
|
||||
// stuck in effectively an infinite loop - it fails every time...
|
||||
assertEquals("fail", processed.get(2));
|
||||
assertEquals("fail", processed.get(3));
|
||||
assertEquals("fail", processed.get(4));
|
||||
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void testTransactionalHandlingWithRepeat() throws Exception {
|
||||
|
||||
List<String> list = TransactionAwareProxyFactory.createTransactionalList();
|
||||
list.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray("a,b,fail,d,e,f,g,h,j,k")));
|
||||
int beforeCount = list.size();
|
||||
|
||||
Target handler = new Target() {
|
||||
public boolean send(Message<?> message) {
|
||||
Object payload = message.getPayload();
|
||||
logger.debug("Handling: " + payload);
|
||||
boolean result = processed.add((String) payload);
|
||||
if ("fail".equals(payload)) {
|
||||
throw new RuntimeException("Planned failure: " + payload);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
Source<Object> source = getPollableSource(list);
|
||||
DirectChannel channel = getChannel(handler, source);
|
||||
SourceEndpoint endpoint = getSourceEndpoint(source, channel);
|
||||
endpoint.setTaskAdviceChain(Arrays.asList(new Advice[] { getTransactionInterceptor(),
|
||||
getRepeatOperationsInterceptor(3) }));
|
||||
endpoint.initializeTask();
|
||||
MessagingTaskScheduler scheduler = getSchedulerWithErrorHandler(endpoint);
|
||||
|
||||
waitForResults(scheduler, 6, 100);
|
||||
|
||||
assertEquals(6, processed.size());
|
||||
assertFalse("No messages got to processor", processed.isEmpty());
|
||||
// Two TX rolled back so list is same size as when it started
|
||||
assertEquals(beforeCount, list.size());
|
||||
assertEquals("a", processed.get(0));
|
||||
assertEquals("b", processed.get(1));
|
||||
// stuck in effectively an infinite loop - it fails every time with the
|
||||
// same 3 records...
|
||||
assertEquals("fail", processed.get(2));
|
||||
assertEquals("a", processed.get(3));
|
||||
assertEquals("b", processed.get(4));
|
||||
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void testTransactionalHandlingWithRetry() throws Exception {
|
||||
|
||||
List<String> list = TransactionAwareProxyFactory.createTransactionalList();
|
||||
list.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray("a,b,fail,d,e,f,g,h,j,k")));
|
||||
int beforeCount = list.size();
|
||||
|
||||
Target handler = new Target() {
|
||||
public boolean send(Message<?> message) {
|
||||
if (message == null) {
|
||||
return false;
|
||||
}
|
||||
Object payload = message.getPayload();
|
||||
logger.debug("Handling: " + payload);
|
||||
boolean result = processed.add((String) payload);
|
||||
// INT-184 this won't work if it is a "real" handler that throws
|
||||
// MessageHandlingException
|
||||
if ("fail".equals(payload)) {
|
||||
throw new RuntimeException("Planned failure: " + payload);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
Source<Object> source = getPollableSource(list);
|
||||
MessageChannel channel = getChannel(handler, source);
|
||||
SourceEndpoint endpoint = getSourceEndpoint(source, channel);
|
||||
endpoint.setTaskAdviceChain(Arrays.asList(new Advice[] { getTransactionInterceptor() }));
|
||||
endpoint
|
||||
.setDispatchAdviceChain(Arrays.asList(new Advice[] { getRetryOperationsInterceptor(itemKeyGenerator) }));
|
||||
endpoint.initializeTask();
|
||||
MessagingTaskScheduler scheduler = getSchedulerWithErrorHandler(endpoint);
|
||||
|
||||
waitForResults(scheduler, 4, 20);
|
||||
|
||||
assertEquals(4, processed.size());
|
||||
assertEquals(1, recovered.size());
|
||||
assertFalse("No messages got to processor", processed.isEmpty());
|
||||
// 4 items from list should have been processed (with no repeats, since
|
||||
// the failed item was recovered with no retry - NeverRetryPolicy)
|
||||
assertEquals(beforeCount - 4, list.size());
|
||||
assertEquals("a", processed.get(0));
|
||||
assertEquals("b", processed.get(1));
|
||||
// retry makes it fail once then recover...
|
||||
assertEquals("fail", processed.get(2));
|
||||
assertEquals("d", processed.get(3));
|
||||
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void testTransactionalHandlingWithRepeatAndRetry() throws Exception {
|
||||
|
||||
List<String> list = TransactionAwareProxyFactory.createTransactionalList();
|
||||
list.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray("a,fail,c,d,e,f,g,h,j,k")));
|
||||
int beforeCount = list.size();
|
||||
|
||||
Target handler = new Target() {
|
||||
public boolean send(Message<?> message) {
|
||||
Object payload = message.getPayload();
|
||||
logger.debug("Handling: " + payload);
|
||||
boolean result = processed.add((String) payload);
|
||||
if ("fail".equals(payload)) {
|
||||
throw new RuntimeException("Planned failure: " + payload);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
Source<Object> source = getPollableSource(list);
|
||||
MessageChannel channel = getChannel(handler, source);
|
||||
SourceEndpoint endpoint = getSourceEndpoint(source, channel);
|
||||
endpoint.setTaskAdviceChain(Arrays.asList(new Advice[] { getTransactionInterceptor(),
|
||||
getRepeatOperationsInterceptor(3) }));
|
||||
endpoint
|
||||
.setDispatchAdviceChain(Arrays.asList(new Advice[] { getRetryOperationsInterceptor(itemKeyGenerator) }));
|
||||
endpoint.initializeTask();
|
||||
MessagingTaskScheduler scheduler = getSchedulerWithErrorHandler(endpoint);
|
||||
|
||||
waitForResults(scheduler, 6, 100);
|
||||
System.err.println(processed);
|
||||
System.err.println(list);
|
||||
|
||||
assertEquals(6, processed.size());
|
||||
assertFalse("No messages got to processor", processed.isEmpty());
|
||||
// One roll back and then start again with a,b,d,e
|
||||
assertEquals(beforeCount - 5, list.size());
|
||||
assertEquals("a", processed.get(0));
|
||||
assertEquals("fail", processed.get(1));
|
||||
// retry makes it fail once then recover...
|
||||
assertEquals("a", processed.get(2));
|
||||
assertEquals("c", processed.get(3));
|
||||
assertEquals("d", processed.get(4));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param source
|
||||
* @param channel
|
||||
* @return
|
||||
*/
|
||||
private SourceEndpoint getSourceEndpoint(Source<Object> source, MessageChannel channel) {
|
||||
PollingSchedule schedule = new PollingSchedule(50);
|
||||
schedule.setFixedRate(true); // used to be the default
|
||||
return new SourceEndpoint(source, channel, schedule);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param handler
|
||||
* @param source
|
||||
* @return
|
||||
*/
|
||||
private DirectChannel getChannel(Target handler, Source<Object> source) {
|
||||
DirectChannel channel = new DirectChannel(source);
|
||||
channel.setName("input");
|
||||
channel.subscribe(handler);
|
||||
return channel;
|
||||
}
|
||||
|
||||
private void waitForResults(Lifecycle lifecycle, int count, int maxTries) throws InterruptedException {
|
||||
lifecycle.start();
|
||||
int timeout = 0;
|
||||
while (processed.size() < count && timeout++ < maxTries) {
|
||||
Thread.sleep(10);
|
||||
}
|
||||
lifecycle.stop();
|
||||
}
|
||||
|
||||
private Source<Object> getPollableSource(List<String> list) {
|
||||
final ItemReader reader = new ListItemReader(list) {
|
||||
public Object read() {
|
||||
Object item = super.read();
|
||||
logger.debug("Reading: " + item);
|
||||
return item;
|
||||
}
|
||||
};
|
||||
Source<Object> source = new Source<Object>() {
|
||||
public Message<Object> receive() {
|
||||
try {
|
||||
return new GenericMessage<Object>(reader.read());
|
||||
}
|
||||
catch (RuntimeException e) {
|
||||
throw e;
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
};
|
||||
return source;
|
||||
}
|
||||
|
||||
// Workaround for INT-182
|
||||
private MessagingTaskScheduler getSchedulerWithErrorHandler(Runnable task) {
|
||||
SimpleMessagingTaskScheduler scheduler = new SimpleMessagingTaskScheduler(Executors
|
||||
.newSingleThreadScheduledExecutor());
|
||||
scheduler.setErrorHandler(new ErrorHandler() {
|
||||
public void handle(Throwable t) {
|
||||
logger.error("Exception in scheduler", t);
|
||||
// throw (RuntimeException)t;
|
||||
}
|
||||
});
|
||||
scheduler.schedule(task);
|
||||
return scheduler;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param itemKeyGenerator
|
||||
* @return
|
||||
*/
|
||||
private StatefulRetryOperationsInterceptor getRetryOperationsInterceptor(ItemKeyGenerator itemKeyGenerator) {
|
||||
StatefulRetryOperationsInterceptor advice = new StatefulRetryOperationsInterceptor();
|
||||
advice.setRecoverer(new ItemRecoverer() {
|
||||
@SuppressWarnings("unchecked")
|
||||
public Object recover(Object data, Throwable cause) {
|
||||
if (data == null) {
|
||||
return false;
|
||||
}
|
||||
if (data.getClass().isArray()) {
|
||||
data = ((Object[]) data)[0];
|
||||
}
|
||||
recovered.add(((Message<String>) data).getPayload());
|
||||
return true;
|
||||
}
|
||||
});
|
||||
advice.setKeyGenerator(itemKeyGenerator);
|
||||
return advice;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return
|
||||
*/
|
||||
private TransactionInterceptor getTransactionInterceptor() {
|
||||
return new TransactionInterceptor(new ResourcelessTransactionManager(), PropertiesConverter
|
||||
.stringToProperties("*=PROPAGATION_REQUIRED"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param commitInterval
|
||||
* @return
|
||||
*/
|
||||
private RepeatOperationsInterceptor getRepeatOperationsInterceptor(int commitInterval) {
|
||||
RepeatOperationsInterceptor advice = new RepeatOperationsInterceptor();
|
||||
RepeatTemplate repeatTemplate = new RepeatTemplate();
|
||||
repeatTemplate.setCompletionPolicy(new SimpleCompletionPolicy(commitInterval));
|
||||
advice.setRepeatOperations(repeatTemplate);
|
||||
return advice;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans:beans xmlns="http://www.springframework.org/schema/integration"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:beans="http://www.springframework.org/schema/beans"
|
||||
xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
|
||||
http://www.springframework.org/schema/integration
|
||||
http://www.springframework.org/schema/integration/spring-integration-1.0.xsd
|
||||
http://www.springframework.org/schema/context
|
||||
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">
|
||||
<message-bus auto-create-channels="true" />
|
||||
<annotation-driven />
|
||||
<direct-channel id="smokein"/>
|
||||
<channel id="smokeout"/>
|
||||
</beans:beans>
|
||||
@@ -0,0 +1,14 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans:beans xmlns="http://www.springframework.org/schema/integration"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:beans="http://www.springframework.org/schema/beans"
|
||||
xmlns:context="http://www.springframework.org/schema/context"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
|
||||
http://www.springframework.org/schema/integration
|
||||
http://www.springframework.org/schema/integration/spring-integration-1.0.xsd
|
||||
http://www.springframework.org/schema/context
|
||||
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
|
||||
<message-bus auto-create-channels="true" />
|
||||
<channel id="jobs" />
|
||||
|
||||
</beans:beans>
|
||||
10
spring-batch-integration/src/test/resources/log4j.properties
Normal file
10
spring-batch-integration/src/test/resources/log4j.properties
Normal file
@@ -0,0 +1,10 @@
|
||||
log4j.rootCategory=WARN, stdout
|
||||
|
||||
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.integration.batch=DEBUG
|
||||
log4j.logger.org.springframework.batch=DEBUG
|
||||
log4j.category.org.springframework.integration=DEBUG
|
||||
log4j.category.org.springframework.transaction=DEBUG
|
||||
@@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans:beans xmlns="http://www.springframework.org/schema/integration"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:beans="http://www.springframework.org/schema/beans"
|
||||
xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
|
||||
http://www.springframework.org/schema/integration
|
||||
http://www.springframework.org/schema/integration/spring-integration-1.0.xsd
|
||||
http://www.springframework.org/schema/context
|
||||
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">
|
||||
|
||||
<message-bus auto-create-channels="true" />
|
||||
|
||||
<annotation-driven />
|
||||
|
||||
<channel id="requests" />
|
||||
<channel id="replies" />
|
||||
|
||||
<beans:bean id="transactionManager"
|
||||
class="org.springframework.batch.support.transaction.ResourcelessTransactionManager" />
|
||||
<tx:annotation-driven />
|
||||
|
||||
<beans:bean id="chunkHandler" class="org.springframework.integration.batch.chunk.ItemWriterChunkHandler">
|
||||
<beans:property name="itemWriter">
|
||||
<beans:bean class="org.springframework.integration.batch.chunk.TestItemWriter"></beans:bean>
|
||||
</beans:property>
|
||||
</beans:bean>
|
||||
|
||||
<handler-endpoint input-channel="requests" output-channel="replies" handler="chunkHandler" method="handleChunk" />
|
||||
|
||||
</beans:beans>
|
||||
@@ -0,0 +1,18 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:integration="http://www.springframework.org/schema/integration"
|
||||
xmlns:context="http://www.springframework.org/schema/context"
|
||||
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
|
||||
xmlns:p="http://www.springframework.org/schema/p" 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.5.xsd
|
||||
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
|
||||
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
|
||||
http://www.springframework.org/schema/integration
|
||||
http://www.springframework.org/schema/integration/spring-integration-1.0.xsd
|
||||
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
|
||||
<integration:message-bus auto-create-channels="true" />
|
||||
<integration:annotation-driven/>
|
||||
<integration:channel id="resources" />
|
||||
<integration:channel id="requests" />
|
||||
</beans>
|
||||
@@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:integration="http://www.springframework.org/schema/integration"
|
||||
xmlns:context="http://www.springframework.org/schema/context"
|
||||
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
|
||||
xmlns:p="http://www.springframework.org/schema/p" 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.5.xsd
|
||||
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
|
||||
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
|
||||
http://www.springframework.org/schema/integration
|
||||
http://www.springframework.org/schema/integration/spring-integration-1.0.xsd
|
||||
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
|
||||
<integration:message-bus auto-create-channels="true" />
|
||||
<integration:channel id="requests" />
|
||||
<bean id="itemWriter" class="org.springframework.integration.batch.item.MessageChannelItemWriter">
|
||||
<property name="channel" ref="requests"/>
|
||||
</bean>
|
||||
</beans>
|
||||
@@ -0,0 +1,47 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:integration="http://www.springframework.org/schema/integration"
|
||||
xmlns:context="http://www.springframework.org/schema/context"
|
||||
xmlns:aop="http://www.springframework.org/schema/aop"
|
||||
xmlns:tx="http://www.springframework.org/schema/tx"
|
||||
xmlns:p="http://www.springframework.org/schema/p"
|
||||
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.5.xsd
|
||||
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
|
||||
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
|
||||
http://www.springframework.org/schema/integration
|
||||
http://www.springframework.org/schema/integration/spring-integration-1.0.xsd
|
||||
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
|
||||
<import resource="classpath:/simple-job-launcher-context.xml" />
|
||||
<integration:annotation-driven/>
|
||||
<integration:message-bus auto-create-channels="true" />
|
||||
<integration:channel id="requests" />
|
||||
<integration:channel id="replies" />
|
||||
<bean id="job" parent="simpleJob">
|
||||
<property name="steps">
|
||||
<bean
|
||||
class="org.springframework.integration.batch.job.MessageOrientedStep">
|
||||
<property name="name" value="TODO: I shouldn't have to set this"/>
|
||||
<property name="requestChannel" ref="requests" />
|
||||
<property name="replyChannel" ref="replies" />
|
||||
<property name="jobRepository" ref="jobRepository" />
|
||||
</bean>
|
||||
</property>
|
||||
<property name="jobRepository" ref="jobRepository" />
|
||||
</bean>
|
||||
<bean id="step"
|
||||
class="org.springframework.integration.batch.job.StepExecutionMessageHandler">
|
||||
<property name="step">
|
||||
<bean parent="taskletStep">
|
||||
<property name="tasklet">
|
||||
<bean
|
||||
class="org.springframework.integration.batch.job.TestTasklet" />
|
||||
</property>
|
||||
</bean>
|
||||
</property>
|
||||
<property name="jobRepository" ref="jobRepository" />
|
||||
</bean>
|
||||
<integration:handler-endpoint handler="step" method="handle" input-channel="requests"
|
||||
output-channel="replies" />
|
||||
</beans>
|
||||
@@ -0,0 +1,44 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:integration="http://www.springframework.org/schema/integration"
|
||||
xmlns:context="http://www.springframework.org/schema/context"
|
||||
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
|
||||
xmlns:p="http://www.springframework.org/schema/p" 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.5.xsd
|
||||
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
|
||||
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
|
||||
http://www.springframework.org/schema/integration
|
||||
http://www.springframework.org/schema/integration/spring-integration-1.0.xsd
|
||||
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
|
||||
|
||||
<import resource="classpath:simple-job-launcher-context.xml"/>
|
||||
|
||||
<integration:message-bus auto-create-channels="true" />
|
||||
<integration:annotation-driven />
|
||||
<integration:channel id="requests" />
|
||||
<integration:channel id="response" />
|
||||
|
||||
<integration:handler-endpoint input-channel="requests" handler="jobLaunchingHandler" method="handle"/>
|
||||
|
||||
<bean id="jobLaunchingHandler" class="org.springframework.integration.batch.launch.JobLaunchingMessageHandler">
|
||||
<constructor-arg ref="jobLauncher"/>
|
||||
<constructor-arg ref="messageToJobStrategy"/>
|
||||
</bean>
|
||||
|
||||
<bean id="messageToJobStrategy" class="org.springframework.integration.batch.launch.StringPayloadAsJobNameStrategy">
|
||||
<constructor-arg ref="jobRegistry" />
|
||||
</bean>
|
||||
|
||||
<bean id="testJob" parent="simpleJob">
|
||||
<property name="steps" ref="step"/>
|
||||
</bean>
|
||||
|
||||
<bean id="step" class="org.springframework.batch.core.step.tasklet.TaskletStep">
|
||||
<property name="tasklet">
|
||||
<bean class="org.springframework.integration.batch.job.TestTasklet"/>
|
||||
</property>
|
||||
<property name="jobRepository" ref="jobRepository"/>
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
@@ -0,0 +1,80 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
|
||||
xmlns:p="http://www.springframework.org/schema/p" 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.5.xsd
|
||||
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
|
||||
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">
|
||||
<bean id="jobRegistryBeanPostProcessor"
|
||||
class="org.springframework.batch.core.configuration.support.JobRegistryBeanPostProcessor">
|
||||
<property name="jobRegistry" ref="jobRegistry" />
|
||||
</bean>
|
||||
<bean id="jobLauncher"
|
||||
class="org.springframework.batch.core.launch.support.SimpleJobLauncher">
|
||||
<property name="jobRepository" ref="jobRepository" />
|
||||
</bean>
|
||||
<bean id="jobRegistry"
|
||||
class="org.springframework.batch.core.configuration.support.MapJobRegistry" />
|
||||
<bean id="transactionManager"
|
||||
class="org.springframework.batch.support.transaction.ResourcelessTransactionManager" />
|
||||
<bean id="jobRepository"
|
||||
class="org.springframework.batch.core.repository.support.SimpleJobRepository">
|
||||
<constructor-arg ref="mapJobInstanceDao" />
|
||||
<constructor-arg ref="mapJobExecutionDao" />
|
||||
<constructor-arg ref="mapStepExecutionDao" />
|
||||
</bean>
|
||||
<bean id="mapJobInstanceDao" lazy-init="true"
|
||||
class="org.springframework.batch.core.repository.dao.MapJobInstanceDao" />
|
||||
<bean id="mapJobExecutionDao" lazy-init="true"
|
||||
class="org.springframework.batch.core.repository.dao.MapJobExecutionDao" />
|
||||
<bean id="mapStepExecutionDao" lazy-init="true"
|
||||
class="org.springframework.batch.core.repository.dao.MapStepExecutionDao" />
|
||||
<bean id="simpleJob" class="org.springframework.batch.core.job.SimpleJob"
|
||||
abstract="true">
|
||||
<property name="jobRepository" ref="jobRepository" />
|
||||
<property name="restartable" value="true" />
|
||||
</bean>
|
||||
<bean id="taskletStep" class="org.springframework.batch.core.step.tasklet.TaskletStep"
|
||||
abstract="true">
|
||||
<property name="jobRepository" ref="jobRepository" />
|
||||
<property name="allowStartIfComplete" value="true" />
|
||||
</bean>
|
||||
<bean id="simpleStep"
|
||||
class="org.springframework.batch.core.step.item.SimpleStepFactoryBean"
|
||||
abstract="true">
|
||||
<property name="transactionManager" ref="transactionManager" />
|
||||
<property name="jobRepository" ref="jobRepository" />
|
||||
<property name="startLimit" value="100" />
|
||||
<property name="commitInterval" value="1" />
|
||||
</bean>
|
||||
<bean id="skipLimitStep"
|
||||
class="org.springframework.batch.core.step.item.SkipLimitStepFactoryBean"
|
||||
parent="simpleStep" abstract="true">
|
||||
<property name="skipLimit" value="0" />
|
||||
</bean>
|
||||
<bean id="customEditorConfigurer"
|
||||
class="org.springframework.beans.factory.config.CustomEditorConfigurer">
|
||||
<property name="customEditors">
|
||||
<map>
|
||||
<entry key="int[]">
|
||||
<bean class="org.springframework.batch.support.IntArrayPropertyEditor" />
|
||||
</entry>
|
||||
<entry key="org.springframework.batch.item.file.transform.Range[]">
|
||||
<bean
|
||||
class="org.springframework.batch.item.file.transform.RangeArrayPropertyEditor" />
|
||||
</entry>
|
||||
<entry key="java.util.Date">
|
||||
<bean class="org.springframework.beans.propertyeditors.CustomDateEditor">
|
||||
<constructor-arg>
|
||||
<bean class="java.text.SimpleDateFormat">
|
||||
<constructor-arg value="yyyyMMdd" />
|
||||
</bean>
|
||||
</constructor-arg>
|
||||
<constructor-arg value="false" />
|
||||
</bean>
|
||||
</entry>
|
||||
</map>
|
||||
</property>
|
||||
</bean>
|
||||
</beans>
|
||||
Reference in New Issue
Block a user