|
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;
|
@@ -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,
|
@@ -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