25
25
import com .optimizely .ab .error .ErrorHandler ;
26
26
import com .optimizely .ab .error .NoOpErrorHandler ;
27
27
import com .optimizely .ab .event .*;
28
- import com .optimizely .ab .event .internal .*;
28
+ import com .optimizely .ab .event .internal .ClientEngineInfo ;
29
+ import com .optimizely .ab .event .internal .EventFactory ;
30
+ import com .optimizely .ab .event .internal .UserEvent ;
31
+ import com .optimizely .ab .event .internal .UserEventFactory ;
29
32
import com .optimizely .ab .event .internal .payload .EventBatch ;
30
33
import com .optimizely .ab .notification .*;
31
34
import com .optimizely .ab .optimizelyconfig .OptimizelyConfig ;
32
35
import com .optimizely .ab .optimizelyconfig .OptimizelyConfigManager ;
33
36
import com .optimizely .ab .optimizelyconfig .OptimizelyConfigService ;
37
+ import com .optimizely .ab .optimizelyjson .OptimizelyJSON ;
34
38
import org .slf4j .Logger ;
35
39
import org .slf4j .LoggerFactory ;
36
40
37
41
import javax .annotation .Nonnull ;
38
42
import javax .annotation .Nullable ;
39
43
import javax .annotation .concurrent .ThreadSafe ;
40
44
import java .io .Closeable ;
41
- import java .util .ArrayList ;
42
- import java .util .Collections ;
43
- import java .util .HashMap ;
44
- import java .util .List ;
45
- import java .util .Map ;
45
+ import java .util .*;
46
46
47
47
import static com .optimizely .ab .internal .SafetyUtils .tryClose ;
48
48
@@ -601,6 +601,46 @@ public String getFeatureVariableString(@Nonnull String featureKey,
601
601
FeatureVariable .STRING_TYPE );
602
602
}
603
603
604
+ /**
605
+ * Get the JSON value of the specified variable in the feature.
606
+ *
607
+ * @param featureKey The unique key of the feature.
608
+ * @param variableKey The unique key of the variable.
609
+ * @param userId The ID of the user.
610
+ * @return An OptimizelyJSON instance for the JSON variable value.
611
+ * Null if the feature or variable could not be found.
612
+ */
613
+ @ Nullable
614
+ public OptimizelyJSON getFeatureVariableJSON (@ Nonnull String featureKey ,
615
+ @ Nonnull String variableKey ,
616
+ @ Nonnull String userId ) {
617
+ return getFeatureVariableJSON (featureKey , variableKey , userId , Collections .<String , String >emptyMap ());
618
+ }
619
+
620
+ /**
621
+ * Get the JSON value of the specified variable in the feature.
622
+ *
623
+ * @param featureKey The unique key of the feature.
624
+ * @param variableKey The unique key of the variable.
625
+ * @param userId The ID of the user.
626
+ * @param attributes The user's attributes.
627
+ * @return An OptimizelyJSON instance for the JSON variable value.
628
+ * Null if the feature or variable could not be found.
629
+ */
630
+ @ Nullable
631
+ public OptimizelyJSON getFeatureVariableJSON (@ Nonnull String featureKey ,
632
+ @ Nonnull String variableKey ,
633
+ @ Nonnull String userId ,
634
+ @ Nonnull Map <String , ?> attributes ) {
635
+
636
+ return getFeatureVariableValueForType (
637
+ featureKey ,
638
+ variableKey ,
639
+ userId ,
640
+ attributes ,
641
+ FeatureVariable .JSON_TYPE );
642
+ }
643
+
604
644
@ VisibleForTesting
605
645
<T > T getFeatureVariableValueForType (@ Nonnull String featureKey ,
606
646
@ Nonnull String variableKey ,
@@ -671,6 +711,10 @@ <T> T getFeatureVariableValueForType(@Nonnull String featureKey,
671
711
}
672
712
673
713
Object convertedValue = convertStringToType (variableValue , variableType );
714
+ Object notificationValue = convertedValue ;
715
+ if (convertedValue instanceof OptimizelyJSON ) {
716
+ notificationValue = ((OptimizelyJSON ) convertedValue ).toMap ();
717
+ }
674
718
675
719
DecisionNotification decisionNotification = DecisionNotification .newFeatureVariableDecisionNotificationBuilder ()
676
720
.withUserId (userId )
@@ -679,7 +723,7 @@ <T> T getFeatureVariableValueForType(@Nonnull String featureKey,
679
723
.withFeatureEnabled (featureEnabled )
680
724
.withVariableKey (variableKey )
681
725
.withVariableType (variableType )
682
- .withVariableValue (convertedValue )
726
+ .withVariableValue (notificationValue )
683
727
.withFeatureDecision (featureDecision )
684
728
.build ();
685
729
@@ -714,6 +758,8 @@ Object convertStringToType(String variableValue, String type) {
714
758
"\" as Integer. " + exception .toString ());
715
759
}
716
760
break ;
761
+ case FeatureVariable .JSON_TYPE :
762
+ return new OptimizelyJSON (variableValue );
717
763
default :
718
764
return variableValue ;
719
765
}
@@ -722,6 +768,103 @@ Object convertStringToType(String variableValue, String type) {
722
768
return null ;
723
769
}
724
770
771
+ /**
772
+ * Get the values of all variables in the feature.
773
+ *
774
+ * @param featureKey The unique key of the feature.
775
+ * @param userId The ID of the user.
776
+ * @return An OptimizelyJSON instance for all variable values.
777
+ * Null if the feature could not be found.
778
+ */
779
+ @ Nullable
780
+ public OptimizelyJSON getAllFeatureVariables (@ Nonnull String featureKey ,
781
+ @ Nonnull String userId ) {
782
+ return getAllFeatureVariables (featureKey , userId , Collections .<String , String >emptyMap ());
783
+ }
784
+
785
+ /**
786
+ * Get the values of all variables in the feature.
787
+ *
788
+ * @param featureKey The unique key of the feature.
789
+ * @param userId The ID of the user.
790
+ * @param attributes The user's attributes.
791
+ * @return An OptimizelyJSON instance for all variable values.
792
+ * Null if the feature could not be found.
793
+ */
794
+ @ Nullable
795
+ public OptimizelyJSON getAllFeatureVariables (@ Nonnull String featureKey ,
796
+ @ Nonnull String userId ,
797
+ @ Nonnull Map <String , ?> attributes ) {
798
+
799
+ if (featureKey == null ) {
800
+ logger .warn ("The featureKey parameter must be nonnull." );
801
+ return null ;
802
+ } else if (userId == null ) {
803
+ logger .warn ("The userId parameter must be nonnull." );
804
+ return null ;
805
+ }
806
+
807
+ ProjectConfig projectConfig = getProjectConfig ();
808
+ if (projectConfig == null ) {
809
+ logger .error ("Optimizely instance is not valid, failing getAllFeatureVariableValues call. type" );
810
+ return null ;
811
+ }
812
+
813
+ FeatureFlag featureFlag = projectConfig .getFeatureKeyMapping ().get (featureKey );
814
+ if (featureFlag == null ) {
815
+ logger .info ("No feature flag was found for key \" {}\" ." , featureKey );
816
+ return null ;
817
+ }
818
+
819
+ Map <String , ?> copiedAttributes = copyAttributes (attributes );
820
+ FeatureDecision featureDecision = decisionService .getVariationForFeature (featureFlag , userId , copiedAttributes , projectConfig );
821
+ Boolean featureEnabled = false ;
822
+ Variation variation = featureDecision .variation ;
823
+
824
+ if (variation != null ) {
825
+ if (!variation .getFeatureEnabled ()) {
826
+ logger .info ("Feature \" {}\" for variation \" {}\" was not enabled. " +
827
+ "The default value is being returned." , featureKey , featureDecision .variation .getKey ());
828
+ }
829
+
830
+ featureEnabled = variation .getFeatureEnabled ();
831
+ } else {
832
+ logger .info ("User \" {}\" was not bucketed into any variation for feature flag \" {}\" . " +
833
+ "The default values are being returned." , userId , featureKey );
834
+ }
835
+
836
+ Map <String , Object > valuesMap = new HashMap <String , Object >();
837
+ for (FeatureVariable variable : featureFlag .getVariables ()) {
838
+ String value = variable .getDefaultValue ();
839
+ if (featureEnabled ) {
840
+ FeatureVariableUsageInstance instance = variation .getVariableIdToFeatureVariableUsageInstanceMap ().get (variable .getId ());
841
+ if (instance != null ) {
842
+ value = instance .getValue ();
843
+ }
844
+ }
845
+
846
+ Object convertedValue = convertStringToType (value , variable .getType ());
847
+ if (convertedValue instanceof OptimizelyJSON ) {
848
+ convertedValue = ((OptimizelyJSON ) convertedValue ).toMap ();
849
+ }
850
+
851
+ valuesMap .put (variable .getKey (), convertedValue );
852
+ }
853
+
854
+ DecisionNotification decisionNotification = DecisionNotification .newFeatureVariableDecisionNotificationBuilder ()
855
+ .withUserId (userId )
856
+ .withAttributes (copiedAttributes )
857
+ .withFeatureKey (featureKey )
858
+ .withFeatureEnabled (featureEnabled )
859
+ .withVariableValues (valuesMap )
860
+ .withFeatureDecision (featureDecision )
861
+ .build ();
862
+
863
+ notificationCenter .send (decisionNotification );
864
+
865
+ return new OptimizelyJSON (valuesMap );
866
+ }
867
+
725
868
/**
726
869
* Get the list of features that are enabled for the user.
727
870
* TODO revisit this method. Calling this as-is can dramatically increase visitor impression counts.
0 commit comments