eventHandler;
+ private final FlagTracker flagTracker;
+
/**
* Creates a new client to connect to feature flag center with a specified configuration.
*
@@ -109,13 +111,18 @@ public FBClientImp(String envSecret, FBConfig config) {
return item == null ? null : (DataModel.Segment) item;
};
this.evaluator = new EvaluatorImp(flagGetter, segmentGetter);
+
+ this.sharedExecutorService = new ScheduledThreadPoolExecutor(1, Utils.createThreadFactory("featbit-shared-worker-%d", true));
+ EventBroadcasterImpl dataUpdateStateNotifier = EventBroadcasterImpl.forDataUpdateStates(this.sharedExecutorService, logger);
+ EventBroadcasterImpl flagChangeEventNotifier = EventBroadcasterImpl.forFlagChangeEvents(this.sharedExecutorService, logger);
+ this.flagTracker = new FlagTrackerImpl(flagChangeEventNotifier, (key, user) -> variation(key, user, null));
//data updator
- Status.DataUpdaterImpl dataUpdatorImpl = new Status.DataUpdaterImpl(this.storage);
+ Status.DataUpdaterImpl dataUpdatorImpl = new Status.DataUpdaterImpl(this.storage, dataUpdateStateNotifier, flagChangeEventNotifier);
this.dataUpdater = dataUpdatorImpl;
//data processor
this.dataSynchronizer = config.getDataSynchronizerFactory().createDataSynchronizer(context, dataUpdatorImpl);
//data update status provider
- this.dataUpdateStatusProvider = new Status.DataUpdateStatusProviderImpl(dataUpdatorImpl);
+ this.dataUpdateStatusProvider = new Status.DataUpdateStatusProviderImpl(dataUpdatorImpl, dataUpdateStateNotifier);
// data sync
Duration startWait = config.getStartWaitTime();
@@ -287,6 +294,12 @@ public void close() throws IOException {
this.storage.close();
this.dataSynchronizer.close();
this.insightProcessor.close();
+ this.sharedExecutorService.shutdownNow();
+ }
+
+ @Override
+ public FlagTracker getFlagTracker() {
+ return this.flagTracker;
}
@Override
diff --git a/src/main/java/co/featbit/server/FlagChange.java b/src/main/java/co/featbit/server/FlagChange.java
new file mode 100644
index 0000000..e9afcf5
--- /dev/null
+++ b/src/main/java/co/featbit/server/FlagChange.java
@@ -0,0 +1,36 @@
+package co.featbit.server;
+
+import java.util.Objects;
+
+public abstract class FlagChange {
+
+ public static class FlagChangeEvent {
+ private final String key;
+
+ public FlagChangeEvent(String key) {
+ this.key = key;
+ }
+
+ public String getKey() {
+ return key;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (o == null || getClass() != o.getClass()) return false;
+ FlagChangeEvent that = (FlagChangeEvent) o;
+ return Objects.equals(key, that.key);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(key);
+ }
+ }
+
+ public interface FlagChangeListener {
+ void onFlagChange(FlagChangeEvent event);
+ }
+
+}
diff --git a/src/main/java/co/featbit/server/FlagTrackerImpl.java b/src/main/java/co/featbit/server/FlagTrackerImpl.java
new file mode 100644
index 0000000..c943cd5
--- /dev/null
+++ b/src/main/java/co/featbit/server/FlagTrackerImpl.java
@@ -0,0 +1,65 @@
+package co.featbit.server;
+
+import co.featbit.commons.model.FBUser;
+import co.featbit.server.exterior.FlagTracker;
+import co.featbit.server.exterior.FlagValueChangeEvent;
+import co.featbit.server.exterior.FlagValueChangeListener;
+
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.BiFunction;
+
+class FlagTrackerImpl implements FlagTracker {
+
+ private final EventBroadcaster flagChangeEventNotifier;
+
+ private final BiFunction evaluateFn;
+
+ FlagTrackerImpl(EventBroadcaster flagChangeEventNotifier,
+ BiFunction evaluateFn) {
+ this.flagChangeEventNotifier = flagChangeEventNotifier;
+ this.evaluateFn = evaluateFn;
+ }
+
+ @Override
+ public FlagChange.FlagChangeListener addFlagValueChangeListener(String flagKey, FBUser user, FlagValueChangeListener listener) {
+ FlagChange.FlagChangeListener adapter = new FlagValueChangeAdapter(flagKey, user, listener);
+ addFlagChangeListener(adapter);
+ return adapter;
+ }
+
+ @Override
+ public void removeFlagChangeListener(FlagChange.FlagChangeListener listener) {
+ flagChangeEventNotifier.removeListener(listener);
+ }
+
+ @Override
+ public void addFlagChangeListener(FlagChange.FlagChangeListener listener) {
+ flagChangeEventNotifier.addListener(listener);
+ }
+
+ private final class FlagValueChangeAdapter implements FlagChange.FlagChangeListener {
+ private final String flagKey;
+ private final FBUser user;
+ private final FlagValueChangeListener listener;
+ private final AtomicReference