From 4a1bfbc764e2e3a2775e49bfb3816cf1921cc540 Mon Sep 17 00:00:00 2001 From: Oleg Zhurakousky Date: Mon, 27 Mar 2023 18:51:48 +0200 Subject: [PATCH] GH-1014 Fix CustomRuntimeEventLoop to default to RoutingFunction Resolves #1014 --- .../adapter/aws/CustomRuntimeEventLoop.java | 13 ++++++- .../function-sample-aws-native/Dockerfile | 5 +-- .../function-sample-aws-native/README.md | 8 ++++- .../function-sample-aws-native/pom.xml | 35 +++++++++++++++++++ .../src/assembly/native.xml | 2 +- .../demo/NativeUppercaseApplication.java | 28 ++++++++++++++- .../src/shell/native/bootstrap | 2 +- .../cloudevent/DemoApplicationTests.java | 4 +-- .../function-sample-cloudevent-stream/pom.xml | 2 +- .../src/main/resources/application.properties | 3 -- .../src/main/resources/application.yaml | 15 ++++++++ 11 files changed, 102 insertions(+), 15 deletions(-) delete mode 100644 spring-cloud-function-samples/function-sample-cloudevent-stream/src/main/resources/application.properties create mode 100644 spring-cloud-function-samples/function-sample-cloudevent-stream/src/main/resources/application.yaml diff --git a/spring-cloud-function-adapters/spring-cloud-function-adapter-aws/src/main/java/org/springframework/cloud/function/adapter/aws/CustomRuntimeEventLoop.java b/spring-cloud-function-adapters/spring-cloud-function-adapter-aws/src/main/java/org/springframework/cloud/function/adapter/aws/CustomRuntimeEventLoop.java index ac9c5c01c..8c9e79df2 100644 --- a/spring-cloud-function-adapters/spring-cloud-function-adapter-aws/src/main/java/org/springframework/cloud/function/adapter/aws/CustomRuntimeEventLoop.java +++ b/spring-cloud-function-adapters/spring-cloud-function-adapter-aws/src/main/java/org/springframework/cloud/function/adapter/aws/CustomRuntimeEventLoop.java @@ -33,6 +33,7 @@ import org.apache.commons.logging.LogFactory; import org.springframework.cloud.function.context.FunctionCatalog; import org.springframework.cloud.function.context.catalog.SimpleFunctionRegistry.FunctionInvocationWrapper; +import org.springframework.cloud.function.context.config.RoutingFunction; import org.springframework.cloud.function.json.JsonMapper; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.context.SmartLifecycle; @@ -218,7 +219,8 @@ public final class CustomRuntimeEventLoop implements SmartLifecycle { return null; } - private FunctionInvocationWrapper locateFunction(Environment environment, FunctionCatalog functionCatalog, HttpHeaders httpHeaders) { + private FunctionInvocationWrapper locateFunction(Environment environment, FunctionCatalog functionCatalog, + HttpHeaders httpHeaders) { MediaType contentType = httpHeaders.getContentType(); String handlerName = environment.getProperty("DEFAULT_HANDLER"); if (logger.isDebugEnabled()) { @@ -257,6 +259,15 @@ public final class CustomRuntimeEventLoop implements SmartLifecycle { function = functionCatalog.lookup(handlerName, contentType.toString()); } + if (function == null) { + function = functionCatalog.lookup(RoutingFunction.FUNCTION_NAME, "application/json"); + if (function != null && logger.isInfoEnabled()) { + logger.info("Will default to RoutingFunction, since multiple functions available in FunctionCatalog." + + "Expecting 'spring.cloud.function.definition' or 'spring.cloud.function.routing-expression' as Message headers. " + + "If invocation is over API Gateway, Message headers can be provided as HTTP headers."); + } + } + Assert.notNull(function, "Failed to locate function. Tried locating default function, " + "function by 'DEFAULT_HANDLER', '_HANDLER' env variable as well as'spring.cloud.function.definition'. " + "Functions available in catalog are: " + functionCatalog.getNames(null)); diff --git a/spring-cloud-function-samples/function-sample-aws-native/Dockerfile b/spring-cloud-function-samples/function-sample-aws-native/Dockerfile index 0811ea44c..170191389 100644 --- a/spring-cloud-function-samples/function-sample-aws-native/Dockerfile +++ b/spring-cloud-function-samples/function-sample-aws-native/Dockerfile @@ -40,7 +40,4 @@ RUN ln -s /usr/lib/gradle/bin/gradle /usr/bin/gradle ENV JAVA_HOME /usr/lib/graalvm -ENTRYPOINT ["sh"] -COPY . /home -WORKDIR /home -ENTRYPOINT ["sh"] \ No newline at end of file +WORKDIR /function-sample-aws-native diff --git a/spring-cloud-function-samples/function-sample-aws-native/README.md b/spring-cloud-function-samples/function-sample-aws-native/README.md index 3dc4936be..5a4e5a0a6 100644 --- a/spring-cloud-function-samples/function-sample-aws-native/README.md +++ b/spring-cloud-function-samples/function-sample-aws-native/README.md @@ -1,3 +1,9 @@ +# Introduction + +This example shows GraaalVM native spring-cloud-function application. The application itself is very simple and contains two functions - `uppercase` & `lowercase`. +Unless specific value is specified as `handler`, the application will fall back on `RoutingFunction` where you can pass the routing instruction +via `spring.cloud.function.definition` Message header. If using API Gateway you can pass such header as HTTP header. + # To run ## If you are on OSX Apple M1 Pro (arch64) @@ -11,7 +17,7 @@ $ docker build -t "al2-graalvm19:native-uppercase" . Start the container ``` -$ docker run -dit al2-graalvm19:native-uppercase +$ docker run -dit -v `pwd`:`pwd` -w `pwd` -v ~/.m2:/root/.m2 al2-graalvm19:native-uppercase ``` Now navigate to the image terminal. Your working directory is alredy set for the root of the project. You can verify it by executing `ls`. diff --git a/spring-cloud-function-samples/function-sample-aws-native/pom.xml b/spring-cloud-function-samples/function-sample-aws-native/pom.xml index c27efef72..ca73d588c 100644 --- a/spring-cloud-function-samples/function-sample-aws-native/pom.xml +++ b/spring-cloud-function-samples/function-sample-aws-native/pom.xml @@ -148,5 +148,40 @@ + + + + spring-snapshots + Spring Snapshots + https://repo.spring.io/snapshot + + + spring-milestones + Spring Milestones + https://repo.spring.io/milestone + + + spring-releases + Spring Releases + https://repo.spring.io/release + + + + + spring-snapshots + Spring Snapshots + https://repo.spring.io/snapshot + + + spring-milestones + Spring Milestones + https://repo.spring.io/milestone + + + spring-releases + Spring Releases + https://repo.spring.io/release + + diff --git a/spring-cloud-function-samples/function-sample-aws-native/src/assembly/native.xml b/spring-cloud-function-samples/function-sample-aws-native/src/assembly/native.xml index 389aeae88..805947c52 100644 --- a/spring-cloud-function-samples/function-sample-aws-native/src/assembly/native.xml +++ b/spring-cloud-function-samples/function-sample-aws-native/src/assembly/native.xml @@ -22,7 +22,7 @@ true 0775 - native-uppercase + function-sample-aws-native diff --git a/spring-cloud-function-samples/function-sample-aws-native/src/main/java/com/example/demo/NativeUppercaseApplication.java b/spring-cloud-function-samples/function-sample-aws-native/src/main/java/com/example/demo/NativeUppercaseApplication.java index 75a254ab5..cb3f3adcb 100644 --- a/spring-cloud-function-samples/function-sample-aws-native/src/main/java/com/example/demo/NativeUppercaseApplication.java +++ b/spring-cloud-function-samples/function-sample-aws-native/src/main/java/com/example/demo/NativeUppercaseApplication.java @@ -2,17 +2,35 @@ package com.example.demo; import java.util.function.Function; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.function.context.DefaultMessageRoutingHandler; +import org.springframework.cloud.function.context.MessageRoutingCallback; import org.springframework.context.annotation.Bean; +import org.springframework.messaging.Message; @SpringBootApplication public class NativeUppercaseApplication { + Log logger = LogFactory.getLog(NativeUppercaseApplication.class); + public static void main(String[] args) { SpringApplication.run(NativeUppercaseApplication.class, args); } - + + @Bean + public MessageRoutingCallback customRouter() { + return new MessageRoutingCallback() { + @Override + public String routingResult(Message message) { + logger.info("Received message: " + message); + return (String) message.getHeaders().get("spring.cloud.function.definition"); + } + }; + } + @Bean public Function uppercase() { return v -> { @@ -21,4 +39,12 @@ public class NativeUppercaseApplication { }; } + @Bean + public Function lowercase() { + return v -> { + System.out.println("Lowercasing " + v); + return v.toUpperCase(); + }; + } + } diff --git a/spring-cloud-function-samples/function-sample-aws-native/src/shell/native/bootstrap b/spring-cloud-function-samples/function-sample-aws-native/src/shell/native/bootstrap index 59564fbba..356bae8ce 100644 --- a/spring-cloud-function-samples/function-sample-aws-native/src/shell/native/bootstrap +++ b/spring-cloud-function-samples/function-sample-aws-native/src/shell/native/bootstrap @@ -2,4 +2,4 @@ cd ${LAMBDA_TASK_ROOT:-.} -./native-uppercase -Dlogging.level.org.springframework=DEBUG \ No newline at end of file +./function-sample-aws-native -Dlogging.level.org.springframework=DEBUG diff --git a/spring-cloud-function-samples/function-sample-cloudevent-rsocket/src/test/java/io/spring/cloudevent/DemoApplicationTests.java b/spring-cloud-function-samples/function-sample-cloudevent-rsocket/src/test/java/io/spring/cloudevent/DemoApplicationTests.java index 1cc2a39b1..87e232a57 100644 --- a/spring-cloud-function-samples/function-sample-cloudevent-rsocket/src/test/java/io/spring/cloudevent/DemoApplicationTests.java +++ b/spring-cloud-function-samples/function-sample-cloudevent-rsocket/src/test/java/io/spring/cloudevent/DemoApplicationTests.java @@ -21,7 +21,7 @@ import org.springframework.messaging.rsocket.RSocketRequester; import org.springframework.util.MimeTypeUtils; -@SpringBootTest(properties = {"spring.rsocket.server.port=55555"}) +@SpringBootTest(properties = {"spring.rsocket.server.port=55551"}) @ExtendWith(DemoApplicationTests.TestRule.class) public class DemoApplicationTests { @@ -44,7 +44,7 @@ public class DemoApplicationTests { " }\n" + "}"; - this.rsocketRequesterBuilder.tcp("localhost", 55555) + this.rsocketRequesterBuilder.tcp("localhost", 55551) .route("hire") .metadata("{\"content-type\":\"application/cloudevents+json\"}", MimeTypeUtils.APPLICATION_JSON) .data(payload) diff --git a/spring-cloud-function-samples/function-sample-cloudevent-stream/pom.xml b/spring-cloud-function-samples/function-sample-cloudevent-stream/pom.xml index 623513379..914ccde22 100644 --- a/spring-cloud-function-samples/function-sample-cloudevent-stream/pom.xml +++ b/spring-cloud-function-samples/function-sample-cloudevent-stream/pom.xml @@ -28,7 +28,7 @@ org.springframework.cloud spring-cloud-stream - 4.0.0-SNAPSHOT + 4.0.2-SNAPSHOT diff --git a/spring-cloud-function-samples/function-sample-cloudevent-stream/src/main/resources/application.properties b/spring-cloud-function-samples/function-sample-cloudevent-stream/src/main/resources/application.properties deleted file mode 100644 index fbcf55609..000000000 --- a/spring-cloud-function-samples/function-sample-cloudevent-stream/src/main/resources/application.properties +++ /dev/null @@ -1,3 +0,0 @@ -spring.cloud.function.definition=hire -spring.cloud.stream.bindings.hire-in-0.binder=rabbit -spring.cloud.stream.bindings.hire-out-0.binder=kafka diff --git a/spring-cloud-function-samples/function-sample-cloudevent-stream/src/main/resources/application.yaml b/spring-cloud-function-samples/function-sample-cloudevent-stream/src/main/resources/application.yaml new file mode 100644 index 000000000..7dbd85990 --- /dev/null +++ b/spring-cloud-function-samples/function-sample-cloudevent-stream/src/main/resources/application.yaml @@ -0,0 +1,15 @@ +spring: + cloud: + stream: + bindings: + hire-in-0: + binder: rabbit1 + hire-out-0: + binder: kafka1 + binders: + rabbit1: + type: rabbit + kafka1: + type: kafka + function: + definition: hire \ No newline at end of file