Skip to content

Commit

Permalink
fix: add read/write locks to client/api
Browse files Browse the repository at this point in the history
Signed-off-by: Todd Baert <[email protected]>
  • Loading branch information
toddbaert committed Oct 7, 2022
1 parent e52fe0b commit 2426fee
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 21 deletions.
51 changes: 36 additions & 15 deletions src/main/java/dev/openfeature/sdk/OpenFeatureAPI.java
Original file line number Diff line number Diff line change
@@ -1,43 +1,45 @@
package dev.openfeature.sdk;

import lombok.Getter;
import lombok.Setter;

import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import javax.annotation.Nullable;

import dev.openfeature.sdk.internal.AutoCloseableLock;
import dev.openfeature.sdk.internal.AutoCloseableReentrantReadWriteLock;
import lombok.Getter;
import lombok.Setter;

/**
* A global singleton which holds base configuration for the OpenFeature library.
* Configuration here will be shared across all {@link Client}s.
*/
public class OpenFeatureAPI {
private static OpenFeatureAPI api;
// package-private multi-read/single-write lock
static AutoCloseableReentrantReadWriteLock rwLock = new AutoCloseableReentrantReadWriteLock();
@Getter
@Setter
private FeatureProvider provider;
@Getter
@Setter
private EvaluationContext evaluationContext;
@Getter
private List<Hook> apiHooks;

public OpenFeatureAPI() {
private OpenFeatureAPI() {
this.apiHooks = new ArrayList<>();
}

private static class SingletonHolder {
private static final OpenFeatureAPI INSTANCE = new OpenFeatureAPI();
}

/**
* Provisions the {@link OpenFeatureAPI} singleton (if needed) and returns it.
* @return The singleton instance.
*/
public static OpenFeatureAPI getInstance() {
synchronized (OpenFeatureAPI.class) {
if (api == null) {
api = new OpenFeatureAPI();
}
}
return api;
return SingletonHolder.INSTANCE;
}

public Metadata getProviderMetadata() {
Expand All @@ -56,11 +58,30 @@ public Client getClient(@Nullable String name, @Nullable String version) {
return new OpenFeatureClient(this, name, version);
}

/**
* {@inheritDoc}
*/
public void setProvider(FeatureProvider provider) {
try (AutoCloseableLock __ = rwLock.writeLockAutoCloseable()) {
this.provider = provider;
}
}

/**
* {@inheritDoc}
*/
public void addHooks(Hook... hooks) {
this.apiHooks.addAll(Arrays.asList(hooks));
try (AutoCloseableLock __ = rwLock.writeLockAutoCloseable()) {
this.apiHooks.addAll(Arrays.asList(hooks));
}
}

/**
* {@inheritDoc}
*/
public void clearHooks() {
this.apiHooks.clear();
try (AutoCloseableLock __ = rwLock.writeLockAutoCloseable()) {
this.apiHooks.clear();
}
}
}
20 changes: 14 additions & 6 deletions src/main/java/dev/openfeature/sdk/OpenFeatureClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

import dev.openfeature.sdk.exceptions.GeneralError;
import dev.openfeature.sdk.exceptions.OpenFeatureError;
import dev.openfeature.sdk.internal.AutoCloseableLock;
import dev.openfeature.sdk.internal.AutoCloseableReentrantReadWriteLock;
import dev.openfeature.sdk.internal.ObjectUtils;
import lombok.Getter;
import lombok.Setter;
Expand All @@ -25,6 +27,7 @@ public class OpenFeatureClient implements Client {
@Getter
private final List<Hook> clientHooks;
private final HookSupport hookSupport;
private AutoCloseableReentrantReadWriteLock rwLock = new AutoCloseableReentrantReadWriteLock();

@Getter
@Setter
Expand All @@ -48,7 +51,9 @@ public OpenFeatureClient(OpenFeatureAPI openFeatureAPI, String name, String vers

@Override
public void addHooks(Hook... hooks) {
this.clientHooks.addAll(Arrays.asList(hooks));
try (AutoCloseableLock __ = this.rwLock.writeLockAutoCloseable()) {
this.clientHooks.addAll(Arrays.asList(hooks));
}
}

private <T> FlagEvaluationDetails<T> evaluateFlag(FlagValueType type, String key, T defaultValue,
Expand All @@ -57,16 +62,19 @@ private <T> FlagEvaluationDetails<T> evaluateFlag(FlagValueType type, String key
() -> FlagEvaluationOptions.builder().build());
Map<String, Object> hints = Collections.unmodifiableMap(flagOptions.getHookHints());
ctx = ObjectUtils.defaultIfNull(ctx, () -> new MutableContext());
FeatureProvider provider = ObjectUtils.defaultIfNull(openfeatureApi.getProvider(), () -> {
log.debug("No provider configured, using no-op provider.");
return new NoOpProvider();
});


FlagEvaluationDetails<T> details = null;
List<Hook> mergedHooks = null;
HookContext<T> hookCtx = null;

try {
try (AutoCloseableLock __ = OpenFeatureAPI.rwLock.readLockAutoCloseable();
AutoCloseableLock ___ = this.rwLock.readLockAutoCloseable()) {

FeatureProvider provider = ObjectUtils.defaultIfNull(openfeatureApi.getProvider(), () -> {
log.debug("No provider configured, using no-op provider.");
return new NoOpProvider();
});

hookCtx = HookContext.from(key, type, this.getMetadata(),
openfeatureApi.getProvider().getMetadata(), ctx, defaultValue);
Expand Down
10 changes: 10 additions & 0 deletions src/main/java/dev/openfeature/sdk/internal/AutoCloseableLock.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package dev.openfeature.sdk.internal;

public interface AutoCloseableLock extends AutoCloseable {

/**
* Override the exception in AutoClosable.
*/
@Override
void close();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package dev.openfeature.sdk.internal;

import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
* A utility class that wraps a multi-read/single-write lock construct as AutoCloseable, so it can
* be used in a try-with-resources.
*/
public class AutoCloseableReentrantReadWriteLock extends ReentrantReadWriteLock {

/**
* Get the single write lock as an AutoCloseableLock.
* @return unlock method ref
*/
public AutoCloseableLock writeLockAutoCloseable() {
this.writeLock().lock();
return this.writeLock()::unlock;
}

/**
* Get the multi read lock as an AutoCloseableLock.
* @return unlock method ref
*/
public AutoCloseableLock readLockAutoCloseable() {
this.readLock().lock();
return this.readLock()::unlock;
}
}

0 comments on commit 2426fee

Please sign in to comment.