content: /*
   * Copyright (C) 2015 Actor LLC. <https://actor.im>
   */
  
  package im.actor.core.util;
  
  import java.util.ArrayList;
  import java.util.HashMap;
  import java.util.List;
  
  import im.actor.runtime.actors.messages.Void;
  import im.actor.runtime.promise.Promise;
  import im.actor.runtime.storage.KeyValueEngine;
  import im.actor.runtime.storage.KeyValueItem;
  import im.actor.runtime.storage.KeyValueRecord;
  import im.actor.runtime.storage.KeyValueStorage;
  
  public abstract class BaseKeyValueEngine<T extends KeyValueItem> implements KeyValueEngine<T> {
      private final HashMap<Long, T> cache = new HashMap<>();
  
      private KeyValueStorage storage;
  
      protected BaseKeyValueEngine(KeyValueStorage storage) {
          this.storage = storage;
      }
  
      protected abstract byte[] serialize(T value);
  
      protected abstract T deserialize(byte[] data);
  
      @Override
      public synchronized void addOrUpdateItem(T item) {
          cache.put(item.getEngineId(), item);
          byte[] data = serialize(item);
          storage.addOrUpdateItem(item.getEngineId(), data);
      }
  
      @Override
      public synchronized void addOrUpdateItems(List<T> values) {
          for (T t : values) {
              cache.put(t.getEngineId(), t);
          }
  
          ArrayList<KeyValueRecord> records = new ArrayList<>();
          for (T v : values) {
              records.add(new KeyValueRecord(v.getEngineId(), serialize(v)));
          }
          storage.addOrUpdateItems(records);
      }
  
      @Override
      public synchronized void removeItem(long id) {
          cache.remove(id);
          storage.removeItem(id);
      }
  
      @Override
      public synchronized void removeItems(long[] ids) {
          for (long l : ids) {
              cache.remove(l);
          }
          storage.removeItems(ids);
      }
  
      @Override
      public synchronized void clear() {
          cache.clear();
          storage.clear();
      }
  
      @Override
      public synchronized T getValue(long id) {
          if (cache.containsKey(id)) {
              return cache.get(id);
          }
  
          byte[] data = storage.loadItem(id);
          if (data != null) {
              T res = deserialize(data);
              if (res != null) {
                  cache.put(res.getEngineId(), res);
                  return res;
              }
          }
          return null;
      }
  
      @Override
      public Promise<T> getValueAsync(long key) {
          T res = getValue(key);
          if (res != null) {
              return Promise.success(res);
          } else {
              return Promise.failure(new RuntimeException());
          }
      }
  
      @Override
      public Promise<Boolean> containsAsync(long key) {
          T res = getValue(key);
          return Promise.success(res != null);
      }
  }
  