Improvements RoutingFunction and MessageFunction
Added error handling to RoutingFunction Added support for Function<Flux, Flux> to MessageFunction
This commit is contained in:
@@ -26,6 +26,7 @@ import reactor.core.publisher.Mono;
|
|||||||
import org.springframework.cloud.function.core.FluxConsumer;
|
import org.springframework.cloud.function.core.FluxConsumer;
|
||||||
import org.springframework.cloud.function.core.FluxFunction;
|
import org.springframework.cloud.function.core.FluxFunction;
|
||||||
import org.springframework.cloud.function.core.FluxToMonoFunction;
|
import org.springframework.cloud.function.core.FluxToMonoFunction;
|
||||||
|
import org.springframework.cloud.function.core.FluxedFunction;
|
||||||
import org.springframework.cloud.function.core.MonoToFluxFunction;
|
import org.springframework.cloud.function.core.MonoToFluxFunction;
|
||||||
import org.springframework.messaging.Message;
|
import org.springframework.messaging.Message;
|
||||||
import org.springframework.messaging.MessageHeaders;
|
import org.springframework.messaging.MessageHeaders;
|
||||||
@@ -36,7 +37,7 @@ import org.springframework.messaging.support.MessageBuilder;
|
|||||||
* @since 2.1
|
* @since 2.1
|
||||||
*/
|
*/
|
||||||
public class MessageFunction
|
public class MessageFunction
|
||||||
implements Function<Publisher<Message<?>>, Publisher<Message<?>>> {
|
implements Function<Publisher<?>, Publisher<Message<?>>> {
|
||||||
|
|
||||||
private final Function<?, ?> delegate;
|
private final Function<?, ?> delegate;
|
||||||
|
|
||||||
@@ -44,11 +45,18 @@ public class MessageFunction
|
|||||||
this.delegate = delegate;
|
this.delegate = delegate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||||
@Override
|
@Override
|
||||||
public Publisher<Message<?>> apply(Publisher<Message<?>> input) {
|
public Publisher<Message<?>> apply(Publisher<?> input) {
|
||||||
Flux<Message<?>> flux = Flux.from(input);
|
Flux<Object> incomingFlux = Flux.from(input);
|
||||||
|
Flux<Message<?>> flux = incomingFlux.map(value -> {
|
||||||
|
if (!(value instanceof Message)) {
|
||||||
|
return MessageBuilder.withPayload(value).build();
|
||||||
|
}
|
||||||
|
return (Message<?>) value;
|
||||||
|
});
|
||||||
|
|
||||||
if (this.delegate instanceof FluxFunction) {
|
if (this.delegate instanceof FluxFunction) {
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
Function<Object, Object> target = (Function<Object, Object>) ((FluxFunction<?, ?>) this.delegate)
|
Function<Object, Object> target = (Function<Object, Object>) ((FluxFunction<?, ?>) this.delegate)
|
||||||
.getTarget();
|
.getTarget();
|
||||||
return flux.map(
|
return flux.map(
|
||||||
@@ -56,7 +64,6 @@ public class MessageFunction
|
|||||||
.copyHeaders(value.getHeaders()).build());
|
.copyHeaders(value.getHeaders()).build());
|
||||||
}
|
}
|
||||||
if (this.delegate instanceof MonoToFluxFunction) {
|
if (this.delegate instanceof MonoToFluxFunction) {
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
Function<Mono<Object>, Flux<Object>> target = ((MonoToFluxFunction<Object, Object>) this.delegate)
|
Function<Mono<Object>, Flux<Object>> target = ((MonoToFluxFunction<Object, Object>) this.delegate)
|
||||||
.getTarget();
|
.getTarget();
|
||||||
return flux.next()
|
return flux.next()
|
||||||
@@ -65,7 +72,6 @@ public class MessageFunction
|
|||||||
.copyHeaders(value.getHeaders()).build()));
|
.copyHeaders(value.getHeaders()).build()));
|
||||||
}
|
}
|
||||||
if (this.delegate instanceof FluxToMonoFunction) {
|
if (this.delegate instanceof FluxToMonoFunction) {
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
Function<Flux<Object>, Mono<Object>> target = ((FluxToMonoFunction<Object, Object>) this.delegate)
|
Function<Flux<Object>, Mono<Object>> target = ((FluxToMonoFunction<Object, Object>) this.delegate)
|
||||||
.getTarget();
|
.getTarget();
|
||||||
AtomicReference<MessageHeaders> headers = new AtomicReference<>();
|
AtomicReference<MessageHeaders> headers = new AtomicReference<>();
|
||||||
@@ -76,7 +82,6 @@ public class MessageFunction
|
|||||||
.copyHeaders(headers.get()).build());
|
.copyHeaders(headers.get()).build());
|
||||||
}
|
}
|
||||||
if (this.delegate instanceof FluxConsumer) {
|
if (this.delegate instanceof FluxConsumer) {
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
FluxConsumer<Object> target = ((FluxConsumer<Object>) this.delegate);
|
FluxConsumer<Object> target = ((FluxConsumer<Object>) this.delegate);
|
||||||
AtomicReference<MessageHeaders> headers = new AtomicReference<>();
|
AtomicReference<MessageHeaders> headers = new AtomicReference<>();
|
||||||
Mono<Void> mapped = target.apply(flux.map(messsage -> {
|
Mono<Void> mapped = target.apply(flux.map(messsage -> {
|
||||||
@@ -85,11 +90,17 @@ public class MessageFunction
|
|||||||
}));
|
}));
|
||||||
return mapped.map(value -> MessageBuilder.createMessage(null, headers.get()));
|
return mapped.map(value -> MessageBuilder.createMessage(null, headers.get()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: cover the case that delegate is actually Function<Flux,Flux>
|
// TODO: cover the case that delegate is actually Function<Flux,Flux>
|
||||||
@SuppressWarnings("unchecked")
|
if (this.delegate instanceof FluxedFunction) {
|
||||||
Function<Object, Object> function = (Function<Object, Object>) this.delegate;
|
Function<Flux<Object>, Flux<Object>> target = ((FluxedFunction) this.delegate);
|
||||||
|
return (Flux) flux.map(value -> ((Message) value).getPayload()).transform(target);
|
||||||
|
}
|
||||||
|
Function function = this.delegate;
|
||||||
return flux.map(
|
return flux.map(
|
||||||
value -> MessageBuilder.withPayload(function.apply(value.getPayload()))
|
value -> {
|
||||||
.copyHeaders(value.getHeaders()).build());
|
return MessageBuilder.withPayload(function.apply(value.getPayload()))
|
||||||
|
.copyHeaders(value.getHeaders()).build();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import org.springframework.cloud.function.context.FunctionCatalog;
|
|||||||
import org.springframework.cloud.function.context.catalog.FunctionInspector;
|
import org.springframework.cloud.function.context.catalog.FunctionInspector;
|
||||||
import org.springframework.cloud.function.core.WrappedFunction;
|
import org.springframework.cloud.function.core.WrappedFunction;
|
||||||
import org.springframework.messaging.Message;
|
import org.springframework.messaging.Message;
|
||||||
|
import org.springframework.messaging.MessageHeaders;
|
||||||
import org.springframework.messaging.converter.MessageConverter;
|
import org.springframework.messaging.converter.MessageConverter;
|
||||||
import org.springframework.messaging.support.MessageBuilder;
|
import org.springframework.messaging.support.MessageBuilder;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
@@ -75,13 +76,21 @@ public class RoutingFunction implements Function<Publisher<Message<?>>, Publishe
|
|||||||
return flux.map(message -> {
|
return flux.map(message -> {
|
||||||
Object inputValue = this.convertInput(message, function);
|
Object inputValue = this.convertInput(message, function);
|
||||||
return inputValue;
|
return inputValue;
|
||||||
}).transform(function);
|
})
|
||||||
|
.log()
|
||||||
|
.doOnError(error -> {
|
||||||
|
throw new IllegalStateException("Failed to convert Message. Possible reason; "
|
||||||
|
+ "No suitable converter was found for payload with 'contentType' "
|
||||||
|
+ signal.get().getHeaders().get(MessageHeaders.CONTENT_TYPE), error);
|
||||||
|
})
|
||||||
|
.transform(function);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("rawtypes")
|
@SuppressWarnings("rawtypes")
|
||||||
private WrappedFunction getRouteToFunction(Message<?> message) {
|
private WrappedFunction getRouteToFunction(Message<?> message) {
|
||||||
String routeToFunctionName = (String) message.getHeaders().get("function.name");
|
String routeToFunctionName = (String) message.getHeaders().get("function.name");
|
||||||
|
Assert.hasText(routeToFunctionName, "A 'function.name' was not provided as message header.");
|
||||||
WrappedFunction function = functionCatalog.lookup(routeToFunctionName);
|
WrappedFunction function = functionCatalog.lookup(routeToFunctionName);
|
||||||
Assert.notNull(function, "Failed to locate function specified with 'function.name':"
|
Assert.notNull(function, "Failed to locate function specified with 'function.name':"
|
||||||
+ message.getHeaders().get("function.name"));
|
+ message.getHeaders().get("function.name"));
|
||||||
|
|||||||
Reference in New Issue
Block a user