29
29
import com .optimizely .ab .config .ProjectConfig ;
30
30
import com .optimizely .ab .config .Variation ;
31
31
import com .optimizely .ab .config .parser .ConfigParseException ;
32
- import com .optimizely .ab .config .parser .DefaultConfigParser ;
33
32
import com .optimizely .ab .error .ErrorHandler ;
34
33
import com .optimizely .ab .error .NoOpErrorHandler ;
35
34
import com .optimizely .ab .event .EventHandler ;
@@ -80,33 +79,65 @@ public class Optimizely {
80
79
81
80
private static final Logger logger = LoggerFactory .getLogger (Optimizely .class );
82
81
83
- @ VisibleForTesting final DecisionService decisionService ;
82
+ @ VisibleForTesting DecisionService decisionService ;
84
83
@ VisibleForTesting final EventFactory eventFactory ;
85
- @ VisibleForTesting final ProjectConfig projectConfig ;
84
+ @ VisibleForTesting ProjectConfig projectConfig ;
86
85
@ VisibleForTesting final EventHandler eventHandler ;
87
86
@ VisibleForTesting final ErrorHandler errorHandler ;
87
+ private boolean isValid ;
88
88
public final NotificationCenter notificationCenter = new NotificationCenter ();
89
89
90
90
@ Nullable private final UserProfileService userProfileService ;
91
91
92
- private Optimizely (@ Nonnull ProjectConfig projectConfig ,
93
- @ Nonnull DecisionService decisionService ,
94
- @ Nonnull EventHandler eventHandler ,
92
+ private Optimizely (@ Nonnull EventHandler eventHandler ,
95
93
@ Nonnull EventFactory eventFactory ,
96
94
@ Nonnull ErrorHandler errorHandler ,
95
+ @ Nullable DecisionService decisionService ,
97
96
@ Nullable UserProfileService userProfileService ) {
98
- this .projectConfig = projectConfig ;
99
97
this .decisionService = decisionService ;
100
98
this .eventHandler = eventHandler ;
101
99
this .eventFactory = eventFactory ;
102
100
this .errorHandler = errorHandler ;
103
101
this .userProfileService = userProfileService ;
104
102
}
105
103
106
- // Do work here that should be done once per Optimizely lifecycle
104
+ /**
105
+ * Initializes the SDK state. Can conceivably re-use this in the future with datafile sync where
106
+ * we can re-initialize the SDK instead of re-instantiating.
107
+ */
107
108
@ VisibleForTesting
108
- void initialize () {
109
+ void initialize (@ Nonnull String datafile , @ Nullable ProjectConfig projectConfig ) {
110
+ if (projectConfig == null ) {
111
+ try {
112
+ projectConfig = new ProjectConfig .Builder ()
113
+ .withDatafile (datafile )
114
+ .build ();
115
+ isValid = true ;
116
+ logger .info ("Datafile is valid" );
117
+ } catch (ConfigParseException ex ) {
118
+ logger .error ("Unable to parse the datafile" , ex );
119
+ logger .info ("Datafile is invalid" );
120
+ errorHandler .handleError (new OptimizelyRuntimeException (ex ));
121
+ }
122
+ } else {
123
+ isValid = true ;
124
+ }
125
+
126
+ this .projectConfig = projectConfig ;
127
+ if (decisionService == null ) {
128
+ Bucketer bucketer = new Bucketer (projectConfig );
129
+ decisionService = new DecisionService (bucketer , errorHandler , projectConfig , userProfileService );
130
+ }
131
+ }
109
132
133
+ /**
134
+ * Determine if the instance of the Optimizely client is valid. An instance can be deemed invalid if it was not
135
+ * initialized properly due to an invalid datafile being passed in.
136
+ * @return True if the Optimizely instance is valid.
137
+ * False if the Optimizely instance is not valid.
138
+ */
139
+ public boolean isValid () {
140
+ return isValid ;
110
141
}
111
142
112
143
//======== activate calls ========//
@@ -121,6 +152,10 @@ Variation activate(@Nonnull String experimentKey,
121
152
Variation activate (@ Nonnull String experimentKey ,
122
153
@ Nonnull String userId ,
123
154
@ Nonnull Map <String , ?> attributes ) throws UnknownExperimentException {
155
+ if (!isValid ) {
156
+ logger .error ("Optimizely instance is not valid, failing activate call." );
157
+ return null ;
158
+ }
124
159
125
160
if (experimentKey == null ) {
126
161
logger .error ("The experimentKey parameter must be nonnull." );
@@ -165,6 +200,10 @@ Variation activate(@Nonnull ProjectConfig projectConfig,
165
200
@ Nonnull Experiment experiment ,
166
201
@ Nonnull String userId ,
167
202
@ Nonnull Map <String , ?> attributes ) {
203
+ if (!isValid ) {
204
+ logger .error ("Optimizely instance is not valid, failing activate call." );
205
+ return null ;
206
+ }
168
207
169
208
if (!validateUserId (userId )){
170
209
logger .info ("Not activating user \" {}\" for experiment \" {}\" ." , userId , experiment .getKey ());
@@ -236,6 +275,10 @@ public void track(@Nonnull String eventName,
236
275
@ Nonnull String userId ,
237
276
@ Nonnull Map <String , ?> attributes ,
238
277
@ Nonnull Map <String , ?> eventTags ) throws UnknownEventTypeException {
278
+ if (!isValid ) {
279
+ logger .error ("Optimizely instance is not valid, failing track call." );
280
+ return ;
281
+ }
239
282
240
283
if (!validateUserId (userId )) {
241
284
logger .info ("Not tracking event \" {}\" ." , eventName );
@@ -345,6 +388,11 @@ public void track(@Nonnull String eventName,
345
388
public @ Nonnull Boolean isFeatureEnabled (@ Nonnull String featureKey ,
346
389
@ Nonnull String userId ,
347
390
@ Nonnull Map <String , ?> attributes ) {
391
+ if (!isValid ) {
392
+ logger .error ("Optimizely instance is not valid, failing isFeatureEnabled call." );
393
+ return false ;
394
+ }
395
+
348
396
if (featureKey == null ) {
349
397
logger .warn ("The featureKey parameter must be nonnull." );
350
398
return false ;
@@ -411,6 +459,11 @@ else if (userId == null) {
411
459
@ Nonnull String variableKey ,
412
460
@ Nonnull String userId ,
413
461
@ Nonnull Map <String , ?> attributes ) {
462
+ if (!isValid ) {
463
+ logger .error ("Optimizely instance is not valid, failing getFeatureVariableBoolean call." );
464
+ return null ;
465
+ }
466
+
414
467
String variableValue = getFeatureVariableValueForType (
415
468
featureKey ,
416
469
variableKey ,
@@ -451,6 +504,11 @@ else if (userId == null) {
451
504
@ Nonnull String variableKey ,
452
505
@ Nonnull String userId ,
453
506
@ Nonnull Map <String , ?> attributes ) {
507
+ if (!isValid ) {
508
+ logger .error ("Optimizely instance is not valid, failing getFeatureVariableDouble call." );
509
+ return null ;
510
+ }
511
+
454
512
String variableValue = getFeatureVariableValueForType (
455
513
featureKey ,
456
514
variableKey ,
@@ -496,6 +554,11 @@ else if (userId == null) {
496
554
@ Nonnull String variableKey ,
497
555
@ Nonnull String userId ,
498
556
@ Nonnull Map <String , ?> attributes ) {
557
+ if (!isValid ) {
558
+ logger .error ("Optimizely instance is not valid, failing getFeatureVariableInteger call." );
559
+ return null ;
560
+ }
561
+
499
562
String variableValue = getFeatureVariableValueForType (
500
563
featureKey ,
501
564
variableKey ,
@@ -541,6 +604,11 @@ else if (userId == null) {
541
604
@ Nonnull String variableKey ,
542
605
@ Nonnull String userId ,
543
606
@ Nonnull Map <String , ?> attributes ) {
607
+ if (!isValid ) {
608
+ logger .error ("Optimizely instance is not valid, failing getFeatureVariableString call." );
609
+ return null ;
610
+ }
611
+
544
612
return getFeatureVariableValueForType (
545
613
featureKey ,
546
614
variableKey ,
@@ -617,6 +685,11 @@ else if (userId == null) {
617
685
public List <String > getEnabledFeatures (@ Nonnull String userId , @ Nonnull Map <String , ?> attributes ) {
618
686
List <String > enabledFeaturesList = new ArrayList <String >();
619
687
688
+ if (!isValid ) {
689
+ logger .error ("Optimizely instance is not valid, failing getEnabledFeatures call." );
690
+ return enabledFeaturesList ;
691
+ }
692
+
620
693
if (!validateUserId (userId )){
621
694
return enabledFeaturesList ;
622
695
}
@@ -660,6 +733,11 @@ Variation getVariation(@Nonnull String experimentKey,
660
733
Variation getVariation (@ Nonnull String experimentKey ,
661
734
@ Nonnull String userId ,
662
735
@ Nonnull Map <String , ?> attributes ) {
736
+ if (!isValid ) {
737
+ logger .error ("Optimizely instance is not valid, failing getVariation call." );
738
+ return null ;
739
+ }
740
+
663
741
if (!validateUserId (userId )) {
664
742
return null ;
665
743
}
@@ -697,7 +775,10 @@ Variation getVariation(@Nonnull String experimentKey,
697
775
public boolean setForcedVariation (@ Nonnull String experimentKey ,
698
776
@ Nonnull String userId ,
699
777
@ Nullable String variationKey ) {
700
-
778
+ if (!isValid ) {
779
+ logger .error ("Optimizely instance is not valid, failing setForcedVariation call." );
780
+ return false ;
781
+ }
701
782
702
783
return projectConfig .setForcedVariation (experimentKey , userId , variationKey );
703
784
}
@@ -715,6 +796,11 @@ public boolean setForcedVariation(@Nonnull String experimentKey,
715
796
*/
716
797
public @ Nullable Variation getForcedVariation (@ Nonnull String experimentKey ,
717
798
@ Nonnull String userId ) {
799
+ if (!isValid ) {
800
+ logger .error ("Optimizely instance is not valid, failing getForcedVariation call." );
801
+ return null ;
802
+ }
803
+
718
804
return projectConfig .getForcedVariation (experimentKey , userId );
719
805
}
720
806
@@ -869,17 +955,7 @@ protected Builder withConfig(ProjectConfig projectConfig) {
869
955
return this ;
870
956
}
871
957
872
- public Optimizely build () throws ConfigParseException {
873
- if (projectConfig == null ) {
874
- projectConfig = new ProjectConfig .Builder ()
875
- .withDatafile (datafile )
876
- .build ();
877
- }
878
-
879
- if (bucketer == null ) {
880
- bucketer = new Bucketer (projectConfig );
881
- }
882
-
958
+ public Optimizely build () {
883
959
if (clientEngine == null ) {
884
960
clientEngine = ClientEngine .JAVA_SDK ;
885
961
}
@@ -897,12 +973,13 @@ public Optimizely build() throws ConfigParseException {
897
973
errorHandler = new NoOpErrorHandler ();
898
974
}
899
975
900
- if (decisionService == null ) {
976
+ // Used for convenience while unit testing to override/mock bucketing. This interface is NOT public and should be refactored out.
977
+ if (bucketer != null && decisionService == null ) {
901
978
decisionService = new DecisionService (bucketer , errorHandler , projectConfig , userProfileService );
902
979
}
903
980
904
- Optimizely optimizely = new Optimizely (projectConfig , decisionService , eventHandler , eventFactory , errorHandler , userProfileService );
905
- optimizely .initialize ();
981
+ Optimizely optimizely = new Optimizely (eventHandler , eventFactory , errorHandler , decisionService , userProfileService );
982
+ optimizely .initialize (datafile , projectConfig );
906
983
return optimizely ;
907
984
}
908
985
}
0 commit comments