From 9dab9fa0a02e19123149e2fe661ec61cac955120 Mon Sep 17 00:00:00 2001 From: Ittay Stern Date: Tue, 14 Jan 2020 20:35:51 +0200 Subject: Honor user-cookie to select a temporal feature set Issue-ID: VID-747 Change-Id: I5acd4685bedfed8570a6fd698101f541d03c8d82 Signed-off-by: Ittay Stern --- .../org/onap/vid/properties/FeatureSetsManager.kt | 82 ++++++++++++++++++++++ .../properties/FeaturesTogglingConfiguration.java | 13 ++-- 2 files changed, 89 insertions(+), 6 deletions(-) create mode 100644 vid-app-common/src/main/java/org/onap/vid/properties/FeatureSetsManager.kt (limited to 'vid-app-common/src/main/java/org') diff --git a/vid-app-common/src/main/java/org/onap/vid/properties/FeatureSetsManager.kt b/vid-app-common/src/main/java/org/onap/vid/properties/FeatureSetsManager.kt new file mode 100644 index 000000000..207bde7aa --- /dev/null +++ b/vid-app-common/src/main/java/org/onap/vid/properties/FeatureSetsManager.kt @@ -0,0 +1,82 @@ +package org.onap.vid.properties + +import org.apache.commons.io.filefilter.WildcardFileFilter +import org.springframework.web.context.request.RequestContextHolder.getRequestAttributes +import org.springframework.web.context.request.ServletRequestAttributes +import org.togglz.core.Feature +import org.togglz.core.manager.FeatureManager +import org.togglz.core.manager.FeatureManagerBuilder +import org.togglz.core.repository.file.FileBasedStateRepository +import java.io.File +import java.io.FilenameFilter +import javax.servlet.ServletContext +import javax.servlet.http.HttpServletRequest + + +private const val SLOW_RELOAD = 60_000 +private const val COOKIE_NAME = "features.set" + +class FeatureSetsManager( + private val defaultManager: FeatureManager, + private val nameProvider: AlternativeFeatureSetNameProvider, + private val servletContext: ServletContext +) : FeatureManager by defaultManager { + + override fun isActive(feature: Feature?): Boolean { + return resolvedFeatureManager().isActive(feature) + } + + private fun resolvedFeatureManager(): FeatureManager { + return when (val alternativeFeatureSetName = nameProvider.alternativeFeatureSetName) { + null -> defaultManager + else -> allFeatureManagers.getValue(alternativeFeatureSetName) + } + } + + internal val allFeatureManagers: Map by lazy { + allFeatureSetFiles().associateBy( + { it.name }, + { newFeatureManager(it) } + ).withDefault { allFeaturesOff } + } + + private val allFeaturesOff = + FeatureManagerBuilder().featureEnum(Features::class.java).build() + + private fun newFeatureManager(file: File): FeatureManager { + return FeatureManagerBuilder() + .featureEnum(Features::class.java) + .stateRepository(FileBasedStateRepository(file, SLOW_RELOAD)) + .build() + } + + private fun allFeatureSetFiles(): Array { + val dir = File(servletContext.getRealPath("/WEB-INF/conf/")) + val fileFilter: FilenameFilter = WildcardFileFilter("*.features.properties") + + return dir.listFiles(fileFilter) ?: emptyArray() + } +} + +interface AlternativeFeatureSetNameProvider { + val alternativeFeatureSetName: String? +} + +class AlternativeFeatureSetNameFromCookie: AlternativeFeatureSetNameProvider { + override val alternativeFeatureSetName: String? + get() = valueFromCookie(currentHttpRequest()) + + internal fun valueFromCookie(httpServletRequest: HttpServletRequest?): String? { + return httpServletRequest + ?.cookies + ?.firstOrNull { it.name == COOKIE_NAME } + ?.value + } + + internal fun currentHttpRequest(): HttpServletRequest? { + return when (val requestAttributes = getRequestAttributes()) { + is ServletRequestAttributes -> requestAttributes.request + else -> null + } + } +} diff --git a/vid-app-common/src/main/java/org/onap/vid/properties/FeaturesTogglingConfiguration.java b/vid-app-common/src/main/java/org/onap/vid/properties/FeaturesTogglingConfiguration.java index 4d4387d4e..96331b7c4 100644 --- a/vid-app-common/src/main/java/org/onap/vid/properties/FeaturesTogglingConfiguration.java +++ b/vid-app-common/src/main/java/org/onap/vid/properties/FeaturesTogglingConfiguration.java @@ -20,6 +20,8 @@ package org.onap.vid.properties; +import java.io.File; +import javax.servlet.ServletContext; import org.apache.commons.lang3.StringUtils; import org.springframework.context.ApplicationListener; import org.springframework.context.annotation.Bean; @@ -30,9 +32,6 @@ import org.togglz.core.manager.FeatureManagerBuilder; import org.togglz.core.repository.file.FileBasedStateRepository; import org.togglz.spring.listener.TogglzApplicationContextBinderApplicationListener; -import javax.servlet.ServletContext; -import java.io.File; - @Configuration public class FeaturesTogglingConfiguration { @Bean @@ -52,11 +51,13 @@ public class FeaturesTogglingConfiguration { filename = StringUtils.trimToNull(filename); - return new FeatureManagerBuilder() + return new FeatureSetsManager( + new FeatureManagerBuilder() .featureEnum(Features.class) .stateRepository(new FileBasedStateRepository( - new File(filename.startsWith("/")? filename : servletContext.getRealPath("/WEB-INF/conf/" + filename)) + new File(filename.startsWith("/") ? filename : servletContext.getRealPath("/WEB-INF/conf/" + filename)) )) - .build(); + .build(), new AlternativeFeatureSetNameFromCookie(), servletContext + ); } } -- cgit 1.2.3-korg