diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/configurations/FeatureFlagConfig.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/configurations/FeatureFlagConfig.java
deleted file mode 100644
index 9a8b4807d3..0000000000
--- a/app/server/appsmith-server/src/main/java/com/appsmith/server/configurations/FeatureFlagConfig.java
+++ /dev/null
@@ -1,17 +0,0 @@
-package com.appsmith.server.configurations;
-
-import org.ff4j.FF4j;
-import org.ff4j.conf.XmlParser;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-
-@Configuration
-public class FeatureFlagConfig {
-
- // Since we rely on cloud services to retrieve the most up-to-date flags, we avoid automatically generating the same
- // flag in the FF4J context.
- @Bean
- public FF4j ff4j() {
- return new FF4j(new XmlParser(), "features/init-flags.xml").audit(true).autoCreate(false);
- }
-}
diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/featureflags/FeatureFlagEnum.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/featureflags/FeatureFlagEnum.java
index b8742b34a2..2e9fbc1936 100644
--- a/app/server/appsmith-server/src/main/java/com/appsmith/server/featureflags/FeatureFlagEnum.java
+++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/featureflags/FeatureFlagEnum.java
@@ -1,19 +1,5 @@
package com.appsmith.server.featureflags;
-import org.ff4j.core.FlippingStrategy;
-import org.ff4j.strategy.PonderationStrategy;
-import org.ff4j.strategy.time.OfficeHourStrategy;
-
-/**
- * This enum lists all the feature flags available along with their flipping strategy.
- * In order to create a new feature flag, create another enum entry and add the same string to {@link features/init-flags.xml}
- *
- * If you wish to define a custom flipping strategy, define a class that implements {@link FlippingStrategy} and
- * ensure that you've mentioned this custom class when defining the feature in {@link features/init-flags.xml}
- *
- * The feature flag implementation class should extend an existing feature flag implementation like {@link PonderationStrategy},
- * {@link OfficeHourStrategy} etc. These default classes provide a lot of basic functionality out of the box.
- */
public enum FeatureFlagEnum {
// ------------------- These features are only for JUnit testing. DO NOT use these features in your code path.--- //
// ------------------- Couldn't find a better way to do this ---------------------------------------------------- //
diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/featureflags/strategies/AppsmithUserStrategy.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/featureflags/strategies/AppsmithUserStrategy.java
deleted file mode 100644
index 52682333bc..0000000000
--- a/app/server/appsmith-server/src/main/java/com/appsmith/server/featureflags/strategies/AppsmithUserStrategy.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package com.appsmith.server.featureflags.strategies;
-
-import com.appsmith.server.constants.FieldName;
-import com.appsmith.server.domains.User;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.lang3.StringUtils;
-import org.ff4j.core.FeatureStore;
-import org.ff4j.core.FlippingExecutionContext;
-import org.ff4j.strategy.AbstractFlipStrategy;
-
-/**
- * This strategy enables a given feature for Appsmith users only. Useful when features are under development and not
- * ready for prime-time
- */
-@Slf4j
-public class AppsmithUserStrategy extends AbstractFlipStrategy {
-
- @Override
- public boolean evaluate(String featureName, FeatureStore store, FlippingExecutionContext executionContext) {
- User user = (User) executionContext.getValue(FieldName.USER, true);
-
- return StringUtils.endsWith(user.getEmail(), "@appsmith.com");
- }
-}
diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/featureflags/strategies/EmailBasedRolloutStrategy.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/featureflags/strategies/EmailBasedRolloutStrategy.java
deleted file mode 100644
index 3171aa420f..0000000000
--- a/app/server/appsmith-server/src/main/java/com/appsmith/server/featureflags/strategies/EmailBasedRolloutStrategy.java
+++ /dev/null
@@ -1,63 +0,0 @@
-package com.appsmith.server.featureflags.strategies;
-
-import com.appsmith.server.constants.FieldName;
-import com.appsmith.server.domains.User;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.lang3.StringUtils;
-import org.ff4j.core.FeatureStore;
-import org.ff4j.core.FlippingExecutionContext;
-import org.ff4j.strategy.AbstractFlipStrategy;
-
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-
-@Slf4j
-public class EmailBasedRolloutStrategy extends AbstractFlipStrategy {
-
- List validDomains = new ArrayList<>();
- List validEmails = new ArrayList<>();
-
- private static final String PARAM_EMAIL_DOMAINS = "emailDomains";
- private static final String PARAM_EMAILS = "emails";
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void init(String featureName, Map initParam) {
- super.init(featureName, initParam);
- if (!initParam.containsKey(PARAM_EMAIL_DOMAINS) && !initParam.containsKey(PARAM_EMAILS)) {
- String msg = String.format(
- "Either '%s' or '%s' is required for EmailBasedRolloutStrategy", PARAM_EMAIL_DOMAINS, PARAM_EMAILS);
- throw new IllegalArgumentException(msg);
- }
- if (!StringUtils.isEmpty(initParam.get(PARAM_EMAIL_DOMAINS))) {
- this.validDomains = Arrays.asList(initParam.get(PARAM_EMAIL_DOMAINS).split(","));
- }
- if (!StringUtils.isEmpty(initParam.get(PARAM_EMAILS))) {
- this.validEmails = Arrays.asList(initParam.get(PARAM_EMAILS).split(","));
- }
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public boolean evaluate(String featureName, FeatureStore store, FlippingExecutionContext executionContext) {
- User user = (User) executionContext.getValue(FieldName.USER, true);
- int atIndex = user.getEmail().indexOf("@");
-
- if (atIndex > 0) {
- // If the email domain is valid, check the user's email ID against the list of validated domains
- String domain = user.getEmail().substring(atIndex + 1).toLowerCase();
- if (validDomains.contains(domain)) {
- return true;
- } else {
- return validEmails.contains(user.getEmail());
- }
- }
- return false;
- }
-}
diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/FeatureFlagServiceImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/FeatureFlagServiceImpl.java
index 8ba5d4bdae..103a3fd5df 100644
--- a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/FeatureFlagServiceImpl.java
+++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/FeatureFlagServiceImpl.java
@@ -2,21 +2,18 @@ package com.appsmith.server.services;
import com.appsmith.server.helpers.FeatureFlagMigrationHelper;
import com.appsmith.server.services.ce.FeatureFlagServiceCEImpl;
-import org.ff4j.FF4j;
import org.springframework.stereotype.Component;
@Component
public class FeatureFlagServiceImpl extends FeatureFlagServiceCEImpl implements FeatureFlagService {
public FeatureFlagServiceImpl(
SessionUserService sessionUserService,
- FF4j ff4j,
TenantService tenantService,
UserIdentifierService userIdentifierService,
CacheableFeatureFlagHelper cacheableFeatureFlagHelper,
FeatureFlagMigrationHelper featureFlagMigrationHelper) {
super(
sessionUserService,
- ff4j,
tenantService,
userIdentifierService,
cacheableFeatureFlagHelper,
diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/CacheableFeatureFlagHelperCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/CacheableFeatureFlagHelperCEImpl.java
index 369aa3f1f1..cc612e32dc 100644
--- a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/CacheableFeatureFlagHelperCEImpl.java
+++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/CacheableFeatureFlagHelperCEImpl.java
@@ -152,7 +152,7 @@ public class CacheableFeatureFlagHelperCEImpl implements CacheableFeatureFlagHel
// We're gobbling up errors here so that all feature flags are turned off by default
// This will be problematic if we do not maintain code to reflect validity of flags
log.debug("Received error from CS for feature flags: {}", error.getMessage());
- return Mono.just(Map.of());
+ return Mono.just(new HashMap<>());
});
}
@@ -166,8 +166,14 @@ public class CacheableFeatureFlagHelperCEImpl implements CacheableFeatureFlagHel
public Mono fetchCachedTenantFeatures(String tenantId) {
return this.forceAllRemoteFeaturesForTenant(tenantId).flatMap(flags -> {
CachedFeatures cachedFeatures = new CachedFeatures();
- cachedFeatures.setRefreshedAt(Instant.now());
cachedFeatures.setFeatures(flags);
+ // If CS is down we expect the empty flags, from upstream method. Hence, setting the refreshed at to past
+ // so that the next call will have the force refresh.
+ if (CollectionUtils.isNullOrEmpty(flags)) {
+ cachedFeatures.setRefreshedAt(Instant.now().minus(1, ChronoUnit.DAYS));
+ } else {
+ cachedFeatures.setRefreshedAt(Instant.now());
+ }
return Mono.just(cachedFeatures);
});
}
diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/FeatureFlagServiceCE.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/FeatureFlagServiceCE.java
index 806726ea94..f617e92971 100644
--- a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/FeatureFlagServiceCE.java
+++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/FeatureFlagServiceCE.java
@@ -1,7 +1,6 @@
package com.appsmith.server.services.ce;
import com.appsmith.server.domains.Tenant;
-import com.appsmith.server.domains.User;
import com.appsmith.server.featureflags.CachedFeatures;
import com.appsmith.server.featureflags.FeatureFlagEnum;
import reactor.core.publisher.Mono;
@@ -10,16 +9,6 @@ import java.util.Map;
public interface FeatureFlagServiceCE {
- /**
- * Used to check if a particular feature is enabled for a given user. Useful in contexts where we already have the
- * User object and simply wish to do a boolean check
- *
- * @param featureEnum
- * @param user
- * @return Boolean
- */
- Mono check(FeatureFlagEnum featureEnum, User user);
-
/**
* Check if a particular feature is enabled for the current logged in user. Useful in chaining reactive functions
* while writing business logic that may depend on a feature flag
@@ -29,8 +18,6 @@ public interface FeatureFlagServiceCE {
*/
Mono check(FeatureFlagEnum featureEnum);
- Boolean check(String featureName, User user);
-
/**
* Fetch all the flags and their values for the current logged in user
*
diff --git a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/FeatureFlagServiceCEImpl.java b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/FeatureFlagServiceCEImpl.java
index 6c761ce537..d73a419d60 100644
--- a/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/FeatureFlagServiceCEImpl.java
+++ b/app/server/appsmith-server/src/main/java/com/appsmith/server/services/ce/FeatureFlagServiceCEImpl.java
@@ -1,6 +1,5 @@
package com.appsmith.server.services.ce;
-import com.appsmith.server.constants.FieldName;
import com.appsmith.server.constants.MigrationStatus;
import com.appsmith.server.domains.Tenant;
import com.appsmith.server.domains.TenantConfiguration;
@@ -16,19 +15,13 @@ import com.appsmith.server.services.TenantService;
import com.appsmith.server.services.UserIdentifierService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
-import org.ff4j.FF4j;
-import org.ff4j.core.FlippingExecutionContext;
-import org.ff4j.exception.FeatureNotFoundException;
-import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
-import reactor.util.function.Tuple2;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.HashMap;
import java.util.Map;
-
-import static java.lang.Boolean.TRUE;
+import java.util.Objects;
@Slf4j
@RequiredArgsConstructor
@@ -36,8 +29,6 @@ public class FeatureFlagServiceCEImpl implements FeatureFlagServiceCE {
private final SessionUserService sessionUserService;
- private final FF4j ff4j;
-
private final TenantService tenantService;
private final UserIdentifierService userIdentifierService;
@@ -49,26 +40,6 @@ public class FeatureFlagServiceCEImpl implements FeatureFlagServiceCE {
private CachedFeatures cachedTenantFeatureFlags;
- private Mono checkAll(String featureName, User user) {
- Boolean check = check(featureName, user);
-
- if (TRUE.equals(check)) {
- return Mono.just(true);
- }
-
- return getAllFeatureFlagsForUser()
- .flatMap(featureMap -> Mono.justOrEmpty(featureMap.get(featureName)))
- .switchIfEmpty(Mono.just(false));
- }
-
- @Override
- public Mono check(FeatureFlagEnum featureEnum, User user) {
- if (featureEnum == null) {
- return Mono.just(false);
- }
- return checkAll(featureEnum.toString(), user);
- }
-
/**
* This function checks if the feature is enabled for the current user. In case the user object is not present,
* i.e. when the method is getting called internally via cron or other mechanism check for tenant level flag and
@@ -79,32 +50,11 @@ public class FeatureFlagServiceCEImpl implements FeatureFlagServiceCE {
*/
@Override
public Mono check(FeatureFlagEnum featureEnum) {
- // Check if the feature is supported at the tenant level and provide a fallback as falsy value
- // i.e. not supported
- Mono isTenantFeatureSupported = this.getTenantFeatures()
- .flatMap(featureMap -> Mono.justOrEmpty(featureMap.get(featureEnum.name())))
- .switchIfEmpty(Mono.just(false));
-
- return sessionUserService
- .getCurrentUser()
- .flatMap(user -> check(featureEnum, user))
- .switchIfEmpty(isTenantFeatureSupported);
- }
-
- @Override
- public Boolean check(String featureName, User user) {
- try {
- return ff4j.check(featureName, new FlippingExecutionContext(Map.of(FieldName.USER, user)));
- } catch (Exception e) {
- // FF4J is configured not to auto-generate a flag if it's not present in init-flags.xml
- // (see FeatureFlagConfig.java).
- // Consequently, we anticipate that the flag may not exist in the FF4J context and need to handle any
- // related exceptions silently.
- if (!(e instanceof FeatureNotFoundException)) {
- log.error("Error checking feature flag: {}", featureName, e);
- }
+ if (Objects.isNull(featureEnum)) {
+ return Mono.just(Boolean.FALSE);
}
- return false;
+ return this.getAllFeatureFlagsForUser()
+ .map(featureMap -> featureMap.getOrDefault(featureEnum.name(), Boolean.FALSE));
}
/**
@@ -115,27 +65,16 @@ public class FeatureFlagServiceCEImpl implements FeatureFlagServiceCE {
*/
@Override
public Mono