/** {@link DataModelAccessor} implementation based on {@link Cache}. */
public class CacheBasedDataModelAccessor implements DataModelAccessor {
  private static final Logger log = LoggerFactory.getLogger(CacheBasedDataModelAccessor.class);

  public static final String DATA_MODEL_TO_ID_CACHE_NAME = "dataModelToIdCache";
  public static final String DATA_MODEL_TO_NAME_CACHE_NAME = "dataModelToNameCache";
  public static final String DATA_MODELS_FOR_EXECUTION_CACHE_NAME = "dataModelsForExecutionCache";

  protected Cache<IDataModelId, IDataModel> dataModelToIdCache =
      Caching.getCache(DATA_MODEL_TO_ID_CACHE_NAME, IDataModelId.class, IDataModel.class);
  protected Cache<String, IDataModel> dataModelToNameCache =
      Caching.getCache(DATA_MODEL_TO_NAME_CACHE_NAME, String.class, IDataModel.class);

  @Override
  public void add(IDataModel dataModel) {
    this.dataModelToIdCache.put(dataModel.getDataModelId(), dataModel);
    this.dataModelToNameCache.put(dataModel.getName(), dataModel);

    log.debug("DataModel {} is added to DataModelStorage.", dataModel.getName());
  }

  @Override
  public void addAll(Collection<IDataModel> dataModels) {
    dataModels.forEach(
        dm -> {
          if (dm == null) {
            return;
          }
          this.dataModelToIdCache.put(dm.getDataModelId(), dm);
          this.dataModelToNameCache.put(dm.getName(), dm);
        });

    log.debug(
        "DataModels {} are added to DataModelStorage.",
        dataModels.stream().map(IDataModel::toString).collect(Collectors.<String>toList()));
  }

  @Override
  public IDataModel get(IDataModelId dataModelId) {
    return this.dataModelToIdCache.get(dataModelId);
  }

  @Override
  public IDataModel get(String dataModelName) {
    return this.dataModelToNameCache.get(dataModelName);
  }

  @Override
  public Map<IDataModelId, IDataModel> getAll() {
    Map<IDataModelId, IDataModel> dms = new HashMap<>();
    for (Entry<IDataModelId, IDataModel> entry : this.dataModelToIdCache) {
      dms.put(entry.getKey(), entry.getValue());
    }
    return Collections.<IDataModelId, IDataModel>unmodifiableMap(dms);
  }

  public void setDataModelToIdCache(Cache<IDataModelId, IDataModel> dataModelToIdCache) {
    this.dataModelToIdCache = dataModelToIdCache;
  }

  public void setDataModelToNameCache(Cache<String, IDataModel> dataModelToNameCache) {
    this.dataModelToNameCache = dataModelToNameCache;
  }
}