Simplified support for implicit functions in composition
added test for namless Supplier | Function
This commit is contained in:
@@ -16,17 +16,18 @@
|
|||||||
|
|
||||||
package org.springframework.cloud.function.context.catalog;
|
package org.springframework.cloud.function.context.catalog;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import reactor.core.publisher.Flux;
|
import reactor.core.publisher.Flux;
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
@@ -167,8 +168,7 @@ public abstract class AbstractComposableFunctionRegistry implements FunctionRegi
|
|||||||
* @return the name of the function or null.
|
* @return the name of the function or null.
|
||||||
*/
|
*/
|
||||||
public String lookupFunctionName(Object function) {
|
public String lookupFunctionName(Object function) {
|
||||||
return function != null && this.names.containsKey(function)
|
return this.names.containsKey(function) ? this.names.get(function) : null;
|
||||||
? this.names.get(function) : null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -310,11 +310,15 @@ public abstract class AbstractComposableFunctionRegistry implements FunctionRegi
|
|||||||
composedFunction = lookup.values().iterator().next();
|
composedFunction = lookup.values().iterator().next();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
||||||
String[] stages = StringUtils.delimitedListToStringArray(name, "|");
|
String[] stages = StringUtils.delimitedListToStringArray(name, "|");
|
||||||
List<FunctionRegistration<?>> composableFunctions = find(stages);
|
if (Stream.of(stages).allMatch(funcName -> contains(funcName))) {
|
||||||
if (!composableFunctions.isEmpty()) {
|
|
||||||
|
|
||||||
|
AtomicBoolean supplierPresent = new AtomicBoolean();
|
||||||
|
List<FunctionRegistration<?>> composableFunctions = Stream.of(stages)
|
||||||
|
.map(funcName -> find(funcName, supplierPresent.get()))
|
||||||
|
.filter(x -> x != null)
|
||||||
|
.peek(f -> supplierPresent.set(f.getTarget() instanceof Supplier))
|
||||||
|
.collect(Collectors.toList());
|
||||||
FunctionRegistration<?> composedRegistration = composableFunctions
|
FunctionRegistration<?> composedRegistration = composableFunctions
|
||||||
.stream().reduce((a, z) -> composeFunctions(a, z))
|
.stream().reduce((a, z) -> composeFunctions(a, z))
|
||||||
.orElseGet(() -> null);
|
.orElseGet(() -> null);
|
||||||
@@ -348,60 +352,15 @@ public abstract class AbstractComposableFunctionRegistry implements FunctionRegi
|
|||||||
return name.replaceAll(",", "|").trim();
|
return name.replaceAll(",", "|").trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<FunctionRegistration<?>> find(String[] stages) {
|
private boolean contains(String name) {
|
||||||
if (stages.length == 0) {
|
if (!StringUtils.hasText(name)) {
|
||||||
return Collections.emptyList();
|
return true;
|
||||||
}
|
}
|
||||||
if (stages.length == 1) {
|
return getSupplierNames().contains(name) || getFunctionNames().contains(name)
|
||||||
FunctionRegistration<?> found = find(stages[0]);
|
|| getConsumerNames().contains(name);
|
||||||
return found == null ? Collections.emptyList() : Arrays.asList(found);
|
|
||||||
}
|
|
||||||
List<FunctionRegistration<?>> list = new ArrayList<>();
|
|
||||||
for (int i = 0; i < stages.length; i++) {
|
|
||||||
String name = stages[i];
|
|
||||||
FunctionRegistration<?> registration = find(name);
|
|
||||||
if (registration != null) {
|
|
||||||
list.add(registration);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (i == 0) {
|
|
||||||
// Supplier or Function
|
|
||||||
if (this.suppliers.size() == 1) {
|
|
||||||
name = this.suppliers.keySet().iterator().next();
|
|
||||||
}
|
|
||||||
else if (this.functions.size() == 1) {
|
|
||||||
name = this.functions.keySet().iterator().next();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (i == stages.length - 1) {
|
|
||||||
// Consumer or Function
|
|
||||||
if (this.consumers.size() == 1) {
|
|
||||||
name = this.consumers.keySet().iterator().next();
|
|
||||||
}
|
|
||||||
else if (this.functions.size() == 1) {
|
|
||||||
name = this.functions.keySet().iterator().next();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// Function
|
|
||||||
if (this.functions.size() == 1) {
|
|
||||||
name = this.functions.keySet().iterator().next();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
registration = find(name);
|
|
||||||
if (registration != null) {
|
|
||||||
list.add(registration);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// Can't find default stage so we can't compose anything
|
|
||||||
return Collections.emptyList();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return list;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private FunctionRegistration<?> find(String name) {
|
private FunctionRegistration<?> find(String name, boolean supplierFound) {
|
||||||
Object result = this.suppliers.get(name);
|
Object result = this.suppliers.get(name);
|
||||||
if (result == null) {
|
if (result == null) {
|
||||||
result = this.functions.get(name);
|
result = this.functions.get(name);
|
||||||
@@ -409,6 +368,15 @@ public abstract class AbstractComposableFunctionRegistry implements FunctionRegi
|
|||||||
if (result == null) {
|
if (result == null) {
|
||||||
result = this.consumers.get(name);
|
result = this.consumers.get(name);
|
||||||
}
|
}
|
||||||
|
if (result == null && !StringUtils.hasText(name)) {
|
||||||
|
if (supplierFound && this.functions.size() == 1) {
|
||||||
|
result = this.functions.values().iterator().next();
|
||||||
|
}
|
||||||
|
else if (!supplierFound && this.suppliers.size() == 1) {
|
||||||
|
result = this.suppliers.values().iterator().next();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return getRegistration(result);
|
return getRegistration(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -103,6 +103,24 @@ public class InMemoryFunctionCatalogTests {
|
|||||||
assertThat(lookedUpFunction.get().blockFirst()).isEqualTo("olleh");
|
assertThat(lookedUpFunction.get().blockFirst()).isEqualTo("olleh");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFunctionCompletelyImplicitComposition() {
|
||||||
|
FunctionRegistration<Words> wordsRegistration = new FunctionRegistration<>(
|
||||||
|
new Words(), "words").type(FunctionType.of(Words.class));
|
||||||
|
FunctionRegistration<Reverse> reverseRegistration = new FunctionRegistration<>(
|
||||||
|
new Reverse(), "reverse").type(FunctionType.of(Reverse.class));
|
||||||
|
InMemoryFunctionCatalog catalog = new InMemoryFunctionCatalog();
|
||||||
|
catalog.register(wordsRegistration);
|
||||||
|
catalog.register(reverseRegistration);
|
||||||
|
|
||||||
|
// There's only one function, we should be able to leave that blank
|
||||||
|
Supplier<Flux<String>> lookedUpFunction = catalog.lookup("|");
|
||||||
|
assertThat(catalog.getFunctionType("|").isMessage()).isFalse();
|
||||||
|
|
||||||
|
assertThat(lookedUpFunction).isNotNull();
|
||||||
|
assertThat(lookedUpFunction.get().blockFirst()).isEqualTo("olleh");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testFunctionCompositionExplicit() {
|
public void testFunctionCompositionExplicit() {
|
||||||
FunctionRegistration<Words> wordsRegistration = new FunctionRegistration<>(
|
FunctionRegistration<Words> wordsRegistration = new FunctionRegistration<>(
|
||||||
|
|||||||
Reference in New Issue
Block a user