GH-460 Add support for function filtering
Added support for function filtering in the event there are more then one function in catalog. This is primarily to ensure that we have a mechanism to specify which functions to export as web enpoints (instead of all) Resolves #460
This commit is contained in:
@@ -24,6 +24,7 @@ import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
@@ -51,6 +52,7 @@ import org.springframework.aop.support.AopUtils;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.cloud.function.context.FunctionCatalog;
|
||||
@@ -94,7 +96,7 @@ import org.springframework.util.StringUtils;
|
||||
* @since 3.0
|
||||
*/
|
||||
public class BeanFactoryAwareFunctionRegistry
|
||||
implements FunctionRegistry, FunctionInspector, ApplicationContextAware {
|
||||
implements FunctionRegistry, FunctionInspector, ApplicationContextAware, InitializingBean {
|
||||
|
||||
private static Log logger = LogFactory.getLog(BeanFactoryAwareFunctionRegistry.class);
|
||||
|
||||
@@ -118,10 +120,22 @@ public class BeanFactoryAwareFunctionRegistry
|
||||
|
||||
private final CompositeMessageConverter messageConverter;
|
||||
|
||||
private List<String> declaredFunctionDefinitions;
|
||||
|
||||
public BeanFactoryAwareFunctionRegistry(ConversionService conversionService,
|
||||
@Nullable CompositeMessageConverter messageConverter) {
|
||||
this.conversionService = conversionService;
|
||||
this.messageConverter = messageConverter;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
String userDefinition = this.applicationContext.getEnvironment().getProperty("spring.cloud.function.definition");
|
||||
this.declaredFunctionDefinitions = StringUtils.hasText(userDefinition) ? Arrays.asList(userDefinition.split(";")) : Collections.emptyList();
|
||||
if (this.declaredFunctionDefinitions.contains(RoutingFunction.FUNCTION_NAME)) {
|
||||
Assert.isTrue(this.declaredFunctionDefinitions.size() == 1, "It is illegal to declare more then one function when using RoutingFunction");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -139,9 +153,36 @@ public class BeanFactoryAwareFunctionRegistry
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T lookup(String definition, String... acceptedOutputTypes) {
|
||||
if (!StringUtils.hasText(definition)) {
|
||||
definition = this.applicationContext.getEnvironment().getProperty("spring.cloud.function.definition");
|
||||
definition = StringUtils.hasText(definition) ? definition.replaceAll(",", "|") : "";
|
||||
|
||||
boolean routing = definition.contains(RoutingFunction.FUNCTION_NAME)
|
||||
|| this.declaredFunctionDefinitions.contains(RoutingFunction.FUNCTION_NAME);
|
||||
|
||||
if (!routing && this.declaredFunctionDefinitions.size() > 0) {
|
||||
if (StringUtils.hasText(definition)) {
|
||||
if (this.declaredFunctionDefinitions.size() > 1 &&!this.declaredFunctionDefinitions.contains(definition)) {
|
||||
logger.warn("Attempted to access un-declared function definition '" + definition + "'. Declared functions are '" + this.declaredFunctionDefinitions
|
||||
+ "' specified via `spring.cloud.function.definition` property. If the intention is to access "
|
||||
+ "any function available in FunctionCatalog, please remove `spring.cloud.function.definition` property.");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (this.declaredFunctionDefinitions.size() == 1) {
|
||||
definition = this.declaredFunctionDefinitions.get(0);
|
||||
}
|
||||
else if (this.declaredFunctionDefinitions.size() > 1) {
|
||||
logger.warn("Default function can not be mapped since multiple functions are declared " + this.declaredFunctionDefinitions);
|
||||
return null;
|
||||
}
|
||||
else {
|
||||
logger.warn("Default function can not be mapped since multiple functions are available in FunctionCatalog. "
|
||||
+ "Please use 'spring.cloud.function.definition' property.");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Object function = this
|
||||
.proxyInvokerIfNecessary((FunctionInvocationWrapper) this.compose(null, definition, acceptedOutputTypes));
|
||||
return (T) function;
|
||||
|
||||
@@ -28,6 +28,7 @@ import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import reactor.core.publisher.Flux;
|
||||
@@ -77,6 +78,11 @@ public class BeanFactoryAwareFunctionRegistryTests {
|
||||
return catalog;
|
||||
}
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
System.clearProperty("spring.cloud.function.definition");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaultLookup() throws Exception {
|
||||
FunctionCatalog catalog = this.configureCatalog();
|
||||
@@ -84,6 +90,7 @@ public class BeanFactoryAwareFunctionRegistryTests {
|
||||
assertThat(function).isNull();
|
||||
//==
|
||||
System.setProperty("spring.cloud.function.definition", "uppercase");
|
||||
catalog = this.configureCatalog();
|
||||
function = catalog.lookup("");
|
||||
assertThat(function).isNotNull();
|
||||
Field field = ReflectionUtils.findField(FunctionInvocationWrapper.class, "composed");
|
||||
@@ -91,6 +98,7 @@ public class BeanFactoryAwareFunctionRegistryTests {
|
||||
assertThat(((boolean) field.get(function))).isFalse();
|
||||
//==
|
||||
System.setProperty("spring.cloud.function.definition", "uppercase|uppercaseFlux");
|
||||
catalog = this.configureCatalog();
|
||||
function = catalog.lookup("", "application/json");
|
||||
Function<Flux<String>, Flux<Message<String>>> typedFunction = (Function<Flux<String>, Flux<Message<String>>>) function;
|
||||
Object blockFirst = typedFunction.apply(Flux.just("hello")).blockFirst();
|
||||
@@ -354,7 +362,7 @@ public class BeanFactoryAwareFunctionRegistryTests {
|
||||
FunctionCatalog catalog = this.configureCatalog(CollectionOutConfiguration.class);
|
||||
FunctionInvocationWrapper function = catalog.lookup("parseToList", "application/json");
|
||||
assertThat(function).isNotNull();
|
||||
Object result = (Message) function.apply(MessageBuilder.withPayload("1, 2, 3".getBytes()).setHeader(MessageHeaders.CONTENT_TYPE, "text/plain").build());
|
||||
Object result = function.apply(MessageBuilder.withPayload("1, 2, 3".getBytes()).setHeader(MessageHeaders.CONTENT_TYPE, "text/plain").build());
|
||||
assertThat(result instanceof Message).isTrue();
|
||||
|
||||
function = catalog.lookup("parseToListOfMessages", "application/json");
|
||||
|
||||
Reference in New Issue
Block a user