@@ -72,7 +72,7 @@ public void updateEnvironment() {
7272 * @return
7373 */
7474 public Flags getEnvironmentFlags () throws FlagsmithClientError {
75- if (flagsmithSdk . getConfig (). getEnableLocalEvaluation ()) {
75+ if (getShouldUseEnvironmentDocument ()) {
7676 return getEnvironmentFlagsFromDocument ();
7777 }
7878
@@ -105,7 +105,7 @@ public Flags getIdentityFlags(String identifier)
105105 */
106106 public Flags getIdentityFlags (String identifier , Map <String , Object > traits )
107107 throws FlagsmithClientError {
108- if (flagsmithSdk . getConfig (). getEnableLocalEvaluation ()) {
108+ if (getShouldUseEnvironmentDocument ()) {
109109 return getIdentityFlagsFromDocument (identifier , traits );
110110 }
111111
@@ -165,23 +165,23 @@ public void close() {
165165
166166 private Flags getEnvironmentFlagsFromDocument () throws FlagsmithClientError {
167167 if (environment == null ) {
168- if (flagsmithSdk . getConfig ().getFlagsmithFlagDefaults () == null ) {
168+ if (getConfig ().getFlagsmithFlagDefaults () == null ) {
169169 throw new FlagsmithClientError ("Unable to get flags. No environment present." );
170170 }
171171 return getDefaultFlags ();
172172 }
173173
174174 return Flags .fromFeatureStateModels (
175175 Engine .getEnvironmentFeatureStates (environment ),
176- flagsmithSdk . getConfig ().getAnalyticsProcessor (),
176+ getConfig ().getAnalyticsProcessor (),
177177 null ,
178- flagsmithSdk . getConfig ().getFlagsmithFlagDefaults ());
178+ getConfig ().getFlagsmithFlagDefaults ());
179179 }
180180
181181 private Flags getIdentityFlagsFromDocument (String identifier , Map <String , Object > traits )
182182 throws FlagsmithClientError {
183183 if (environment == null ) {
184- if (flagsmithSdk . getConfig ().getFlagsmithFlagDefaults () == null ) {
184+ if (getConfig ().getFlagsmithFlagDefaults () == null ) {
185185 throw new FlagsmithClientError ("Unable to get flags. No environment present." );
186186 }
187187 return getDefaultFlags ();
@@ -192,17 +192,23 @@ private Flags getIdentityFlagsFromDocument(String identifier, Map<String, Object
192192
193193 return Flags .fromFeatureStateModels (
194194 featureStates ,
195- flagsmithSdk . getConfig ().getAnalyticsProcessor (),
195+ getConfig ().getAnalyticsProcessor (),
196196 identity .getCompositeKey (),
197- flagsmithSdk . getConfig ().getFlagsmithFlagDefaults ());
197+ getConfig ().getFlagsmithFlagDefaults ());
198198 }
199199
200200 private Flags getEnvironmentFlagsFromApi () throws FlagsmithApiError {
201201 try {
202202 return flagsmithSdk .getFeatureFlags (Boolean .TRUE );
203203 } catch (Exception e ) {
204- if (flagsmithSdk . getConfig ().getFlagsmithFlagDefaults () != null ) {
204+ if (getConfig ().getFlagsmithFlagDefaults () != null ) {
205205 return getDefaultFlags ();
206+ } else if (environment != null ) {
207+ try {
208+ return getEnvironmentFlagsFromDocument ();
209+ } catch (FlagsmithClientError ce ) {
210+ // Do nothing and fall through to FlagsmithApiError
211+ }
206212 }
207213
208214 throw new FlagsmithApiError ("Failed to get feature flags." );
@@ -225,8 +231,14 @@ private Flags getIdentityFlagsFromApi(String identifier, Map<String, Object> tra
225231 traitsList ,
226232 Boolean .TRUE );
227233 } catch (Exception e ) {
228- if (flagsmithSdk . getConfig ().getFlagsmithFlagDefaults () != null ) {
234+ if (getConfig ().getFlagsmithFlagDefaults () != null ) {
229235 return getDefaultFlags ();
236+ } else if (environment != null ) {
237+ try {
238+ return getIdentityFlagsFromDocument (identifier , traits );
239+ } catch (FlagsmithClientError ce ) {
240+ // Do nothing and fall through to FlagsmithApiError
241+ }
230242 }
231243
232244 throw new FlagsmithApiError ("Failed to get feature flags." );
@@ -258,19 +270,23 @@ private IdentityModel buildIdentityModel(String identifier, Map<String, Object>
258270
259271 private Flags getDefaultFlags () {
260272 Flags flags = new Flags ();
261- flags .setDefaultFlagHandler (flagsmithSdk . getConfig ().getFlagsmithFlagDefaults ());
273+ flags .setDefaultFlagHandler (getConfig ().getFlagsmithFlagDefaults ());
262274 return flags ;
263275 }
264276
265277 private String getEnvironmentUpdateErrorMessage () {
266278 if (this .environment == null ) {
267279 return "Unable to update environment from API. "
268- + "No environment configured - using defaultHandler if configured." ;
280+ + "No environment configured - using defaultHandler if configured." ;
269281 } else {
270282 return "Unable to update environment from API. Continuing to use previous copy." ;
271283 }
272284 }
273285
286+ private FlagsmithConfig getConfig () {
287+ return flagsmithSdk .getConfig ();
288+ }
289+
274290 /**
275291 * Returns a FlagsmithCache cache object that encapsulates methods to manipulate
276292 * the cache.
@@ -281,6 +297,15 @@ public FlagsmithCache getCache() {
281297 return this .flagsmithSdk .getCache ();
282298 }
283299
300+ /**
301+ * Returns a boolean indicating whether the flags should be retrieved from a
302+ * locally stored environment document instead of retrieved from the API.
303+ */
304+ private Boolean getShouldUseEnvironmentDocument () {
305+ FlagsmithConfig config = getConfig ();
306+ return config .getEnableLocalEvaluation () | config .getOfflineMode ();
307+ }
308+
284309 public static class Builder {
285310
286311 private final FlagsmithClient client ;
@@ -451,33 +476,40 @@ public Builder withFlagsmithApiWrapper(FlagsmithApiWrapper flagsmithApiWrapper)
451476 * @return a FlagsmithClient
452477 */
453478 public FlagsmithClient build () {
454- final FlagsmithApiWrapper flagsmithApiWrapper ;
479+ if (configuration .getOfflineMode ()) {
480+ if (configuration .getOfflineHandler () == null ) {
481+ throw new FlagsmithRuntimeError ("Offline handler must be provided to use offline mode." );
482+ }
483+ }
455484
456485 if (this .flagsmithApiWrapper != null ) {
457- flagsmithApiWrapper = this .flagsmithApiWrapper ;
486+ client . flagsmithSdk = this .flagsmithApiWrapper ;
458487 } else if (cacheConfig != null ) {
459- flagsmithApiWrapper = new FlagsmithApiWrapper (
488+ client . flagsmithSdk = new FlagsmithApiWrapper (
460489 cacheConfig .getCache (),
461490 this .configuration ,
462491 this .customHeaders ,
463492 client .logger ,
464493 apiKey );
465494 } else {
466- flagsmithApiWrapper = new FlagsmithApiWrapper (
495+ client . flagsmithSdk = new FlagsmithApiWrapper (
467496 this .configuration ,
468497 this .customHeaders ,
469498 client .logger ,
470499 apiKey );
471500 }
472501
473- client .flagsmithSdk = flagsmithApiWrapper ;
474-
475502 if (configuration .getAnalyticsProcessor () != null ) {
476- configuration .getAnalyticsProcessor ().setApi (flagsmithApiWrapper );
503+ configuration .getAnalyticsProcessor ().setApi (client . flagsmithSdk );
477504 configuration .getAnalyticsProcessor ().setLogger (client .logger );
478505 }
479506
480507 if (configuration .getEnableLocalEvaluation ()) {
508+ if (configuration .getOfflineHandler () != null ) {
509+ throw new FlagsmithRuntimeError (
510+ "Local evaluation and offline handler cannot be used together." );
511+ }
512+
481513 if (!apiKey .startsWith ("ser." )) {
482514 throw new FlagsmithRuntimeError (
483515 "In order to use local evaluation, please generate a server key "
@@ -495,6 +527,14 @@ public FlagsmithClient build() {
495527 client .pollingManager .startPolling ();
496528 }
497529
530+ if (configuration .getOfflineHandler () != null ) {
531+ if (configuration .getFlagsmithFlagDefaults () != null ) {
532+ throw new FlagsmithRuntimeError (
533+ "Cannot use both default flag handler and offline handler." );
534+ }
535+ client .environment = configuration .getOfflineHandler ().getEnvironment ();
536+ }
537+
498538 return this .client ;
499539 }
500540 }
0 commit comments