Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: feature flag polling for local evaluation (1/4) #54

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
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
509 changes: 509 additions & 0 deletions posthog/src/main/java/com/posthog/java/FeatureFlagPoller.java

Large diffs are not rendered by default.

21 changes: 21 additions & 0 deletions posthog/src/main/java/com/posthog/java/Getter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.posthog.java;

import org.json.JSONObject;

import java.util.Map;

/*
* Getter interface for making HTTP GET requests to the PostHog API
*/
interface Getter {

/*
* Make a GET request to the PostHog API
*
* @param route The route to make the GET request to
* @param headers The headers to include in the GET request
* @return The JSON response from the GET request
*/
JSONObject get(String route, Map<String, String> headers);

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.posthog.java;

public class InconclusiveMatchException extends Exception {
public InconclusiveMatchException(String message) {
super(message);
}
}
158 changes: 158 additions & 0 deletions posthog/src/main/java/com/posthog/java/flags/FeatureFlag.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
package com.posthog.java.flags;

import java.util.Objects;
import java.util.Optional;
import java.util.StringJoiner;

public class FeatureFlag {
private final String key;
private final String name;
private final int id;
private final int teamId;
private final int rolloutPercentage;
private final boolean isSimpleFlag;
private final boolean active;
private final boolean ensureExperienceContinuity;
private final boolean deleted;
private final FeatureFlagFilter featureFlagFilter;

public static class Builder {
private final String key;
private final int id;
private final int teamId;

private int rolloutPercentage;
private String name;
private boolean isSimpleFlag;
private boolean active;
private boolean ensureExperienceContinuity;
private boolean deleted;
private FeatureFlagFilter featureFlagFilter;

public Builder(String key, int id, int teamId) {
this.key = key;
this.id = id;
this.teamId = teamId;
}

public Builder name(String name) {
this.name = name;
return this;
}

public Builder rolloutPercentage(int rolloutPercentage) {
this.rolloutPercentage = rolloutPercentage;
return this;
}

public Builder isSimpleFlag(boolean isSimpleFlag) {
this.isSimpleFlag = isSimpleFlag;
return this;
}

public Builder active(boolean active) {
this.active = active;
return this;
}

public Builder deleted(boolean deleted) {
this.deleted = deleted;
return this;
}

public Builder ensureExperienceContinuity(boolean ensureExperienceContinuity) {
this.ensureExperienceContinuity = ensureExperienceContinuity;
return this;
}

public Builder filter(FeatureFlagFilter featureFlagFilter) {
this.featureFlagFilter = featureFlagFilter;
return this;
}

public FeatureFlag build() {
return new FeatureFlag(this);
}
}

private FeatureFlag(Builder builder) {
this.key = builder.key;
this.name = builder.name;
this.id = builder.id;
this.teamId = builder.teamId;
this.rolloutPercentage = builder.rolloutPercentage;
this.isSimpleFlag = builder.isSimpleFlag;
this.active = builder.active;
this.ensureExperienceContinuity = builder.ensureExperienceContinuity;
this.featureFlagFilter = builder.featureFlagFilter;
this.deleted = builder.deleted;
}

public String getKey() {
return key;
}

public String getName() {
return name;
}

public int getId() {
return id;
}

public int getTeamId() {
return teamId;
}

public int getRolloutPercentage() {
return rolloutPercentage;
}

public boolean isSimpleFlag() {
return isSimpleFlag;
}

public boolean isActive() {
return active;
}

public boolean isDeleted() {
return deleted;
}

public boolean isEnsureExperienceContinuity() {
return ensureExperienceContinuity;
}

public Optional<FeatureFlagFilter> getFilter() {
return Optional.ofNullable(featureFlagFilter);
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
FeatureFlag that = (FeatureFlag) o;
return isActive() == that.isActive() && Objects.equals(getKey(), that.getKey()) && Objects.equals(getId(), that.getId()) && Objects.equals(getTeamId(), that.getTeamId());
}

@Override
public int hashCode() {
return Objects.hash(getKey(), getId(), getTeamId(), isActive());
}

@Override
public String toString() {
return new StringJoiner(", ", FeatureFlag.class.getSimpleName() + "[", "]")
.add("key='" + key + "'")
.add("name='" + name + "'")
.add("id='" + id + "'")
.add("teamId='" + teamId + "'")
.add("rolloutPercentage=" + rolloutPercentage)
.add("isSimpleFlag=" + isSimpleFlag)
.add("active=" + active)
.add("ensureExperienceContinuity=" + ensureExperienceContinuity)
.add("filters=" + featureFlagFilter)
.toString();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
package com.posthog.java.flags;

import java.util.*;

public class FeatureFlagCondition {
private final List<FeatureFlagProperty> properties;
private final int rolloutPercentage;
private final String variant;

private FeatureFlagCondition(final Builder builder) {
this.properties = builder.properties;
this.rolloutPercentage = builder.rolloutPercentage;
this.variant = builder.variant;
}

public static class Builder {
private List<FeatureFlagProperty> properties = new ArrayList<>();
private int rolloutPercentage = 0;
private String variant = "";

public Builder properties(List<FeatureFlagProperty> properties) {
this.properties = properties;
return this;
}

public Builder rolloutPercentage(int rolloutPercentage) {
this.rolloutPercentage = rolloutPercentage;
return this;
}

public Builder variant(String variant) {
this.variant = variant;
return this;
}

public FeatureFlagCondition build() {
return new FeatureFlagCondition(this);
}
}

public List<FeatureFlagProperty> getProperties() {
return properties;
}

public int getRolloutPercentage() {
return rolloutPercentage;
}

public Optional<String> getVariant() {
if (variant == null || variant.isEmpty()) {
return Optional.empty();
}

return Optional.of(variant);
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
FeatureFlagCondition that = (FeatureFlagCondition) o;
return getRolloutPercentage() == that.getRolloutPercentage() && Objects.equals(getProperties(), that.getProperties()) && Objects.equals(getVariant(), that.getVariant());
}

@Override
public int hashCode() {
return Objects.hash(getProperties(), getRolloutPercentage(), getVariant());
}

@Override
public String toString() {
return new StringJoiner(", ", FeatureFlagCondition.class.getSimpleName() + "[", "]")
.add("properties=" + properties)
.add("rolloutPercentage=" + rolloutPercentage)
.add("variant='" + variant + "'")
.toString();
}
}
126 changes: 126 additions & 0 deletions posthog/src/main/java/com/posthog/java/flags/FeatureFlagConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
package com.posthog.java.flags;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.StringJoiner;

public class FeatureFlagConfig {

private final String key;
private final String distinctId;
private final Map<String, Object> groups;
private final Map<String, String> personProperties;
private final Map<String, Map<String, String>> groupProperties;
private final boolean onlyEvaluateLocally;
private final boolean sendFeatureFlagEvents;

private FeatureFlagConfig(Builder builder) {
this.key = builder.key;
this.distinctId = builder.distinctId;
this.groups = builder.groups;
this.personProperties = builder.personProperties;
this.groupProperties = builder.groupProperties;
this.onlyEvaluateLocally = builder.onlyEvaluateLocally;
this.sendFeatureFlagEvents = builder.sendFeatureFlagEvents;
}

public static class Builder {
private final String key;
private final String distinctId;

private Map<String, Object> groups = new HashMap<>();
private Map<String, String> personProperties = new HashMap<>();
private Map<String, Map<String, String>> groupProperties = new HashMap<>();
private boolean onlyEvaluateLocally = false;
private boolean sendFeatureFlagEvents = false;

public Builder(String key, String distinctId) {
this.key = key;
this.distinctId = distinctId;
}

public Builder groups(Map<String, Object> groups) {
this.groups = groups;
return this;
}

public Builder personProperties(Map<String, String> personProperties) {
this.personProperties = personProperties;
return this;
}

public Builder groupProperties(Map<String, Map<String, String>> groupProperties) {
this.groupProperties = groupProperties;
return this;
}

public Builder onlyEvaluateLocally(boolean onlyEvaluateLocally) {
this.onlyEvaluateLocally = onlyEvaluateLocally;
return this;
}

public Builder sendFeatureFlagEvents(boolean sendFeatureFlagEvents) {
this.sendFeatureFlagEvents = sendFeatureFlagEvents;
return this;
}

public FeatureFlagConfig build() {
return new FeatureFlagConfig(this);
}
}

public String getKey() {
return key;
}

public String getDistinctId() {
return distinctId;
}

public Map<String, Object> getGroups() {
return groups;
}

public Map<String, String> getPersonProperties() {
return personProperties;
}

public Map<String, Map<String, String>> getGroupProperties() {
return groupProperties;
}

public boolean isOnlyEvaluateLocally() {
return onlyEvaluateLocally;
}

public boolean isSendFeatureFlagEvents() {
return sendFeatureFlagEvents;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
FeatureFlagConfig that = (FeatureFlagConfig) o;
return isOnlyEvaluateLocally() == that.isOnlyEvaluateLocally() && isSendFeatureFlagEvents() == that.isSendFeatureFlagEvents() && Objects.equals(getKey(), that.getKey()) && Objects.equals(getDistinctId(), that.getDistinctId()) && Objects.equals(getGroups(), that.getGroups()) && Objects.equals(getPersonProperties(), that.getPersonProperties()) && Objects.equals(getGroupProperties(), that.getGroupProperties());
}

@Override
public int hashCode() {
return Objects.hash(getKey(), getDistinctId(), getGroups(), getPersonProperties(), getGroupProperties(), isOnlyEvaluateLocally(), isSendFeatureFlagEvents());
}

@Override
public String toString() {
return new StringJoiner(", ", FeatureFlagConfig.class.getSimpleName() + "[", "]")
.add("key='" + key + "'")
.add("distinctId='" + distinctId + "'")
.add("groups=" + groups)
.add("personProperties=" + personProperties)
.add("groupProperties=" + groupProperties)
.add("onlyEvaluateLocally=" + onlyEvaluateLocally)
.add("sendFeatureFlagEvents=" + sendFeatureFlagEvents)
.toString();
}
}
Loading