Skip to content

Commit e284ca2

Browse files
authored
add support for feature flags (#46)
* add support for feature flags * add support for variant_splits in rollouts * add support for hash salts in feature flag definitions and evaluation --------- Co-authored-by: Mark Siebert <[email protected]>
1 parent 6180bbe commit e284ca2

27 files changed

+4414
-27
lines changed

README.md

Lines changed: 81 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
This is the official Mixpanel tracking library for Java.
1+
This is the official Mixpanel tracking library for Java.
2+
3+
## Latest Version
24

3-
Latest Version
4-
--------------
55
##### _May 08, 2024_ - [v1.5.3](https://github.com/mixpanel/mixpanel-java/releases/tag/mixpanel-java-1.5.3)
6+
67
```
78
<dependency>
89
<groupId>com.mixpanel</groupId>
@@ -13,8 +14,8 @@ Latest Version
1314

1415
You can alternatively download the library jar directly from Maven Central [here](https://central.sonatype.com/artifact/com.mixpanel/mixpanel-java).
1516

16-
How To Use
17-
----------
17+
## How To Use
18+
1819
The library is designed to produce events and people updates in one process or thread, and
1920
consume the events and people updates in another thread or process. Specially formatted JSON objects
2021
are built by `MessageBuilder` objects, and those messages can be consumed by the
@@ -42,17 +43,84 @@ Gzip compression can reduce bandwidth usage and improve performance, especially
4243

4344
The library supports importing historical events (events older than 5 days that are not accepted using /track) via the `/import` endpoint. Project token will be used for basic auth.
4445

45-
Learn More
46-
----------
46+
## Feature Flags
47+
48+
The Mixpanel Java SDK supports feature flags with both local and remote evaluation modes.
49+
50+
### Local Evaluation (Recommended)
51+
52+
Fast, low-latency flag checks with background polling for flag definitions:
53+
54+
```java
55+
import com.mixpanel.mixpanelapi.*;
56+
import com.mixpanel.mixpanelapi.featureflags.config.*;
57+
import java.util.*;
58+
59+
// Initialize with your project token
60+
LocalFlagsConfig config = LocalFlagsConfig.builder()
61+
.projectToken("YOUR_PROJECT_TOKEN")
62+
.pollingIntervalSeconds(60)
63+
.build();
64+
65+
MixpanelAPI mixpanel = new MixpanelAPI(config);
66+
67+
// Start polling for flag definitions
68+
mixpanel.getLocalFlags().startPollingForDefinitions();
69+
70+
// Wait for flags to be ready (optional but recommended)
71+
while (!mixpanel.getLocalFlags().areFlagsReady()) {
72+
Thread.sleep(100);
73+
}
74+
75+
// Evaluate flags
76+
Map<String, Object> context = new HashMap<>();
77+
context.put("distinct_id", "user-123");
78+
79+
// Check if a feature is enabled
80+
boolean isEnabled = mixpanel.getLocalFlags().isEnabled("new-feature", context);
81+
82+
// Get a variant value with fallback
83+
String theme = mixpanel.getLocalFlags().getVariantValue("ui-theme", "light", context);
84+
85+
// Cleanup
86+
mixpanel.close();
87+
```
88+
89+
### Remote Evaluation
90+
91+
Real-time flag evaluation with server-side API calls:
92+
93+
```java
94+
import com.mixpanel.mixpanelapi.*;
95+
import com.mixpanel.mixpanelapi.featureflags.config.*;
96+
import java.util.*;
97+
98+
RemoteFlagsConfig config = RemoteFlagsConfig.builder()
99+
.projectToken("YOUR_PROJECT_TOKEN")
100+
.build();
101+
102+
try (MixpanelAPI mixpanel = new MixpanelAPI(config)) {
103+
Map<String, Object> context = new HashMap<>();
104+
context.put("distinct_id", "user-456");
105+
106+
boolean isEnabled = mixpanel.getRemoteFlags().isEnabled("premium-features", context);
107+
}
108+
```
109+
110+
For complete feature flags documentation, configuration options, advanced usage, and best practices, see:
111+
112+
https://docs.mixpanel.com/docs/tracking-methods/sdks/java/java-flags
113+
114+
## Learn More
115+
47116
This library in particular has more in-depth documentation at
48117

49118
https://mixpanel.com/docs/integration-libraries/java
50-
119+
51120
Mixpanel maintains documentation at
52121

53122
http://www.mixpanel.com/docs
54123

55-
56124
The library also contains a simple demo application, that demonstrates
57125
using this library in an asynchronous environment.
58126

@@ -62,9 +130,9 @@ support for persistent properties, etc. Two interesting ones are at:
62130

63131
https://github.com/eranation/mixpanel-java
64132
https://github.com/scalascope/mixpanel-java
65-
66-
Other Mixpanel Libraries
67-
------------------------
133+
134+
## Other Mixpanel Libraries
135+
68136
Mixpanel also maintains a full-featured library for tracking events from Android apps at https://github.com/mixpanel/mixpanel-android
69137

70138
And a full-featured client side library for web applications, in Javascript, that can be loaded
@@ -73,8 +141,7 @@ directly from Mixpanel servers. To learn more about our Javascript library, see:
73141
This library is intended for use in back end applications or API services that can't take
74142
advantage of the Android libraries or the Javascript library.
75143

76-
License
77-
-------
144+
## License
78145

79146
```
80147
See LICENSE File for details. The Base64Coder class used by this software

pom.xml

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
<groupId>com.mixpanel</groupId>
55
<artifactId>mixpanel-java</artifactId>
6-
<version>1.5.4</version>
6+
<version>1.6.0-flags</version>
77
<packaging>jar</packaging>
88
<name>mixpanel-java</name>
99
<description>
@@ -50,6 +50,16 @@
5050
</distributionManagement>
5151

5252
<build>
53+
<resources>
54+
<resource>
55+
<directory>src/main/resources</directory>
56+
<filtering>true</filtering>
57+
<includes>
58+
<include>**/*.properties</include>
59+
</includes>
60+
</resource>
61+
</resources>
62+
5363
<plugins>
5464
<!-- Central Publishing Maven Plugin for Maven Central Portal -->
5565
<plugin>
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
package com.mixpanel.mixpanelapi.featureflags.demo;
2+
3+
import com.mixpanel.mixpanelapi.MixpanelAPI;
4+
import com.mixpanel.mixpanelapi.featureflags.config.LocalFlagsConfig;
5+
import com.mixpanel.mixpanelapi.featureflags.model.SelectedVariant;
6+
7+
import java.util.HashMap;
8+
import java.util.Map;
9+
10+
/**
11+
* Example demonstrating local feature flag evaluation.
12+
*
13+
* This example shows how to:
14+
* 1. Configure and initialize a local flags client
15+
* 2. Start polling for flag definitions
16+
* 3. Evaluate flags with different contexts
17+
* 4. Properly clean up resources
18+
*/
19+
public class LocalEvaluationExample {
20+
21+
public static void main(String[] args) throws Exception {
22+
// Replace with your actual Mixpanel project token
23+
String projectToken = "YOUR_PROJECT_TOKEN";
24+
25+
// 1. Configure local evaluation
26+
LocalFlagsConfig config = LocalFlagsConfig.builder()
27+
.projectToken(projectToken)
28+
.apiHost("api.mixpanel.com") // Use "api-eu.mixpanel.com" for EU
29+
.pollingIntervalSeconds(60) // Poll every 60 seconds
30+
.enablePolling(true) // Enable background polling
31+
.requestTimeoutSeconds(10) // 10 second timeout for HTTP requests
32+
.build();
33+
34+
try (MixpanelAPI mixpanel = new MixpanelAPI(config)) {
35+
36+
// 2. Start polling for flag definitions
37+
System.out.println("Starting flag polling...");
38+
mixpanel.getLocalFlags().startPollingForDefinitions();
39+
40+
System.out.println("Waiting for flags to be ready...");
41+
int retries = 0;
42+
while (!mixpanel.getLocalFlags().areFlagsReady() && retries < 50) {
43+
Thread.sleep(100);
44+
retries++;
45+
}
46+
47+
if (!mixpanel.getLocalFlags().areFlagsReady()) {
48+
System.err.println("Warning: Flags not ready after 5 seconds, will use fallback values");
49+
} else {
50+
System.out.println("Flags are ready!");
51+
}
52+
53+
// 3. Example 1: Simple boolean flag check
54+
System.out.println("\n=== Example 1: Boolean Flag ===");
55+
Map<String, Object> context1 = new HashMap<>();
56+
context1.put("distinct_id", "user-123");
57+
58+
boolean newFeatureEnabled = mixpanel.getLocalFlags().isEnabled(
59+
"new-checkout-flow",
60+
context1
61+
);
62+
63+
System.out.println("New checkout flow enabled: " + newFeatureEnabled);
64+
65+
// Example 2: String variant value
66+
System.out.println("\n=== Example 2: String Variant ===");
67+
String buttonColor = mixpanel.getLocalFlags().getVariantValue(
68+
"button-color",
69+
"blue", // fallback value
70+
context1
71+
);
72+
73+
System.out.println("Button color: " + buttonColor);
74+
75+
// Example 3: With custom properties for targeting
76+
System.out.println("\n=== Example 3: Targeted Flag ===");
77+
Map<String, Object> context2 = new HashMap<>();
78+
context2.put("distinct_id", "user-456");
79+
80+
// Add custom properties for runtime evaluation
81+
Map<String, Object> customProps = new HashMap<>();
82+
customProps.put("subscription_tier", "premium");
83+
customProps.put("country", "US");
84+
context2.put("custom_properties", customProps);
85+
86+
boolean premiumFeatureEnabled = mixpanel.getLocalFlags().isEnabled(
87+
"premium-analytics-dashboard",
88+
context2
89+
);
90+
91+
System.out.println("Premium analytics enabled: " + premiumFeatureEnabled);
92+
93+
// Example 4: Get full variant information
94+
System.out.println("\n=== Example 4: Full Variant Info ===");
95+
SelectedVariant<Object> variant = mixpanel.getLocalFlags().getVariant(
96+
"recommendation-algorithm",
97+
new SelectedVariant<>("default-algorithm"), // fallback
98+
context1
99+
);
100+
101+
if (variant.isSuccess()) {
102+
System.out.println("Variant key: " + variant.getVariantKey());
103+
System.out.println("Variant value: " + variant.getVariantValue());
104+
} else {
105+
System.out.println("Using fallback variant");
106+
}
107+
108+
// Example 5: Number variant
109+
System.out.println("\n=== Example 5: Number Variant ===");
110+
Integer maxItems = mixpanel.getLocalFlags().getVariantValue(
111+
"max-cart-items",
112+
10, // fallback value
113+
context1
114+
);
115+
116+
System.out.println("Max cart items: " + maxItems);
117+
118+
System.out.println("\n=== Example Complete ===");
119+
System.out.println("MixpanelAPI will be automatically closed");
120+
121+
// 4. Properly clean up resources
122+
mixpanel.close();
123+
124+
}
125+
126+
System.out.println("Resources cleaned up successfully");
127+
}
128+
}

0 commit comments

Comments
 (0)