5
5
import dev .openfeature .sdk .internal .AutoCloseableReentrantReadWriteLock ;
6
6
import java .util .ArrayList ;
7
7
import java .util .Arrays ;
8
+ import java .util .Collection ;
8
9
import java .util .List ;
9
10
import java .util .Optional ;
10
11
import java .util .Set ;
12
+ import java .util .concurrent .ConcurrentLinkedQueue ;
13
+ import java .util .concurrent .atomic .AtomicReference ;
11
14
import java .util .function .Consumer ;
12
15
import lombok .extern .slf4j .Slf4j ;
13
16
21
24
public class OpenFeatureAPI implements EventBus <OpenFeatureAPI > {
22
25
// package-private multi-read/single-write lock
23
26
static AutoCloseableReentrantReadWriteLock lock = new AutoCloseableReentrantReadWriteLock ();
24
- private final List <Hook > apiHooks ;
27
+ private final ConcurrentLinkedQueue <Hook > apiHooks ;
25
28
private ProviderRepository providerRepository ;
26
29
private EventSupport eventSupport ;
27
- private EvaluationContext evaluationContext ;
30
+ private final AtomicReference < EvaluationContext > evaluationContext = new AtomicReference <>() ;
28
31
private TransactionContextPropagator transactionContextPropagator ;
29
32
30
33
protected OpenFeatureAPI () {
31
- apiHooks = new ArrayList <>();
34
+ apiHooks = new ConcurrentLinkedQueue <>();
32
35
providerRepository = new ProviderRepository (this );
33
36
eventSupport = new EventSupport ();
34
37
transactionContextPropagator = new NoOpTransactionContextPropagator ();
@@ -115,9 +118,7 @@ public Client getClient(String domain, String version) {
115
118
* @return api instance
116
119
*/
117
120
public OpenFeatureAPI setEvaluationContext (EvaluationContext evaluationContext ) {
118
- try (AutoCloseableLock __ = lock .writeLockAutoCloseable ()) {
119
- this .evaluationContext = evaluationContext ;
120
- }
121
+ this .evaluationContext .set (evaluationContext );
121
122
return this ;
122
123
}
123
124
@@ -127,16 +128,14 @@ public OpenFeatureAPI setEvaluationContext(EvaluationContext evaluationContext)
127
128
* @return evaluation context
128
129
*/
129
130
public EvaluationContext getEvaluationContext () {
130
- try (AutoCloseableLock __ = lock .readLockAutoCloseable ()) {
131
- return this .evaluationContext ;
132
- }
131
+ return evaluationContext .get ();
133
132
}
134
133
135
134
/**
136
135
* Return the transaction context propagator.
137
136
*/
138
137
public TransactionContextPropagator getTransactionContextPropagator () {
139
- try (AutoCloseableLock __ = lock .readLockAutoCloseable ()) {
138
+ try (AutoCloseableLock ignored = lock .readLockAutoCloseable ()) {
140
139
return this .transactionContextPropagator ;
141
140
}
142
141
}
@@ -150,7 +149,7 @@ public void setTransactionContextPropagator(TransactionContextPropagator transac
150
149
if (transactionContextPropagator == null ) {
151
150
throw new IllegalArgumentException ("Transaction context propagator cannot be null" );
152
151
}
153
- try (AutoCloseableLock __ = lock .writeLockAutoCloseable ()) {
152
+ try (AutoCloseableLock ignored = lock .writeLockAutoCloseable ()) {
154
153
this .transactionContextPropagator = transactionContextPropagator ;
155
154
}
156
155
}
@@ -176,7 +175,7 @@ public void setTransactionContext(EvaluationContext evaluationContext) {
176
175
* Set the default provider.
177
176
*/
178
177
public void setProvider (FeatureProvider provider ) {
179
- try (AutoCloseableLock __ = lock .writeLockAutoCloseable ()) {
178
+ try (AutoCloseableLock ignored = lock .writeLockAutoCloseable ()) {
180
179
providerRepository .setProvider (
181
180
provider ,
182
181
this ::attachEventProvider ,
@@ -194,7 +193,7 @@ public void setProvider(FeatureProvider provider) {
194
193
* @param provider The provider to set.
195
194
*/
196
195
public void setProvider (String domain , FeatureProvider provider ) {
197
- try (AutoCloseableLock __ = lock .writeLockAutoCloseable ()) {
196
+ try (AutoCloseableLock ignored = lock .writeLockAutoCloseable ()) {
198
197
providerRepository .setProvider (
199
198
domain ,
200
199
provider ,
@@ -216,7 +215,7 @@ public void setProvider(String domain, FeatureProvider provider) {
216
215
* @throws OpenFeatureError if the provider fails during initialization.
217
216
*/
218
217
public void setProviderAndWait (FeatureProvider provider ) throws OpenFeatureError {
219
- try (AutoCloseableLock __ = lock .writeLockAutoCloseable ()) {
218
+ try (AutoCloseableLock ignored = lock .writeLockAutoCloseable ()) {
220
219
providerRepository .setProvider (
221
220
provider ,
222
221
this ::attachEventProvider ,
@@ -238,7 +237,7 @@ public void setProviderAndWait(FeatureProvider provider) throws OpenFeatureError
238
237
* @throws OpenFeatureError if the provider fails during initialization.
239
238
*/
240
239
public void setProviderAndWait (String domain , FeatureProvider provider ) throws OpenFeatureError {
241
- try (AutoCloseableLock __ = lock .writeLockAutoCloseable ()) {
240
+ try (AutoCloseableLock ignored = lock .writeLockAutoCloseable ()) {
242
241
providerRepository .setProvider (
243
242
domain ,
244
243
provider ,
@@ -252,9 +251,7 @@ public void setProviderAndWait(String domain, FeatureProvider provider) throws O
252
251
253
252
private void attachEventProvider (FeatureProvider provider ) {
254
253
if (provider instanceof EventProvider ) {
255
- ((EventProvider ) provider ).attach ((p , event , details ) -> {
256
- runHandlersForProvider (p , event , details );
257
- });
254
+ ((EventProvider ) provider ).attach (this ::runHandlersForProvider );
258
255
}
259
256
}
260
257
@@ -307,9 +304,7 @@ public FeatureProvider getProvider(String domain) {
307
304
* @param hooks The hook to add.
308
305
*/
309
306
public void addHooks (Hook ... hooks ) {
310
- try (AutoCloseableLock __ = lock .writeLockAutoCloseable ()) {
311
- this .apiHooks .addAll (Arrays .asList (hooks ));
312
- }
307
+ this .apiHooks .addAll (Arrays .asList (hooks ));
313
308
}
314
309
315
310
/**
@@ -318,18 +313,23 @@ public void addHooks(Hook... hooks) {
318
313
* @return A list of {@link Hook}s.
319
314
*/
320
315
public List <Hook > getHooks () {
321
- try (AutoCloseableLock __ = lock .readLockAutoCloseable ()) {
322
- return this .apiHooks ;
323
- }
316
+ return new ArrayList <>(this .apiHooks );
317
+ }
318
+
319
+ /**
320
+ * Returns a reference to the collection of {@link Hook}s.
321
+ *
322
+ * @return The collection of {@link Hook}s.
323
+ */
324
+ Collection <Hook > getMutableHooks () {
325
+ return this .apiHooks ;
324
326
}
325
327
326
328
/**
327
329
* Removes all hooks.
328
330
*/
329
331
public void clearHooks () {
330
- try (AutoCloseableLock __ = lock .writeLockAutoCloseable ()) {
331
- this .apiHooks .clear ();
332
- }
332
+ this .apiHooks .clear ();
333
333
}
334
334
335
335
/**
@@ -339,7 +339,7 @@ public void clearHooks() {
339
339
* Once shut down is complete, API is reset and ready to use again.
340
340
*/
341
341
public void shutdown () {
342
- try (AutoCloseableLock __ = lock .writeLockAutoCloseable ()) {
342
+ try (AutoCloseableLock ignored = lock .writeLockAutoCloseable ()) {
343
343
providerRepository .shutdown ();
344
344
eventSupport .shutdown ();
345
345
@@ -385,7 +385,7 @@ public OpenFeatureAPI onProviderError(Consumer<EventDetails> handler) {
385
385
*/
386
386
@ Override
387
387
public OpenFeatureAPI on (ProviderEvent event , Consumer <EventDetails > handler ) {
388
- try (AutoCloseableLock __ = lock .writeLockAutoCloseable ()) {
388
+ try (AutoCloseableLock ignored = lock .writeLockAutoCloseable ()) {
389
389
this .eventSupport .addGlobalHandler (event , handler );
390
390
return this ;
391
391
}
@@ -396,18 +396,20 @@ public OpenFeatureAPI on(ProviderEvent event, Consumer<EventDetails> handler) {
396
396
*/
397
397
@ Override
398
398
public OpenFeatureAPI removeHandler (ProviderEvent event , Consumer <EventDetails > handler ) {
399
- this .eventSupport .removeGlobalHandler (event , handler );
399
+ try (AutoCloseableLock ignored = lock .writeLockAutoCloseable ()) {
400
+ this .eventSupport .removeGlobalHandler (event , handler );
401
+ }
400
402
return this ;
401
403
}
402
404
403
405
void removeHandler (String domain , ProviderEvent event , Consumer <EventDetails > handler ) {
404
- try (AutoCloseableLock __ = lock .writeLockAutoCloseable ()) {
406
+ try (AutoCloseableLock ignored = lock .writeLockAutoCloseable ()) {
405
407
eventSupport .removeClientHandler (domain , event , handler );
406
408
}
407
409
}
408
410
409
411
void addHandler (String domain , ProviderEvent event , Consumer <EventDetails > handler ) {
410
- try (AutoCloseableLock __ = lock .writeLockAutoCloseable ()) {
412
+ try (AutoCloseableLock ignored = lock .writeLockAutoCloseable ()) {
411
413
// if the provider is in the state associated with event, run immediately
412
414
if (Optional .ofNullable (this .providerRepository .getProviderState (domain ))
413
415
.orElse (ProviderState .READY )
@@ -431,32 +433,28 @@ FeatureProviderStateManager getFeatureProviderStateManager(String domain) {
431
433
* @param details the event details
432
434
*/
433
435
private void runHandlersForProvider (FeatureProvider provider , ProviderEvent event , ProviderEventDetails details ) {
434
- try (AutoCloseableLock __ = lock .readLockAutoCloseable ()) {
436
+ try (AutoCloseableLock ignored = lock .readLockAutoCloseable ()) {
435
437
436
438
List <String > domainsForProvider = providerRepository .getDomainsForProvider (provider );
437
439
438
440
final String providerName = Optional .ofNullable (provider .getMetadata ())
439
- .map (metadata -> metadata . getName () )
441
+ .map (Metadata :: getName )
440
442
.orElse (null );
441
443
442
444
// run the global handlers
443
445
eventSupport .runGlobalHandlers (event , EventDetails .fromProviderEventDetails (details , providerName ));
444
446
445
447
// run the handlers associated with domains for this provider
446
- domainsForProvider .forEach (domain -> {
447
- eventSupport .runClientHandlers (
448
- domain , event , EventDetails .fromProviderEventDetails (details , providerName , domain ));
449
- });
448
+ domainsForProvider .forEach (domain -> eventSupport .runClientHandlers (
449
+ domain , event , EventDetails .fromProviderEventDetails (details , providerName , domain )));
450
450
451
451
if (providerRepository .isDefaultProvider (provider )) {
452
452
// run handlers for clients that have no bound providers (since this is the default)
453
453
Set <String > allDomainNames = eventSupport .getAllDomainNames ();
454
454
Set <String > boundDomains = providerRepository .getAllBoundDomains ();
455
455
allDomainNames .removeAll (boundDomains );
456
- allDomainNames .forEach (domain -> {
457
- eventSupport .runClientHandlers (
458
- domain , event , EventDetails .fromProviderEventDetails (details , providerName , domain ));
459
- });
456
+ allDomainNames .forEach (domain -> eventSupport .runClientHandlers (
457
+ domain , event , EventDetails .fromProviderEventDetails (details , providerName , domain )));
460
458
}
461
459
}
462
460
}
0 commit comments