Streamline and refactor the azure and the azure-web adapters.
- Add SCF/Azure Gradle sample and docs. - Move the function-azure-di-samples into standalone projects. - Apply the name convetion and project structure for the SCF adaptes. E.g. function-sample-azure-XXX projects under the spring-cloud-function-samples root. - Remove the redudant samples. - Improve the samples docs and the Adapter generic docs. - Streamline docs. - Add azure web adapter sample and README. - Add Spring Azure Functions banner for azure and azure web adapters. - azure-web adapter fixes: - Fix issues in serverles-web ProxyHttpServletResponse implementation. - Remove the custom FunctionClassUtils utils in favor of scf-context/util/FunctionClassUtils. - Remove redundant files. - Add FunctionInvoker deprecation annotations. - Extend the time trigger sample with Retry policies example.
This commit is contained in:
@@ -0,0 +1,11 @@
|
||||
=== Introduction
|
||||
|
||||
Light weight Azure Function forwarding proxy which can deploy any existing Spring Boot web application as Azure Functions.
|
||||
Infernally uses the Azure Http Trigger mapping.
|
||||
|
||||
This module is identified as the only additional dependency to the existing web-app.
|
||||
|
||||
A sample is provided in https://github.com/spring-cloud/spring-cloud-function/tree/main/spring-cloud-function-samples/function-sample-azure-web[azure-web sample]
|
||||
|
||||
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
#### Introduction
|
||||
|
||||
This module represents a concept of a light weight AWS forwarding proxy which deploys and interacts with existing
|
||||
Spring Boot web application deployed as AWS Lambda.
|
||||
|
||||
A sample is provided in [sample](https://github.com/spring-cloud/spring-cloud-function/tree/serverless-web/spring-cloud-function-adapters/spring-cloud-function-adapter-aws-web/sample/pet-store) directory. It contain README and SAM template file to simplify the deployment. This module is identified as the only additional dependnecy to the existing web-app.
|
||||
|
||||
_NOTE: Although this module is AWS specific, this dependency is protocol only (not binary), therefore there is no AWS dependnecies._
|
||||
|
||||
The aformentioned proxy is identified as AWS Lambda [handler](https://github.com/spring-cloud/spring-cloud-function/blob/serverless-web/spring-cloud-function-adapters/spring-cloud-function-adapter-aws-web/sample/pet-store/template.yml#L14)
|
||||
|
||||
The main Spring Boot configuration file is identified as [MAIN_CLASS](https://github.com/spring-cloud/spring-cloud-function/blob/serverless-web/spring-cloud-function-adapters/spring-cloud-function-adapter-aws-web/sample/pet-store/template.yml#L22)
|
||||
@@ -24,10 +24,18 @@
|
||||
<artifactId>annotations</artifactId>
|
||||
<version>3.0.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-function-context</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-function-serverless-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-autoconfigure</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.microsoft.azure.functions</groupId>
|
||||
<artifactId>azure-functions-java-library</artifactId>
|
||||
|
||||
@@ -38,6 +38,7 @@ import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.cloud.function.serverless.web.ProxyHttpServletRequest;
|
||||
import org.springframework.cloud.function.serverless.web.ProxyHttpServletResponse;
|
||||
import org.springframework.cloud.function.serverless.web.ProxyMvc;
|
||||
import org.springframework.cloud.function.utils.FunctionClassUtils;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@@ -61,7 +62,6 @@ public class AzureWebProxyInvoker implements FunctionInstanceInjector {
|
||||
|
||||
@Override
|
||||
public <T> T getInstance(Class<T> functionClass) throws Exception {
|
||||
// System.setProperty("MAIN_CLASS", "oz.spring.petstore.PetStoreSpringAppConfig");
|
||||
this.initialize();
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
@@ -1,153 +0,0 @@
|
||||
/*
|
||||
* Copyright 2019-2021 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cloud.function.adapter.azure.web;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.jar.JarFile;
|
||||
import java.util.jar.Manifest;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
//import org.springframework.boot.SpringBootConfiguration;
|
||||
//import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.core.KotlinDetector;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* General utility class which aggregates various class-level utility functions
|
||||
* used by the framework.
|
||||
*
|
||||
* @author Oleg Zhurakousky
|
||||
* @since 3.0.1
|
||||
*/
|
||||
public final class FunctionClassUtils {
|
||||
|
||||
private static Log logger = LogFactory.getLog(FunctionClassUtils.class);
|
||||
|
||||
private FunctionClassUtils() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Discovers the start class in the currently running application.
|
||||
* The discover search order is 'MAIN_CLASS' environment property,
|
||||
* 'MAIN_CLASS' system property, META-INF/MANIFEST.MF:'Start-Class' attribute,
|
||||
* meta-inf/manifest.mf:'Start-Class' attribute.
|
||||
*
|
||||
* @return instance of Class which represent the start class of the application.
|
||||
*/
|
||||
public static Class<?> getStartClass() {
|
||||
ClassLoader classLoader = FunctionClassUtils.class.getClassLoader();
|
||||
return getStartClass(classLoader);
|
||||
}
|
||||
|
||||
static Class<?> getStartClass(ClassLoader classLoader) {
|
||||
Class<?> mainClass = null;
|
||||
if (System.getenv("MAIN_CLASS") != null) {
|
||||
mainClass = ClassUtils.resolveClassName(System.getenv("MAIN_CLASS"), classLoader);
|
||||
}
|
||||
else if (System.getProperty("MAIN_CLASS") != null) {
|
||||
mainClass = ClassUtils.resolveClassName(System.getProperty("MAIN_CLASS"), classLoader);
|
||||
}
|
||||
else {
|
||||
try {
|
||||
Class<?> result = getStartClass(
|
||||
Collections.list(classLoader.getResources(JarFile.MANIFEST_NAME)), classLoader);
|
||||
if (result == null) {
|
||||
result = getStartClass(Collections
|
||||
.list(classLoader.getResources("meta-inf/manifest.mf")), classLoader);
|
||||
}
|
||||
Assert.notNull(result, "Failed to locate main class");
|
||||
mainClass = result;
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new IllegalStateException("Failed to discover main class. An attempt was made to discover "
|
||||
+ "main class as 'MAIN_CLASS' environment variable, system property as well as "
|
||||
+ "entry in META-INF/MANIFEST.MF (in that order).", ex);
|
||||
}
|
||||
}
|
||||
logger.info("Main class: " + mainClass);
|
||||
return mainClass;
|
||||
}
|
||||
|
||||
private static Class<?> getStartClass(List<URL> list, ClassLoader classLoader) {
|
||||
if (logger.isTraceEnabled()) {
|
||||
logger.trace("Searching manifests: " + list);
|
||||
}
|
||||
for (URL url : list) {
|
||||
try {
|
||||
InputStream inputStream = null;
|
||||
Manifest manifest = new Manifest(url.openStream());
|
||||
logger.info("Searching for start class in manifest: " + url);
|
||||
if (logger.isDebugEnabled()) {
|
||||
manifest.write(System.out);
|
||||
}
|
||||
try {
|
||||
String startClassName = manifest.getMainAttributes().getValue("Start-Class");
|
||||
if (!StringUtils.hasText(startClassName)) {
|
||||
startClassName = manifest.getMainAttributes().getValue("Main-Class");
|
||||
}
|
||||
|
||||
if (StringUtils.hasText(startClassName)) {
|
||||
Class<?> startClass = ClassUtils.forName(startClassName, classLoader);
|
||||
|
||||
if (KotlinDetector.isKotlinType(startClass)) {
|
||||
PathMatchingResourcePatternResolver r = new PathMatchingResourcePatternResolver(classLoader);
|
||||
String packageName = startClass.getPackage().getName();
|
||||
Resource[] resources = r.getResources("classpath:" + packageName.replace(".", "/") + "/*.class");
|
||||
for (int i = 0; i < resources.length; i++) {
|
||||
Resource resource = resources[i];
|
||||
String className = packageName + "." + (resource.getFilename().replace("/", ".")).replace(".class", "");
|
||||
startClass = ClassUtils.forName(className, classLoader);
|
||||
// if (isSpringBootApplication(startClass)) {
|
||||
// logger.info("Loaded Main Kotlin Class: " + startClass);
|
||||
// return startClass;
|
||||
// }
|
||||
}
|
||||
}
|
||||
// else if (isSpringBootApplication(startClass)) {
|
||||
// logger.info("Loaded Start Class: " + startClass);
|
||||
// return startClass;
|
||||
// }
|
||||
}
|
||||
}
|
||||
finally {
|
||||
if (inputStream != null) {
|
||||
inputStream.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex) {
|
||||
logger.debug("Failed to determine Start-Class in manifest file of " + url, ex);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// private static boolean isSpringBootApplication(Class<?> startClass) {
|
||||
// return startClass.getDeclaredAnnotation(SpringBootApplication.class) != null
|
||||
// || startClass.getDeclaredAnnotation(SpringBootConfiguration.class) != null;
|
||||
// }
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
spring.banner.location=classpath:/spring-azure-function-banner.txt
|
||||
@@ -0,0 +1,8 @@
|
||||
____ _ _ _____ _ _
|
||||
/ ___| _ __ _ __(_)_ __ __ _ / \ _____ _ _ __ ___ | ___| _ _ __ ___| |_(_) ___ _ __ ___
|
||||
\___ \| '_ \| '__| | '_ \ / _` | / _ \ |_ / | | | '__/ _ \ | |_ | | | | '_ \ / __| __| |/ _ \| '_ \/ __|
|
||||
___) | |_) | | | | | | | (_| | / ___ \ / /| |_| | | | __/ | _|| |_| | | | | (__| |_| | (_) | | | \__ \
|
||||
|____/| .__/|_| |_|_| |_|\__, | /_/ \_\/___|\__,_|_| \___| |_| \__,_|_| |_|\___|\__|_|\___/|_| |_|___/
|
||||
|_| |___/
|
||||
${application.title} ${application.version}
|
||||
Powered by Spring Boot ${spring-boot.version} and Azure Functions
|
||||
@@ -7,6 +7,11 @@ Edit the files in the src/main/asciidoc/ directory instead.
|
||||
This project provides an adapter layer for a Spring Cloud Function application onto Azure.
|
||||
You can write an app with a single `@Bean` of type `Function` and it will be deployable in Azure if you get the JAR file laid out right.
|
||||
|
||||
== Sample Function
|
||||
== Sample Functions
|
||||
|
||||
Go to the link:../../spring-cloud-function-samples/function-sample-azure/[function-sample-azure] to learn about how the sample works, and how to run and test it.
|
||||
- ../../spring-cloud-function-samples/function-sample-azure-http-trigger[Azure HTTP Trigger (Maven)]
|
||||
- ../../spring-cloud-function-samples/function-sample-azure-http-trigger-gradle[Azure HTTP Trigger (Gradle)]
|
||||
- ../../spring-cloud-function-samples/function-sample-azure-blob-trigger[Azure Blob Trigger (Maven)]
|
||||
- ../../spring-cloud-function-samples/function-sample-azure-timer-trigger[Azure Timer Trigger (Maven)]
|
||||
- ../../spring-cloud-function-samples/function-sample-azure-kafka-trigger[Azure Kafka Trigger & Output Binding (Maven)]
|
||||
- ../../spring-cloud-function-samples/function-sample-azure/[(Legacy - FunctionInvoker) Azure HTTP Trigger (Maven)]
|
||||
|
||||
@@ -22,10 +22,12 @@ import com.microsoft.azure.functions.spi.inject.FunctionInstanceInjector;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.boot.ResourceBanner;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.WebApplicationType;
|
||||
import org.springframework.cloud.function.utils.FunctionClassUtils;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.core.io.DefaultResourceLoader;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
@@ -96,6 +98,8 @@ public class AzureFunctionInstanceInjector implements FunctionInstanceInjector {
|
||||
SpringApplication application = new org.springframework.cloud.function.context.FunctionalSpringApplication(
|
||||
configurationClass);
|
||||
application.setWebApplicationType(WebApplicationType.NONE);
|
||||
application.setBanner(new ResourceBanner(
|
||||
new DefaultResourceLoader().getResource("classpath:/spring-azure-function-banner.txt")));
|
||||
return application;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,8 +65,14 @@ import org.springframework.util.StringUtils;
|
||||
* @param <O> result type
|
||||
* @author Oleg Zhurakousky
|
||||
* @author Chris Bono
|
||||
* @author Christian Tzolov
|
||||
*
|
||||
* @since 3.2
|
||||
*
|
||||
* @deprecated since 4.0.0 in favor of the dependency injection implementation {@link AzureFunctionInstanceInjector}.
|
||||
* Follow the official documentation for further information.
|
||||
*/
|
||||
@Deprecated
|
||||
public class FunctionInvoker<I, O> {
|
||||
|
||||
private static Log logger = LogFactory.getLog(FunctionInvoker.class);
|
||||
@@ -109,11 +115,13 @@ public class FunctionInvoker<I, O> {
|
||||
|
||||
private FunctionInvocationWrapper discoverFunction(String functionDefinition) {
|
||||
FunctionInvocationWrapper function = FUNCTION_CATALOG.lookup(functionDefinition);
|
||||
if (function != null && StringUtils.hasText(functionDefinition) && !function.getFunctionDefinition().equals(functionDefinition)) {
|
||||
if (function != null && StringUtils.hasText(functionDefinition)
|
||||
&& !function.getFunctionDefinition().equals(functionDefinition)) {
|
||||
this.registerFunction(functionDefinition);
|
||||
function = FUNCTION_CATALOG.lookup(functionDefinition);
|
||||
}
|
||||
else if (function == null && StringUtils.hasText(functionDefinition) && APPLICATION_CONTEXT.containsBean(functionDefinition)) {
|
||||
else if (function == null && StringUtils.hasText(functionDefinition)
|
||||
&& APPLICATION_CONTEXT.containsBean(functionDefinition)) {
|
||||
this.registerFunction(functionDefinition);
|
||||
function = FUNCTION_CATALOG.lookup(functionDefinition);
|
||||
}
|
||||
@@ -128,20 +136,22 @@ public class FunctionInvoker<I, O> {
|
||||
Object functionResult = function.apply(enhancedInput);
|
||||
|
||||
if (functionResult instanceof Publisher) {
|
||||
return postProcessReactiveFunctionResult(input, enhancedInput, (Publisher<?>) functionResult, function, executionContext);
|
||||
return postProcessReactiveFunctionResult(input, enhancedInput, (Publisher<?>) functionResult, function,
|
||||
executionContext);
|
||||
}
|
||||
return postProcessImperativeFunctionResult(input, enhancedInput, functionResult, function, executionContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* Post-processes the result from a non-reactive function invocation before returning it to the Azure
|
||||
* runtime. The default behavior is to {@link #convertOutputIfNecessary possibly convert} the result.
|
||||
* Post-processes the result from a non-reactive function invocation before returning it to the Azure runtime. The
|
||||
* default behavior is to {@link #convertOutputIfNecessary possibly convert} the result.
|
||||
*
|
||||
* <p>Provides a hook for custom function invokers to extend/modify the function results handling.
|
||||
* <p>
|
||||
* Provides a hook for custom function invokers to extend/modify the function results handling.
|
||||
*
|
||||
* @param rawInputs the inputs passed in from the Azure runtime
|
||||
* @param functionInputs the actual inputs used for the function invocation; may be
|
||||
* {@link #enhanceInputIfNecessary different} from the {@literal rawInputs}
|
||||
* @param functionInputs the actual inputs used for the function invocation; may be {@link #enhanceInputIfNecessary
|
||||
* different} from the {@literal rawInputs}
|
||||
* @param functionResult the result from the function invocation
|
||||
* @param function the invoked function
|
||||
* @param executionContext the Azure execution context
|
||||
@@ -149,44 +159,47 @@ public class FunctionInvoker<I, O> {
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
protected O postProcessImperativeFunctionResult(I rawInputs, Object functionInputs, Object functionResult,
|
||||
FunctionInvocationWrapper function, ExecutionContext executionContext
|
||||
) {
|
||||
FunctionInvocationWrapper function, ExecutionContext executionContext) {
|
||||
return (O) this.convertOutputIfNecessary(rawInputs, functionResult);
|
||||
}
|
||||
|
||||
/**
|
||||
* Post-processes the result from a reactive function invocation before returning it to the Azure
|
||||
* runtime. The default behavior is to delegate to {@link #postProcessMonoFunctionResult} or
|
||||
* Post-processes the result from a reactive function invocation before returning it to the Azure runtime. The
|
||||
* default behavior is to delegate to {@link #postProcessMonoFunctionResult} or
|
||||
* {@link #postProcessFluxFunctionResult} based on the result type.
|
||||
*
|
||||
* <p>Provides a hook for custom function invokers to extend/modify the function results handling.
|
||||
* <p>
|
||||
* Provides a hook for custom function invokers to extend/modify the function results handling.
|
||||
*
|
||||
* @param rawInputs the inputs passed in from the Azure runtime
|
||||
* @param functionInputs the actual inputs used for the function invocation; may be
|
||||
* {@link #enhanceInputIfNecessary different} from the {@literal rawInputs}
|
||||
* @param functionInputs the actual inputs used for the function invocation; may be {@link #enhanceInputIfNecessary
|
||||
* different} from the {@literal rawInputs}
|
||||
* @param functionResult the result from the function invocation
|
||||
* @param function the invoked function
|
||||
* @param executionContext the Azure execution context
|
||||
* @return the possibly modified function results
|
||||
*/
|
||||
protected O postProcessReactiveFunctionResult(I rawInputs, Object functionInputs, Publisher<?> functionResult,
|
||||
FunctionInvocationWrapper function, ExecutionContext executionContext
|
||||
) {
|
||||
FunctionInvocationWrapper function, ExecutionContext executionContext) {
|
||||
if (FunctionTypeUtils.isMono(function.getOutputType())) {
|
||||
return postProcessMonoFunctionResult(rawInputs, functionInputs, Mono.from(functionResult), function, executionContext);
|
||||
return postProcessMonoFunctionResult(rawInputs, functionInputs, Mono.from(functionResult), function,
|
||||
executionContext);
|
||||
}
|
||||
return postProcessFluxFunctionResult(rawInputs, functionInputs, Flux.from(functionResult), function, executionContext);
|
||||
return postProcessFluxFunctionResult(rawInputs, functionInputs, Flux.from(functionResult), function,
|
||||
executionContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* Post-processes the {@code Mono} result from a reactive function invocation before returning it to the Azure
|
||||
* runtime. The default behavior is to {@link Mono#blockOptional()} and {@link #convertOutputIfNecessary possibly convert} the result.
|
||||
* runtime. The default behavior is to {@link Mono#blockOptional()} and {@link #convertOutputIfNecessary possibly
|
||||
* convert} the result.
|
||||
*
|
||||
* <p>Provides a hook for custom function invokers to extend/modify the function results handling.
|
||||
* <p>
|
||||
* Provides a hook for custom function invokers to extend/modify the function results handling.
|
||||
*
|
||||
* @param rawInputs the inputs passed in from the Azure runtime
|
||||
* @param functionInputs the actual inputs used for the function invocation; may be
|
||||
* {@link #enhanceInputIfNecessary different} from the {@literal rawInputs}
|
||||
* @param functionInputs the actual inputs used for the function invocation; may be {@link #enhanceInputIfNecessary
|
||||
* different} from the {@literal rawInputs}
|
||||
* @param functionResult the Mono result from the function invocation
|
||||
* @param function the invoked function
|
||||
* @param executionContext the Azure execution context
|
||||
@@ -194,20 +207,21 @@ public class FunctionInvoker<I, O> {
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
protected O postProcessMonoFunctionResult(I rawInputs, Object functionInputs, Mono<?> functionResult,
|
||||
FunctionInvocationWrapper function, ExecutionContext executionContext
|
||||
) {
|
||||
FunctionInvocationWrapper function, ExecutionContext executionContext) {
|
||||
return (O) this.convertOutputIfNecessary(rawInputs, functionResult.blockOptional().get());
|
||||
}
|
||||
|
||||
/**
|
||||
* Post-processes the {@code Flux} result from a reactive function invocation before returning it to the Azure
|
||||
* runtime. The default behavior is to {@link Flux#toIterable() block} and {@link #convertOutputIfNecessary possibly convert} the results.
|
||||
* runtime. The default behavior is to {@link Flux#toIterable() block} and {@link #convertOutputIfNecessary possibly
|
||||
* convert} the results.
|
||||
*
|
||||
* <p>Provides a hook for custom function invokers to extend/modify the function results handling.
|
||||
* <p>
|
||||
* Provides a hook for custom function invokers to extend/modify the function results handling.
|
||||
*
|
||||
* @param rawInputs the inputs passed in from the Azure runtime
|
||||
* @param functionInputs the actual inputs used for the function invocation; may be
|
||||
* {@link #enhanceInputIfNecessary different} from the {@literal rawInputs}
|
||||
* @param functionInputs the actual inputs used for the function invocation; may be {@link #enhanceInputIfNecessary
|
||||
* different} from the {@literal rawInputs}
|
||||
* @param functionResult the Mono result from the function invocation
|
||||
* @param function the invoked function
|
||||
* @param executionContext the Azure execution context
|
||||
@@ -215,16 +229,16 @@ public class FunctionInvoker<I, O> {
|
||||
*/
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
protected O postProcessFluxFunctionResult(I rawInputs, Object functionInputs, Flux<?> functionResult,
|
||||
FunctionInvocationWrapper function, ExecutionContext executionContext
|
||||
) {
|
||||
FunctionInvocationWrapper function, ExecutionContext executionContext) {
|
||||
List resultList = new ArrayList<>();
|
||||
for (Object resultItem : functionResult.toIterable()) {
|
||||
if (resultItem instanceof Collection) {
|
||||
resultList.addAll((Collection) resultItem);
|
||||
}
|
||||
else {
|
||||
if (!function.isSupplier() && Collection.class.isAssignableFrom(FunctionTypeUtils.getRawType(function.getInputType()))
|
||||
&& !Collection.class.isAssignableFrom(FunctionTypeUtils.getRawType(function.getOutputType()))) {
|
||||
if (!function.isSupplier()
|
||||
&& Collection.class.isAssignableFrom(FunctionTypeUtils.getRawType(function.getInputType()))
|
||||
&& !Collection.class.isAssignableFrom(FunctionTypeUtils.getRawType(function.getOutputType()))) {
|
||||
return (O) this.convertOutputIfNecessary(rawInputs, resultItem);
|
||||
}
|
||||
else {
|
||||
@@ -238,11 +252,10 @@ public class FunctionInvoker<I, O> {
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
private void registerFunction(String functionDefinition) {
|
||||
if (APPLICATION_CONTEXT.containsBean(functionDefinition)) {
|
||||
FunctionRegistration functionRegistration =
|
||||
new FunctionRegistration(APPLICATION_CONTEXT.getBean(functionDefinition), functionDefinition);
|
||||
FunctionRegistration functionRegistration = new FunctionRegistration(
|
||||
APPLICATION_CONTEXT.getBean(functionDefinition), functionDefinition);
|
||||
|
||||
Type type = FunctionContextUtils.
|
||||
findType(functionDefinition, APPLICATION_CONTEXT.getBeanFactory());
|
||||
Type type = FunctionContextUtils.findType(functionDefinition, APPLICATION_CONTEXT.getBeanFactory());
|
||||
|
||||
functionRegistration = functionRegistration.type(type);
|
||||
|
||||
@@ -305,8 +318,9 @@ public class FunctionInvoker<I, O> {
|
||||
MessageBuilder<?> messageBuilder = null;
|
||||
if (input instanceof HttpRequestMessage) {
|
||||
HttpRequestMessage<I> requestMessage = (HttpRequestMessage<I>) input;
|
||||
Object payload = requestMessage.getHttpMethod() != null && requestMessage.getHttpMethod().equals(HttpMethod.GET)
|
||||
? requestMessage.getQueryParameters()
|
||||
Object payload = requestMessage.getHttpMethod() != null
|
||||
&& requestMessage.getHttpMethod().equals(HttpMethod.GET)
|
||||
? requestMessage.getQueryParameters()
|
||||
: requestMessage.getBody();
|
||||
|
||||
if (payload == null) {
|
||||
@@ -352,8 +366,10 @@ public class FunctionInvoker<I, O> {
|
||||
if (CollectionUtils.isEmpty(mf)) {
|
||||
OBJECT_MAPPER = new JacksonMapper(new ObjectMapper());
|
||||
JsonMessageConverter jsonConverter = new JsonMessageConverter(OBJECT_MAPPER);
|
||||
SmartCompositeMessageConverter messageConverter = new SmartCompositeMessageConverter(Collections.singletonList(jsonConverter));
|
||||
FUNCTION_CATALOG = new SimpleFunctionRegistry(APPLICATION_CONTEXT.getBeanFactory().getConversionService(),
|
||||
SmartCompositeMessageConverter messageConverter = new SmartCompositeMessageConverter(
|
||||
Collections.singletonList(jsonConverter));
|
||||
FUNCTION_CATALOG = new SimpleFunctionRegistry(
|
||||
APPLICATION_CONTEXT.getBeanFactory().getConversionService(),
|
||||
messageConverter, OBJECT_MAPPER);
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -29,7 +29,11 @@ import com.microsoft.azure.functions.HttpResponseMessage;
|
||||
* @author Oleg Zhurakousky
|
||||
*
|
||||
* @since 3.2
|
||||
*
|
||||
* @deprecated since 4.0.0 in favor of the dependency injection implementation {@link AzureFunctionInstanceInjector}.
|
||||
* Follow the official documentation for further information.
|
||||
*/
|
||||
@Deprecated
|
||||
public class HttpFunctionInvoker<I> extends
|
||||
FunctionInvoker<HttpRequestMessage<I>, HttpResponseMessage> {
|
||||
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
____ _ _ _____ _ _
|
||||
/ ___| _ __ _ __(_)_ __ __ _ / \ _____ _ _ __ ___ | ___| _ _ __ ___| |_(_) ___ _ __ ___
|
||||
\___ \| '_ \| '__| | '_ \ / _` | / _ \ |_ / | | | '__/ _ \ | |_ | | | | '_ \ / __| __| |/ _ \| '_ \/ __|
|
||||
___) | |_) | | | | | | | (_| | / ___ \ / /| |_| | | | __/ | _|| |_| | | | | (__| |_| | (_) | | | \__ \
|
||||
|____/| .__/|_| |_|_| |_|\__, | /_/ \_\/___|\__,_|_| \___| |_| \__,_|_| |_|\___|\__|_|\___/|_| |_|___/
|
||||
|_| |___/
|
||||
${application.title} ${application.version}
|
||||
Powered by Spring Boot ${spring-boot.version} and Azure Functions
|
||||
@@ -136,7 +136,7 @@ public class ProxyHttpServletResponse implements HttpServletResponse {
|
||||
|
||||
@Override
|
||||
public void setContentLengthLong(long len) {
|
||||
throw new UnsupportedOperationException();
|
||||
// Ignore
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user