55import dev .openfeature .sdk .internal .AutoCloseableReentrantReadWriteLock ;
66import java .util .ArrayList ;
77import java .util .Arrays ;
8+ import java .util .Collection ;
89import java .util .List ;
910import java .util .Optional ;
1011import java .util .Set ;
12+ import java .util .concurrent .ConcurrentLinkedQueue ;
13+ import java .util .concurrent .atomic .AtomicReference ;
1114import java .util .function .Consumer ;
1215import lombok .extern .slf4j .Slf4j ;
1316
2124public class OpenFeatureAPI implements EventBus <OpenFeatureAPI > {
2225 // package-private multi-read/single-write lock
2326 static AutoCloseableReentrantReadWriteLock lock = new AutoCloseableReentrantReadWriteLock ();
24- private final List <Hook > apiHooks ;
27+ private final ConcurrentLinkedQueue <Hook > apiHooks ;
2528 private ProviderRepository providerRepository ;
2629 private EventSupport eventSupport ;
27- private EvaluationContext evaluationContext ;
30+ private final AtomicReference < EvaluationContext > evaluationContext = new AtomicReference <>() ;
2831 private TransactionContextPropagator transactionContextPropagator ;
2932
3033 protected OpenFeatureAPI () {
31- apiHooks = new ArrayList <>();
34+ apiHooks = new ConcurrentLinkedQueue <>();
3235 providerRepository = new ProviderRepository (this );
3336 eventSupport = new EventSupport ();
3437 transactionContextPropagator = new NoOpTransactionContextPropagator ();
@@ -115,9 +118,7 @@ public Client getClient(String domain, String version) {
115118 * @return api instance
116119 */
117120 public OpenFeatureAPI setEvaluationContext (EvaluationContext evaluationContext ) {
118- try (AutoCloseableLock __ = lock .writeLockAutoCloseable ()) {
119- this .evaluationContext = evaluationContext ;
120- }
121+ this .evaluationContext .set (evaluationContext );
121122 return this ;
122123 }
123124
@@ -127,16 +128,14 @@ public OpenFeatureAPI setEvaluationContext(EvaluationContext evaluationContext)
127128 * @return evaluation context
128129 */
129130 public EvaluationContext getEvaluationContext () {
130- try (AutoCloseableLock __ = lock .readLockAutoCloseable ()) {
131- return this .evaluationContext ;
132- }
131+ return evaluationContext .get ();
133132 }
134133
135134 /**
136135 * Return the transaction context propagator.
137136 */
138137 public TransactionContextPropagator getTransactionContextPropagator () {
139- try (AutoCloseableLock __ = lock .readLockAutoCloseable ()) {
138+ try (AutoCloseableLock ignored = lock .readLockAutoCloseable ()) {
140139 return this .transactionContextPropagator ;
141140 }
142141 }
@@ -150,7 +149,7 @@ public void setTransactionContextPropagator(TransactionContextPropagator transac
150149 if (transactionContextPropagator == null ) {
151150 throw new IllegalArgumentException ("Transaction context propagator cannot be null" );
152151 }
153- try (AutoCloseableLock __ = lock .writeLockAutoCloseable ()) {
152+ try (AutoCloseableLock ignored = lock .writeLockAutoCloseable ()) {
154153 this .transactionContextPropagator = transactionContextPropagator ;
155154 }
156155 }
@@ -176,7 +175,7 @@ public void setTransactionContext(EvaluationContext evaluationContext) {
176175 * Set the default provider.
177176 */
178177 public void setProvider (FeatureProvider provider ) {
179- try (AutoCloseableLock __ = lock .writeLockAutoCloseable ()) {
178+ try (AutoCloseableLock ignored = lock .writeLockAutoCloseable ()) {
180179 providerRepository .setProvider (
181180 provider ,
182181 this ::attachEventProvider ,
@@ -194,7 +193,7 @@ public void setProvider(FeatureProvider provider) {
194193 * @param provider The provider to set.
195194 */
196195 public void setProvider (String domain , FeatureProvider provider ) {
197- try (AutoCloseableLock __ = lock .writeLockAutoCloseable ()) {
196+ try (AutoCloseableLock ignored = lock .writeLockAutoCloseable ()) {
198197 providerRepository .setProvider (
199198 domain ,
200199 provider ,
@@ -216,7 +215,7 @@ public void setProvider(String domain, FeatureProvider provider) {
216215 * @throws OpenFeatureError if the provider fails during initialization.
217216 */
218217 public void setProviderAndWait (FeatureProvider provider ) throws OpenFeatureError {
219- try (AutoCloseableLock __ = lock .writeLockAutoCloseable ()) {
218+ try (AutoCloseableLock ignored = lock .writeLockAutoCloseable ()) {
220219 providerRepository .setProvider (
221220 provider ,
222221 this ::attachEventProvider ,
@@ -238,7 +237,7 @@ public void setProviderAndWait(FeatureProvider provider) throws OpenFeatureError
238237 * @throws OpenFeatureError if the provider fails during initialization.
239238 */
240239 public void setProviderAndWait (String domain , FeatureProvider provider ) throws OpenFeatureError {
241- try (AutoCloseableLock __ = lock .writeLockAutoCloseable ()) {
240+ try (AutoCloseableLock ignored = lock .writeLockAutoCloseable ()) {
242241 providerRepository .setProvider (
243242 domain ,
244243 provider ,
@@ -252,9 +251,7 @@ public void setProviderAndWait(String domain, FeatureProvider provider) throws O
252251
253252 private void attachEventProvider (FeatureProvider provider ) {
254253 if (provider instanceof EventProvider ) {
255- ((EventProvider ) provider ).attach ((p , event , details ) -> {
256- runHandlersForProvider (p , event , details );
257- });
254+ ((EventProvider ) provider ).attach (this ::runHandlersForProvider );
258255 }
259256 }
260257
@@ -307,9 +304,7 @@ public FeatureProvider getProvider(String domain) {
307304 * @param hooks The hook to add.
308305 */
309306 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 ));
313308 }
314309
315310 /**
@@ -318,18 +313,23 @@ public void addHooks(Hook... hooks) {
318313 * @return A list of {@link Hook}s.
319314 */
320315 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 ;
324326 }
325327
326328 /**
327329 * Removes all hooks.
328330 */
329331 public void clearHooks () {
330- try (AutoCloseableLock __ = lock .writeLockAutoCloseable ()) {
331- this .apiHooks .clear ();
332- }
332+ this .apiHooks .clear ();
333333 }
334334
335335 /**
@@ -339,7 +339,7 @@ public void clearHooks() {
339339 * Once shut down is complete, API is reset and ready to use again.
340340 */
341341 public void shutdown () {
342- try (AutoCloseableLock __ = lock .writeLockAutoCloseable ()) {
342+ try (AutoCloseableLock ignored = lock .writeLockAutoCloseable ()) {
343343 providerRepository .shutdown ();
344344 eventSupport .shutdown ();
345345
@@ -385,7 +385,7 @@ public OpenFeatureAPI onProviderError(Consumer<EventDetails> handler) {
385385 */
386386 @ Override
387387 public OpenFeatureAPI on (ProviderEvent event , Consumer <EventDetails > handler ) {
388- try (AutoCloseableLock __ = lock .writeLockAutoCloseable ()) {
388+ try (AutoCloseableLock ignored = lock .writeLockAutoCloseable ()) {
389389 this .eventSupport .addGlobalHandler (event , handler );
390390 return this ;
391391 }
@@ -396,18 +396,20 @@ public OpenFeatureAPI on(ProviderEvent event, Consumer<EventDetails> handler) {
396396 */
397397 @ Override
398398 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+ }
400402 return this ;
401403 }
402404
403405 void removeHandler (String domain , ProviderEvent event , Consumer <EventDetails > handler ) {
404- try (AutoCloseableLock __ = lock .writeLockAutoCloseable ()) {
406+ try (AutoCloseableLock ignored = lock .writeLockAutoCloseable ()) {
405407 eventSupport .removeClientHandler (domain , event , handler );
406408 }
407409 }
408410
409411 void addHandler (String domain , ProviderEvent event , Consumer <EventDetails > handler ) {
410- try (AutoCloseableLock __ = lock .writeLockAutoCloseable ()) {
412+ try (AutoCloseableLock ignored = lock .writeLockAutoCloseable ()) {
411413 // if the provider is in the state associated with event, run immediately
412414 if (Optional .ofNullable (this .providerRepository .getProviderState (domain ))
413415 .orElse (ProviderState .READY )
@@ -431,32 +433,28 @@ FeatureProviderStateManager getFeatureProviderStateManager(String domain) {
431433 * @param details the event details
432434 */
433435 private void runHandlersForProvider (FeatureProvider provider , ProviderEvent event , ProviderEventDetails details ) {
434- try (AutoCloseableLock __ = lock .readLockAutoCloseable ()) {
436+ try (AutoCloseableLock ignored = lock .readLockAutoCloseable ()) {
435437
436438 List <String > domainsForProvider = providerRepository .getDomainsForProvider (provider );
437439
438440 final String providerName = Optional .ofNullable (provider .getMetadata ())
439- .map (metadata -> metadata . getName () )
441+ .map (Metadata :: getName )
440442 .orElse (null );
441443
442444 // run the global handlers
443445 eventSupport .runGlobalHandlers (event , EventDetails .fromProviderEventDetails (details , providerName ));
444446
445447 // 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 )));
450450
451451 if (providerRepository .isDefaultProvider (provider )) {
452452 // run handlers for clients that have no bound providers (since this is the default)
453453 Set <String > allDomainNames = eventSupport .getAllDomainNames ();
454454 Set <String > boundDomains = providerRepository .getAllBoundDomains ();
455455 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 )));
460458 }
461459 }
462460 }
0 commit comments