Search in sources :

Example 6 with TaskCompletionSource

use of bolts.TaskCompletionSource in project Parse-SDK-Android by ParsePlatform.

the class ParseCommandCache method enqueueEventuallyAsync.

/**
   * Attempts to run the given command and any pending commands. Adds the command to the pending set
   * if it can't be run yet.
   *
   * @param command
   *          - The command to run.
   * @param preferOldest
   *          - When the disk is full, if preferOldest, drop new commands. Otherwise, the oldest
   *          commands will be deleted to make room.
   * @param object
   *          - See runEventually.
   */
private Task<JSONObject> enqueueEventuallyAsync(ParseRESTCommand command, boolean preferOldest, ParseObject object) {
    Parse.requirePermission(Manifest.permission.ACCESS_NETWORK_STATE);
    TaskCompletionSource<JSONObject> tcs = new TaskCompletionSource<>();
    byte[] json;
    try {
        // objectId after the save completes.
        if (object != null && object.getObjectId() == null) {
            command.setLocalId(object.getOrCreateLocalId());
        }
        JSONObject jsonObject = command.toJSONObject();
        json = jsonObject.toString().getBytes("UTF-8");
    } catch (UnsupportedEncodingException e) {
        if (Parse.LOG_LEVEL_WARNING >= Parse.getLogLevel()) {
            log.log(Level.WARNING, "UTF-8 isn't supported.  This shouldn't happen.", e);
        }
        notifyTestHelper(TestHelper.COMMAND_NOT_ENQUEUED);
        return Task.forResult(null);
    }
    // even bother trying.
    if (json.length > maxCacheSizeBytes) {
        if (Parse.LOG_LEVEL_WARNING >= Parse.getLogLevel()) {
            log.warning("Unable to save command for later because it's too big.");
        }
        notifyTestHelper(TestHelper.COMMAND_NOT_ENQUEUED);
        return Task.forResult(null);
    }
    synchronized (lock) {
        try {
            // Is there enough free storage space?
            String[] fileNames = cachePath.list();
            if (fileNames != null) {
                Arrays.sort(fileNames);
                int size = 0;
                for (String fileName : fileNames) {
                    File file = new File(cachePath, fileName);
                    // Should be safe to convert long to int, because we don't allow
                    // files larger than 2GB.
                    size += (int) file.length();
                }
                size += json.length;
                if (size > maxCacheSizeBytes) {
                    if (preferOldest) {
                        if (Parse.LOG_LEVEL_WARNING >= Parse.getLogLevel()) {
                            log.warning("Unable to save command for later because storage is full.");
                        }
                        return Task.forResult(null);
                    } else {
                        if (Parse.LOG_LEVEL_WARNING >= Parse.getLogLevel()) {
                            log.warning("Deleting old commands to make room in command cache.");
                        }
                        int indexToDelete = 0;
                        while (size > maxCacheSizeBytes && indexToDelete < fileNames.length) {
                            File file = new File(cachePath, fileNames[indexToDelete++]);
                            size -= (int) file.length();
                            removeFile(file);
                        }
                    }
                }
            }
            // Get the current time to store in the filename, so that we process them in order.
            String prefix1 = Long.toHexString(System.currentTimeMillis());
            if (prefix1.length() < 16) {
                char[] zeroes = new char[16 - prefix1.length()];
                Arrays.fill(zeroes, '0');
                prefix1 = new String(zeroes) + prefix1;
            }
            // Then add another incrementing number in case we enqueue items faster than the system's
            // time granularity.
            String prefix2 = Integer.toHexString(filenameCounter++);
            if (prefix2.length() < 8) {
                char[] zeroes = new char[8 - prefix2.length()];
                Arrays.fill(zeroes, '0');
                prefix2 = new String(zeroes) + prefix2;
            }
            String prefix = "CachedCommand_" + prefix1 + "_" + prefix2 + "_";
            // Get a unique filename to store this command in.
            File path = File.createTempFile(prefix, "", cachePath);
            // Write the command to that file.
            pendingTasks.put(path, tcs);
            command.retainLocalIds();
            ParseFileUtils.writeByteArrayToFile(path, json);
            notifyTestHelper(TestHelper.COMMAND_ENQUEUED);
            unprocessedCommandsExist = true;
        } catch (IOException e) {
            if (Parse.LOG_LEVEL_WARNING >= Parse.getLogLevel()) {
                log.log(Level.WARNING, "Unable to save command for later.", e);
            }
        } finally {
            lock.notifyAll();
        }
    }
    return tcs.getTask();
}
Also used : TaskCompletionSource(bolts.TaskCompletionSource) JSONObject(org.json.JSONObject) UnsupportedEncodingException(java.io.UnsupportedEncodingException) IOException(java.io.IOException) File(java.io.File)

Example 7 with TaskCompletionSource

use of bolts.TaskCompletionSource 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(new Continuation<String, ParseObject>() {

            @Override
            public ParseObject then(Task<String> task) throws Exception {
                return 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(new Continuation<Void, Void>() {

        @Override
        public Void then(Task<Void> task) throws Exception {
            // This will signal that the UUID does represent a row in the database.
            tcs.setResult(newUUID);
            return null;
        }
    });
    return tcs.getTask();
}
Also used : ContentValues(android.content.ContentValues) TaskCompletionSource(bolts.TaskCompletionSource) Continuation(bolts.Continuation) Task(bolts.Task) JSONException(org.json.JSONException)

Example 8 with TaskCompletionSource

use of bolts.TaskCompletionSource in project Parse-SDK-Android by ParsePlatform.

the class ParseFile method getDataStreamInBackground.

/**
   * Asynchronously gets the data stream from cached file if available or fetches its content from
   * the network, saves the content as cached file and returns the data stream of the cached file.
   * The {@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 stream of this object has been fetched.
   */
public Task<InputStream> getDataStreamInBackground(final ProgressCallback progressCallback) {
    final TaskCompletionSource<Void> cts = new TaskCompletionSource<>();
    currentTasks.add(cts);
    return taskQueue.enqueue(new Continuation<Void, Task<InputStream>>() {

        @Override
        public Task<InputStream> then(Task<Void> toAwait) throws Exception {
            return fetchInBackground(progressCallback, toAwait, cts.getTask()).onSuccess(new Continuation<File, InputStream>() {

                @Override
                public InputStream then(Task<File> task) throws Exception {
                    return new FileInputStream(task.getResult());
                }
            });
        }
    }).continueWithTask(new Continuation<InputStream, Task<InputStream>>() {

        @Override
        public Task<InputStream> then(Task<InputStream> task) throws Exception {
            // release
            cts.trySetResult(null);
            currentTasks.remove(cts);
            return task;
        }
    });
}
Also used : Continuation(bolts.Continuation) Task(bolts.Task) FileInputStream(java.io.FileInputStream) InputStream(java.io.InputStream) IOException(java.io.IOException) JSONException(org.json.JSONException) FileInputStream(java.io.FileInputStream) TaskCompletionSource(bolts.TaskCompletionSource) File(java.io.File)

Example 9 with TaskCompletionSource

use of bolts.TaskCompletionSource in project Parse-SDK-Android by ParsePlatform.

the class ParseTaskUtils method callbackOnMainThreadAsync.

/**
   * Calls the callback after a task completes on the main thread, returning a Task that completes
   * with the same result as the input task after the callback has been run. If reportCancellation
   * is false, the callback will not be called if the task was cancelled.
   */
/* package */
static <T> Task<T> callbackOnMainThreadAsync(Task<T> task, final ParseCallback2<T, ParseException> callback, final boolean reportCancellation) {
    if (callback == null) {
        return task;
    }
    final TaskCompletionSource<T> tcs = new TaskCompletionSource();
    task.continueWith(new Continuation<T, Void>() {

        @Override
        public Void then(final Task<T> task) throws Exception {
            if (task.isCancelled() && !reportCancellation) {
                tcs.setCancelled();
                return null;
            }
            ParseExecutors.main().execute(new Runnable() {

                @Override
                public void run() {
                    try {
                        Exception error = task.getError();
                        if (error != null && !(error instanceof ParseException)) {
                            error = new ParseException(error);
                        }
                        callback.done(task.getResult(), (ParseException) error);
                    } finally {
                        if (task.isCancelled()) {
                            tcs.setCancelled();
                        } else if (task.isFaulted()) {
                            tcs.setError(task.getError());
                        } else {
                            tcs.setResult(task.getResult());
                        }
                    }
                }
            });
            return null;
        }
    });
    return tcs.getTask();
}
Also used : TaskCompletionSource(bolts.TaskCompletionSource) AggregateException(bolts.AggregateException) CancellationException(java.util.concurrent.CancellationException)

Example 10 with TaskCompletionSource

use of bolts.TaskCompletionSource 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 e) {
        throw new RuntimeException(e);
    } catch (MalformedURLException e) {
        throw new RuntimeException(e);
    }
    ParseRESTCommand command = new ParseRESTObjectBatchCommand("batch", ParseHttpRequest.Method.POST, parameters, sessionToken);
    command.executeAsync(client).continueWith(new Continuation<JSONObject, Void>() {

        @Override
        public Void then(Task<JSONObject> task) throws Exception {
            TaskCompletionSource<JSONObject> tcs;
            if (task.isFaulted() || task.isCancelled()) {
                // REST command failed or canceled, fail or cancel all tasks
                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) {
                // Invalid response, fail all tasks
                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;
}
Also used : Task(bolts.Task) MalformedURLException(java.net.MalformedURLException) ArrayList(java.util.ArrayList) URL(java.net.URL) TaskCompletionSource(bolts.TaskCompletionSource) ArrayList(java.util.ArrayList) List(java.util.List) JSONArray(org.json.JSONArray) JSONException(org.json.JSONException) MalformedURLException(java.net.MalformedURLException) IOException(java.io.IOException) JSONException(org.json.JSONException) JSONObject(org.json.JSONObject)

Aggregations

TaskCompletionSource (bolts.TaskCompletionSource)16 JSONException (org.json.JSONException)12 Task (bolts.Task)10 JSONObject (org.json.JSONObject)9 TextUtils (android.text.TextUtils)6 RCLog (chat.rocket.android.log.RCLog)6 RxWebSocketCallback (chat.rocket.android_ddp.rx.RxWebSocketCallback)6 TimeoutException (java.util.concurrent.TimeoutException)6 JSONArray (org.json.JSONArray)6 NonNull (android.support.annotation.NonNull)5 Nullable (android.support.annotation.Nullable)5 RxWebSocket (chat.rocket.android_ddp.rx.RxWebSocket)5 Flowable (io.reactivex.Flowable)5 CompositeDisposable (io.reactivex.disposables.CompositeDisposable)5 TimeUnit (java.util.concurrent.TimeUnit)5 OkHttpClient (okhttp3.OkHttpClient)5 Continuation (bolts.Continuation)3 IOException (java.io.IOException)3 Capture (bolts.Capture)2 Realm (io.realm.Realm)2