Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions src/main/java/com/hubspot/jinjava/JinjavaConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
import com.hubspot.jinjava.el.JinjavaObjectUnwrapper;
import com.hubspot.jinjava.el.JinjavaProcessors;
import com.hubspot.jinjava.el.ObjectUnwrapper;
import com.hubspot.jinjava.features.FeatureConfig;
import com.hubspot.jinjava.features.Features;
import com.hubspot.jinjava.interpret.Context;
import com.hubspot.jinjava.interpret.Context.Library;
import com.hubspot.jinjava.interpret.InterpreterFactory;
Expand Down Expand Up @@ -80,6 +82,8 @@ public class JinjavaConfig {
private final boolean enablePreciseDivideFilter;
private final ObjectMapper objectMapper;

private final Features features;

private final ObjectUnwrapper objectUnwrapper;
private final JinjavaProcessors processors;

Expand Down Expand Up @@ -140,6 +144,7 @@ private JinjavaConfig(Builder builder) {
objectMapper = setupObjectMapper(builder.objectMapper);
objectUnwrapper = builder.objectUnwrapper;
processors = builder.processors;
features = new Features(builder.featureConfig);
}

private ObjectMapper setupObjectMapper(@Nullable ObjectMapper objectMapper) {
Expand Down Expand Up @@ -288,6 +293,10 @@ public DateTimeProvider getDateTimeProvider() {
return dateTimeProvider;
}

public Features getFeatures() {
return features;
}

public static class Builder {
private Charset charset = StandardCharsets.UTF_8;
private Locale locale = Locale.ENGLISH;
Expand Down Expand Up @@ -322,6 +331,7 @@ public static class Builder {

private ObjectUnwrapper objectUnwrapper = new JinjavaObjectUnwrapper();
private JinjavaProcessors processors = JinjavaProcessors.newBuilder().build();
private FeatureConfig featureConfig = FeatureConfig.newBuilder().build();

private Builder() {}

Expand Down Expand Up @@ -508,6 +518,11 @@ public Builder withProcessors(JinjavaProcessors jinjavaProcessors) {
return this;
}

public Builder withFeatureConfig(FeatureConfig featureConfig) {
this.featureConfig = featureConfig;
return this;
}

public JinjavaConfig build() {
return new JinjavaConfig(this);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.hubspot.jinjava.features;

import com.hubspot.jinjava.interpret.Context;
import java.time.LocalDateTime;

public class DateTimeFeatureActivationStrategy implements FeatureActivationStrategy {
private final LocalDateTime activateAt;

public static DateTimeFeatureActivationStrategy of(LocalDateTime activateAt) {
return new DateTimeFeatureActivationStrategy(activateAt);
}

private DateTimeFeatureActivationStrategy(LocalDateTime activateAt) {
this.activateAt = activateAt;
}

@Override
public boolean isActive(Context context) {
return LocalDateTime.now().isAfter(activateAt);
}

public LocalDateTime getActivateAt() {
return activateAt;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.hubspot.jinjava.features;

import com.hubspot.jinjava.interpret.Context;

public interface FeatureActivationStrategy {
boolean isActive(Context context);
}
34 changes: 34 additions & 0 deletions src/main/java/com/hubspot/jinjava/features/FeatureConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.hubspot.jinjava.features;

import com.google.common.collect.ImmutableMap;
import java.util.HashMap;
import java.util.Map;

public class FeatureConfig {
Map<String, FeatureActivationStrategy> features;

private FeatureConfig(Map<String, FeatureActivationStrategy> features) {
this.features = ImmutableMap.copyOf(features);
}

public FeatureActivationStrategy getFeature(String name) {
return features.getOrDefault(name, FeatureStrategies.INACTIVE);
}

public static FeatureConfig.Builder newBuilder() {
return new Builder();
}

public static class Builder {
private final Map<String, FeatureActivationStrategy> features = new HashMap<>();

public Builder add(String name, FeatureActivationStrategy strategy) {
features.put(name, strategy);
return this;
}

public FeatureConfig build() {
return new FeatureConfig(features);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.hubspot.jinjava.features;

public class FeatureStrategies {
public static final FeatureActivationStrategy INACTIVE = c -> false;
public static final FeatureActivationStrategy ACTIVE = c -> true;
}
19 changes: 19 additions & 0 deletions src/main/java/com/hubspot/jinjava/features/Features.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.hubspot.jinjava.features;

import com.hubspot.jinjava.interpret.Context;

public class Features {
private final FeatureConfig featureConfig;

public Features(FeatureConfig featureConfig) {
this.featureConfig = featureConfig;
}

public boolean isActive(String featureName, Context context) {
return getActivationStrategy(featureName).isActive(context);
}

public FeatureActivationStrategy getActivationStrategy(String featureName) {
return featureConfig.getFeature(featureName);
}
}
74 changes: 74 additions & 0 deletions src/test/java/com/hubspot/jinjava/FeaturesTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package com.hubspot.jinjava;

import static org.assertj.core.api.Assertions.assertThat;

import com.hubspot.jinjava.features.DateTimeFeatureActivationStrategy;
import com.hubspot.jinjava.features.FeatureConfig;
import com.hubspot.jinjava.features.FeatureStrategies;
import com.hubspot.jinjava.features.Features;
import com.hubspot.jinjava.interpret.Context;
import java.time.LocalDateTime;
import org.junit.Before;
import org.junit.Test;

public class FeaturesTest {
private static final String ALWAYS_OFF = "alwaysOff";
private static final String ALWAYS_ON = "alwaysOn";
private static final String DATE_PAST = "datePast";
private static final String DATE_FUTURE = "dateFuture";
private static final String DELEGATING = "delegating";

private Features features;

private boolean delegateActive = false;

private Context context = new Context();

@Before
public void setUp() throws Exception {
features =
new Features(
FeatureConfig
.newBuilder()
.add(ALWAYS_OFF, FeatureStrategies.INACTIVE)
.add(ALWAYS_ON, FeatureStrategies.ACTIVE)
.add(DATE_PAST, DateTimeFeatureActivationStrategy.of(LocalDateTime.MIN))
.add(DATE_FUTURE, DateTimeFeatureActivationStrategy.of(LocalDateTime.MAX))
.add(DELEGATING, d -> delegateActive)
.build()
);
}

@Test
public void itHasEnabledFeature() {
assertThat(features.isActive(ALWAYS_ON, context)).isTrue();
}

@Test
public void itDoesNotHaveDisabledFeature() {
assertThat(features.isActive(ALWAYS_OFF, context)).isFalse();
}

@Test
public void itHasPastEnabledFeature() {
assertThat(features.isActive(DATE_PAST, context)).isTrue();
}

@Test
public void itDoesNotHaveFutureEnabledFeature() {
assertThat(features.isActive(DATE_FUTURE, context)).isFalse();
}

@Test
public void itUsesDelegate() {
delegateActive = false;
assertThat(features.isActive(DELEGATING, context)).isEqualTo(delegateActive);
delegateActive = true;
assertThat(features.isActive(DELEGATING, context)).isEqualTo(delegateActive);
}

@Test
public void itDefaultsToFalse() {
assertThat(features.isActive("unknown", context)).isFalse();
}
}