18
18
19
19
import com .optimizely .ab .annotations .VisibleForTesting ;
20
20
import com .optimizely .ab .bucketing .Bucketer ;
21
- import com .optimizely .ab .bucketing .UserExperimentRecord ;
21
+ import com .optimizely .ab .bucketing .UserProfile ;
22
22
import com .optimizely .ab .config .Attribute ;
23
23
import com .optimizely .ab .config .EventType ;
24
24
import com .optimizely .ab .config .Experiment ;
25
+ import com .optimizely .ab .config .LiveVariable ;
26
+ import com .optimizely .ab .config .LiveVariableUsageInstance ;
25
27
import com .optimizely .ab .config .ProjectConfig ;
26
28
import com .optimizely .ab .config .Variation ;
27
29
import com .optimizely .ab .config .parser .ConfigParseException ;
@@ -102,7 +104,7 @@ private Optimizely(@Nonnull ProjectConfig projectConfig,
102
104
103
105
// Do work here that should be done once per Optimizely lifecycle
104
106
@ VisibleForTesting void initialize () {
105
- bucketer .cleanUserExperimentRecords ();
107
+ bucketer .cleanUserProfiles ();
106
108
}
107
109
108
110
//======== activate calls ========//
@@ -253,12 +255,136 @@ private void track(@Nonnull String eventName,
253
255
}
254
256
}
255
257
258
+ //======== live variable getters ========//
259
+
260
+ public @ Nullable String getVariableString (@ Nonnull String variableKey ,
261
+ boolean activateExperiment ,
262
+ @ Nonnull String userId ) throws UnknownLiveVariableException {
263
+ return getVariableString (variableKey , activateExperiment , userId , Collections .<String , String >emptyMap ());
264
+ }
265
+
266
+ public @ Nullable String getVariableString (@ Nonnull String variableKey ,
267
+ boolean activateExperiment ,
268
+ @ Nonnull String userId ,
269
+ @ Nonnull Map <String , String > attributes )
270
+ throws UnknownLiveVariableException {
271
+
272
+ LiveVariable variable = getLiveVariableOrThrow (projectConfig , variableKey );
273
+ if (variable == null ) {
274
+ return null ;
275
+ }
276
+
277
+ List <Experiment > experimentsUsingLiveVariable =
278
+ projectConfig .getLiveVariableIdToExperimentsMapping ().get (variable .getId ());
279
+ Map <String , Map <String , LiveVariableUsageInstance >> variationToLiveVariableUsageInstanceMapping =
280
+ projectConfig .getVariationToLiveVariableUsageInstanceMapping ();
281
+
282
+ if (experimentsUsingLiveVariable == null ) {
283
+ logger .warn ("No experiment is using variable \" {}\" ." , variable .getKey ());
284
+ return variable .getDefaultValue ();
285
+ }
286
+
287
+ for (Experiment experiment : experimentsUsingLiveVariable ) {
288
+ Variation variation ;
289
+ if (activateExperiment ) {
290
+ variation = activate (experiment , userId , attributes );
291
+ } else {
292
+ variation = getVariation (experiment , userId , attributes );
293
+ }
294
+
295
+ if (variation != null ) {
296
+ LiveVariableUsageInstance usageInstance =
297
+ variationToLiveVariableUsageInstanceMapping .get (variation .getId ()).get (variable .getId ());
298
+ return usageInstance .getValue ();
299
+ }
300
+ }
301
+
302
+ return variable .getDefaultValue ();
303
+ }
304
+
305
+ public @ Nullable Boolean getVariableBoolean (@ Nonnull String variableKey ,
306
+ boolean activateExperiment ,
307
+ @ Nonnull String userId ) throws UnknownLiveVariableException {
308
+ return getVariableBoolean (variableKey , activateExperiment , userId , Collections .<String , String >emptyMap ());
309
+ }
310
+
311
+ public @ Nullable Boolean getVariableBoolean (@ Nonnull String variableKey ,
312
+ boolean activateExperiment ,
313
+ @ Nonnull String userId ,
314
+ @ Nonnull Map <String , String > attributes )
315
+ throws UnknownLiveVariableException {
316
+
317
+ String variableValueString = getVariableString (variableKey , activateExperiment , userId , attributes );
318
+ if (variableValueString != null ) {
319
+ return Boolean .parseBoolean (variableValueString );
320
+ }
321
+
322
+ return null ;
323
+ }
324
+
325
+ public @ Nullable Integer getVariableInteger (@ Nonnull String variableKey ,
326
+ boolean activateExperiment ,
327
+ @ Nonnull String userId ) throws UnknownLiveVariableException {
328
+ return getVariableInteger (variableKey , activateExperiment , userId , Collections .<String , String >emptyMap ());
329
+ }
330
+
331
+ public @ Nullable Integer getVariableInteger (@ Nonnull String variableKey ,
332
+ boolean activateExperiment ,
333
+ @ Nonnull String userId ,
334
+ @ Nonnull Map <String , String > attributes )
335
+ throws UnknownLiveVariableException {
336
+
337
+ String variableValueString = getVariableString (variableKey , activateExperiment , userId , attributes );
338
+ if (variableValueString != null ) {
339
+ try {
340
+ return Integer .parseInt (variableValueString );
341
+ } catch (NumberFormatException e ) {
342
+ logger .error ("Variable value \" {}\" for live variable \" {}\" is not an integer." , variableValueString ,
343
+ variableKey );
344
+ }
345
+ }
346
+
347
+ return null ;
348
+ }
349
+
350
+ public @ Nullable Float getVariableFloat (@ Nonnull String variableKey ,
351
+ boolean activateExperiment ,
352
+ @ Nonnull String userId ) throws UnknownLiveVariableException {
353
+ return getVariableFloat (variableKey , activateExperiment , userId , Collections .<String , String >emptyMap ());
354
+ }
355
+
356
+ public @ Nullable Float getVariableFloat (@ Nonnull String variableKey ,
357
+ boolean activateExperiment ,
358
+ @ Nonnull String userId ,
359
+ @ Nonnull Map <String , String > attributes )
360
+ throws UnknownLiveVariableException {
361
+
362
+ String variableValueString = getVariableString (variableKey , activateExperiment , userId , attributes );
363
+ if (variableValueString != null ) {
364
+ try {
365
+ return Float .parseFloat (variableValueString );
366
+ } catch (NumberFormatException e ) {
367
+ logger .error ("Variable value \" {}\" for live variable \" {}\" is not a float." , variableValueString ,
368
+ variableKey );
369
+ }
370
+ }
371
+
372
+ return null ;
373
+ }
374
+
256
375
//======== getVariation calls ========//
257
376
258
377
public @ Nullable Variation getVariation (@ Nonnull Experiment experiment ,
259
378
@ Nonnull String userId ) throws UnknownExperimentException {
260
379
261
- return getVariation (getProjectConfig (), experiment , Collections .<String , String >emptyMap (), userId );
380
+ return getVariation (experiment , userId , Collections .<String , String >emptyMap ());
381
+ }
382
+
383
+ public @ Nullable Variation getVariation (@ Nonnull Experiment experiment ,
384
+ @ Nonnull String userId ,
385
+ @ Nonnull Map <String , String > attributes ) throws UnknownExperimentException {
386
+
387
+ return getVariation (getProjectConfig (), experiment , attributes , userId );
262
388
}
263
389
264
390
public @ Nullable Variation getVariation (@ Nonnull String experimentKey ,
@@ -372,6 +498,36 @@ private EventType getEventTypeOrThrow(ProjectConfig projectConfig, String eventN
372
498
return eventType ;
373
499
}
374
500
501
+ /**
502
+ * Helper method to retrieve the {@link LiveVariable} for the given variable key.
503
+ * If {@link RaiseExceptionErrorHandler} is provided, either a live variable is returned, or an exception is
504
+ * thrown.
505
+ * If {@link NoOpErrorHandler} is used, either a live variable or {@code null} is returned.
506
+ *
507
+ * @param projectConfig the current project config
508
+ * @param variableKey the key for the live variable being retrieved from the current project config
509
+ * @return the live variable to retrieve for the given variable key
510
+ *
511
+ * @throws UnknownLiveVariableException if there are no event types in the current project config with the given
512
+ * name
513
+ */
514
+ private LiveVariable getLiveVariableOrThrow (ProjectConfig projectConfig , String variableKey )
515
+ throws UnknownLiveVariableException {
516
+
517
+ LiveVariable liveVariable = projectConfig
518
+ .getLiveVariableKeyMapping ()
519
+ .get (variableKey );
520
+
521
+ if (liveVariable == null ) {
522
+ String unknownLiveVariableKeyError =
523
+ String .format ("Live variable \" %s\" is not in the datafile." , variableKey );
524
+ logger .error (unknownLiveVariableKeyError );
525
+ errorHandler .handleError (new UnknownLiveVariableException (unknownLiveVariableKeyError ));
526
+ }
527
+
528
+ return liveVariable ;
529
+ }
530
+
375
531
/**
376
532
* Helper method to verify that the given attributes map contains only keys that are present in the
377
533
* {@link ProjectConfig}.
@@ -420,6 +576,7 @@ private boolean validateUserId(String userId) {
420
576
421
577
return true ;
422
578
}
579
+
423
580
//======== Builder ========//
424
581
425
582
public static Builder builder (@ Nonnull String datafile ,
@@ -439,7 +596,7 @@ public static class Builder {
439
596
440
597
private String datafile ;
441
598
private Bucketer bucketer ;
442
- private UserExperimentRecord userExperimentRecord ;
599
+ private UserProfile userProfile ;
443
600
private ErrorHandler errorHandler ;
444
601
private EventHandler eventHandler ;
445
602
private EventBuilder eventBuilder ;
@@ -458,8 +615,8 @@ public Builder withErrorHandler(ErrorHandler errorHandler) {
458
615
return this ;
459
616
}
460
617
461
- public Builder withUserExperimentRecord ( UserExperimentRecord userExperimentRecord ) {
462
- this .userExperimentRecord = userExperimentRecord ;
618
+ public Builder withUserProfile ( UserProfile userProfile ) {
619
+ this .userProfile = userProfile ;
463
620
return this ;
464
621
}
465
622
@@ -496,7 +653,7 @@ public Optimizely build() throws ConfigParseException {
496
653
497
654
// use the default bucketer and event builder, if no overrides were provided
498
655
if (bucketer == null ) {
499
- bucketer = new Bucketer (projectConfig , userExperimentRecord );
656
+ bucketer = new Bucketer (projectConfig , userProfile );
500
657
}
501
658
502
659
if (clientEngine == null ) {
@@ -508,7 +665,7 @@ public Optimizely build() throws ConfigParseException {
508
665
}
509
666
510
667
if (eventBuilder == null ) {
511
- if (projectConfig .getVersion ().equals (ProjectConfig .V1 )) {
668
+ if (projectConfig .getVersion ().equals (ProjectConfig .Version . V1 . toString () )) {
512
669
eventBuilder = new EventBuilderV1 ();
513
670
} else {
514
671
eventBuilder = new EventBuilderV2 (clientEngine , clientVersion );
0 commit comments