5
5
import dev .openfeature .sdk .internal .AutoCloseableReentrantReadWriteLock ;
6
6
import lombok .extern .slf4j .Slf4j ;
7
7
8
- import java .util .ArrayList ;
9
- import java .util .Arrays ;
10
- import java .util .List ;
11
- import java .util .Optional ;
12
- import java .util .Set ;
8
+ import java .io .IOException ;
9
+ import java .io .InputStream ;
10
+ import java .util .*;
13
11
import java .util .function .Consumer ;
14
12
15
13
/**
@@ -35,10 +33,6 @@ protected OpenFeatureAPI() {
35
33
transactionContextPropagator = new NoOpTransactionContextPropagator ();
36
34
}
37
35
38
- private static class SingletonHolder {
39
- private static final OpenFeatureAPI INSTANCE = new OpenFeatureAPI ();
40
- }
41
-
42
36
/**
43
37
* Provisions the {@link OpenFeatureAPI} singleton (if needed) and returns it.
44
38
*
@@ -86,7 +80,7 @@ public Client getClient() {
86
80
* Multiple clients can be used to segment feature flag configuration.
87
81
* If there is already a provider bound to this domain, this provider will be used.
88
82
* Otherwise, the default provider is used until a provider is assigned to that domain.
89
- *
83
+ *
90
84
* @param domain an identifier which logically binds clients with providers
91
85
* @return a new client instance
92
86
*/
@@ -100,8 +94,8 @@ public Client getClient(String domain) {
100
94
* Multiple clients can be used to segment feature flag configuration.
101
95
* If there is already a provider bound to this domain, this provider will be used.
102
96
* 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
97
+ *
98
+ * @param domain a identifier which logically binds clients with providers
105
99
* @param version a version identifier
106
100
* @return a new client instance
107
101
*/
@@ -111,6 +105,17 @@ public Client getClient(String domain, String version) {
111
105
version );
112
106
}
113
107
108
+ /**
109
+ * Gets the global evaluation context, which will be used for all evaluations.
110
+ *
111
+ * @return evaluation context
112
+ */
113
+ public EvaluationContext getEvaluationContext () {
114
+ try (AutoCloseableLock __ = lock .readLockAutoCloseable ()) {
115
+ return this .evaluationContext ;
116
+ }
117
+ }
118
+
114
119
/**
115
120
* Sets the global evaluation context, which will be used for all evaluations.
116
121
*
@@ -124,17 +129,6 @@ public OpenFeatureAPI setEvaluationContext(EvaluationContext evaluationContext)
124
129
return this ;
125
130
}
126
131
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
132
/**
139
133
* Return the transaction context propagator.
140
134
*/
@@ -175,39 +169,6 @@ public void setTransactionContext(EvaluationContext evaluationContext) {
175
169
this .transactionContextPropagator .setTransactionContext (evaluationContext );
176
170
}
177
171
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
172
/**
212
173
* Set the default provider and wait for initialization to finish.
213
174
*/
@@ -226,8 +187,8 @@ public void setProviderAndWait(FeatureProvider provider) throws OpenFeatureError
226
187
/**
227
188
* Add a provider for a domain and wait for initialization to finish.
228
189
*
229
- * @param domain The domain to bind the provider to.
230
- * @param provider The provider to set.
190
+ * @param domain The domain to bind the provider to.
191
+ * @param provider The provider to set.
231
192
*/
232
193
public void setProviderAndWait (String domain , FeatureProvider provider ) throws OpenFeatureError {
233
194
try (AutoCloseableLock __ = lock .writeLockAutoCloseable ()) {
@@ -286,6 +247,39 @@ public FeatureProvider getProvider(String domain) {
286
247
return providerRepository .getProvider (domain );
287
248
}
288
249
250
+ /**
251
+ * Set the default provider.
252
+ */
253
+ public void setProvider (FeatureProvider provider ) {
254
+ try (AutoCloseableLock __ = lock .writeLockAutoCloseable ()) {
255
+ providerRepository .setProvider (
256
+ provider ,
257
+ this ::attachEventProvider ,
258
+ this ::emitReady ,
259
+ this ::detachEventProvider ,
260
+ this ::emitError ,
261
+ false );
262
+ }
263
+ }
264
+
265
+ /**
266
+ * Add a provider for a domain.
267
+ *
268
+ * @param domain The domain to bind the provider to.
269
+ * @param provider The provider to set.
270
+ */
271
+ public void setProvider (String domain , FeatureProvider provider ) {
272
+ try (AutoCloseableLock __ = lock .writeLockAutoCloseable ()) {
273
+ providerRepository .setProvider (domain ,
274
+ provider ,
275
+ this ::attachEventProvider ,
276
+ this ::emitReady ,
277
+ this ::detachEventProvider ,
278
+ this ::emitError ,
279
+ false );
280
+ }
281
+ }
282
+
289
283
/**
290
284
* Adds hooks for globally, used for all evaluations.
291
285
* 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 +294,7 @@ public void addHooks(Hook... hooks) {
300
294
301
295
/**
302
296
* Fetch the hooks associated to this client.
297
+ *
303
298
* @return A list of {@link Hook}s.
304
299
*/
305
300
public List <Hook > getHooks () {
@@ -404,7 +399,7 @@ void addHandler(String domain, ProviderEvent event, Consumer<EventDetails> handl
404
399
405
400
/**
406
401
* Runs the handlers associated with a particular provider.
407
- *
402
+ *
408
403
* @param provider the provider from where this event originated
409
404
* @param event the event type
410
405
* @param details the event details
@@ -440,4 +435,42 @@ private void runHandlersForProvider(FeatureProvider provider, ProviderEvent even
440
435
}
441
436
}
442
437
}
438
+
439
+ private static class SingletonHolder {
440
+ private static final OpenFeatureAPI INSTANCE ;
441
+
442
+ static {
443
+ OpenFeatureAPI instance = null ;
444
+ String cls = System .getenv ("OPEN_FEATURE_API_CLASS" );
445
+ if (cls == null ) {
446
+ try (InputStream propertiesFile =
447
+ SingletonHolder .class .getResourceAsStream ("openfeature.properties" )) {
448
+ if (propertiesFile != null ) {
449
+ Properties props = new Properties ();
450
+ props .load (propertiesFile );
451
+ cls = props .getProperty ("openfeature.api.class" );
452
+ }
453
+ } catch (IOException e ) {
454
+ log .error ("Custom OpenFeatureApi could not be initialized" , e );
455
+ }
456
+ }
457
+ if (cls != null ) {
458
+ try {
459
+ Class <?> clazz = Class .forName (cls );
460
+
461
+ instance = (OpenFeatureAPI ) clazz .newInstance ();
462
+ } catch (ClassNotFoundException
463
+ | ClassCastException
464
+ | InstantiationException
465
+ | IllegalAccessException e ) {
466
+ log .error ("Custom OpenFeatureApi could not be initialized" , e );
467
+ }
468
+ }
469
+ if (instance == null ) {
470
+ instance = new OpenFeatureAPI ();
471
+ }
472
+
473
+ INSTANCE = instance ;
474
+ }
475
+ }
443
476
}
0 commit comments