From ba8dd58db6ebdb9e4f1807e304e7414b09089ab0 Mon Sep 17 00:00:00 2001 From: Oleg Zhurakousky Date: Tue, 6 Apr 2021 14:02:04 +0200 Subject: [PATCH] GH-678 Fix race condition leading to NPE in Azure FunctionInvoker Resolves #678 --- .../adapter/azure/FunctionInvoker.java | 45 ++++++++++--------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/spring-cloud-function-adapters/spring-cloud-function-adapter-azure/src/main/java/org/springframework/cloud/function/adapter/azure/FunctionInvoker.java b/spring-cloud-function-adapters/spring-cloud-function-adapter-azure/src/main/java/org/springframework/cloud/function/adapter/azure/FunctionInvoker.java index 4e3f816cf..ff3988182 100644 --- a/spring-cloud-function-adapters/spring-cloud-function-adapter-azure/src/main/java/org/springframework/cloud/function/adapter/azure/FunctionInvoker.java +++ b/spring-cloud-function-adapters/spring-cloud-function-adapter-azure/src/main/java/org/springframework/cloud/function/adapter/azure/FunctionInvoker.java @@ -25,7 +25,6 @@ import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Optional; -import java.util.concurrent.atomic.AtomicBoolean; import com.fasterxml.jackson.databind.ObjectMapper; import com.microsoft.azure.functions.ExecutionContext; @@ -77,18 +76,16 @@ public class FunctionInvoker { private static ConfigurableApplicationContext APPLICATION_CONTEXT; - private static AtomicBoolean initialized = new AtomicBoolean(); + private final static Object LOCK = new Object(); private static JsonMapper OBJECT_MAPPER; public FunctionInvoker(Class configurationClass) { try { - if (initialized.compareAndSet(false, true)) { - initialize(configurationClass); - } + initialize(configurationClass); } catch (Exception e) { - initialized.set(false); + this.close(); throw new IllegalStateException("Failed to initialize", e); } } @@ -102,7 +99,7 @@ public class FunctionInvoker { } public void close() { - initialized.set(false); + FUNCTION_CATALOG = null; } public void handleOutput(I input, OutputBinding binding, @@ -248,23 +245,27 @@ public class FunctionInvoker { } private static void initialize(Class configurationClass) { - logger.info("Initializing: " + configurationClass); - SpringApplication builder = springApplication(configurationClass); - APPLICATION_CONTEXT = builder.run(); + synchronized (LOCK) { + if (FUNCTION_CATALOG == null) { + logger.info("Initializing: " + configurationClass); + SpringApplication builder = springApplication(configurationClass); + APPLICATION_CONTEXT = builder.run(); - Map mf = APPLICATION_CONTEXT.getBeansOfType(FunctionCatalog.class); - 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(), - messageConverter, OBJECT_MAPPER); + Map mf = APPLICATION_CONTEXT.getBeansOfType(FunctionCatalog.class); + 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(), + messageConverter, OBJECT_MAPPER); + } + else { + OBJECT_MAPPER = APPLICATION_CONTEXT.getBean(JsonMapper.class); + FUNCTION_CATALOG = mf.values().iterator().next(); + } + } + } - } - else { - OBJECT_MAPPER = APPLICATION_CONTEXT.getBean(JsonMapper.class); - FUNCTION_CATALOG = mf.values().iterator().next(); - } } private static SpringApplication springApplication(Class configurationClass) {