11package com .eppo .sdk ;
22
33import com .eppo .sdk .constants .Constants ;
4- import com .eppo .sdk .dto .*;
5- import com .eppo .sdk .helpers .*;
4+ import com .eppo .sdk .dto .Allocation ;
5+ import com .eppo .sdk .dto .AssignmentLogData ;
6+ import com .eppo .sdk .dto .EppoClientConfig ;
7+ import com .eppo .sdk .dto .EppoValue ;
8+ import com .eppo .sdk .dto .ExperimentConfiguration ;
9+ import com .eppo .sdk .dto .Rule ;
10+ import com .eppo .sdk .dto .SubjectAttributes ;
11+ import com .eppo .sdk .dto .Variation ;
12+ import com .eppo .sdk .exception .EppoClientIsNotInitializedException ;
13+ import com .eppo .sdk .exception .InvalidInputException ;
14+ import com .eppo .sdk .helpers .AppDetails ;
15+ import com .eppo .sdk .helpers .CacheHelper ;
16+ import com .eppo .sdk .helpers .ConfigurationStore ;
17+ import com .eppo .sdk .helpers .EppoHttpClient ;
18+ import com .eppo .sdk .helpers .ExperimentConfigurationRequestor ;
19+ import com .eppo .sdk .helpers .FetchConfigurationsTask ;
20+ import com .eppo .sdk .helpers .InputValidator ;
21+ import com .eppo .sdk .helpers .RuleValidator ;
22+ import com .eppo .sdk .helpers .Shard ;
623
724import lombok .extern .slf4j .Slf4j ;
825
9- import com .eppo .sdk .exception .*;
1026import org .ehcache .Cache ;
1127
1228import java .util .List ;
@@ -35,55 +51,67 @@ private EppoClient(ConfigurationStore configurationStore, Timer poller, EppoClie
3551 * This function is used to get assignment Value
3652 *
3753 * @param subjectKey
38- * @param experimentKey
54+ * @param flagKey
3955 * @param subjectAttributes
4056 * @return
4157 */
4258 public Optional <String > getAssignment (
4359 String subjectKey ,
44- String experimentKey ,
60+ String flagKey ,
4561 SubjectAttributes subjectAttributes
4662 ) {
4763 // Validate Input Values
4864 InputValidator .validateNotBlank (subjectKey , "Invalid argument: subjectKey cannot be blank" );
49- InputValidator .validateNotBlank (experimentKey , "Invalid argument: experimentKey cannot be blank" );
65+ InputValidator .validateNotBlank (flagKey , "Invalid argument: flagKey cannot be blank" );
5066
5167 // Fetch Experiment Configuration
52- ExperimentConfiguration configuration = this .configurationStore .getExperimentConfiguration (experimentKey );
68+ ExperimentConfiguration configuration = this .configurationStore .getExperimentConfiguration (flagKey );
5369 if (configuration == null ) {
54- log .warn ("No configuration found for experiment key: " + experimentKey );
70+ log .warn ("[Eppo SDK] No configuration found for key: " + flagKey );
5571 return Optional .empty ();
5672 }
5773
5874 // Check if subject has override variations
59- String subjectVariationOverride = this .getSubjectVariationOverride (subjectKey , configuration );
60- if (subjectVariationOverride != null ) {
61- return Optional .of (subjectVariationOverride );
75+ EppoValue subjectVariationOverride = this .getSubjectVariationOverride (subjectKey , configuration );
76+ if (!subjectVariationOverride .isNull ()) {
77+ return Optional .of (subjectVariationOverride .stringValue ());
78+ }
79+
80+ // Check if disabled
81+ if (!configuration .isEnabled ()) {
82+ log .info ("[Eppo SDK] No assigned variation because the experiment or feature flag {} is disabled" , flagKey );
83+ return Optional .empty ();
6284 }
6385
64- // If disabled or not in Experiment Sampler or Rules not satisfied return empty string
65- if (!configuration .enabled ||
66- !this .isInExperimentSample (subjectKey , experimentKey , configuration ) ||
67- !this .subjectAttributesSatisfyRules (subjectAttributes , configuration .rules )
68- ) {
86+ // Find matched rule
87+ Optional <Rule > rule = RuleValidator .findMatchingRule (subjectAttributes , configuration .getRules ());
88+ if (rule .isEmpty ()) {
89+ log .info ("[Eppo SDK] No assigned variation. The subject attributes did not match any targeting rules" );
90+ return Optional .empty ();
91+ }
92+
93+ // Check if in experiment sample
94+ Allocation allocation = configuration .getAllocation (rule .get ().getAllocationKey ());
95+ if (!this .isInExperimentSample (subjectKey , flagKey , configuration .getSubjectShards (), allocation .getPercentExposure ())) {
96+ log .info ("[Eppo SDK] No assigned variation. The subject is not part of the sample population" );
6997 return Optional .empty ();
7098 }
7199
72100 // Get assigned variation
73- Variation assignedVariation = this .getAssignedVariation (subjectKey , experimentKey , configuration );
101+ Variation assignedVariation = this .getAssignedVariation (subjectKey , flagKey , configuration . getSubjectShards (), allocation . getVariations () );
74102
75103 try {
76104 this .eppoClientConfig .getAssignmentLogger ()
77105 .logAssignment (new AssignmentLogData (
78- experimentKey ,
79- assignedVariation .name ,
106+ flagKey ,
107+ assignedVariation .getValue (). stringValue () ,
80108 subjectKey ,
81109 subjectAttributes
82110 ));
83111 } catch (Exception e ){
84112 // Ignore Exception
85113 }
86- return Optional .of (assignedVariation .name );
114+ return Optional .of (assignedVariation .getValue (). stringValue () );
87115 }
88116
89117 /**
@@ -108,11 +136,9 @@ public Optional<String> getAssignment(String subjectKey, String experimentKey) {
108136 private boolean isInExperimentSample (
109137 String subjectKey ,
110138 String experimentKey ,
111- ExperimentConfiguration experimentConfiguration
139+ int subjectShards ,
140+ float percentageExposure
112141 ) {
113- int subjectShards = experimentConfiguration .subjectShards ;
114- float percentageExposure = experimentConfiguration .percentExposure ;
115-
116142 int shard = Shard .getShard ("exposure-" + subjectKey + "-" + experimentKey , subjectShards );
117143 return shard <= percentageExposure * subjectShards ;
118144 }
@@ -128,13 +154,13 @@ private boolean isInExperimentSample(
128154 private Variation getAssignedVariation (
129155 String subjectKey ,
130156 String experimentKey ,
131- ExperimentConfiguration experimentConfiguration
157+ int subjectShards ,
158+ List <Variation > variations
132159 ) {
133- int subjectShards = experimentConfiguration .subjectShards ;
134160 int shard = Shard .getShard ("assignment-" + subjectKey + "-" + experimentKey , subjectShards );
135161
136- Optional <Variation > variation = experimentConfiguration . variations .stream ()
137- .filter (config -> Shard .isShardInRange (shard , config .shardRange ))
162+ Optional <Variation > variation = variations .stream ()
163+ .filter (config -> Shard .isShardInRange (shard , config .getShardRange () ))
138164 .findFirst ();
139165
140166 return variation .get ();
@@ -147,30 +173,12 @@ private Variation getAssignedVariation(
147173 * @param experimentConfiguration
148174 * @return
149175 */
150- private String getSubjectVariationOverride (
176+ private EppoValue getSubjectVariationOverride (
151177 String subjectKey ,
152178 ExperimentConfiguration experimentConfiguration
153179 ) {
154180 String hexedSubjectKey = Shard .getHex (subjectKey );
155- return experimentConfiguration .overrides .getOrDefault (hexedSubjectKey , null );
156- }
157-
158- /**
159- * This function is used to test if subject attributes are satisfying rules or not
160- *
161- * @param subjectAttributes
162- * @param rules
163- * @return
164- * @throws Exception
165- */
166- private boolean subjectAttributesSatisfyRules (
167- SubjectAttributes subjectAttributes ,
168- List <Rule > rules
169- ) {
170- if (rules .size () == 0 ) {
171- return true ;
172- }
173- return RuleValidator .matchesAnyRule (subjectAttributes , rules );
181+ return experimentConfiguration .getOverrides ().getOrDefault (hexedSubjectKey , new EppoValue ());
174182 }
175183
176184 /***
0 commit comments