diff --git a/src/main/java/com/exactpro/th2/common/schema/factory/AbstractCommonFactory.java b/src/main/java/com/exactpro/th2/common/schema/factory/AbstractCommonFactory.java index 494e2ff1..bd42b51e 100644 --- a/src/main/java/com/exactpro/th2/common/schema/factory/AbstractCommonFactory.java +++ b/src/main/java/com/exactpro/th2/common/schema/factory/AbstractCommonFactory.java @@ -84,7 +84,6 @@ import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.atomic.AtomicReference; import static com.exactpro.cradle.CradleStorage.DEFAULT_MAX_MESSAGE_BATCH_SIZE; import static com.exactpro.cradle.CradleStorage.DEFAULT_MAX_TEST_EVENT_BATCH_SIZE; @@ -186,6 +185,8 @@ public AbstractCommonFactory(FactorySettings settings) { public void start() { DefaultExports.initialize(); + // init exporter + prometheusExporter.getOrNull(); livenessMonitor.enable(); } diff --git a/src/main/kotlin/com/exactpro/th2/common/schema/factory/LazyProvider.kt b/src/main/kotlin/com/exactpro/th2/common/schema/factory/LazyProvider.kt index 8aac6b8c..9e005fb1 100644 --- a/src/main/kotlin/com/exactpro/th2/common/schema/factory/LazyProvider.kt +++ b/src/main/kotlin/com/exactpro/th2/common/schema/factory/LazyProvider.kt @@ -32,19 +32,32 @@ internal class LazyProvider private constructor( } fun get(): T { + return getState().value + } + + /** + * The difference from [get] method is that this one does not throw an exception + * if provider already closed. + * However, it will still throw an exception if value initialization is failed + */ + fun getOrNull(): T? { + return getState().takeIf { it is State.Hold }?.value + } + + private fun getState(): State { return if (reference.compareAndSet(null, State.Init)) { val holder = State.Hold(initialize()) if (!reference.compareAndSet(State.Init, holder)) { onClose.consume(holder.value) error("provider '$name' already closed") } - holder.value + holder } else { var currentState: State? do { currentState = reference.get() } while (currentState == State.Init || currentState == null) - currentState.value + currentState } } diff --git a/src/test/kotlin/com/exactpro/th2/common/schema/factory/LazyProviderTest.kt b/src/test/kotlin/com/exactpro/th2/common/schema/factory/LazyProviderTest.kt index 465e866b..e378f9ce 100644 --- a/src/test/kotlin/com/exactpro/th2/common/schema/factory/LazyProviderTest.kt +++ b/src/test/kotlin/com/exactpro/th2/common/schema/factory/LazyProviderTest.kt @@ -16,8 +16,13 @@ package com.exactpro.th2.common.schema.factory +import com.exactpro.th2.common.schema.exception.CommonFactoryException import org.junit.jupiter.api.Assertions import org.junit.jupiter.api.RepeatedTest +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertThrows +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.ValueSource import org.mockito.kotlin.doReturn import org.mockito.kotlin.inOrder import org.mockito.kotlin.mock @@ -29,6 +34,8 @@ import java.util.concurrent.Callable import java.util.concurrent.ExecutionException import java.util.concurrent.ForkJoinPool import java.util.concurrent.ThreadLocalRandom +import kotlin.test.assertContains +import kotlin.test.assertNotNull internal class LazyProviderTest { @RepeatedTest(50) @@ -132,4 +139,22 @@ internal class LazyProviderTest { "unexpected errors thrown: $errors" } } + + @Test + fun `null resources`() { + val provider = LazyProvider.lazy("test") { null } + Assertions.assertEquals(null, provider.get(), "unexpected value") + } + + @ParameterizedTest + @ValueSource(booleans = [true, false]) + fun `exception in supplier`(safeCall: Boolean) { + val provider = LazyProvider.lazy("test") { error("supplier error") } + val ex = assertThrows { + if (safeCall) provider.getOrNull() else provider.get() + } + assertNotNull(ex.cause?.message, "no cause") { + assertContains(it, "supplier error") + } + } } \ No newline at end of file