com.parse.CachedCurrentInstallationController Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of parse-android Show documentation
Show all versions of parse-android Show documentation
A library that gives you access to the powerful Parse cloud platform from your Android app.
/*
* Copyright (c) 2015-present, Parse, LLC.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
package com.parse;
import bolts.Continuation;
import bolts.Task;
/** package */ class CachedCurrentInstallationController
implements ParseCurrentInstallationController {
/* package */ static final String TAG = "com.parse.CachedCurrentInstallationController";
/*
* Note about lock ordering:
*
* You must NOT acquire the ParseInstallation instance mutex (the "mutex" field in ParseObject)
* while holding this current installation lock. (We used to use the ParseInstallation.class lock,
* but moved on to an explicit lock object since anyone could acquire the ParseInstallation.class
* lock as ParseInstallation 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 ParseObjectStore store;
private final InstallationId installationId;
// The "current installation" is the installation for this device. Protected by
// mutex.
/* package for test */ ParseInstallation currentInstallation;
public CachedCurrentInstallationController(
ParseObjectStore store, InstallationId installationId) {
this.store = store;
this.installationId = installationId;
}
@Override
public Task setAsync(final ParseInstallation 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;
}
}, ParseExecutors.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 ParseInstallation then(Task task) throws Exception {
ParseInstallation current = task.getResult();
if (current == null) {
current = ParseObject.create(ParseInstallation.class);
current.updateDeviceInfo(installationId);
} else {
installationId.set(current.getInstallationId());
PLog.v(TAG, "Successfully deserialized Installation object");
}
synchronized (mutex) {
currentInstallation = current;
}
return current;
}
}, ParseExecutors.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();
ParseTaskUtils.wait(store.deleteAsync());
} catch (ParseException e) {
// ignored
}
}
@Override
public boolean isCurrent(ParseInstallation installation) {
synchronized (mutex) {
return currentInstallation == installation;
}
}
}