diff --git a/src/main/java/org/prebid/server/hooks/v1/HookCatalog.java b/src/main/java/org/prebid/server/hooks/v1/HookCatalog.java new file mode 100644 index 00000000000..4a3cb762f49 --- /dev/null +++ b/src/main/java/org/prebid/server/hooks/v1/HookCatalog.java @@ -0,0 +1,55 @@ +package org.prebid.server.hooks.v1; + +import org.prebid.server.hooks.v1.auction.AuctionResponseHook; +import org.prebid.server.hooks.v1.auction.RawAuctionRequestHook; +import org.prebid.server.hooks.v1.bidder.BidderRequestHook; +import org.prebid.server.hooks.v1.bidder.RawBidderResponseHook; +import org.prebid.server.hooks.v1.entrypoint.EntrypointHook; + +import java.util.Collection; +import java.util.Objects; +import java.util.Set; + +/** + * Provides simple access to all {@link Hook}s registered in application. + */ +public class HookCatalog { + + private final Set modules; + + public HookCatalog(Set modules) { + this.modules = Objects.requireNonNull(modules); + } + + public EntrypointHook entrypointHookBy(String moduleCode, String hookImplCode) { + return getHookBy(moduleCode, hookImplCode, EntrypointHook.class); + } + + public RawAuctionRequestHook rawAuctionRequestHookBy(String moduleCode, String hookImplCode) { + return getHookBy(moduleCode, hookImplCode, RawAuctionRequestHook.class); + } + + public BidderRequestHook bidderRequestHookBy(String moduleCode, String hookImplCode) { + return getHookBy(moduleCode, hookImplCode, BidderRequestHook.class); + } + + public RawBidderResponseHook rawBidderResponseHookBy(String moduleCode, String hookImplCode) { + return getHookBy(moduleCode, hookImplCode, RawBidderResponseHook.class); + } + + public AuctionResponseHook auctionResponseHookBy(String moduleCode, String hookImplCode) { + return getHookBy(moduleCode, hookImplCode, AuctionResponseHook.class); + } + + private T getHookBy(String moduleCode, String hookImplCode, Class clazz) { + return modules.stream() + .filter(module -> Objects.equals(module.code(), moduleCode)) + .map(Module::hooks) + .flatMap(Collection::stream) + .filter(hook -> Objects.equals(hook.code(), hookImplCode)) + .filter(clazz::isInstance) + .map(clazz::cast) + .findFirst() + .orElse(null); + } +} diff --git a/src/main/java/org/prebid/server/hooks/v1/Module.java b/src/main/java/org/prebid/server/hooks/v1/Module.java new file mode 100644 index 00000000000..c645915e4a0 --- /dev/null +++ b/src/main/java/org/prebid/server/hooks/v1/Module.java @@ -0,0 +1,22 @@ +package org.prebid.server.hooks.v1; + +import java.util.Collection; + +/** + * Cares of the module identification among other modules and supplies a collection of available {@link Hook}s. + *

+ * This interface is used to keep knowledge of which {@link Hook} is belongs to certain {@link Module} + * while running execution plan. + */ +public interface Module { + + /** + * An identifier that should be unique among other available modules. + */ + String code(); + + /** + * Collection of hooks available through the module. + */ + Collection hooks(); +} diff --git a/src/test/java/org/prebid/server/hooks/v1/HookCatalogTest.java b/src/test/java/org/prebid/server/hooks/v1/HookCatalogTest.java new file mode 100644 index 00000000000..d9a5470da1f --- /dev/null +++ b/src/test/java/org/prebid/server/hooks/v1/HookCatalogTest.java @@ -0,0 +1,133 @@ +package org.prebid.server.hooks.v1; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; +import org.prebid.server.hooks.v1.auction.AuctionResponseHook; +import org.prebid.server.hooks.v1.auction.RawAuctionRequestHook; +import org.prebid.server.hooks.v1.bidder.BidderRequestHook; +import org.prebid.server.hooks.v1.bidder.RawBidderResponseHook; +import org.prebid.server.hooks.v1.entrypoint.EntrypointHook; + +import static java.util.Collections.singleton; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.doReturn; + +public class HookCatalogTest { + + @Rule + public final MockitoRule mockitoRule = MockitoJUnit.rule(); + + @Mock + private Module sampleModule; + @Mock + private Hook sampleHook; + + private HookCatalog hookCatalog; + + @Before + public void setUp() { + given(sampleModule.code()).willReturn("sample-module"); + + hookCatalog = new HookCatalog(singleton(sampleModule)); + } + + @Test + public void entrypointHookByShouldTolerateUnknownModule() { + // when + final Hook foundHook = hookCatalog.entrypointHookBy("unknown-module", null); + + // then + assertThat(foundHook).isNull(); + } + + @Test + public void entrypointHookByShouldTolerateUnknownHook() { + // when + final Hook foundHook = hookCatalog.entrypointHookBy("sample-module", "unknown-hook"); + + // then + assertThat(foundHook).isNull(); + } + + @Test + public void entrypointHookByShouldReturnExpectedResult() { + // given + givenHook(EntrypointHook.class); + + // when + final Hook foundHook = hookCatalog.entrypointHookBy("sample-module", "sample-hook"); + + // then + assertThat(foundHook).isNotNull() + .extracting(Hook::code) + .containsOnly("sample-hook"); + } + + @Test + public void rawAuctionRequestHookByShouldReturnExpectedResult() { + // given + givenHook(RawAuctionRequestHook.class); + + // when + final Hook foundHook = hookCatalog.rawAuctionRequestHookBy("sample-module", "sample-hook"); + + // then + assertThat(foundHook).isNotNull() + .extracting(Hook::code) + .containsOnly("sample-hook"); + } + + @Test + public void bidderRequestHookByShouldReturnExpectedResult() { + // given + givenHook(BidderRequestHook.class); + + // when + final Hook foundHook = hookCatalog.bidderRequestHookBy("sample-module", "sample-hook"); + + // then + assertThat(foundHook).isNotNull() + .extracting(Hook::code) + .containsOnly("sample-hook"); + } + + @Test + public void rawBidderResponseHookByShouldReturnExpectedResult() { + // given + givenHook(RawBidderResponseHook.class); + + // when + final Hook foundHook = hookCatalog.rawBidderResponseHookBy("sample-module", "sample-hook"); + + // then + assertThat(foundHook).isNotNull() + .extracting(Hook::code) + .containsOnly("sample-hook"); + } + + @Test + public void auctionResponseHookByShouldReturnExpectedResult() { + // given + givenHook(AuctionResponseHook.class); + + // when + final Hook foundHook = hookCatalog.auctionResponseHookBy("sample-module", "sample-hook"); + + // then + assertThat(foundHook).isNotNull() + .extracting(Hook::code) + .containsOnly("sample-hook"); + } + + private void givenHook(Class clazz) { + sampleHook = Mockito.mock(clazz); + given(sampleHook.code()).willReturn("sample-hook"); + doReturn(singleton(sampleHook)).when(sampleModule).hooks(); + } +}