diff --git a/spring-cloud-function-adapters/spring-cloud-function-adapter-aws/src/main/java/org/springframework/cloud/function/adapter/aws/SpringBootRequestHandler.java b/spring-cloud-function-adapters/spring-cloud-function-adapter-aws/src/main/java/org/springframework/cloud/function/adapter/aws/SpringBootRequestHandler.java index 4f6cf2d98..46516d373 100644 --- a/spring-cloud-function-adapters/spring-cloud-function-adapter-aws/src/main/java/org/springframework/cloud/function/adapter/aws/SpringBootRequestHandler.java +++ b/spring-cloud-function-adapters/spring-cloud-function-adapter-aws/src/main/java/org/springframework/cloud/function/adapter/aws/SpringBootRequestHandler.java @@ -48,7 +48,7 @@ public class SpringBootRequestHandler extends SpringFunctionInitializer } private Object result(Object input, Flux output) { - List result = new ArrayList<>(); + List result = new ArrayList<>(); for (Object value : output.toIterable()) { result.add(convertOutput(value)); } diff --git a/spring-cloud-function-adapters/spring-cloud-function-adapter-azure/README.adoc b/spring-cloud-function-adapters/spring-cloud-function-adapter-azure/README.adoc index 108e81ba0..1b6e582c4 100644 --- a/spring-cloud-function-adapters/spring-cloud-function-adapter-azure/README.adoc +++ b/spring-cloud-function-adapters/spring-cloud-function-adapter-azure/README.adoc @@ -14,6 +14,30 @@ You don't need the Spring Cloud Function Web at runtime in Azure, so you need to A function application on Azure has to be shaded, but a Spring Boot standalone application does not, so you can run the same app using 2 separate jars (as per the sample here). The sample app creates the shaded jar file, with an `azure` classifier for deploying in Azure. +=== JSON Configuration + +The Azure tooling needs to find some JSON configuration files to tell it how to deploy and intergrate the function (e.g. which Java class to use as the entry point, and which triggers to use). Those files can be created with the Maven plugin for a non-Spring function, but the tooling doesn't work yet with the adapter in its current form. There is an example `function.json` in the sample which hooks the function up as an HTTP endpoint: + +``` +{ + "scriptFile" : "../function-sample-azure-1.0.0.BUILD-SNAPSHOT-azure.jar", + "entryPoint" : "example.FooHandler.handleRequest", + "bindings" : [ { + "type" : "httpTrigger", + "name" : "req", + "direction" : "in", + "authLevel" : "anonymous", + "methods" : [ "get", "post" ] + }, { + "type" : "http", + "name" : "$return", + "direction" : "out" + } ], + "disabled" : false +} +``` + + == Build ---- @@ -22,50 +46,25 @@ The sample app creates the shaded jar file, with an `azure` classifier for deplo == Running the sample -Before running the sample, we need to install a custom azure maven plugin. -Checkout this fork: https://github.com/sobychacko/azure-maven-plugins/tree/for-spring-boot-apps ----- -cd azure-functions-maven-plugin -mvn clean install -Dcheckstyle.skip=true -DskipTests -Dfindbugs.skip=true ----- +You can run the sample locally, just like the other Spring Cloud Function samples: -Build the sample under `spring-cloud-function-samples/function-sample-azure`. +--- +./mvnw spring-boot:run +--- + +and `curl -H "Content-Type: text/plain" localhost:8080/function -d '{"value": "hello foobar"}'`. + +You will need the `az` CLI app and some node.js fu (see https://docs.microsoft.com/en-us/azure/azure-functions/functions-create-first-java-maven for more detail). To deploy the function on Azure runtime: ---- -mvn clean package ----- - -Running Azure function locally. - ----- -mvn azure-functions:run - -On another terminal try this: curl localhost:7071/api/uppercase -d '{"value": "hello foobar"}' ----- - -Deploying the function that ran locally on Azure runtime. - ----- -az login - -mvn azure-functions:deploy +$ az login +$ mvn azure-functions:deploy On another terminal try this: curl https:///api/uppercase -d '{"value": "hello foobar!"}' Please ensure that you use the right URL for the function above. ---- -Running the function as a standalone Spring Boot app - -Go to the samples project and uncomment `spring-cloud-function-web` dependency and `spring-boot-maven-plugin`. - ----- -mvn clean package -java -jar target/ - -On another terminal: curl -H "Content-Type: text/plain" localhost:8080/function -d '{"value": "hello foobar"}' ----- - The input type for the function in the Azure sample is a Foo with a single property called "value". So you would need this to test it with something as below. ---- diff --git a/spring-cloud-function-adapters/spring-cloud-function-adapter-azure/src/main/java/org/springframework/cloud/function/adapter/azure/AzureSpringBootRequestHandler.java b/spring-cloud-function-adapters/spring-cloud-function-adapter-azure/src/main/java/org/springframework/cloud/function/adapter/azure/AzureSpringBootRequestHandler.java index 5bec73e53..47d70938d 100644 --- a/spring-cloud-function-adapters/spring-cloud-function-adapter-azure/src/main/java/org/springframework/cloud/function/adapter/azure/AzureSpringBootRequestHandler.java +++ b/spring-cloud-function-adapters/spring-cloud-function-adapter-azure/src/main/java/org/springframework/cloud/function/adapter/azure/AzureSpringBootRequestHandler.java @@ -21,12 +21,13 @@ import java.util.Collection; import java.util.List; import com.microsoft.azure.serverless.functions.ExecutionContext; + import reactor.core.publisher.Flux; /** * @author Soby Chacko */ -public class AzureSpringBootRequestHandler extends AzureSpringFunctionInitializer { +public class AzureSpringBootRequestHandler extends AzureSpringFunctionInitializer { public Object handleRequest(I foo, ExecutionContext context) { context.getLogger().info("Handler Java HTTP trigger processed a request."); @@ -51,9 +52,9 @@ public class AzureSpringBootRequestHandler extends AzureSpringFunctionIniti private Object result(Object input, Flux output) { List result = new ArrayList<>(); for (Object value : output.toIterable()) { - result.add(value); + result.add(convertOutput(value)); } - if (isSingleValue(input) && result.size()==1) { + if (isSingleValue(input) && result.size() == 1) { return result.get(0); } return result; @@ -63,5 +64,8 @@ public class AzureSpringBootRequestHandler extends AzureSpringFunctionIniti return !(input instanceof Collection); } - + @SuppressWarnings("unchecked") + protected O convertOutput(Object output) { + return (O) output; + } } diff --git a/spring-cloud-function-samples/function-sample-azure/.gitignore b/spring-cloud-function-samples/function-sample-azure/.gitignore new file mode 100644 index 000000000..9e4ebfc83 --- /dev/null +++ b/spring-cloud-function-samples/function-sample-azure/.gitignore @@ -0,0 +1,6 @@ +lib/ +node/ +package-lock.json +node_modules/ +etc/ + diff --git a/spring-cloud-function-samples/function-sample-azure/npm b/spring-cloud-function-samples/function-sample-azure/npm new file mode 100755 index 000000000..e5e7ed560 --- /dev/null +++ b/spring-cloud-function-samples/function-sample-azure/npm @@ -0,0 +1,4 @@ +#!/bin/sh +cd $(dirname $0) +PATH="$PWD/node/":$PATH +node "node/node_modules/npm/bin/npm-cli.js" "$@" diff --git a/spring-cloud-function-samples/function-sample-azure/pom.xml b/spring-cloud-function-samples/function-sample-azure/pom.xml index c3a99b80c..904b6c9f5 100644 --- a/spring-cloud-function-samples/function-sample-azure/pom.xml +++ b/spring-cloud-function-samples/function-sample-azure/pom.xml @@ -1,153 +1,162 @@ - - 4.0.0 + + 4.0.0 - io.spring.sample - function-sample-azure - 1.0.0.BUILD-SNAPSHOT - jar + io.spring.sample + function-sample-azure + 1.0.0.BUILD-SNAPSHOT + jar - Azure Java Functions + Azure Java Functions - - org.springframework.boot - spring-boot-starter-parent - 1.5.8.RELEASE - - + + org.springframework.boot + spring-boot-starter-parent + 1.5.8.RELEASE + + - - UTF-8 - 1.8 - 1.8 - function-sample-azure-11262017190909 - westus - example.FooConfig - + + UTF-8 + 1.8 + 1.8 + function-sample-azure + westus + example.FooConfig + - - - com.microsoft.azure - azure-functions-java-core - [1.0.0-beta-1,1.0.0) - - - - - - - - org.springframework.cloud - spring-cloud-function-adapter-azure - 1.0.0.BUILD-SNAPSHOT - - - io.projectreactor - reactor-core - 3.0.7.RELEASE - + + + com.microsoft.azure + azure-functions-java-core + 1.0.0-beta-2 + + + org.springframework.cloud + spring-cloud-function-web + 1.0.0.BUILD-SNAPSHOT + provided + + + org.springframework.cloud + spring-cloud-function-adapter-azure + 1.0.0.BUILD-SNAPSHOT + + + io.projectreactor + reactor-core + 3.1.2.RELEASE + - - - junit - junit - 4.12 - test - - - org.mockito - mockito-core - 2.4.0 - test - - + + + junit + junit + test + + + org.mockito + mockito-core + test + + - - - - - maven-resources-plugin - 3.0.2 - - - com.microsoft.azure - azure-functions-maven-plugin - 0.1.7-SNAPSHOT - - - + + + + + maven-resources-plugin + 3.0.2 + + + com.microsoft.azure + azure-functions-maven-plugin + 0.1.6 + + + - - - com.microsoft.azure - azure-functions-maven-plugin - - java-functions-group - ${functionAppName} - ${functionAppRegion} - - - FUNCTIONS_EXTENSION_VERSION - beta - - - - - - package-functions - - package - - - - - - maven-resources-plugin - - - copy-resources - package - - copy-resources - - - true - ${project.build.directory}/azure-functions/${functionAppName} - - - - ${project.basedir} - - host.json - local.settings.json - - - - - - - - - - - + + + com.github.eirslett + frontend-maven-plugin + 1.6 + + v8.8.1 + + + + install-npm + + install-node-and-npm + + + + npm-install + + npm + + + + + + com.microsoft.azure + azure-functions-maven-plugin + + java-functions-group + ${functionAppName} + ${functionAppRegion} + + + FUNCTIONS_EXTENSION_VERSION + beta + + + + + + maven-resources-plugin + + + copy-resources + package + + copy-resources + + + true + ${project.build.directory}/azure-functions/${functionAppName} + + + + ${project.basedir}/src/main/azure + + uppercase/** + host.json + local.settings.json + + + + + + + - - org.apache.maven.plugins - maven-shade-plugin - - false - true - azure - ${project.build.directory}/azure-functions/${functionAppName} - - + + org.apache.maven.plugins + maven-shade-plugin + + false + true + azure + ${project.build.directory}/azure-functions/${functionAppName} + + - + - + diff --git a/spring-cloud-function-samples/function-sample-azure/host.json b/spring-cloud-function-samples/function-sample-azure/src/main/azure/host.json similarity index 100% rename from spring-cloud-function-samples/function-sample-azure/host.json rename to spring-cloud-function-samples/function-sample-azure/src/main/azure/host.json diff --git a/spring-cloud-function-samples/function-sample-azure/local.settings.json b/spring-cloud-function-samples/function-sample-azure/src/main/azure/local.settings.json similarity index 100% rename from spring-cloud-function-samples/function-sample-azure/local.settings.json rename to spring-cloud-function-samples/function-sample-azure/src/main/azure/local.settings.json diff --git a/spring-cloud-function-samples/function-sample-azure/src/main/azure/uppercase/function.json b/spring-cloud-function-samples/function-sample-azure/src/main/azure/uppercase/function.json new file mode 100644 index 000000000..bf9a8ab0c --- /dev/null +++ b/spring-cloud-function-samples/function-sample-azure/src/main/azure/uppercase/function.json @@ -0,0 +1,16 @@ +{ + "scriptFile" : "../function-sample-azure-1.0.0.BUILD-SNAPSHOT-azure.jar", + "entryPoint" : "example.FooHandler.handleRequest", + "bindings" : [ { + "type" : "httpTrigger", + "name" : "foo", + "direction" : "in", + "authLevel" : "anonymous", + "methods" : [ "get", "post" ] + }, { + "type" : "http", + "name" : "$return", + "direction" : "out" + } ], + "disabled" : false +} \ No newline at end of file diff --git a/spring-cloud-function-samples/function-sample-azure/src/main/java/example/FooHandler.java b/spring-cloud-function-samples/function-sample-azure/src/main/java/example/FooHandler.java index cbdfceabb..0c9bfc06c 100644 --- a/spring-cloud-function-samples/function-sample-azure/src/main/java/example/FooHandler.java +++ b/spring-cloud-function-samples/function-sample-azure/src/main/java/example/FooHandler.java @@ -17,18 +17,22 @@ package example; import com.microsoft.azure.serverless.functions.ExecutionContext; +import com.microsoft.azure.serverless.functions.annotation.HttpOutput; +import com.microsoft.azure.serverless.functions.annotation.HttpTrigger; import org.springframework.cloud.function.adapter.azure.AzureSpringBootRequestHandler; /** * @author Soby Chacko */ -public class FooHandler extends AzureSpringBootRequestHandler { +public class FooHandler extends AzureSpringBootRequestHandler { - @SuppressWarnings("unchecked") - public Bar handleRequest(Foo foo, ExecutionContext context) { + @Override + public @HttpOutput(name = "bar") Bar handleRequest( + @HttpTrigger(name = "foo", methods = { "get", "post" }) Foo foo, + ExecutionContext context) { context.getLogger().info("Invoking entry point method"); - return (Bar)super.handleRequest(foo,context); + return (Bar) super.handleRequest(foo, context); } }