Skip to content

Commit 40913d1

Browse files
authored
Merge pull request #465 from splitio/development
Some Flag sets fixes
2 parents 31935fc + e712e61 commit 40913d1

File tree

19 files changed

+155
-46
lines changed

19 files changed

+155
-46
lines changed

CHANGES.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
4.10.2 (Dec 1, 2023)
2+
- Added getTreatmentsByFlagSets without attributes.
3+
- Fixed some issues for flag sets: Not logging a warning when using flag sets that don't contain cached feature flags.
4+
15
4.10.1 (Nov 9, 2023)
26
- Fixed handler for response http headers.
37

client/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
<parent>
66
<groupId>io.split.client</groupId>
77
<artifactId>java-client-parent</artifactId>
8-
<version>4.10.1</version>
8+
<version>4.10.2</version>
99
</parent>
1010
<artifactId>java-client</artifactId>
1111
<packaging>jar</packaging>

client/src/main/java/io/split/client/SplitClient.java

Lines changed: 63 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -256,7 +256,7 @@ public interface SplitClient {
256256
Map<String, SplitResult> getTreatmentsWithConfig(String key, List<String> featureFlagNames, Map<String, Object> attributes);
257257

258258
/**
259-
* Same as {@link #getTreatments(Key, List<String>, Map)} but it returns for each feature flag the configuration associated to the
259+
* Same as {@link #getTreatments(Key, List, Map)} but it returns for each feature flag the configuration associated to the
260260
* matching treatment if any. Otherwise {@link SplitResult.configurations()} will be null.
261261
*
262262
* @param key the matching and bucketing keys. MUST NOT be null.
@@ -268,6 +268,21 @@ public interface SplitClient {
268268
*/
269269
Map<String, SplitResult> getTreatmentsWithConfig(Key key, List<String> featureFlagNames, Map<String, Object> attributes);
270270

271+
/**
272+
* Same as {@link #getTreatments(String, List<String>, Map)} but it returns for each feature flag the configuration associated to the
273+
* matching treatment if any. Otherwise {@link SplitResult.configurations()} will be null.
274+
* <p/>
275+
* <p/>
276+
* Examples include showing a different treatment to users on trial plan
277+
* vs. premium plan. Another example is to show a different treatment
278+
* to users created after a certain date.
279+
*
280+
* @param key a unique key of your customer (e.g. user_id, user_email, account_id, etc.) MUST not be null or empty.
281+
* @param flagSet the Flag Set name that you want to evaluate. MUST not be null or empty.
282+
* @return for each feature flag the evaluated treatment, the default treatment of this feature flag, or 'control'.
283+
*/
284+
Map<String, String> getTreatmentsByFlagSet(String key, String flagSet);
285+
271286
/**
272287
* Same as {@link #getTreatments(String, List<String>, Map)} but it returns for each feature flag the configuration associated to the
273288
* matching treatment if any. Otherwise {@link SplitResult.configurations()} will be null.
@@ -300,6 +315,21 @@ public interface SplitClient {
300315
*/
301316
Map<String, String> getTreatmentsByFlagSet(Key key, String flagSet, Map<String, Object> attributes);
302317

318+
/**
319+
* Same as {@link #getTreatments(String, List<String>, Map)} but it returns for each feature flag the configuration associated to the
320+
* matching treatment if any. Otherwise {@link SplitResult.configurations()} will be null.
321+
* <p/>
322+
* <p/>
323+
* Examples include showing a different treatment to users on trial plan
324+
* vs. premium plan. Another example is to show a different treatment
325+
* to users created after a certain date.
326+
*
327+
* @param key a unique key of your customer (e.g. user_id, user_email, account_id, etc.) MUST not be null or empty.
328+
* @param flagSets the names of Flag Sets that you want to evaluate. MUST not be null or empty.
329+
* @return for each feature flag the evaluated treatment, the default treatment of this feature flag, or 'control'.
330+
*/
331+
Map<String, String> getTreatmentsByFlagSets(String key, List<String> flagSets);
332+
303333
/**
304334
* Same as {@link #getTreatments(String, List<String>, Map)} but it returns for each feature flag the configuration associated to the
305335
* matching treatment if any. Otherwise {@link SplitResult.configurations()} will be null.
@@ -332,6 +362,22 @@ public interface SplitClient {
332362
*/
333363
Map<String, String> getTreatmentsByFlagSets(Key key, List<String> flagSets, Map<String, Object> attributes);
334364

365+
/**
366+
* Same as {@link #getTreatments(String, List<String>, Map)} but it returns for each feature flag the configuration associated to the
367+
* matching treatment if any. Otherwise {@link SplitResult.configurations()} will be null.
368+
* <p/>
369+
* <p/>
370+
* Examples include showing a different treatment to users on trial plan
371+
* vs. premium plan. Another example is to show a different treatment
372+
* to users created after a certain date.
373+
*
374+
* @param key a unique key of your customer (e.g. user_id, user_email, account_id, etc.) MUST not be null or empty.
375+
* @param flagSet the Flag Set name that you want to evaluate. MUST not be null or empty.
376+
* @return for each feature flag the evaluated treatment (the default treatment of this feature flag, or 'control') and a configuration
377+
* associated to this treatment if set.
378+
*/
379+
Map<String, SplitResult> getTreatmentsWithConfigByFlagSet(String key, String flagSet);
380+
335381
/**
336382
* Same as {@link #getTreatments(String, List<String>, Map)} but it returns for each feature flag the configuration associated to the
337383
* matching treatment if any. Otherwise {@link SplitResult.configurations()} will be null.
@@ -366,6 +412,22 @@ public interface SplitClient {
366412
*/
367413
Map<String, SplitResult> getTreatmentsWithConfigByFlagSet(Key key, String flagSet, Map<String, Object> attributes);
368414

415+
/**
416+
* Same as {@link #getTreatments(String, List<String>, Map)} but it returns for each feature flag the configuration associated to the
417+
* matching treatment if any. Otherwise {@link SplitResult.configurations()} will be null.
418+
* <p/>
419+
* <p/>
420+
* Examples include showing a different treatment to users on trial plan
421+
* vs. premium plan. Another example is to show a different treatment
422+
* to users created after a certain date.
423+
*
424+
* @param key a unique key of your customer (e.g. user_id, user_email, account_id, etc.) MUST not be null or empty.
425+
* @param flagSets the names of Flag Sets that you want to evaluate. MUST not be null or empty.
426+
* @return for each feature flag the evaluated treatment (the default treatment of this feature flag, or 'control') and a configuration
427+
* associated to this treatment if set.
428+
*/
429+
Map<String, SplitResult> getTreatmentsWithConfigByFlagSets(String key, List<String> flagSets);
430+
369431
/**
370432
* Same as {@link #getTreatments(String, List<String>, Map)} but it returns for each feature flag the configuration associated to the
371433
* matching treatment if any. Otherwise {@link SplitResult.configurations()} will be null.
@@ -444,7 +506,6 @@ public interface SplitClient {
444506
* @param key the identifier of the entity
445507
* @param trafficType the type of the event
446508
* @param eventType the type of the event
447-
* @param value the value of the event
448509
*
449510
* @return true if the track was successful, false otherwise
450511
*/

client/src/main/java/io/split/client/SplitClientImpl.java

Lines changed: 49 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ public final class SplitClientImpl implements SplitClient {
4848
public static final SplitResult SPLIT_RESULT_CONTROL = new SplitResult(Treatments.CONTROL, null);
4949
private static final String CLIENT_DESTROY = "Client has already been destroyed - no calls possible";
5050
private static final String CATCHALL_EXCEPTION = "CatchAll Exception";
51+
private static final String MATCHING_KEY = "matchingKey";
5152

5253
private static final Logger _log = LoggerFactory.getLogger(SplitClientImpl.class);
5354

@@ -150,6 +151,13 @@ public Map<String, SplitResult> getTreatmentsWithConfig(Key key, List<String> fe
150151
MethodEnum.TREATMENTS_WITH_CONFIG);
151152
}
152153

154+
@Override
155+
public Map<String, String> getTreatmentsByFlagSet(String key, String flagSet) {
156+
return getTreatmentsBySetsWithConfigInternal(key, null, new ArrayList<>(Arrays.asList(flagSet)),
157+
null, MethodEnum.TREATMENTS_BY_FLAG_SET).entrySet().stream()
158+
.collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().treatment()));
159+
}
160+
153161
@Override
154162
public Map<String, String> getTreatmentsByFlagSet(String key, String flagSet, Map<String, Object> attributes) {
155163
return getTreatmentsBySetsWithConfigInternal(key, null, new ArrayList<>(Arrays.asList(flagSet)),
@@ -164,6 +172,13 @@ public Map<String, String> getTreatmentsByFlagSet(Key key, String flagSet, Map<S
164172
.collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().treatment()));
165173
}
166174

175+
@Override
176+
public Map<String, String> getTreatmentsByFlagSets(String key, List<String> flagSets) {
177+
return getTreatmentsBySetsWithConfigInternal(key, null, flagSets,
178+
null, MethodEnum.TREATMENTS_BY_FLAG_SETS).entrySet().stream()
179+
.collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().treatment()));
180+
}
181+
167182
@Override
168183
public Map<String, String> getTreatmentsByFlagSets(String key, List<String> flagSets, Map<String, Object> attributes) {
169184
return getTreatmentsBySetsWithConfigInternal(key, null, flagSets,
@@ -178,6 +193,12 @@ public Map<String, String> getTreatmentsByFlagSets(Key key, List<String> flagSet
178193
.collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().treatment()));
179194
}
180195

196+
@Override
197+
public Map<String, SplitResult> getTreatmentsWithConfigByFlagSet(String key, String flagSet) {
198+
return getTreatmentsBySetsWithConfigInternal(key, null, new ArrayList<>(Arrays.asList(flagSet)),
199+
null, MethodEnum.TREATMENTS_WITH_CONFIG_BY_FLAG_SET);
200+
}
201+
181202
@Override
182203
public Map<String, SplitResult> getTreatmentsWithConfigByFlagSet(String key, String flagSet, Map<String, Object> attributes) {
183204
return getTreatmentsBySetsWithConfigInternal(key, null, new ArrayList<>(Arrays.asList(flagSet)),
@@ -190,6 +211,12 @@ public Map<String, SplitResult> getTreatmentsWithConfigByFlagSet(Key key, String
190211
attributes, MethodEnum.TREATMENTS_WITH_CONFIG_BY_FLAG_SET);
191212
}
192213

214+
@Override
215+
public Map<String, SplitResult> getTreatmentsWithConfigByFlagSets(String key, List<String> flagSets) {
216+
return getTreatmentsBySetsWithConfigInternal(key, null, flagSets,
217+
null, MethodEnum.TREATMENTS_WITH_CONFIG_BY_FLAG_SETS);
218+
}
219+
193220
@Override
194221
public Map<String, SplitResult> getTreatmentsWithConfigByFlagSets(String key, List<String> flagSets, Map<String, Object> attributes) {
195222
return getTreatmentsBySetsWithConfigInternal(key, null, flagSets,
@@ -295,7 +322,7 @@ private SplitResult getTreatmentWithConfigInternal(String matchingKey, String bu
295322
return SPLIT_RESULT_CONTROL;
296323
}
297324

298-
if (!KeyValidator.isValid(matchingKey, "matchingKey", _config.maxStringLength(), methodEnum.getMethod())) {
325+
if (!KeyValidator.isValid(matchingKey, MATCHING_KEY, _config.maxStringLength(), methodEnum.getMethod())) {
299326
return SPLIT_RESULT_CONTROL;
300327
}
301328

@@ -381,14 +408,14 @@ private Map<String, SplitResult> getTreatmentsBySetsWithConfigInternal(String ma
381408
return new HashMap<>();
382409
}
383410
Set cleanFlagSets = cleanup(sets);
384-
if (filterSetsAreInConfig(cleanFlagSets, methodEnum).isEmpty()) {
411+
cleanFlagSets = filterSetsAreInConfig(cleanFlagSets, methodEnum);
412+
if (cleanFlagSets.isEmpty()) {
385413
return new HashMap<>();
386414
}
387415
List<String> featureFlagNames = new ArrayList<>();
388416
try {
389417
checkSDKReady(methodEnum);
390-
featureFlagNames = getAllFlags(cleanFlagSets);
391-
Map<String, SplitResult> result = validateBeforeEvaluate(featureFlagNames, matchingKey, methodEnum,bucketingKey);
418+
Map<String, SplitResult> result = validateBeforeEvaluateByFlagSets(matchingKey, methodEnum,bucketingKey);
392419
if(result != null) {
393420
return result;
394421
}
@@ -405,7 +432,6 @@ private Map<String, SplitResult> getTreatmentsBySetsWithConfigInternal(String ma
405432
return createMapControl(featureFlagNames);
406433
}
407434
}
408-
409435
private Map<String, SplitResult> processEvaluatorResult(Map<String, EvaluatorImp.TreatmentLabelAndChangeNumber> evaluatorResult,
410436
MethodEnum methodEnum, String matchingKey, String bucketingKey, Map<String,
411437
Object> attributes, long initTime){
@@ -430,13 +456,28 @@ private Map<String, SplitResult> processEvaluatorResult(Map<String, EvaluatorImp
430456
return result;
431457
}
432458

459+
private Map<String, SplitResult> validateBeforeEvaluateByFlagSets(String matchingKey, MethodEnum methodEnum,
460+
String bucketingKey) {
461+
if (_container.isDestroyed()) {
462+
_log.error(CLIENT_DESTROY);
463+
return new HashMap<>();
464+
}
465+
if (!KeyValidator.isValid(matchingKey, MATCHING_KEY, _config.maxStringLength(), methodEnum.getMethod())) {
466+
return new HashMap<>();
467+
}
468+
if (!KeyValidator.bucketingKeyIsValid(bucketingKey, _config.maxStringLength(), methodEnum.getMethod())) {
469+
return new HashMap<>();
470+
}
471+
return null;
472+
}
473+
433474
private Map<String, SplitResult> validateBeforeEvaluate(List<String> featureFlagNames, String matchingKey, MethodEnum methodEnum,
434475
String bucketingKey) {
435476
if (_container.isDestroyed()) {
436477
_log.error(CLIENT_DESTROY);
437478
return createMapControl(featureFlagNames);
438479
}
439-
if (!KeyValidator.isValid(matchingKey, "matchingKey", _config.maxStringLength(), methodEnum.getMethod())) {
480+
if (!KeyValidator.isValid(matchingKey, MATCHING_KEY, _config.maxStringLength(), methodEnum.getMethod())) {
440481
return createMapControl(featureFlagNames);
441482
}
442483
if (!KeyValidator.bucketingKeyIsValid(bucketingKey, _config.maxStringLength(), methodEnum.getMethod())) {
@@ -447,8 +488,8 @@ private Map<String, SplitResult> validateBeforeEvaluate(List<String> featureFlag
447488
}
448489
return null;
449490
}
450-
private List<String> filterSetsAreInConfig(Set<String> sets, MethodEnum methodEnum) {
451-
List<String> setsToReturn = new ArrayList<>();
491+
private Set<String> filterSetsAreInConfig(Set<String> sets, MethodEnum methodEnum) {
492+
Set<String> setsToReturn = new HashSet<>();
452493
for (String set : sets) {
453494
if (!_flagSetsFilter.intersect(set)) {
454495
_log.warn(String.format("%s: you passed %s which is not part of the configured FlagSetsFilter, " +
@@ -459,16 +500,6 @@ private List<String> filterSetsAreInConfig(Set<String> sets, MethodEnum methodEn
459500
}
460501
return setsToReturn;
461502
}
462-
463-
private List<String> getAllFlags(Set<String> sets) {
464-
Map<String, HashSet<String>> namesBySets = _splitCacheConsumer.getNamesByFlagSets(new ArrayList<>(sets));
465-
HashSet<String> flags = new HashSet<>();
466-
for (String set: namesBySets.keySet()) {
467-
flags.addAll(namesBySets.get(set));
468-
}
469-
return new ArrayList<>(flags);
470-
}
471-
472503
private void recordStats(String matchingKey, String bucketingKey, String featureFlagName, long start, String result,
473504
String operation, String label, Long changeNumber, Map<String, Object> attributes) {
474505
try {

client/src/main/java/io/split/engine/evaluator/EvaluatorImp.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ private List<String> getFeatureFlagNamesByFlagSets(List<String> flagSets) {
6363
Map<String, HashSet<String>> namesByFlagSets = _splitCacheConsumer.getNamesByFlagSets(flagSets);
6464
for (String set: flagSets) {
6565
HashSet<String> flags = namesByFlagSets.get(set);
66-
if (flags == null) {
66+
if (flags == null || flags.isEmpty()) {
6767
_log.warn(String.format("You passed %s Flag Set that does not contain cached feature flag names, please double check " +
6868
"what Flag Sets are in use in the Split user interface.", set));
6969
continue;

client/src/main/java/io/split/inputValidation/FlagSetsValidator.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ public static Set<String> cleanup(List<String> flagSets) {
3333
}
3434
if (!Pattern.matches(FLAG_SET_REGEX, flagSet)) {
3535
_log.warn(String.format("you passed %s, Flag Set must adhere to the regular expressions %s. This means a Flag Set must be " +
36-
"start with a letter, be in lowercase, alphanumeric and have a max length of 50 characters. %s was discarded.",
36+
"start with a letter or number, be in lowercase, alphanumeric and have a max length of 50 characters. %s was discarded.",
3737
flagSet, FLAG_SET_REGEX, flagSet));
3838
continue;
3939
}

client/src/main/java/io/split/storages/memory/InMemoryCacheImp.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -110,9 +110,7 @@ public Map<String, HashSet<String>> getNamesByFlagSets(List<String> flagSets) {
110110
Map<String, HashSet<String>> toReturn = new HashMap<>();
111111
for (String set: flagSets) {
112112
HashSet<String> keys = _flagSets.get(set);
113-
if(keys != null){
114-
toReturn.put(set, keys);
115-
}
113+
toReturn.put(set, keys);
116114
}
117115
return toReturn;
118116
}

client/src/main/java/io/split/storages/pluggable/synchronizer/TelemetryConsumerSubmitter.java

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,6 @@ ConfigConsumer generateConfig(SplitClientConfig splitClientConfig, Map<String, L
6464
config.setActiveFactories(factoryInstances.size());
6565
config.setRedundantFactories(getRedundantFactories(factoryInstances));
6666
config.setTags(tags.size() < 10 ? tags : tags.subList(0, 10));
67-
int invalidSets = splitClientConfig.getInvalidSets();
68-
config.setFlagSetsTotal(splitClientConfig.getSetsFilter().size() + invalidSets);
69-
config.setFlagSetsInvalid(invalidSets);
7067
return config;
7168
}
7269

client/src/main/java/io/split/telemetry/synchronizer/HttpTelemetryMemorySender.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
import com.google.common.annotations.VisibleForTesting;
44
import io.split.client.dtos.UniqueKeys;
55
import io.split.client.utils.Utils;
6-
import io.split.engine.segments.SegmentFetcherImp;
76
import io.split.service.HttpPostImp;
87
import io.split.telemetry.domain.Config;
98
import io.split.telemetry.domain.Stats;

client/src/main/java/io/split/telemetry/synchronizer/TelemetrySyncTask.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package io.split.telemetry.synchronizer;
22

3-
import io.split.client.SplitClientConfig;
43
import org.slf4j.Logger;
54
import org.slf4j.LoggerFactory;
65

0 commit comments

Comments
 (0)