use of com.parse.boltsinternal.Task in project Parse-SDK-Android by ParsePlatform.
the class ParseObject method deepSaveAsync.
/**
* This saves all of the objects and files reachable from the given object. It does its work in
* multiple waves, saving as many as possible in each wave. If there's ever an error, it just
* gives up, sets error, and returns NO.
*/
private static Task<Void> deepSaveAsync(final Object object, final String sessionToken) {
Set<ParseObject> objects = new HashSet<>();
Set<ParseFile> files = new HashSet<>();
collectDirtyChildren(object, objects, files);
// This has to happen separately from everything else because ParseUser.save() is
// special-cased to work for lazy users, but new users can't be created by
// ParseMultiCommand's regular save.
Set<ParseUser> users = new HashSet<>();
for (ParseObject o : objects) {
if (o instanceof ParseUser) {
ParseUser user = (ParseUser) o;
if (user.isLazy()) {
users.add((ParseUser) o);
}
}
}
objects.removeAll(users);
// objects will need to wait for files to be complete since they may be nested children.
final AtomicBoolean filesComplete = new AtomicBoolean(false);
List<Task<Void>> tasks = new ArrayList<>();
for (ParseFile file : files) {
tasks.add(file.saveAsync(sessionToken, null, null));
}
Task<Void> filesTask = Task.whenAll(tasks).continueWith(task -> {
filesComplete.set(true);
return null;
});
// objects will need to wait for users to be complete since they may be nested children.
final AtomicBoolean usersComplete = new AtomicBoolean(false);
tasks = new ArrayList<>();
for (final ParseUser user : users) {
tasks.add(user.saveAsync(sessionToken));
}
Task<Void> usersTask = Task.whenAll(tasks).continueWith(task -> {
usersComplete.set(true);
return null;
});
final Capture<Set<ParseObject>> remaining = new Capture<>(objects);
Task<Void> objectsTask = Task.forResult(null).continueWhile(() -> remaining.get().size() > 0, task -> {
// Partition the objects into two sets: those that can be save
// immediately,
// and those that rely on other objects to be created first.
final List<ParseObject> current = new ArrayList<>();
final Set<ParseObject> nextBatch = new HashSet<>();
for (ParseObject obj : remaining.get()) {
if (obj.canBeSerialized()) {
current.add(obj);
} else {
nextBatch.add(obj);
}
}
remaining.set(nextBatch);
if (current.size() == 0 && filesComplete.get() && usersComplete.get()) {
// exception instead of an infinite loop.
throw new RuntimeException("Unable to save a ParseObject with a relation to a cycle.");
}
// Package all save commands together
if (current.size() == 0) {
return Task.forResult(null);
}
return enqueueForAll(current, toAwait -> saveAllAsync(current, sessionToken, toAwait));
});
return Task.whenAll(Arrays.asList(filesTask, usersTask, objectsTask));
}
use of com.parse.boltsinternal.Task in project Parse-SDK-Android by ParsePlatform.
the class ParseRESTObjectBatchCommand method executeBatch.
public static List<Task<JSONObject>> executeBatch(ParseHttpClient client, List<ParseRESTObjectCommand> commands, String sessionToken) {
final int batchSize = commands.size();
List<Task<JSONObject>> tasks = new ArrayList<>(batchSize);
if (batchSize == 1) {
// There's only one, just execute it
tasks.add(commands.get(0).executeAsync(client));
return tasks;
}
if (batchSize > COMMAND_OBJECT_BATCH_MAX_SIZE) {
// There's more than the max, split it up into batches
List<List<ParseRESTObjectCommand>> batches = Lists.partition(commands, COMMAND_OBJECT_BATCH_MAX_SIZE);
for (int i = 0, size = batches.size(); i < size; i++) {
List<ParseRESTObjectCommand> batch = batches.get(i);
tasks.addAll(executeBatch(client, batch, sessionToken));
}
return tasks;
}
final List<TaskCompletionSource<JSONObject>> tcss = new ArrayList<>(batchSize);
for (int i = 0; i < batchSize; i++) {
TaskCompletionSource<JSONObject> tcs = new TaskCompletionSource<>();
tcss.add(tcs);
tasks.add(tcs.getTask());
}
JSONObject parameters = new JSONObject();
JSONArray requests = new JSONArray();
try {
for (ParseRESTObjectCommand command : commands) {
JSONObject requestParameters = new JSONObject();
requestParameters.put("method", command.method.toString());
requestParameters.put("path", new URL(server, command.httpPath).getPath());
JSONObject body = command.jsonParameters;
if (body != null) {
requestParameters.put("body", body);
}
requests.put(requestParameters);
}
parameters.put("requests", requests);
} catch (JSONException | MalformedURLException e) {
throw new RuntimeException(e);
}
ParseRESTCommand command = new ParseRESTObjectBatchCommand("batch", ParseHttpRequest.Method.POST, parameters, sessionToken);
command.executeAsync(client).continueWith((Continuation<JSONObject, Void>) task -> {
TaskCompletionSource<JSONObject> tcs;
if (task.isFaulted() || task.isCancelled()) {
for (int i = 0; i < batchSize; i++) {
tcs = tcss.get(i);
if (task.isFaulted()) {
tcs.setError(task.getError());
} else {
tcs.setCancelled();
}
}
}
JSONObject json = task.getResult();
JSONArray results = json.getJSONArray(KEY_RESULTS);
int resultLength = results.length();
if (resultLength != batchSize) {
for (int i = 0; i < batchSize; i++) {
tcs = tcss.get(i);
tcs.setError(new IllegalStateException("Batch command result count expected: " + batchSize + " but was: " + resultLength));
}
}
for (int i = 0; i < batchSize; i++) {
JSONObject result = results.getJSONObject(i);
tcs = tcss.get(i);
if (result.has("success")) {
JSONObject success = result.getJSONObject("success");
tcs.setResult(success);
} else if (result.has("error")) {
JSONObject error = result.getJSONObject("error");
tcs.setError(new ParseException(error.getInt("code"), error.getString("error")));
}
}
return null;
});
return tasks;
}
use of com.parse.boltsinternal.Task in project Parse-SDK-Android by ParsePlatform.
the class ParseSQLiteDatabase method rawQueryAsync.
/**
* Runs a raw query.
*
* @see SQLiteDatabase#rawQuery
*/
public Task<Cursor> rawQueryAsync(final String sql, final String[] args) {
synchronized (currentLock) {
Task<Cursor> task = current.onSuccess(task13 -> db.rawQuery(sql, args), dbExecutor).onSuccess(task12 -> {
Cursor cursor = task12.getResult();
// Ensure the cursor window is filled on the dbExecutor
// thread. We need to do this because
// the cursor cannot be filled from a different thread than
// it was created on.
cursor.getCount();
return cursor;
}, dbExecutor);
current = task.makeVoid();
return task.continueWithTask(task1 -> {
// We want to jump off the dbExecutor
return task1;
}, Task.BACKGROUND_EXECUTOR);
}
}
use of com.parse.boltsinternal.Task in project Parse-SDK-Android by ParsePlatform.
the class OfflineStore method getOrCreateUUIDAsync.
/**
* Gets the UUID for the given object, if it has one. Otherwise, creates a new UUID for the
* object and adds a new row to the database for the object with no data.
*/
private Task<String> getOrCreateUUIDAsync(final ParseObject object, ParseSQLiteDatabase db) {
final String newUUID = UUID.randomUUID().toString();
final TaskCompletionSource<String> tcs = new TaskCompletionSource<>();
synchronized (lock) {
Task<String> uuidTask = objectToUuidMap.get(object);
if (uuidTask != null) {
return uuidTask;
}
// The object doesn't have a UUID yet, so we're gonna have to make one.
objectToUuidMap.put(object, tcs.getTask());
uuidToObjectMap.put(newUUID, object);
fetchedObjects.put(object, tcs.getTask().onSuccess(task -> object));
}
/*
* We need to put a placeholder row in the database so that later on, the save can just be an
* update. This could be a pointer to an object that itself never gets saved offline, in which
* case the consumer will just have to deal with that.
*/
ContentValues values = new ContentValues();
values.put(OfflineSQLiteOpenHelper.KEY_UUID, newUUID);
values.put(OfflineSQLiteOpenHelper.KEY_CLASS_NAME, object.getClassName());
db.insertOrThrowAsync(OfflineSQLiteOpenHelper.TABLE_OBJECTS, values).continueWith((Continuation<Void, Void>) task -> {
tcs.setResult(newUUID);
return null;
});
return tcs.getTask();
}
use of com.parse.boltsinternal.Task in project Parse-SDK-Android by ParsePlatform.
the class OfflineStore method deleteDataForObjectAsync.
private Task<Void> deleteDataForObjectAsync(final ParseObject object, final ParseSQLiteDatabase db) {
final Capture<String> uuid = new Capture<>();
// Make sure the object has a UUID.
Task<String> uuidTask;
synchronized (lock) {
uuidTask = objectToUuidMap.get(object);
if (uuidTask == null) {
// database.
return Task.forResult(null);
}
}
uuidTask = uuidTask.onSuccessTask(task -> {
uuid.set(task.getResult());
return task;
});
// If the object was the root of a pin, unpin it.
Task<Void> unpinTask = uuidTask.onSuccessTask(task -> {
// Find all the roots for this object.
String[] select = { OfflineSQLiteOpenHelper.KEY_KEY };
String where = OfflineSQLiteOpenHelper.KEY_UUID + "=?";
String[] args = { uuid.get() };
return db.queryAsync(OfflineSQLiteOpenHelper.TABLE_DEPENDENCIES, select, where, args);
}).onSuccessTask(task -> {
// Try to unpin this object from the pin label if it's a root of
// the ParsePin.
Cursor cursor = task.getResult();
List<String> uuids = new ArrayList<>();
for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
uuids.add(cursor.getString(0));
}
cursor.close();
List<Task<Void>> tasks = new ArrayList<>();
for (final String uuid1 : uuids) {
Task<Void> unpinTask1 = getPointerAsync(uuid1, db).onSuccessTask(task12 -> {
ParsePin pin = (ParsePin) task12.getResult();
return fetchLocallyAsync(pin, db);
}).continueWithTask(task1 -> {
ParsePin pin = task1.getResult();
List<ParseObject> modified = pin.getObjects();
if (modified == null || !modified.contains(object)) {
return task1.makeVoid();
}
modified.remove(object);
if (modified.size() == 0) {
return unpinAsync(uuid1, db);
}
pin.setObjects(modified);
return saveLocallyAsync(pin, true, db);
});
tasks.add(unpinTask1);
}
return Task.whenAll(tasks);
});
// Delete the object from the Local Datastore in case it wasn't the root of a pin.
return unpinTask.onSuccessTask(task -> {
String where = OfflineSQLiteOpenHelper.KEY_UUID + "=?";
String[] args = { uuid.get() };
return db.deleteAsync(OfflineSQLiteOpenHelper.TABLE_DEPENDENCIES, where, args);
}).onSuccessTask(task -> {
String where = OfflineSQLiteOpenHelper.KEY_UUID + "=?";
String[] args = { uuid.get() };
return db.deleteAsync(OfflineSQLiteOpenHelper.TABLE_OBJECTS, where, args);
}).onSuccessTask(task -> {
synchronized (lock) {
// Clean up
// TODO (grantland): we should probably clean up uuidToObjectMap and
// objectToUuidMap, but
// getting the uuid requires a task and things might get a little
// funky...
fetchedObjects.remove(object);
}
return task;
});
}
Aggregations