3
3
import static cloud .eppo .Constants .DEFAULT_JITTER_INTERVAL_RATIO ;
4
4
import static cloud .eppo .Constants .DEFAULT_POLLING_INTERVAL_MILLIS ;
5
5
import static cloud .eppo .Utils .throwIfEmptyOrNull ;
6
+ import static cloud .eppo .Utils .throwIfNull ;
7
+ import static cloud .eppo .ValuedFlagEvaluationResultType .BAD_VALUE_TYPE ;
8
+ import static cloud .eppo .ValuedFlagEvaluationResultType .BAD_VARIATION_TYPE ;
9
+ import static cloud .eppo .ValuedFlagEvaluationResultType .FLAG_DISABLED ;
10
+ import static cloud .eppo .ValuedFlagEvaluationResultType .NO_ALLOCATION ;
11
+ import static cloud .eppo .ValuedFlagEvaluationResultType .NO_FLAG_CONFIG ;
12
+ import static cloud .eppo .ValuedFlagEvaluationResultType .OK ;
6
13
7
14
import cloud .eppo .api .*;
8
15
import cloud .eppo .cache .AssignmentCacheEntry ;
@@ -190,28 +197,33 @@ protected CompletableFuture<Void> loadConfigurationAsync() {
190
197
return future ;
191
198
}
192
199
193
- protected EppoValue getTypedAssignment (
194
- String flagKey ,
195
- String subjectKey ,
196
- Attributes subjectAttributes ,
197
- EppoValue defaultValue ,
198
- VariationType expectedType ) {
199
-
200
+ @ NotNull
201
+ protected ValuedFlagEvaluationResult getTypedAssignmentResult (
202
+ @ NotNull String flagKey ,
203
+ @ NotNull String subjectKey ,
204
+ @ NotNull Attributes subjectAttributes ,
205
+ @ NotNull EppoValue defaultValue ,
206
+ @ NotNull VariationType expectedType ) {
200
207
throwIfEmptyOrNull (flagKey , "flagKey must not be empty" );
201
208
throwIfEmptyOrNull (subjectKey , "subjectKey must not be empty" );
209
+ throwIfNull (subjectAttributes , "subjectAttributes must not be empty" );
210
+ throwIfNull (defaultValue , "defaultValue must not be empty" );
211
+ throwIfNull (expectedType , "expectedType must not be empty" );
202
212
203
- Configuration config = getConfiguration ();
213
+ @ NotNull final Configuration config = getConfiguration ();
204
214
205
- FlagConfig flag = config .getFlag (flagKey );
206
- if (flag == null ) {
215
+ @ Nullable final FlagConfig maybeFlag = config .getFlag (flagKey );
216
+ if (maybeFlag == null ) {
207
217
log .warn ("no configuration found for key: {}" , flagKey );
208
- return defaultValue ;
218
+ return new ValuedFlagEvaluationResult ( defaultValue , null , NO_FLAG_CONFIG ) ;
209
219
}
210
220
221
+ @ NotNull final FlagConfig flag = maybeFlag ;
222
+
211
223
if (!flag .isEnabled ()) {
212
224
log .info (
213
225
"no assigned variation because the experiment or feature flag is disabled: {}" , flagKey );
214
- return defaultValue ;
226
+ return new ValuedFlagEvaluationResult ( defaultValue , null , FLAG_DISABLED ) ;
215
227
}
216
228
217
229
if (flag .getVariationType () != expectedType ) {
@@ -220,74 +232,94 @@ protected EppoValue getTypedAssignment(
220
232
flagKey ,
221
233
flag .getVariationType (),
222
234
expectedType );
223
- return defaultValue ;
235
+ return new ValuedFlagEvaluationResult ( defaultValue , null , BAD_VARIATION_TYPE ) ;
224
236
}
225
237
226
- FlagEvaluationResult evaluationResult =
238
+ @ NotNull final FlagEvaluationResult evaluationResult =
227
239
FlagEvaluator .evaluateFlag (
228
240
flag , flagKey , subjectKey , subjectAttributes , config .isConfigObfuscated ());
229
- EppoValue assignedValue =
230
- evaluationResult .getVariation () != null ? evaluationResult .getVariation ().getValue () : null ;
231
-
232
- if (assignedValue != null && !valueTypeMatchesExpected (expectedType , assignedValue )) {
233
- log .warn (
241
+ @ Nullable final FlagEvaluationAllocationKeyAndVariation allocationKeyAndVariation =
242
+ evaluationResult .getAllocationKeyAndVariation ();
243
+
244
+ @ NotNull final ValuedFlagEvaluationResult valuedEvaluationResult ;
245
+ if (allocationKeyAndVariation == null ) {
246
+ valuedEvaluationResult = new ValuedFlagEvaluationResult (defaultValue , evaluationResult , NO_ALLOCATION );
247
+ } else {
248
+ @ NotNull final EppoValue assignedValue = allocationKeyAndVariation .getVariation ().getValue ();
249
+ if (!valueTypeMatchesExpected (expectedType , assignedValue )) {
250
+ log .warn (
234
251
"no assigned variation because the flag type doesn't match the variation type: {} has type {}, variation value is {}" ,
235
252
flagKey ,
236
253
flag .getVariationType (),
237
254
assignedValue );
238
- return defaultValue ;
239
- }
255
+ return new ValuedFlagEvaluationResult (defaultValue , evaluationResult , BAD_VALUE_TYPE );
256
+ } else {
257
+ valuedEvaluationResult = new ValuedFlagEvaluationResult (assignedValue , evaluationResult , OK );
258
+ if (assignmentLogger != null && evaluationResult .doLog ()) {
240
259
241
- if (assignedValue != null && assignmentLogger != null && evaluationResult .doLog ()) {
242
-
243
- try {
244
- String allocationKey = evaluationResult .getAllocationKey ();
245
- String experimentKey =
246
- flagKey
247
- + '-'
248
- + allocationKey ; // Our experiment key is derived by hyphenating the flag key and
249
- // allocation key
250
- String variationKey = evaluationResult .getVariation ().getKey ();
251
- Map <String , String > extraLogging = evaluationResult .getExtraLogging ();
252
- Map <String , String > metaData = buildLogMetaData (config .isConfigObfuscated ());
253
-
254
- Assignment assignment =
255
- new Assignment (
256
- experimentKey ,
257
- flagKey ,
258
- allocationKey ,
259
- variationKey ,
260
- subjectKey ,
261
- subjectAttributes ,
262
- extraLogging ,
263
- metaData );
264
-
265
- // Deduplication of assignment logging is possible by providing an `IAssignmentCache`.
266
- // Default to true, only avoid logging if there's a cache hit.
267
- boolean logAssignment = true ;
268
- AssignmentCacheEntry cacheEntry = AssignmentCacheEntry .fromVariationAssignment (assignment );
269
- if (assignmentCache != null ) {
270
- if (assignmentCache .hasEntry (cacheEntry )) {
271
- logAssignment = false ;
272
- }
273
- }
260
+ try {
261
+ @ NotNull final String allocationKey = allocationKeyAndVariation .getAllocationKey ();
262
+ @ NotNull final String experimentKey =
263
+ flagKey
264
+ + '-'
265
+ + allocationKey ; // Our experiment key is derived by hyphenating the flag key and
266
+ // allocation key
267
+ @ NotNull final String variationKey = allocationKeyAndVariation .getVariation ().getKey ();
268
+ @ NotNull final Map <String , String > extraLogging = evaluationResult .getExtraLogging ();
269
+ @ NotNull final Map <String , String > metaData = buildLogMetaData (config .isConfigObfuscated ());
270
+
271
+ @ NotNull final Assignment assignment =
272
+ new Assignment (
273
+ experimentKey ,
274
+ flagKey ,
275
+ allocationKey ,
276
+ variationKey ,
277
+ subjectKey ,
278
+ subjectAttributes ,
279
+ extraLogging ,
280
+ metaData );
281
+
282
+ // Deduplication of assignment logging is possible by providing an `IAssignmentCache`.
283
+ // Default to true, only avoid logging if there's a cache hit.
284
+ boolean logAssignment = true ;
285
+ @ NotNull final AssignmentCacheEntry cacheEntry = AssignmentCacheEntry .fromVariationAssignment (assignment );
286
+ if (assignmentCache != null ) {
287
+ if (assignmentCache .hasEntry (cacheEntry )) {
288
+ logAssignment = false ;
289
+ }
290
+ }
274
291
275
- if (logAssignment ) {
276
- assignmentLogger .logAssignment (assignment );
292
+ if (logAssignment ) {
293
+ assignmentLogger .logAssignment (assignment );
277
294
278
- if (assignmentCache != null ) {
279
- assignmentCache .put (cacheEntry );
295
+ if (assignmentCache != null ) {
296
+ assignmentCache .put (cacheEntry );
297
+ }
298
+ }
299
+
300
+ } catch (Exception e ) {
301
+ log .error ("Error logging assignment: {}" , e .getMessage (), e );
280
302
}
281
303
}
282
-
283
- } catch (Exception e ) {
284
- log .error ("Error logging assignment: {}" , e .getMessage (), e );
285
304
}
286
305
}
287
- return assignedValue != null ? assignedValue : defaultValue ;
306
+ return valuedEvaluationResult ;
307
+ }
308
+
309
+ @ NotNull
310
+ protected EppoValue getTypedAssignment (
311
+ @ NotNull String flagKey ,
312
+ @ NotNull String subjectKey ,
313
+ @ NotNull Attributes subjectAttributes ,
314
+ @ NotNull EppoValue defaultValue ,
315
+ @ NotNull VariationType expectedType ) {
316
+
317
+ @ NotNull final ValuedFlagEvaluationResult valuedEvaluationResult = getTypedAssignmentResult (
318
+ flagKey , subjectKey , subjectAttributes , defaultValue , expectedType );
319
+ return valuedEvaluationResult .getValue ();
288
320
}
289
321
290
- private boolean valueTypeMatchesExpected (VariationType expectedType , EppoValue value ) {
322
+ private boolean valueTypeMatchesExpected (@ NotNull VariationType expectedType , @ NotNull EppoValue value ) {
291
323
boolean typeMatch ;
292
324
switch (expectedType ) {
293
325
case BOOLEAN :
@@ -318,14 +350,14 @@ private boolean valueTypeMatchesExpected(VariationType expectedType, EppoValue v
318
350
return typeMatch ;
319
351
}
320
352
321
- public boolean getBooleanAssignment (String flagKey , String subjectKey , boolean defaultValue ) {
353
+ public boolean getBooleanAssignment (@ NotNull String flagKey , @ NotNull String subjectKey , boolean defaultValue ) {
322
354
return this .getBooleanAssignment (flagKey , subjectKey , new Attributes (), defaultValue );
323
355
}
324
356
325
357
public boolean getBooleanAssignment (
326
- String flagKey , String subjectKey , Attributes subjectAttributes , boolean defaultValue ) {
358
+ @ NotNull String flagKey , @ NotNull String subjectKey , @ NotNull Attributes subjectAttributes , boolean defaultValue ) {
327
359
try {
328
- EppoValue value =
360
+ @ NotNull final EppoValue value =
329
361
this .getTypedAssignment (
330
362
flagKey ,
331
363
subjectKey ,
@@ -338,14 +370,14 @@ public boolean getBooleanAssignment(
338
370
}
339
371
}
340
372
341
- public int getIntegerAssignment (String flagKey , String subjectKey , int defaultValue ) {
373
+ public int getIntegerAssignment (@ NotNull String flagKey , @ NotNull String subjectKey , int defaultValue ) {
342
374
return getIntegerAssignment (flagKey , subjectKey , new Attributes (), defaultValue );
343
375
}
344
376
345
377
public int getIntegerAssignment (
346
- String flagKey , String subjectKey , Attributes subjectAttributes , int defaultValue ) {
378
+ @ NotNull String flagKey , @ NotNull String subjectKey , @ NotNull Attributes subjectAttributes , int defaultValue ) {
347
379
try {
348
- EppoValue value =
380
+ @ NotNull final EppoValue value =
349
381
this .getTypedAssignment (
350
382
flagKey ,
351
383
subjectKey ,
@@ -358,14 +390,16 @@ public int getIntegerAssignment(
358
390
}
359
391
}
360
392
361
- public Double getDoubleAssignment (String flagKey , String subjectKey , double defaultValue ) {
393
+ @ NotNull
394
+ public Double getDoubleAssignment (@ NotNull String flagKey , @ NotNull String subjectKey , double defaultValue ) {
362
395
return getDoubleAssignment (flagKey , subjectKey , new Attributes (), defaultValue );
363
396
}
364
397
398
+ @ NotNull
365
399
public Double getDoubleAssignment (
366
- String flagKey , String subjectKey , Attributes subjectAttributes , double defaultValue ) {
400
+ @ NotNull String flagKey , @ NotNull String subjectKey , @ NotNull Attributes subjectAttributes , double defaultValue ) {
367
401
try {
368
- EppoValue value =
402
+ @ NotNull final EppoValue value =
369
403
this .getTypedAssignment (
370
404
flagKey ,
371
405
subjectKey ,
@@ -378,14 +412,16 @@ public Double getDoubleAssignment(
378
412
}
379
413
}
380
414
381
- public String getStringAssignment (String flagKey , String subjectKey , String defaultValue ) {
415
+ @ NotNull
416
+ public String getStringAssignment (@ NotNull String flagKey , @ NotNull String subjectKey , @ NotNull String defaultValue ) {
382
417
return this .getStringAssignment (flagKey , subjectKey , new Attributes (), defaultValue );
383
418
}
384
419
420
+ @ NotNull
385
421
public String getStringAssignment (
386
- String flagKey , String subjectKey , Attributes subjectAttributes , String defaultValue ) {
422
+ @ NotNull String flagKey , @ NotNull String subjectKey , @ NotNull Attributes subjectAttributes , @ NotNull String defaultValue ) {
387
423
try {
388
- EppoValue value =
424
+ @ NotNull final EppoValue value =
389
425
this .getTypedAssignment (
390
426
flagKey ,
391
427
subjectKey ,
@@ -408,7 +444,8 @@ public String getStringAssignment(
408
444
* @param defaultValue the default value to return if the flag is not found
409
445
* @return the JSON string value of the assignment
410
446
*/
411
- public JsonNode getJSONAssignment (String flagKey , String subjectKey , JsonNode defaultValue ) {
447
+ @ NotNull
448
+ public JsonNode getJSONAssignment (@ NotNull String flagKey , @ NotNull String subjectKey , @ NotNull JsonNode defaultValue ) {
412
449
return getJSONAssignment (flagKey , subjectKey , new Attributes (), defaultValue );
413
450
}
414
451
@@ -422,17 +459,19 @@ public JsonNode getJSONAssignment(String flagKey, String subjectKey, JsonNode de
422
459
* @param defaultValue the default value to return if the flag is not found
423
460
* @return the JSON string value of the assignment
424
461
*/
462
+ @ NotNull
425
463
public JsonNode getJSONAssignment (
426
- String flagKey , String subjectKey , Attributes subjectAttributes , JsonNode defaultValue ) {
464
+ @ NotNull String flagKey , @ NotNull String subjectKey , @ NotNull Attributes subjectAttributes , @ NotNull JsonNode defaultValue ) {
427
465
try {
428
- EppoValue value =
466
+ @ NotNull final EppoValue value =
429
467
this .getTypedAssignment (
430
468
flagKey ,
431
469
subjectKey ,
432
470
subjectAttributes ,
433
471
EppoValue .valueOf (defaultValue .toString ()),
434
472
VariationType .JSON );
435
- return parseJsonString (value .stringValue ());
473
+ @ Nullable final JsonNode jsonValue = parseJsonString (value .stringValue ());
474
+ return jsonValue != null ? jsonValue : defaultValue ;
436
475
} catch (Exception e ) {
437
476
return throwIfNotGraceful (e , defaultValue );
438
477
}
@@ -448,10 +487,11 @@ public JsonNode getJSONAssignment(
448
487
* @param defaultValue the default value to return if the flag is not found
449
488
* @return the JSON string value of the assignment
450
489
*/
490
+ @ NotNull
451
491
public String getJSONStringAssignment (
452
- String flagKey , String subjectKey , Attributes subjectAttributes , String defaultValue ) {
492
+ @ NotNull String flagKey , @ NotNull String subjectKey , @ NotNull Attributes subjectAttributes , @ NotNull String defaultValue ) {
453
493
try {
454
- EppoValue value =
494
+ @ NotNull final EppoValue value =
455
495
this .getTypedAssignment (
456
496
flagKey ,
457
497
subjectKey ,
@@ -474,11 +514,13 @@ public String getJSONStringAssignment(
474
514
* @param defaultValue the default value to return if the flag is not found
475
515
* @return the JSON string value of the assignment
476
516
*/
477
- public String getJSONStringAssignment (String flagKey , String subjectKey , String defaultValue ) {
517
+ @ NotNull
518
+ public String getJSONStringAssignment (@ NotNull String flagKey , @ NotNull String subjectKey , @ NotNull String defaultValue ) {
478
519
return this .getJSONStringAssignment (flagKey , subjectKey , new Attributes (), defaultValue );
479
520
}
480
521
481
- private JsonNode parseJsonString (String jsonString ) {
522
+ @ Nullable
523
+ private JsonNode parseJsonString (@ NotNull String jsonString ) {
482
524
try {
483
525
return mapper .readTree (jsonString );
484
526
} catch (JsonProcessingException e ) {
@@ -557,15 +599,17 @@ public BanditResult getBanditAction(
557
599
}
558
600
}
559
601
602
+ @ NotNull
560
603
private Map <String , String > buildLogMetaData (boolean isConfigObfuscated ) {
561
- HashMap <String , String > metaData = new HashMap <>();
604
+ @ NotNull final HashMap <String , String > metaData = new HashMap <>();
562
605
metaData .put ("obfuscated" , Boolean .valueOf (isConfigObfuscated ).toString ());
563
606
metaData .put ("sdkLanguage" , sdkName );
564
607
metaData .put ("sdkLibVersion" , sdkVersion );
565
608
return metaData ;
566
609
}
567
610
568
- private <T > T throwIfNotGraceful (Exception e , T defaultValue ) {
611
+ @ NotNull
612
+ private <T > T throwIfNotGraceful (@ NotNull Exception e , @ NotNull T defaultValue ) {
569
613
if (this .isGracefulMode ) {
570
614
log .info ("error getting assignment value: {}" , e .getMessage ());
571
615
return defaultValue ;
0 commit comments