BATCH-2241 & BATCH-2243 - add namespace support for remote chunking

This commit is contained in:
Chris Schaefer
2014-06-12 03:14:34 -04:00
parent deb4c6fb5b
commit 4f32f623f0
18 changed files with 926 additions and 5 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 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.
@@ -21,15 +21,16 @@ import org.springframework.integration.config.xml.AbstractIntegrationNamespaceHa
* The namespace handler for the Spring Batch Integration namespace.
*
* @author Gunnar Hillert
* @author Chris Schaefer
* @since 1.3
*
*/
public class BatchIntegrationNamespaceHandler extends AbstractIntegrationNamespaceHandler {
/* (non-Javadoc)
* @see org.springframework.beans.factory.xml.NamespaceHandler#init()
*/
public void init() {
this.registerBeanDefinitionParser("job-launching-gateway", new JobLaunchingGatewayParser());
this.registerBeanDefinitionParser("remote-chunking-master", new RemoteChunkingMasterParser());
this.registerBeanDefinitionParser("remote-chunking-slave", new RemoteChunkingSlaveParser());
}
}

View File

@@ -0,0 +1,83 @@
/*
* Copyright 2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.batch.integration.config.xml;
import org.springframework.batch.integration.chunk.ChunkMessageChannelItemWriter;
import org.springframework.batch.integration.chunk.RemoteChunkHandlerFactoryBean;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.util.Assert;
import org.w3c.dom.Element;
/**
* <p>
* Parser for the remote-chunking-master namespace element.
* </p>
*
* @author Chris Schaefer
* @since 3.1
*/
public class RemoteChunkingMasterParser extends AbstractBeanDefinitionParser {
private static final String MESSAGE_TEMPLATE_ATTRIBUTE = "message-template";
private static final String STEP_ATTRIBUTE = "step";
private static final String REPLY_CHANNEL_ATTRIBUTE = "reply-channel";
private static final String MESSAGING_OPERATIONS_PROPERTY = "messagingOperations";
private static final String REPLY_CHANNEL_PROPERTY = "replyChannel";
private static final String CHUNK_WRITER_PROPERTY = "chunkWriter";
private static final String STEP_PROPERTY = "step";
private static final String CHUNK_HANDLER_BEAN_NAME_PREFIX = "remoteChunkHandlerFactoryBean_";
@Override
public AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
String id = element.getAttribute(ID_ATTRIBUTE);
Assert.hasText(id, "The id attribute must be specified");
String messageTemplate = element.getAttribute(MESSAGE_TEMPLATE_ATTRIBUTE);
Assert.hasText(messageTemplate, "The message-template attribute must be specified");
String step = element.getAttribute(STEP_ATTRIBUTE);
Assert.hasText(step, "The step attribute must be specified");
String replyChannel = element.getAttribute(REPLY_CHANNEL_ATTRIBUTE);
Assert.hasText(replyChannel, "The reply-channel attribute must be specified");
BeanDefinitionRegistry beanDefinitionRegistry = parserContext.getRegistry();
BeanDefinition chunkMessageChannelItemWriter =
BeanDefinitionBuilder
.genericBeanDefinition(ChunkMessageChannelItemWriter.class)
.addPropertyReference(MESSAGING_OPERATIONS_PROPERTY, messageTemplate)
.addPropertyReference(REPLY_CHANNEL_PROPERTY, replyChannel)
.getBeanDefinition();
beanDefinitionRegistry.registerBeanDefinition(id, chunkMessageChannelItemWriter);
BeanDefinition remoteChunkHandlerFactoryBean =
BeanDefinitionBuilder
.genericBeanDefinition(RemoteChunkHandlerFactoryBean.class)
.addPropertyValue(CHUNK_WRITER_PROPERTY, chunkMessageChannelItemWriter)
.addPropertyValue(STEP_PROPERTY, step)
.getBeanDefinition();
beanDefinitionRegistry.registerBeanDefinition(CHUNK_HANDLER_BEAN_NAME_PREFIX + step, remoteChunkHandlerFactoryBean);
return null;
}
}

View File

@@ -0,0 +1,117 @@
/*
* Copyright 2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.batch.integration.config.xml;
import org.springframework.batch.core.step.item.SimpleChunkProcessor;
import org.springframework.batch.integration.chunk.ChunkProcessorChunkHandler;
import org.springframework.batch.item.support.PassThroughItemProcessor;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.integration.config.ServiceActivatorFactoryBean;
import org.springframework.integration.config.xml.AbstractConsumerEndpointParser;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.w3c.dom.Element;
/**
* <p>
* Parser for the remote-chunking-slave namespace element. If an
* {@link org.springframework.batch.item.ItemProcessor} is not provided, an
* {@link org.springframework.batch.item.support.PassThroughItemProcessor} will be
* configured.
* </p>
*
* @author Chris Schaefer
* @since 3.1
*/
public class RemoteChunkingSlaveParser extends AbstractBeanDefinitionParser {
private static final String INPUT_CHANNEL_ATTRIBUTE = "input-channel";
private static final String OUTPUT_CHANNEL_ATTRIBUTE = "output-channel";
private static final String ITEM_PROCESSOR_ATTRIBUTE = "item-processor";
private static final String ITEM_WRITER_ATTRIBUTE = "item-writer";
private static final String ITEM_PROCESSOR_PROPERTY_NAME = "itemProcessor";
private static final String ITEM_WRITER_PROPERTY_NAME = "itemWriter";
private static final String CHUNK_PROCESSOR_PROPERTY_NAME = "chunkProcessor";
private static final String CHUNK_PROCESSOR_CHUNK_HANDLER_BEAN_NAME_PREFIX = "chunkProcessorChunkHandler_";
@Override
protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
String id = element.getAttribute(ID_ATTRIBUTE);
Assert.hasText(id, "The id attribute must be specified");
String inputChannel = element.getAttribute(INPUT_CHANNEL_ATTRIBUTE);
Assert.hasText(inputChannel, "The input-channel attribute must be specified");
String outputChannel = element.getAttribute(OUTPUT_CHANNEL_ATTRIBUTE);
Assert.hasText(outputChannel, "The output-channel attribute must be specified");
String itemProcessor = element.getAttribute(ITEM_PROCESSOR_ATTRIBUTE);
String itemWriter = element.getAttribute(ITEM_WRITER_ATTRIBUTE);
Assert.hasText(itemWriter, "The item-writer attribute must be specified");
BeanDefinitionRegistry beanDefinitionRegistry = parserContext.getRegistry();
BeanDefinitionBuilder chunkProcessorBuilder =
BeanDefinitionBuilder
.genericBeanDefinition(SimpleChunkProcessor.class)
.addPropertyReference(ITEM_WRITER_PROPERTY_NAME, itemWriter);
if(StringUtils.hasText(itemProcessor)) {
chunkProcessorBuilder.addPropertyReference(ITEM_PROCESSOR_PROPERTY_NAME, itemProcessor);
} else {
chunkProcessorBuilder.addPropertyValue(ITEM_PROCESSOR_PROPERTY_NAME, new PassThroughItemProcessor());
}
BeanDefinition chunkProcessorChunkHandler =
BeanDefinitionBuilder
.genericBeanDefinition(ChunkProcessorChunkHandler.class)
.addPropertyValue(CHUNK_PROCESSOR_PROPERTY_NAME, chunkProcessorBuilder.getBeanDefinition())
.getBeanDefinition();
beanDefinitionRegistry.registerBeanDefinition(CHUNK_PROCESSOR_CHUNK_HANDLER_BEAN_NAME_PREFIX + id, chunkProcessorChunkHandler);
new ServiceActivatorParser(id).parse(element, parserContext);
return null;
}
private static class ServiceActivatorParser extends AbstractConsumerEndpointParser {
private static final String TARGET_METHOD_NAME_PROPERTY_NAME = "targetMethodName";
private static final String TARGET_OBJECT_PROPERTY_NAME = "targetObject";
private static final String HANDLE_CHUNK_METHOD_NAME = "handleChunk";
private static final String CHUNK_PROCESSOR_CHUNK_HANDLER_BEAN_NAME_PREFIX = "chunkProcessorChunkHandler_";
private String id;
public ServiceActivatorParser(String id) {
this.id = id;
}
@Override
protected BeanDefinitionBuilder parseHandler(Element element, ParserContext parserContext) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(ServiceActivatorFactoryBean.class);
builder.addPropertyValue(TARGET_METHOD_NAME_PROPERTY_NAME, HANDLE_CHUNK_METHOD_NAME);
builder.addPropertyValue(TARGET_OBJECT_PROPERTY_NAME, new RuntimeBeanReference(CHUNK_PROCESSOR_CHUNK_HANDLER_BEAN_NAME_PREFIX + id));
return builder;
}
}
}

View File

@@ -1,2 +1,3 @@
http\://www.springframework.org/schema/batch-integration/spring-batch-integration-1.3.xsd=org/springframework/batch/integration/config/xml/spring-batch-integration-1.3.xsd
http\://www.springframework.org/schema/batch-integration/spring-batch-integration.xsd=org/springframework/batch/integration/config/xml/spring-batch-integration-1.3.xsd
http\://www.springframework.org/schema/batch-integration/spring-batch-integration-3.1.xsd=org/springframework/batch/integration/config/xml/spring-batch-integration-3.1.xsd
http\://www.springframework.org/schema/batch-integration/spring-batch-integration.xsd=org/springframework/batch/integration/config/xml/spring-batch-integration-3.1.xsd

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns="http://www.springframework.org/schema/batch-integration"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:tool="http://www.springframework.org/schema/tool"
xmlns:integration="http://www.springframework.org/schema/integration"
targetNamespace="http://www.springframework.org/schema/batch-integration"

View File

@@ -0,0 +1,244 @@
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns="http://www.springframework.org/schema/batch-integration"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:tool="http://www.springframework.org/schema/tool"
xmlns:integration="http://www.springframework.org/schema/integration"
targetNamespace="http://www.springframework.org/schema/batch-integration"
elementFormDefault="qualified" attributeFormDefault="unqualified">
<xsd:import namespace="http://www.springframework.org/schema/beans"/>
<xsd:import namespace="http://www.springframework.org/schema/tool"/>
<xsd:import namespace="http://www.springframework.org/schema/integration"
schemaLocation="http://www.springframework.org/schema/integration/spring-integration.xsd"/>
<xsd:annotation>
<xsd:documentation><![CDATA[
Defines the configuration elements for the Spring Batch Integration
Support.
]]></xsd:documentation>
</xsd:annotation>
<xsd:element name="job-launching-gateway">
<xsd:annotation>
<xsd:documentation><![CDATA[
This Outbound Gateway is used to launch Batch Jobs. The
payload of Messages to be processed MUST be an instance
of JobLaunchRequest.
]]></xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<xsd:sequence>
<xsd:element ref="integration:poller" minOccurs="0" maxOccurs="1"/>
</xsd:sequence>
<xsd:attributeGroup ref="corespringBatchIntegrationComponentAttributes"/>
<xsd:attribute name="request-channel" type="xsd:string">
<xsd:annotation>
<xsd:documentation><![CDATA[
The input Message Channel of this endpoint.
]]></xsd:documentation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:expected-type type="org.springframework.integration.MessageChannel"/>
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="reply-channel" type="xsd:string">
<xsd:annotation>
<xsd:documentation><![CDATA[
Message Channel to which the resulting JobExecution
payload will be sent.
]]></xsd:documentation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:expected-type type="org.springframework.integration.MessageChannel"/>
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="reply-timeout" type="xsd:string">
<xsd:annotation>
<xsd:documentation><![CDATA[
Allows you to specify how long this gateway will wait for
the reply message to be sent successfully to the reply channel
before throwing an exception. This attribute only applies when the
channel might block, for example when using a bounded queue channel that
is currently full.
Also, keep in mind that when sending to a DirectChannel, the
invocation will occur in the sender's thread. Therefore,
the failing of the send operation may be caused by other
components further downstream.
The "reply-timeout" attribute maps to the "sendTimeout" property of the
underlying 'MessagingTemplate' instance (org.springframework.integration.core.MessagingTemplate).
The attribute will default, if not specified, to '-1', meaning that
by default, the Gateway will wait indefinitely. The value is
specified in milliseconds.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="job-launcher" type="xsd:string">
<xsd:annotation>
<xsd:appinfo>
<xsd:documentation><![CDATA[
Pass in a custom JobLauncher bean reference.
This attribute is optional. If not specified the
adapter will re-use the default instance (under
the id 'jobLauncher', e.g. when using the
@EnableBatchProcessing annotation via JavaConfig).
If no default instance exists an exception is
thrown.
]]></xsd:documentation>
<tool:annotation kind="ref">
<tool:expected-type type="org.springframework.batch.core.launch.JobLauncher"/>
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="order">
<xsd:annotation>
<xsd:documentation><![CDATA[
Specifies the order for invocation when this endpoint
is connected as a subscriber to a SubscribableChannel.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
</xsd:element>
<xsd:attributeGroup name="corespringBatchIntegrationComponentAttributes">
<xsd:attribute name="id" type="xsd:string" use="optional">
<xsd:annotation>
<xsd:documentation><![CDATA[
Identifies the underlying Spring bean definition, which is an
instance of either 'EventDrivenConsumer' or 'PollingConsumer',
depending on whether the component's input channel is a
'SubscribableChannel' or 'PollableChannel'.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="auto-startup" default="true" use="optional">
<xsd:annotation>
<xsd:documentation><![CDATA[
Flag to indicate that the component should start automatically
on startup (default true).
]]></xsd:documentation>
</xsd:annotation>
<xsd:simpleType>
<xsd:union memberTypes="xsd:boolean xsd:string"/>
</xsd:simpleType>
</xsd:attribute>
</xsd:attributeGroup>
<xsd:element name="remote-chunking-master">
<xsd:annotation>
<xsd:documentation><![CDATA[
The remote chunking master is used as the writer in batch jobs
to communicate with the middleware used to send chunks remotely.
]]></xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<xsd:attribute name="id" type="xsd:ID" use="required"/>
<xsd:attribute name="message-template" type="xsd:string" use="required">
<xsd:annotation>
<xsd:documentation><![CDATA[
The messaging template to use.
]]></xsd:documentation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:expected-type type="org.springframework.integration.core.MessagingTemplate"/>
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="step" type="xsd:string" use="required">
<xsd:annotation>
<xsd:documentation><![CDATA[
The step to be remotely chunked.
]]></xsd:documentation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:expected-type type="org.springframework.batch.core.Step"/>
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="reply-channel" type="xsd:string" use="required">
<xsd:annotation>
<xsd:documentation><![CDATA[
The channel to use for reply messages from slaves.
]]></xsd:documentation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:expected-type type="org.springframework.integration.MessageChannel"/>
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
</xsd:element>
<xsd:element name="remote-chunking-slave">
<xsd:annotation>
<xsd:documentation><![CDATA[
The remote chunking slave receives chunks sent by the master and
provides the processor and writer to handle the chunks, returning
status back to the master.
]]></xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<xsd:attribute name="id" type="xsd:ID" use="required"/>
<xsd:attribute name="input-channel" type="xsd:string" use="required">
<xsd:annotation>
<xsd:documentation><![CDATA[
The channel to use for receiving messages from the master.
]]></xsd:documentation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:expected-type type="org.springframework.integration.MessageChannel"/>
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="output-channel" type="xsd:string" use="required">
<xsd:annotation>
<xsd:documentation><![CDATA[
The channel to use for sending messages to the master.
]]></xsd:documentation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:expected-type type="org.springframework.integration.MessageChannel"/>
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="item-processor" type="xsd:string" use="optional">
<xsd:annotation>
<xsd:documentation><![CDATA[
The ItemProcessor implementation to use for processing items. If none
provided a PassThroughItemProcessor will be automatically used.
]]></xsd:documentation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:expected-type type="org.springframework.batch.item.ItemProcessor"/>
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="item-writer" type="xsd:string" use="required">
<xsd:annotation>
<xsd:documentation><![CDATA[
The ItemWriter implementation to use for writing items.
]]></xsd:documentation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:expected-type type="org.springframework.batch.item.ItemWriter"/>
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
</xsd:element>
</xsd:schema>

View File

@@ -0,0 +1,276 @@
/*
* Copyright 2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.batch.integration.config.xml;
import org.junit.Test;
import org.springframework.batch.core.step.item.ChunkProcessor;
import org.springframework.batch.core.step.item.SimpleChunkProcessor;
import org.springframework.batch.integration.chunk.ChunkHandler;
import org.springframework.batch.integration.chunk.ChunkMessageChannelItemWriter;
import org.springframework.batch.integration.chunk.ChunkProcessorChunkHandler;
import org.springframework.batch.integration.chunk.RemoteChunkHandlerFactoryBean;
import org.springframework.batch.item.ItemProcessor;
import org.springframework.batch.item.ItemWriter;
import org.springframework.batch.item.support.PassThroughItemProcessor;
import org.springframework.beans.factory.BeanDefinitionStoreException;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.integration.config.ServiceActivatorFactoryBean;
import org.springframework.integration.test.util.TestUtils;
import org.springframework.messaging.MessageChannel;
import java.util.List;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
/**
* <p>
* Test cases for the {@link org.springframework.batch.integration.config.xml.RemoteChunkingSlaveParser}
* and {@link org.springframework.batch.integration.config.xml.RemoteChunkingMasterParser}.
* </p>
*
* @author Chris Schaefer
* @since 3.1
*/
public class RemoteChunkingParserTests {
@Test
public void testRemoteChunkingSlaveParserWithProcessorDefined() {
ApplicationContext applicationContext =
new ClassPathXmlApplicationContext("/org/springframework/batch/integration/config/xml/RemoteChunkingSlaveParserTests.xml");
ChunkHandler chunkHandler = applicationContext.getBean(ChunkProcessorChunkHandler.class);
ChunkProcessor chunkProcessor = (SimpleChunkProcessor) TestUtils.getPropertyValue(chunkHandler, "chunkProcessor");
assertNotNull("ChunkProcessor must not be null", chunkProcessor);
ItemWriter<String> itemWriter = (ItemWriter<String>) TestUtils.getPropertyValue(chunkProcessor, "itemWriter");
assertNotNull("ChunkProcessor ItemWriter must not be null", itemWriter);
assertTrue("Got wrong instance of ItemWriter", itemWriter instanceof Writer);
ItemProcessor<String, String> itemProcessor = (ItemProcessor<String, String>) TestUtils.getPropertyValue(chunkProcessor, "itemProcessor");
assertNotNull("ChunkProcessor ItemWriter must not be null", itemProcessor);
assertTrue("Got wrong instance of ItemProcessor", itemProcessor instanceof Processor);
FactoryBean serviceActivatorFactoryBean = applicationContext.getBean(ServiceActivatorFactoryBean.class);
assertNotNull("ServiceActivatorFactoryBean must not be null", serviceActivatorFactoryBean);
assertNotNull("Output channel must not be null", TestUtils.getPropertyValue(serviceActivatorFactoryBean, "outputChannel"));
MessageChannel inputChannel = applicationContext.getBean("requests", MessageChannel.class);
assertNotNull("Input channel must not be null", inputChannel);
String targetMethodName = (String) TestUtils.getPropertyValue(serviceActivatorFactoryBean, "targetMethodName");
assertNotNull("Target method name must not be null", targetMethodName);
assertTrue("Target method name must be handleChunk, got: " + targetMethodName, "handleChunk".equals(targetMethodName));
ChunkHandler targetObject = (ChunkHandler) TestUtils.getPropertyValue(serviceActivatorFactoryBean, "targetObject");
assertNotNull("Target object must not be null", targetObject);
}
@Test
public void testRemoteChunkingSlaveParserWithProcessorNotDefined() {
ApplicationContext applicationContext =
new ClassPathXmlApplicationContext("/org/springframework/batch/integration/config/xml/RemoteChunkingSlaveParserNoProcessorTests.xml");
ChunkHandler chunkHandler = applicationContext.getBean(ChunkProcessorChunkHandler.class);
ChunkProcessor chunkProcessor = (SimpleChunkProcessor) TestUtils.getPropertyValue(chunkHandler, "chunkProcessor");
assertNotNull("ChunkProcessor must not be null", chunkProcessor);
ItemProcessor<String, String> itemProcessor = (ItemProcessor<String, String>) TestUtils.getPropertyValue(chunkProcessor, "itemProcessor");
assertNotNull("ChunkProcessor ItemWriter must not be null", itemProcessor);
assertTrue("Got wrong instance of ItemProcessor", itemProcessor instanceof PassThroughItemProcessor);
}
@Test
public void testRemoteChunkingMasterParser() {
ApplicationContext applicationContext =
new ClassPathXmlApplicationContext("/org/springframework/batch/integration/config/xml/RemoteChunkingMasterParserTests.xml");
ItemWriter itemWriter = applicationContext.getBean("itemWriter", ChunkMessageChannelItemWriter.class);
assertNotNull("Messaging template must not be null", TestUtils.getPropertyValue(itemWriter, "messagingGateway"));
assertNotNull("Reply channel must not be null", TestUtils.getPropertyValue(itemWriter, "replyChannel"));
FactoryBean remoteChunkingHandlerFactoryBean = applicationContext.getBean(RemoteChunkHandlerFactoryBean.class);
assertNotNull("Chunk writer must not be null", TestUtils.getPropertyValue(remoteChunkingHandlerFactoryBean, "chunkWriter"));
assertNotNull("Step must not be null", TestUtils.getPropertyValue(remoteChunkingHandlerFactoryBean, "step"));
}
@Test
public void testRemoteChunkingMasterIdAttrAssert() throws Exception {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext();
applicationContext.setValidating(false);
applicationContext.setConfigLocation("/org/springframework/batch/integration/config/xml/RemoteChunkingMasterParserMissingIdAttrTests.xml");
try {
applicationContext.refresh();
fail();
} catch (BeanDefinitionStoreException e) {
assertTrue("Nested exception must be of type IllegalArgumentException", e.getCause() instanceof IllegalArgumentException);
IllegalArgumentException iae = (IllegalArgumentException) e.getCause();
assertTrue("Expected: " + "The id attribute must be specified" + " but got: " + iae.getMessage(),
"The id attribute must be specified".equals(iae.getMessage()));
}
}
@Test
public void testRemoteChunkingMasterMessageTemplateAttrAssert() throws Exception {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext();
applicationContext.setValidating(false);
applicationContext.setConfigLocation("/org/springframework/batch/integration/config/xml/RemoteChunkingMasterParserMissingMessageTemplateAttrTests.xml");
try {
applicationContext.refresh();
fail();
} catch (BeanDefinitionStoreException e) {
assertTrue("Nested exception must be of type IllegalArgumentException", e.getCause() instanceof IllegalArgumentException);
IllegalArgumentException iae = (IllegalArgumentException) e.getCause();
assertTrue("Expected: " + "The message-template attribute must be specified" + " but got: " + iae.getMessage(),
"The message-template attribute must be specified".equals(iae.getMessage()));
}
}
@Test
public void testRemoteChunkingMasterStepAttrAssert() throws Exception {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext();
applicationContext.setValidating(false);
applicationContext.setConfigLocation("/org/springframework/batch/integration/config/xml/RemoteChunkingMasterParserMissingStepAttrTests.xml");
try {
applicationContext.refresh();
fail();
} catch (BeanDefinitionStoreException e) {
assertTrue("Nested exception must be of type IllegalArgumentException", e.getCause() instanceof IllegalArgumentException);
IllegalArgumentException iae = (IllegalArgumentException) e.getCause();
assertTrue("Expected: " + "The step attribute must be specified" + " but got: " + iae.getMessage(),
"The step attribute must be specified".equals(iae.getMessage()));
}
}
@Test
public void testRemoteChunkingMasterReplyChannelAttrAssert() throws Exception {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext();
applicationContext.setValidating(false);
applicationContext.setConfigLocation("/org/springframework/batch/integration/config/xml/RemoteChunkingMasterParserMissingReplyChannelAttrTests.xml");
try {
applicationContext.refresh();
fail();
} catch (BeanDefinitionStoreException e) {
assertTrue("Nested exception must be of type IllegalArgumentException", e.getCause() instanceof IllegalArgumentException);
IllegalArgumentException iae = (IllegalArgumentException) e.getCause();
assertTrue("Expected: " + "The reply-channel attribute must be specified" + " but got: " + iae.getMessage(),
"The reply-channel attribute must be specified".equals(iae.getMessage()));
}
}
@Test
public void testRemoteChunkingSlaveIdAttrAssert() throws Exception {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext();
applicationContext.setValidating(false);
applicationContext.setConfigLocation("/org/springframework/batch/integration/config/xml/RemoteChunkingSlaveParserMissingIdAttrTests.xml");
try {
applicationContext.refresh();
fail();
} catch (BeanDefinitionStoreException e) {
assertTrue("Nested exception must be of type IllegalArgumentException", e.getCause() instanceof IllegalArgumentException);
IllegalArgumentException iae = (IllegalArgumentException) e.getCause();
assertTrue("Expected: " + "The id attribute must be specified" + " but got: " + iae.getMessage(),
"The id attribute must be specified".equals(iae.getMessage()));
}
}
@Test
public void testRemoteChunkingSlaveInputChannelAttrAssert() throws Exception {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext();
applicationContext.setValidating(false);
applicationContext.setConfigLocation("/org/springframework/batch/integration/config/xml/RemoteChunkingSlaveParserMissingInputChannelAttrTests.xml");
try {
applicationContext.refresh();
fail();
} catch (BeanDefinitionStoreException e) {
assertTrue("Nested exception must be of type IllegalArgumentException", e.getCause() instanceof IllegalArgumentException);
IllegalArgumentException iae = (IllegalArgumentException) e.getCause();
assertTrue("Expected: " + "The input-channel attribute must be specified" + " but got: " + iae.getMessage(),
"The input-channel attribute must be specified".equals(iae.getMessage()));
}
}
@Test
public void testRemoteChunkingSlaveItemWriterAttrAssert() throws Exception {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext();
applicationContext.setValidating(false);
applicationContext.setConfigLocation("/org/springframework/batch/integration/config/xml/RemoteChunkingSlaveParserMissingItemWriterAttrTests.xml");
try {
applicationContext.refresh();
fail();
} catch (BeanDefinitionStoreException e) {
assertTrue("Nested exception must be of type IllegalArgumentException", e.getCause() instanceof IllegalArgumentException);
IllegalArgumentException iae = (IllegalArgumentException) e.getCause();
assertTrue("Expected: " + "The item-writer attribute must be specified" + " but got: " + iae.getMessage(),
"The item-writer attribute must be specified".equals(iae.getMessage()));
}
}
@Test
public void testRemoteChunkingSlaveOutputChannelAttrAssert() throws Exception {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext();
applicationContext.setValidating(false);
applicationContext.setConfigLocation("/org/springframework/batch/integration/config/xml/RemoteChunkingSlaveParserMissingOutputChannelAttrTests.xml");
try {
applicationContext.refresh();
fail();
} catch (BeanDefinitionStoreException e) {
assertTrue("Nested exception must be of type IllegalArgumentException", e.getCause() instanceof IllegalArgumentException);
IllegalArgumentException iae = (IllegalArgumentException) e.getCause();
assertTrue("Expected: " + "The output-channel attribute must be specified" + " but got: " + iae.getMessage(),
"The output-channel attribute must be specified".equals(iae.getMessage()));
}
}
private static class Writer implements ItemWriter<String> {
@Override
public void write(List<? extends String> items) throws Exception {
//
}
}
private static class Processor implements ItemProcessor<String, String> {
@Override
public String process(String item) throws Exception {
return item;
}
}
}

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:batch-int="http://www.springframework.org/schema/batch-integration"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/batch-integration
http://www.springframework.org/schema/batch-integration/spring-batch-integration.xsd">
<batch-int:remote-chunking-master message-template="messagingTemplate" step="process" reply-channel="replies"/>
</beans>

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:batch-int="http://www.springframework.org/schema/batch-integration"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/batch-integration
http://www.springframework.org/schema/batch-integration/spring-batch-integration.xsd">
<batch-int:remote-chunking-master id="itemWriter" step="process" reply-channel="replies"/>
</beans>

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:batch-int="http://www.springframework.org/schema/batch-integration"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/batch-integration
http://www.springframework.org/schema/batch-integration/spring-batch-integration.xsd">
<batch-int:remote-chunking-master id="itemWriter" message-template="messagingTemplate" step="process"/>
</beans>

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:batch-int="http://www.springframework.org/schema/batch-integration"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/batch-integration
http://www.springframework.org/schema/batch-integration/spring-batch-integration.xsd">
<batch-int:remote-chunking-master id="itemWriter" message-template="messagingTemplate" reply-channel="replies"/>
</beans>

View File

@@ -0,0 +1,57 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:batch="http://www.springframework.org/schema/batch"
xmlns:batch-int="http://www.springframework.org/schema/batch-integration"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:int="http://www.springframework.org/schema/integration"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/batch
http://www.springframework.org/schema/batch/spring-batch.xsd
http://www.springframework.org/schema/batch-integration
http://www.springframework.org/schema/batch-integration/spring-batch-integration.xsd
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd">
<batch:job id="processingJob">
<batch:step id="process">
<batch:tasklet>
<batch:chunk reader="itemReader" writer="itemWriter" commit-interval="6"/>
</batch:tasklet>
</batch:step>
</batch:job>
<batch:job-repository/>
<bean id="itemReader" class="org.springframework.batch.item.support.ListItemReader">
<constructor-arg>
<list>
<value>1</value>
<value>2</value>
<value>3</value>
<value>4</value>
<value>5</value>
<value>6</value>
</list>
</constructor-arg>
</bean>
<batch-int:remote-chunking-master id="itemWriter" message-template="messagingTemplate" step="process" reply-channel="replies"/>
<bean id="messagingTemplate" class="org.springframework.integration.core.MessagingTemplate"/>
<int:channel id="replies">
<int:queue/>
</int:channel>
<bean id="placeholderProperties" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
p:location="classpath:batch-${ENVIRONMENT:hsql}.properties"/>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
p:driverClassName="${batch.jdbc.driver}" p:url="${batch.jdbc.url}"
p:username="${batch.jdbc.user}" p:password="${batch.jdbc.password}"/>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
p:dataSource-ref="dataSource"/>
</beans>

View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:batch-int="http://www.springframework.org/schema/batch-integration"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/batch-integration
http://www.springframework.org/schema/batch-integration/spring-batch-integration.xsd">
<batch-int:remote-chunking-slave input-channel="requests" output-channel="replies"
item-processor="itemProcessor" item-writer="itemWriter"/>
</beans>

View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:batch-int="http://www.springframework.org/schema/batch-integration"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/batch-integration
http://www.springframework.org/schema/batch-integration/spring-batch-integration.xsd">
<batch-int:remote-chunking-slave id="remote-chunking-slave" output-channel="replies"
item-processor="itemProcessor" item-writer="itemWriter"/>
</beans>

View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:batch-int="http://www.springframework.org/schema/batch-integration"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/batch-integration
http://www.springframework.org/schema/batch-integration/spring-batch-integration.xsd">
<batch-int:remote-chunking-slave id="remote-chunking-slave" input-channel="requests" output-channel="replies"
item-processor="itemProcessor"/>
</beans>

View File

@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:batch-int="http://www.springframework.org/schema/batch-integration"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/batch-integration
http://www.springframework.org/schema/batch-integration/spring-batch-integration.xsd">
<batch-int:remote-chunking-slave id="remote-chunking-slave" input-channel="requests"
item-processor="itemProcessor" item-writer="itemWriter"/>
</beans>

View File

@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:batch-int="http://www.springframework.org/schema/batch-integration"
xmlns:int="http://www.springframework.org/schema/integration"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/batch-integration
http://www.springframework.org/schema/batch-integration/spring-batch-integration.xsd">
<batch-int:remote-chunking-slave id="remote-chunking-slave" input-channel="requests" output-channel="replies"
item-writer="itemWriter"/>
<bean id="itemProcessor" class="org.springframework.batch.integration.config.xml.RemoteChunkingParserTests$Processor"/>
<bean id="itemWriter" class="org.springframework.batch.integration.config.xml.RemoteChunkingParserTests$Writer"/>
<int:channel id="requests"/>
<int:channel id="replies"/>
</beans>

View File

@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:batch-int="http://www.springframework.org/schema/batch-integration"
xmlns:int="http://www.springframework.org/schema/integration"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/batch-integration
http://www.springframework.org/schema/batch-integration/spring-batch-integration.xsd">
<batch-int:remote-chunking-slave id="remote-chunking-slave" input-channel="requests" output-channel="replies"
item-processor="itemProcessor" item-writer="itemWriter"/>
<bean id="itemProcessor" class="org.springframework.batch.integration.config.xml.RemoteChunkingParserTests$Processor"/>
<bean id="itemWriter" class="org.springframework.batch.integration.config.xml.RemoteChunkingParserTests$Writer"/>
<int:channel id="requests"/>
<int:channel id="replies"/>
</beans>