Prefix function names with spring-
* Add `spring-` prefix to function names Fixes: #9 This commit renames each sub-module in the common, consumer, function and supplier groups with a prefix of `spring-`. * Update README.adoc links to new prefixed names
This commit is contained in:
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
* Copyright 2011-2020 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
|
||||
*
|
||||
* https://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.cloud.fn.splitter;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.reactivestreams.Publisher;
|
||||
import reactor.core.publisher.Flux;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.AnyNestedCondition;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
import org.springframework.integration.channel.ReactiveStreamsSubscribableChannel;
|
||||
import org.springframework.integration.file.splitter.FileSplitter;
|
||||
import org.springframework.integration.splitter.AbstractMessageSplitter;
|
||||
import org.springframework.integration.splitter.DefaultMessageSplitter;
|
||||
import org.springframework.integration.splitter.ExpressionEvaluatingSplitter;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.MessageChannel;
|
||||
|
||||
@Configuration
|
||||
@EnableConfigurationProperties(SplitterFunctionProperties.class)
|
||||
public class SplitterFunctionConfiguration {
|
||||
|
||||
@Bean
|
||||
public Function<Message<?>, List<Message<?>>> splitterFunction(AbstractMessageSplitter messageSplitter,
|
||||
SplitterFunctionProperties splitterFunctionProperties) {
|
||||
|
||||
messageSplitter.setApplySequence(splitterFunctionProperties.isApplySequence());
|
||||
ThreadLocalFluxSinkMessageChannel outputChannel = new ThreadLocalFluxSinkMessageChannel();
|
||||
messageSplitter.setOutputChannel(outputChannel);
|
||||
return message -> {
|
||||
messageSplitter.handleMessage(message);
|
||||
return outputChannel.publisherThreadLocal.get();
|
||||
};
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnProperty(prefix = "splitter", name = "expression")
|
||||
public AbstractMessageSplitter expressionSplitter(SplitterFunctionProperties splitterFunctionProperties) {
|
||||
return new ExpressionEvaluatingSplitter(
|
||||
new SpelExpressionParser()
|
||||
.parseExpression(splitterFunctionProperties.getExpression()));
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
@Conditional(FileSplitterCondition.class)
|
||||
public AbstractMessageSplitter fileSplitter(SplitterFunctionProperties splitterFunctionProperties) {
|
||||
Boolean markers = splitterFunctionProperties.getFileMarkers();
|
||||
String charset = splitterFunctionProperties.getCharset();
|
||||
if (markers == null) {
|
||||
markers = false;
|
||||
}
|
||||
FileSplitter fileSplitter = new FileSplitter(true, markers, splitterFunctionProperties.getMarkersJson());
|
||||
if (charset != null) {
|
||||
fileSplitter.setCharset(Charset.forName(charset));
|
||||
}
|
||||
return fileSplitter;
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public AbstractMessageSplitter defaultSplitter(SplitterFunctionProperties splitterFunctionProperties) {
|
||||
DefaultMessageSplitter defaultMessageSplitter = new DefaultMessageSplitter();
|
||||
defaultMessageSplitter.setDelimiters(splitterFunctionProperties.getDelimiters());
|
||||
return defaultMessageSplitter;
|
||||
}
|
||||
|
||||
static class FileSplitterCondition extends AnyNestedCondition {
|
||||
|
||||
FileSplitterCondition() {
|
||||
super(ConfigurationPhase.REGISTER_BEAN);
|
||||
}
|
||||
|
||||
@ConditionalOnProperty(prefix = "splitter", name = "charset")
|
||||
static class Charset {
|
||||
}
|
||||
|
||||
@ConditionalOnProperty(prefix = "splitter", name = "fileMarkers")
|
||||
static class FileMarkers {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static final class ThreadLocalFluxSinkMessageChannel
|
||||
implements MessageChannel, ReactiveStreamsSubscribableChannel {
|
||||
|
||||
private final ThreadLocal<List<Message<?>>> publisherThreadLocal = new ThreadLocal<>();
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public void subscribeTo(Publisher<? extends Message<?>> publisher) {
|
||||
this.publisherThreadLocal.set(Flux.from(publisher).collectList().cast(List.class).block());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean send(Message<?> message, long l) {
|
||||
throw new UnsupportedOperationException("This channel only supports a reactive 'subscribeTo()' ");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright 2019-2020 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
|
||||
*
|
||||
* https://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.cloud.fn.splitter;
|
||||
|
||||
import jakarta.validation.constraints.AssertTrue;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
/**
|
||||
* Configuration properties for the Splitter Processor app.
|
||||
*
|
||||
* @author Gary Russell
|
||||
* @author Artem Bilan
|
||||
*/
|
||||
@ConfigurationProperties("splitter")
|
||||
@Validated
|
||||
public class SplitterFunctionProperties {
|
||||
|
||||
/**
|
||||
* A SpEL expression for splitting payloads.
|
||||
*/
|
||||
private String expression;
|
||||
|
||||
/**
|
||||
* When expression is null, delimiters to use when tokenizing
|
||||
* {@link String} payloads.
|
||||
*/
|
||||
private String delimiters;
|
||||
|
||||
/**
|
||||
* Set to true or false to use a {@code FileSplitter} (to split
|
||||
* text-based files by line) that includes
|
||||
* (or not) beginning/end of file markers.
|
||||
*/
|
||||
private Boolean fileMarkers;
|
||||
|
||||
/**
|
||||
* When 'fileMarkers == true', specify if they should be produced
|
||||
* as FileSplitter.FileMarker objects or JSON.
|
||||
*/
|
||||
private boolean markersJson = true;
|
||||
|
||||
/**
|
||||
* The charset to use when converting bytes in text-based files
|
||||
* to String.
|
||||
*/
|
||||
private String charset;
|
||||
|
||||
/**
|
||||
* Add correlation/sequence information in headers to facilitate later
|
||||
* aggregation.
|
||||
*/
|
||||
private boolean applySequence = true;
|
||||
|
||||
public String getExpression() {
|
||||
return this.expression;
|
||||
}
|
||||
|
||||
public void setExpression(String expression) {
|
||||
this.expression = expression;
|
||||
}
|
||||
|
||||
public String getDelimiters() {
|
||||
return this.delimiters;
|
||||
}
|
||||
|
||||
public void setDelimiters(String delimiters) {
|
||||
this.delimiters = delimiters;
|
||||
}
|
||||
|
||||
public Boolean getFileMarkers() {
|
||||
return this.fileMarkers;
|
||||
}
|
||||
|
||||
public void setFileMarkers(Boolean fileMarkers) {
|
||||
this.fileMarkers = fileMarkers;
|
||||
}
|
||||
|
||||
public boolean getMarkersJson() {
|
||||
return this.markersJson;
|
||||
}
|
||||
|
||||
public void setMarkersJson(boolean markersJson) {
|
||||
this.markersJson = markersJson;
|
||||
}
|
||||
|
||||
public String getCharset() {
|
||||
return this.charset;
|
||||
}
|
||||
|
||||
public void setCharset(String charset) {
|
||||
this.charset = charset;
|
||||
}
|
||||
|
||||
public boolean isApplySequence() {
|
||||
return this.applySequence;
|
||||
}
|
||||
|
||||
public void setApplySequence(boolean applySequence) {
|
||||
this.applySequence = applySequence;
|
||||
}
|
||||
|
||||
@AssertTrue(message = "'delimiters' is not allowed when an 'expression' is provided")
|
||||
public boolean isDelimitersAllowed() {
|
||||
return this.expression == null || this.delimiters == null;
|
||||
}
|
||||
|
||||
@AssertTrue(message = "File properties are not allowed when an 'expression' or 'delimiters' property is provided")
|
||||
public boolean isFilePropsAllowed() {
|
||||
return !(this.expression != null || this.delimiters != null) || this.fileMarkers == null && this.charset == null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2011-2020 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
|
||||
*
|
||||
* https://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.cloud.fn.splitter;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.support.GenericMessage;
|
||||
import org.springframework.test.annotation.DirtiesContext;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@SpringBootTest(properties = "splitter.expression=payload.split(',')")
|
||||
@DirtiesContext
|
||||
public class SplitterFunctionApplicationTests {
|
||||
|
||||
@Autowired
|
||||
Function<Message<?>, List<Message<?>>> splitter;
|
||||
|
||||
@Test
|
||||
public void testExpressionSplitter() {
|
||||
List<Message<?>> messageList = this.splitter.apply(new GenericMessage<>("hello,world"));
|
||||
assertThat(messageList).extracting(m -> m.getPayload().toString()).contains("hello", "world");
|
||||
}
|
||||
|
||||
@SpringBootApplication
|
||||
static class SplitterFunctionTestApplication {
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user