INT-3600: FileSplitter Namespace and Docs

JIRA: https://jira.spring.io/browse/INT-3600

Add `<int-file:splitter/>` namespace component.
Add `FileSplitter` documentation.

Polishing
This commit is contained in:
Gary Russell
2015-06-12 13:58:12 -04:00
committed by Artem Bilan
parent 247232bdde
commit 6436aa6d32
9 changed files with 323 additions and 2 deletions

View File

@@ -26,6 +26,7 @@ import org.springframework.integration.config.xml.AbstractIntegrationNamespaceHa
*/
public class FileNamespaceHandler extends AbstractIntegrationNamespaceHandler {
@Override
public void init() {
registerBeanDefinitionParser("inbound-channel-adapter", new FileInboundChannelAdapterParser());
registerBeanDefinitionParser("outbound-channel-adapter", new FileOutboundChannelAdapterParser());
@@ -33,6 +34,7 @@ public class FileNamespaceHandler extends AbstractIntegrationNamespaceHandler {
registerBeanDefinitionParser("file-to-string-transformer", new FileToStringTransformerParser());
registerBeanDefinitionParser("file-to-bytes-transformer", new FileToByteArrayTransformerParser());
registerBeanDefinitionParser("tail-inbound-channel-adapter", new FileTailInboundChannelAdapterParser());
registerBeanDefinitionParser("splitter", new FileSplitterParser());
}
}

View File

@@ -0,0 +1,47 @@
/*
* Copyright 2015 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.file.config;
import org.w3c.dom.Element;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.integration.config.xml.AbstractConsumerEndpointParser;
import org.springframework.integration.config.xml.IntegrationNamespaceUtils;
import org.springframework.integration.file.splitter.FileSplitter;
/**
* @author Gary Russell
* @since 4.2
*
*/
public class FileSplitterParser extends AbstractConsumerEndpointParser {
@Override
protected BeanDefinitionBuilder parseHandler(Element element, ParserContext parserContext) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(FileSplitter.class);
builder.addConstructorArgValue(element.getAttribute("iterator"));
builder.addConstructorArgValue(element.getAttribute("markers"));
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "charset");
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "requires-reply");
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "apply-sequence");
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "send-timeout");
return builder;
}
}

View File

@@ -547,6 +547,92 @@ Only files matching this regular expression will be picked up by this adapter.
</xsd:attribute>
</xsd:complexType>
<xsd:element name="splitter">
<xsd:annotation>
<xsd:documentation>
Defines a Splitter that splits text-based files into lines.
</xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<xsd:choice minOccurs="0" maxOccurs="2">
<xsd:element name="poller" type="integration:basePollerType" minOccurs="0" maxOccurs="1" />
<xsd:element name="request-handler-advice-chain" type="integration:handlerAdviceChainType" minOccurs="0" maxOccurs="1" />
</xsd:choice>
<xsd:attributeGroup ref="integration:inputOutputChannelGroup" />
<xsd:attribute name="id" type="xsd:string">
<xsd:annotation>
<xsd:documentation><![CDATA[Identifies the underlying Spring bean definition (EventDrivenConsumer)]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="charset" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
<![CDATA[Set the charset name to use when reading bytes from the text-based file into String
payloads, e.g. charset="UTF-8". If not set, the default charset of this
Java virtual machine is used.
]]>
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="requires-reply" use="optional" default="false">
<xsd:annotation>
<xsd:documentation>
Specify whether the splitter must return at least one message. This value will be
'false' by default, but if set to 'true', a ReplyRequiredException will be thrown when
the file has no data.
</xsd:documentation>
</xsd:annotation>
<xsd:simpleType>
<xsd:union memberTypes="xsd:boolean xsd:string"/>
</xsd:simpleType>
</xsd:attribute>
<xsd:attribute name="apply-sequence" use="optional">
<xsd:annotation>
<xsd:documentation>
Set this flag to determine whether sequence related headers are added to messages
from this splitter. When true, existing correlation and sequence related headers
are pushed onto a stack; downstream components, such as aggregators may pop
the stack to revert the existing headers after aggregation. Default is 'true'
unless 'markers' is 'true'. Also see 'iterator'.
</xsd:documentation>
</xsd:annotation>
<xsd:simpleType>
<xsd:union memberTypes="xsd:boolean xsd:string"/>
</xsd:simpleType>
</xsd:attribute>
<xsd:attribute name="iterator" use="optional" default="true">
<xsd:annotation>
<xsd:documentation>
Set this flag to determine whether the lines are emitted via an iterator (line at a time)
or the whole file is read into memory and then the lines emitted. When this is 'true', if
'apply-sequence' is also 'true', the 'sequenceSize' header is set to '0'. Default: 'true'.
</xsd:documentation>
</xsd:annotation>
<xsd:simpleType>
<xsd:union memberTypes="xsd:boolean xsd:string"/>
</xsd:simpleType>
</xsd:attribute>
<xsd:attribute name="markers" use="optional" default="false">
<xsd:annotation>
<xsd:documentation>
Set to 'true' to emit start/end of file marker messages before and after the file data.
Markers are messages with 'FileSplitter.FileMarker' payloads (with 'START' and 'END' values
in the 'mark' property).
Markers might be used when sequentially processing files in a downstream flow where some lines
are filtered.
The 'END' marker includes a line count.
They enable the downstream processing to know when a file has been completely processed.
Default: 'false'.
When 'true', 'apply-sequence' is 'false' by default.
</xsd:documentation>
</xsd:annotation>
<xsd:simpleType>
<xsd:union memberTypes="xsd:boolean xsd:string"/>
</xsd:simpleType>
</xsd:attribute>
</xsd:complexType>
</xsd:element>
<xsd:element name="locker">
<xsd:annotation>
<xsd:documentation>

View File

@@ -0,0 +1,25 @@
<?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:int="http://www.springframework.org/schema/integration"
xmlns:int-file="http://www.springframework.org/schema/integration/file"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration/file http://www.springframework.org/schema/integration/file/spring-integration-file.xsd
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd">
<int:channel id="out" />
<int-file:splitter id="fullBoat"
iterator="false"
markers="true"
apply-sequence="true"
requires-reply="true"
charset="UTF-8"
input-channel="in"
output-channel="out"
send-timeout="5"
auto-startup="false"
order="2"
phase="1" />
</beans>

View File

@@ -0,0 +1,74 @@
/*
* Copyright 2015 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.file.config;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.nio.charset.Charset;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.integration.endpoint.EventDrivenConsumer;
import org.springframework.integration.file.splitter.FileSplitter;
import org.springframework.integration.test.util.TestUtils;
import org.springframework.messaging.MessageChannel;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* @author Gary Russell
* @since 4.2
*
*/
@ContextConfiguration
@RunWith(SpringJUnit4ClassRunner.class)
@DirtiesContext
public class FileSplitterParserTests {
@Autowired
private EventDrivenConsumer fullBoat;
@Autowired
private FileSplitter splitter;
@Autowired
private MessageChannel in;
@Autowired
private MessageChannel out;
@Test
public void testComplete() {
assertFalse(TestUtils.getPropertyValue(this.splitter, "iterator", Boolean.class));
assertTrue(TestUtils.getPropertyValue(this.splitter, "markers", Boolean.class));
assertTrue(TestUtils.getPropertyValue(this.splitter, "requiresReply", Boolean.class));
assertTrue(TestUtils.getPropertyValue(this.splitter, "applySequence", Boolean.class));
assertEquals(Charset.forName("UTF-8"), TestUtils.getPropertyValue(this.splitter, "charset"));
assertEquals(5L, TestUtils.getPropertyValue(this.splitter, "messagingTemplate.sendTimeout"));
assertEquals(this.out, TestUtils.getPropertyValue(this.splitter, "outputChannel"));
assertEquals(2, TestUtils.getPropertyValue(this.splitter, "order"));
assertEquals(this.in, TestUtils.getPropertyValue(this.fullBoat, "inputChannel"));
assertFalse(TestUtils.getPropertyValue(this.fullBoat, "autoStartup", Boolean.class));
assertEquals(1, TestUtils.getPropertyValue(this.fullBoat, "phase"));
}
}