5
5
import dev .openfeature .sdk .internal .AutoCloseableReentrantReadWriteLock ;
6
6
import lombok .extern .slf4j .Slf4j ;
7
7
8
+ import java .io .IOException ;
9
+ import java .io .InputStream ;
8
10
import java .util .ArrayList ;
9
11
import java .util .Arrays ;
10
12
import java .util .List ;
11
13
import java .util .Optional ;
14
+ import java .util .Properties ;
12
15
import java .util .Set ;
13
16
import java .util .function .Consumer ;
14
17
@@ -35,10 +38,6 @@ protected OpenFeatureAPI() {
35
38
transactionContextPropagator = new NoOpTransactionContextPropagator ();
36
39
}
37
40
38
- private static class SingletonHolder {
39
- private static final OpenFeatureAPI INSTANCE = new OpenFeatureAPI ();
40
- }
41
-
42
41
/**
43
42
* Provisions the {@link OpenFeatureAPI} singleton (if needed) and returns it.
44
43
*
@@ -86,7 +85,7 @@ public Client getClient() {
86
85
* Multiple clients can be used to segment feature flag configuration.
87
86
* If there is already a provider bound to this domain, this provider will be used.
88
87
* Otherwise, the default provider is used until a provider is assigned to that domain.
89
- *
88
+ *
90
89
* @param domain an identifier which logically binds clients with providers
91
90
* @return a new client instance
92
91
*/
@@ -100,8 +99,8 @@ public Client getClient(String domain) {
100
99
* Multiple clients can be used to segment feature flag configuration.
101
100
* If there is already a provider bound to this domain, this provider will be used.
102
101
* Otherwise, the default provider is used until a provider is assigned to that domain.
103
- *
104
- * @param domain a identifier which logically binds clients with providers
102
+ *
103
+ * @param domain a identifier which logically binds clients with providers
105
104
* @param version a version identifier
106
105
* @return a new client instance
107
106
*/
@@ -111,6 +110,17 @@ public Client getClient(String domain, String version) {
111
110
version );
112
111
}
113
112
113
+ /**
114
+ * Gets the global evaluation context, which will be used for all evaluations.
115
+ *
116
+ * @return evaluation context
117
+ */
118
+ public EvaluationContext getEvaluationContext () {
119
+ try (AutoCloseableLock __ = lock .readLockAutoCloseable ()) {
120
+ return this .evaluationContext ;
121
+ }
122
+ }
123
+
114
124
/**
115
125
* Sets the global evaluation context, which will be used for all evaluations.
116
126
*
@@ -124,17 +134,6 @@ public OpenFeatureAPI setEvaluationContext(EvaluationContext evaluationContext)
124
134
return this ;
125
135
}
126
136
127
- /**
128
- * Gets the global evaluation context, which will be used for all evaluations.
129
- *
130
- * @return evaluation context
131
- */
132
- public EvaluationContext getEvaluationContext () {
133
- try (AutoCloseableLock __ = lock .readLockAutoCloseable ()) {
134
- return this .evaluationContext ;
135
- }
136
- }
137
-
138
137
/**
139
138
* Return the transaction context propagator.
140
139
*/
@@ -175,39 +174,6 @@ public void setTransactionContext(EvaluationContext evaluationContext) {
175
174
this .transactionContextPropagator .setTransactionContext (evaluationContext );
176
175
}
177
176
178
- /**
179
- * Set the default provider.
180
- */
181
- public void setProvider (FeatureProvider provider ) {
182
- try (AutoCloseableLock __ = lock .writeLockAutoCloseable ()) {
183
- providerRepository .setProvider (
184
- provider ,
185
- this ::attachEventProvider ,
186
- this ::emitReady ,
187
- this ::detachEventProvider ,
188
- this ::emitError ,
189
- false );
190
- }
191
- }
192
-
193
- /**
194
- * Add a provider for a domain.
195
- *
196
- * @param domain The domain to bind the provider to.
197
- * @param provider The provider to set.
198
- */
199
- public void setProvider (String domain , FeatureProvider provider ) {
200
- try (AutoCloseableLock __ = lock .writeLockAutoCloseable ()) {
201
- providerRepository .setProvider (domain ,
202
- provider ,
203
- this ::attachEventProvider ,
204
- this ::emitReady ,
205
- this ::detachEventProvider ,
206
- this ::emitError ,
207
- false );
208
- }
209
- }
210
-
211
177
/**
212
178
* Set the default provider and wait for initialization to finish.
213
179
*/
@@ -226,8 +192,8 @@ public void setProviderAndWait(FeatureProvider provider) throws OpenFeatureError
226
192
/**
227
193
* Add a provider for a domain and wait for initialization to finish.
228
194
*
229
- * @param domain The domain to bind the provider to.
230
- * @param provider The provider to set.
195
+ * @param domain The domain to bind the provider to.
196
+ * @param provider The provider to set.
231
197
*/
232
198
public void setProviderAndWait (String domain , FeatureProvider provider ) throws OpenFeatureError {
233
199
try (AutoCloseableLock __ = lock .writeLockAutoCloseable ()) {
@@ -286,6 +252,39 @@ public FeatureProvider getProvider(String domain) {
286
252
return providerRepository .getProvider (domain );
287
253
}
288
254
255
+ /**
256
+ * Set the default provider.
257
+ */
258
+ public void setProvider (FeatureProvider provider ) {
259
+ try (AutoCloseableLock __ = lock .writeLockAutoCloseable ()) {
260
+ providerRepository .setProvider (
261
+ provider ,
262
+ this ::attachEventProvider ,
263
+ this ::emitReady ,
264
+ this ::detachEventProvider ,
265
+ this ::emitError ,
266
+ false );
267
+ }
268
+ }
269
+
270
+ /**
271
+ * Add a provider for a domain.
272
+ *
273
+ * @param domain The domain to bind the provider to.
274
+ * @param provider The provider to set.
275
+ */
276
+ public void setProvider (String domain , FeatureProvider provider ) {
277
+ try (AutoCloseableLock __ = lock .writeLockAutoCloseable ()) {
278
+ providerRepository .setProvider (domain ,
279
+ provider ,
280
+ this ::attachEventProvider ,
281
+ this ::emitReady ,
282
+ this ::detachEventProvider ,
283
+ this ::emitError ,
284
+ false );
285
+ }
286
+ }
287
+
289
288
/**
290
289
* Adds hooks for globally, used for all evaluations.
291
290
* Hooks are run in the order they're added in the before stage. They are run in reverse order for all other stages.
@@ -300,6 +299,7 @@ public void addHooks(Hook... hooks) {
300
299
301
300
/**
302
301
* Fetch the hooks associated to this client.
302
+ *
303
303
* @return A list of {@link Hook}s.
304
304
*/
305
305
public List <Hook > getHooks () {
@@ -404,7 +404,7 @@ void addHandler(String domain, ProviderEvent event, Consumer<EventDetails> handl
404
404
405
405
/**
406
406
* Runs the handlers associated with a particular provider.
407
- *
407
+ *
408
408
* @param provider the provider from where this event originated
409
409
* @param event the event type
410
410
* @param details the event details
@@ -440,4 +440,42 @@ private void runHandlersForProvider(FeatureProvider provider, ProviderEvent even
440
440
}
441
441
}
442
442
}
443
+
444
+ private static class SingletonHolder {
445
+ private static final OpenFeatureAPI INSTANCE ;
446
+
447
+ static {
448
+ OpenFeatureAPI instance = null ;
449
+ String cls = System .getenv ("OPEN_FEATURE_API_CLASS" );
450
+ if (cls == null ) {
451
+ try (InputStream propertiesFile =
452
+ SingletonHolder .class .getResourceAsStream ("openfeature.properties" )) {
453
+ if (propertiesFile != null ) {
454
+ Properties props = new Properties ();
455
+ props .load (propertiesFile );
456
+ cls = props .getProperty ("openfeature.api.class" );
457
+ }
458
+ } catch (IOException e ) {
459
+ log .error ("Custom OpenFeatureApi could not be initialized" , e );
460
+ }
461
+ }
462
+ if (cls != null ) {
463
+ try {
464
+ Class <?> clazz = Class .forName (cls );
465
+
466
+ instance = (OpenFeatureAPI ) clazz .newInstance ();
467
+ } catch (ClassNotFoundException
468
+ | ClassCastException
469
+ | InstantiationException
470
+ | IllegalAccessException e ) {
471
+ log .error ("Custom OpenFeatureApi could not be initialized" , e );
472
+ }
473
+ }
474
+ if (instance == null ) {
475
+ instance = new OpenFeatureAPI ();
476
+ }
477
+
478
+ INSTANCE = instance ;
479
+ }
480
+ }
443
481
}
0 commit comments