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

co.easimart.CachedCurrentInstallationController Maven / Gradle / Ivy

package co.easimart;

import bolts.Continuation;
import bolts.Task;

/** package */ class CachedCurrentInstallationController
    implements EasimartCurrentInstallationController {

  /* package */ static final String TAG = "co.easimart.CachedCurrentInstallationController";

  /*
   * Note about lock ordering:
   *
   * You must NOT acquire the EasimartInstallation instance mutex (the "mutex" field in EasimartObject)
   * while holding this current installation lock. (We used to use the EasimartInstallation.class lock,
   * but moved on to an explicit lock object since anyone could acquire the EasimartInstallation.class
   * lock as EasimartInstallation is a public class.) Acquiring the instance mutex while holding this
   * current installation lock will lead to a deadlock. Here is an example:
   * https://phabricator.fb.com/P3251091
   */
  private final Object mutex = new Object();

  private final TaskQueue taskQueue = new TaskQueue();

  private final EasimartObjectStore store;
  private final InstallationId installationId;

  // The "current installation" is the installation for this device. Protected by
  // mutex.
  /* package for test */ EasimartInstallation currentInstallation;

  public CachedCurrentInstallationController(
      EasimartObjectStore store, InstallationId installationId) {
    this.store = store;
    this.installationId = installationId;
  }

  @Override
  public Task setAsync(final EasimartInstallation installation) {
    if (!isCurrent(installation)) {
      return Task.forResult(null);
    }

    return taskQueue.enqueue(new Continuation>() {
      @Override
      public Task then(Task toAwait) throws Exception {
        return toAwait.continueWithTask(new Continuation>() {
          @Override
          public Task then(Task task) throws Exception {
            return store.setAsync(installation);
          }
        }).continueWithTask(new Continuation>() {
          @Override
          public Task then(Task task) throws Exception {
            installationId.set(installation.getInstallationId());
            return task;
          }
        }, EasimartExecutors.io());
      }
    });
  }

  @Override
  public Task getAsync() {
    synchronized (mutex) {
      if (currentInstallation != null) {
        return Task.forResult(currentInstallation);
      }
    }

    return taskQueue.enqueue(new Continuation>() {
      @Override
      public Task then(Task toAwait) throws Exception {
        return toAwait.continueWithTask(new Continuation>() {
          @Override
          public Task then(Task task) throws Exception {
            synchronized (mutex) {
              if (currentInstallation != null) {
                return Task.forResult(currentInstallation);
              }
            }

            return store.getAsync().continueWith(new Continuation() {
              @Override
              public EasimartInstallation then(Task task) throws Exception {
                EasimartInstallation current = task.getResult();
                if (current == null) {
                  current = EasimartObject.create(EasimartInstallation.class);
                  current.updateDeviceInfo(installationId);
                } else {
                  installationId.set(current.getInstallationId());
                  EasimartLog.v(TAG, "Successfully deserialized Installation object");
                }

                synchronized (mutex) {
                  currentInstallation = current;
                }
                return current;
              }
            }, EasimartExecutors.io());
          }
        });
      }
    });
  }

  @Override
  public Task existsAsync() {
    synchronized (mutex) {
      if (currentInstallation != null) {
        return Task.forResult(true);
      }
    }

    return taskQueue.enqueue(new Continuation>() {
      @Override
      public Task then(Task toAwait) throws Exception {
        return toAwait.continueWithTask(new Continuation>() {
          @Override
          public Task then(Task task) throws Exception {
            return store.existsAsync();
          }
        });
      }
    });
  }

  @Override
  public void clearFromMemory() {
    synchronized (mutex) {
      currentInstallation = null;
    }
  }

  @Override
  public void clearFromDisk() {
    synchronized (mutex) {
      currentInstallation = null;
    }
    try {
      installationId.clear();
      EasimartTaskUtils.wait(store.deleteAsync());
    } catch (EasimartException e) {
      // ignored
    }
  }

  @Override
  public boolean isCurrent(EasimartInstallation installation) {
    synchronized (mutex) {
      return  currentInstallation == installation;
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy