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>