use of com.parse.boltsinternal.Task in project Parse-SDK-Android by ParsePlatform.
the class OfflineStore method saveLocallyAsync.
/**
* Stores a single object in the local database. If the object is a pointer, isn't dirty, and
* has an objectId already, it may not be saved, since it would provide no useful data.
*
* @param object The object to save.
* @param db A database connection to use.
*/
private Task<Void> saveLocallyAsync(final String key, final ParseObject object, final ParseSQLiteDatabase db) {
// If this is just a clean, unfetched pointer known to Parse, then there is nothing to save.
if (object.getObjectId() != null && !object.isDataAvailable() && !object.hasChanges() && !object.hasOutstandingOperations()) {
return Task.forResult(null);
}
final Capture<String> uuidCapture = new Capture<>();
// Make sure we have a UUID for the object to be saved.
return getOrCreateUUIDAsync(object, db).onSuccessTask(task -> {
String uuid = task.getResult();
uuidCapture.set(uuid);
return updateDataForObjectAsync(uuid, object, db);
}).onSuccessTask(task -> {
final ContentValues values = new ContentValues();
values.put(OfflineSQLiteOpenHelper.KEY_KEY, key);
values.put(OfflineSQLiteOpenHelper.KEY_UUID, uuidCapture.get());
return db.insertWithOnConflict(OfflineSQLiteOpenHelper.TABLE_DEPENDENCIES, values, SQLiteDatabase.CONFLICT_IGNORE);
});
}
use of com.parse.boltsinternal.Task in project Parse-SDK-Android by ParsePlatform.
the class ParseCommandCache method maybeRunAllCommandsNow.
/**
* Attempts to run every command in the disk queue in order, synchronously. If there is no
* network connection, returns immediately without doing anything. If there is supposedly a
* connection, but parse can't be reached, waits timeoutRetryWaitSeconds before retrying up to
* retriesRemaining times. Blocks until either there's a connection, or the retries are
* exhausted. If any command fails, just deletes it and moves on to the next one.
*/
private void maybeRunAllCommandsNow(int retriesRemaining) {
synchronized (lock) {
unprocessedCommandsExist = false;
if (!isConnected()) {
// There's no way to do work when there's no network connection.
return;
}
String[] fileNames = cachePath.list();
if (fileNames == null || fileNames.length == 0) {
return;
}
Arrays.sort(fileNames);
for (String fileName : fileNames) {
final File file = new File(cachePath, fileName);
// Read one command from the cache.
JSONObject json;
try {
json = ParseFileUtils.readFileToJSONObject(file);
} catch (FileNotFoundException e) {
// This shouldn't really be possible.
if (Parse.LOG_LEVEL_ERROR >= Parse.getLogLevel()) {
log.log(Level.SEVERE, "File disappeared from cache while being read.", e);
}
continue;
} catch (IOException e) {
if (Parse.LOG_LEVEL_ERROR >= Parse.getLogLevel()) {
log.log(Level.SEVERE, "Unable to read contents of file in cache.", e);
}
removeFile(file);
continue;
} catch (JSONException e) {
if (Parse.LOG_LEVEL_ERROR >= Parse.getLogLevel()) {
log.log(Level.SEVERE, "Error parsing JSON found in cache.", e);
}
removeFile(file);
continue;
}
// Convert the command from a string.
final ParseRESTCommand command;
final TaskCompletionSource<JSONObject> tcs = pendingTasks.containsKey(file) ? pendingTasks.get(file) : null;
try {
command = commandFromJSON(json);
} catch (JSONException e) {
if (Parse.LOG_LEVEL_ERROR >= Parse.getLogLevel()) {
log.log(Level.SEVERE, "Unable to create ParseCommand from JSON.", e);
}
removeFile(file);
continue;
}
try {
Task<JSONObject> commandTask;
if (command == null) {
commandTask = Task.forResult(null);
if (tcs != null) {
tcs.setResult(null);
}
notifyTestHelper(TestHelper.COMMAND_OLD_FORMAT_DISCARDED);
} else {
commandTask = command.executeAsync(httpClient).continueWithTask(task -> {
String localId = command.getLocalId();
Exception error = task.getError();
if (error != null) {
if (!(error instanceof ParseException) || ((ParseException) error).getCode() != ParseException.CONNECTION_FAILED) {
if (tcs != null) {
tcs.setError(error);
}
}
return task;
}
JSONObject json1 = task.getResult();
if (tcs != null) {
tcs.setResult(json1);
} else if (localId != null) {
// If this command created a new objectId,
// add it to the map.
String objectId = json1.optString("objectId", null);
if (objectId != null) {
ParseCorePlugins.getInstance().getLocalIdManager().setObjectId(localId, objectId);
}
}
return task;
});
}
waitForTaskWithoutLock(commandTask);
if (tcs != null) {
waitForTaskWithoutLock(tcs.getTask());
}
// The command succeeded. Remove it from the cache.
removeFile(file);
notifyTestHelper(TestHelper.COMMAND_SUCCESSFUL);
} catch (ParseException e) {
if (e.getCode() == ParseException.CONNECTION_FAILED) {
if (retriesRemaining > 0) {
// anything else.
if (Parse.LOG_LEVEL_INFO >= Parse.getLogLevel()) {
log.info("Network timeout in command cache. Waiting for " + timeoutRetryWaitSeconds + " seconds and then retrying " + retriesRemaining + " times.");
}
long currentTime = System.currentTimeMillis();
long waitUntil = currentTime + (long) (timeoutRetryWaitSeconds * 1000);
while (currentTime < waitUntil) {
// or should stop, just quit.
if (!isConnected() || shouldStop) {
if (Parse.LOG_LEVEL_INFO >= Parse.getLogLevel()) {
log.info("Aborting wait because runEventually thread should stop.");
}
return;
}
try {
lock.wait(waitUntil - currentTime);
} catch (InterruptedException ie) {
shouldStop = true;
}
currentTime = System.currentTimeMillis();
if (currentTime < (waitUntil - (long) (timeoutRetryWaitSeconds * 1000))) {
// This situation should be impossible, so it must mean the
// clock changed.
currentTime = (waitUntil - (long) (timeoutRetryWaitSeconds * 1000));
}
}
maybeRunAllCommandsNow(retriesRemaining - 1);
} else {
setConnected(false);
notifyTestHelper(TestHelper.NETWORK_DOWN);
}
} else {
if (Parse.LOG_LEVEL_ERROR >= Parse.getLogLevel()) {
log.log(Level.SEVERE, "Failed to run command.", e);
}
// Delete the command from the cache, even though it failed.
// Otherwise, we'll just keep trying it forever.
removeFile(file);
notifyTestHelper(TestHelper.COMMAND_FAILED, e);
}
}
}
}
}
use of com.parse.boltsinternal.Task in project Parse-SDK-Android by ParsePlatform.
the class ParseFile method getDataInBackground.
/**
* Asynchronously gets the data from cache if available or fetches its content from the network.
* A {@code ProgressCallback} will be called periodically with progress updates.
*
* @param progressCallback A {@code ProgressCallback} that is called periodically with progress
* updates.
* @return A Task that is resolved when the data has been fetched.
*/
public Task<byte[]> getDataInBackground(final ProgressCallback progressCallback) {
final TaskCompletionSource<Void> cts = new TaskCompletionSource<>();
currentTasks.add(cts);
return taskQueue.enqueue(toAwait -> fetchInBackground(progressCallback, toAwait, cts.getTask()).onSuccess(task -> {
File file = task.getResult();
try {
return ParseFileUtils.readFileToByteArray(file);
} catch (IOException e) {
// do nothing
}
return null;
})).continueWithTask(task -> {
// release
cts.trySetResult(null);
currentTasks.remove(cts);
return task;
});
}
use of com.parse.boltsinternal.Task in project Parse-SDK-Android by ParsePlatform.
the class OfflineQueryLogic method createMatcher.
/**
* Returns a ConstraintMatcher that return true iff the object matches QueryConstraints. This
* takes in a SQLiteDatabase connection because SQLite is finicky about nesting connections, so
* we want to reuse them whenever possible.
*/
private <T extends ParseObject> ConstraintMatcher<T> createMatcher(ParseUser user, QueryConstraints queryConstraints) {
// Make a list of all the matchers to AND together.
final ArrayList<ConstraintMatcher<T>> matchers = new ArrayList<>();
for (final String key : queryConstraints.keySet()) {
final Object queryConstraintValue = queryConstraints.get(key);
if (key.equals("$or")) {
/*
* A set of queries to be OR-ed together.
*/
@SuppressWarnings("unchecked") ConstraintMatcher<T> matcher = createOrMatcher(user, (ArrayList<QueryConstraints>) queryConstraintValue);
matchers.add(matcher);
} else if (queryConstraintValue instanceof KeyConstraints) {
/*
* It's a set of constraints that should be AND-ed together.
*/
KeyConstraints keyConstraints = (KeyConstraints) queryConstraintValue;
for (String operator : keyConstraints.keySet()) {
final Object keyConstraintValue = keyConstraints.get(operator);
ConstraintMatcher<T> matcher = createMatcher(user, operator, keyConstraintValue, key, keyConstraints);
matchers.add(matcher);
}
} else if (queryConstraintValue instanceof RelationConstraint) {
/*
* It's a $relatedTo constraint.
*/
final RelationConstraint relation = (RelationConstraint) queryConstraintValue;
matchers.add(new ConstraintMatcher<T>(user) {
@Override
public Task<Boolean> matchesAsync(T object, ParseSQLiteDatabase db) {
return Task.forResult(relation.getRelation().hasKnownObject(object));
}
});
} else {
/*
* It's not a set of constraints, so it's just a value to compare against.
*/
matchers.add(new ConstraintMatcher<T>(user) {
@Override
public Task<Boolean> matchesAsync(T object, ParseSQLiteDatabase db) {
Object objectValue;
try {
objectValue = getValue(object, key);
} catch (ParseException e) {
return Task.forError(e);
}
return Task.forResult(matchesEqualConstraint(queryConstraintValue, objectValue));
}
});
}
}
/*
* Now AND together the constraints for each key.
*/
return new ConstraintMatcher<T>(user) {
@Override
public Task<Boolean> matchesAsync(final T object, final ParseSQLiteDatabase db) {
Task<Boolean> task = Task.forResult(true);
for (final ConstraintMatcher<T> matcher : matchers) {
task = task.onSuccessTask(task1 -> {
if (!task1.getResult()) {
return task1;
}
return matcher.matchesAsync(object, db);
});
}
return task;
}
};
}
Aggregations