2525import com .optimizely .ab .error .ErrorHandler ;
2626import com .optimizely .ab .error .NoOpErrorHandler ;
2727import 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 ;
2932import com .optimizely .ab .event .internal .payload .EventBatch ;
3033import com .optimizely .ab .notification .*;
3134import com .optimizely .ab .optimizelyconfig .OptimizelyConfig ;
3235import com .optimizely .ab .optimizelyconfig .OptimizelyConfigManager ;
3336import com .optimizely .ab .optimizelyconfig .OptimizelyConfigService ;
37+ import com .optimizely .ab .optimizelyjson .OptimizelyJSON ;
3438import org .slf4j .Logger ;
3539import org .slf4j .LoggerFactory ;
3640
3741import javax .annotation .Nonnull ;
3842import javax .annotation .Nullable ;
3943import javax .annotation .concurrent .ThreadSafe ;
4044import 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 .*;
4646
4747import static com .optimizely .ab .internal .SafetyUtils .tryClose ;
4848
@@ -601,6 +601,46 @@ public String getFeatureVariableString(@Nonnull String featureKey,
601601 FeatureVariable .STRING_TYPE );
602602 }
603603
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+
604644 @ VisibleForTesting
605645 <T > T getFeatureVariableValueForType (@ Nonnull String featureKey ,
606646 @ Nonnull String variableKey ,
@@ -671,6 +711,10 @@ <T> T getFeatureVariableValueForType(@Nonnull String featureKey,
671711 }
672712
673713 Object convertedValue = convertStringToType (variableValue , variableType );
714+ Object notificationValue = convertedValue ;
715+ if (convertedValue instanceof OptimizelyJSON ) {
716+ notificationValue = ((OptimizelyJSON ) convertedValue ).toMap ();
717+ }
674718
675719 DecisionNotification decisionNotification = DecisionNotification .newFeatureVariableDecisionNotificationBuilder ()
676720 .withUserId (userId )
@@ -679,7 +723,7 @@ <T> T getFeatureVariableValueForType(@Nonnull String featureKey,
679723 .withFeatureEnabled (featureEnabled )
680724 .withVariableKey (variableKey )
681725 .withVariableType (variableType )
682- .withVariableValue (convertedValue )
726+ .withVariableValue (notificationValue )
683727 .withFeatureDecision (featureDecision )
684728 .build ();
685729
@@ -714,6 +758,8 @@ Object convertStringToType(String variableValue, String type) {
714758 "\" as Integer. " + exception .toString ());
715759 }
716760 break ;
761+ case FeatureVariable .JSON_TYPE :
762+ return new OptimizelyJSON (variableValue );
717763 default :
718764 return variableValue ;
719765 }
@@ -722,6 +768,103 @@ Object convertStringToType(String variableValue, String type) {
722768 return null ;
723769 }
724770
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+
725868 /**
726869 * Get the list of features that are enabled for the user.
727870 * TODO revisit this method. Calling this as-is can dramatically increase visitor impression counts.
0 commit comments