All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.launchdarkly.client.InMemoryFeatureStore Maven / Gradle / Ivy

package com.launchdarkly.client;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * A thread-safe, versioned store for {@link FeatureFlag} objects based on a
 * {@link HashMap}
 */
public class InMemoryFeatureStore implements FeatureStore {
  private static final Logger logger = LoggerFactory.getLogger(InMemoryFeatureStore.class);

  private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
  private final Map features = new HashMap<>();
  private volatile boolean initialized = false;


  /**
   * Returns the {@link FeatureFlag} to which the specified key is mapped, or
   * null if the key is not associated or the associated {@link FeatureFlag} has
   * been deleted.
   *
   * @param key the key whose associated {@link FeatureFlag} is to be returned
   * @return the {@link FeatureFlag} to which the specified key is mapped, or
   * null if the key is not associated or the associated {@link FeatureFlag} has
   * been deleted.
   */
  @Override
  public FeatureFlag get(String key) {
    try {
      lock.readLock().lock();
      FeatureFlag featureFlag = features.get(key);
      if (featureFlag == null) {
        logger.debug("[get] Key: " + key + " not found in feature store. Returning null");
        return null;
      }
      if (featureFlag.isDeleted()) {
        logger.debug("[get] Key: " + key + " has been deleted. Returning null");
        return null;
      }
      logger.debug("[get] Key: " + key + " with version: " + featureFlag.getVersion() + " found in feature store.");
      return featureFlag;
    } finally {
      lock.readLock().unlock();
    }
  }

  /**
   * Returns a {@link java.util.Map} of all associated features.
   *
   * @return a map of all associated features.
   */
  @Override
  public Map all() {
    try {
      lock.readLock().lock();
      Map fs = new HashMap<>();

      for (Map.Entry entry : features.entrySet()) {
        if (!entry.getValue().isDeleted()) {
          fs.put(entry.getKey(), entry.getValue());
        }
      }
      return fs;
    } finally {
      lock.readLock().unlock();
    }
  }


  /**
   * Initializes (or re-initializes) the store with the specified set of features. Any existing entries
   * will be removed.
   *
   * @param features the features to set the store
   */
  @Override
  public void init(Map features) {
    try {
      lock.writeLock().lock();
      this.features.clear();
      this.features.putAll(features);
      initialized = true;
    } finally {
      lock.writeLock().unlock();
    }
  }

  /**
   * Deletes the feature associated with the specified key, if it exists and its version
   * is less than or equal to the specified version.
   *
   * @param key     the key of the feature to be deleted
   * @param version the version for the delete operation
   */
  @Override
  public void delete(String key, int version) {
    try {
      lock.writeLock().lock();
      FeatureFlag f = features.get(key);
      if (f != null && f.getVersion() < version) {
        FeatureFlagBuilder newBuilder = new FeatureFlagBuilder(f);
        newBuilder.deleted(true);
        newBuilder.version(version);
        features.put(key, newBuilder.build());
      } else if (f == null) {
        f = new FeatureFlagBuilder(key)
            .deleted(true)
            .version(version)
            .build();
        features.put(key, f);
      }
    } finally {
      lock.writeLock().unlock();
    }
  }

  /**
   * Update or insert the feature associated with the specified key, if its version
   * is less than or equal to the version specified in the argument feature.
   *
   * @param key
   * @param feature
   */
  @Override
  public void upsert(String key, FeatureFlag feature) {
    try {
      lock.writeLock().lock();
      FeatureFlag old = features.get(key);

      if (old == null || old.getVersion() < feature.getVersion()) {
        features.put(key, feature);
      }
    } finally {
      lock.writeLock().unlock();
    }
  }

  /**
   * Returns true if this store has been initialized
   *
   * @return true if this store has been initialized
   */
  @Override
  public boolean initialized() {
    return initialized;
  }

  /**
   * Does nothing; this class does not have any resources to release
   *
   * @throws IOException
   */
  @Override
  public void close() throws IOException {
    return;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy