Search in sources :

Example 1 with RealmAsyncTaskImpl

use of io.realm.internal.async.RealmAsyncTaskImpl in project realm-java by realm.

the class SyncUser method loginAsync.

/**
     * Logs in the user to the Realm Object Server. A logged in user is required to be able to create a
     * {@link SyncConfiguration}.
     *
     * @param credentials credentials to use.
     * @param authenticationUrl server that the user is authenticated against.
     * @param callback callback when login has completed or failed. The callback will always happen on the same thread
     *                 as this this method is called on.
     * @throws IllegalArgumentException if not on a Looper thread.
     */
public static RealmAsyncTask loginAsync(final SyncCredentials credentials, final String authenticationUrl, final Callback callback) {
    if (Looper.myLooper() == null) {
        throw new IllegalStateException("Asynchronous login is only possible from looper threads.");
    }
    final Handler handler = new Handler(Looper.myLooper());
    ThreadPoolExecutor networkPoolExecutor = SyncManager.NETWORK_POOL_EXECUTOR;
    Future<?> authenticateRequest = networkPoolExecutor.submit(new Runnable() {

        @Override
        public void run() {
            try {
                SyncUser user = login(credentials, authenticationUrl);
                postSuccess(user);
            } catch (ObjectServerError e) {
                postError(e);
            }
        }

        private void postError(final ObjectServerError error) {
            if (callback != null) {
                handler.post(new Runnable() {

                    @Override
                    public void run() {
                        try {
                            callback.onError(error);
                        } catch (Exception e) {
                            RealmLog.info("onError has thrown an exception but is ignoring it: %s", Util.getStackTrace(e));
                        }
                    }
                });
            }
        }

        private void postSuccess(final SyncUser user) {
            if (callback != null) {
                handler.post(new Runnable() {

                    @Override
                    public void run() {
                        callback.onSuccess(user);
                    }
                });
            }
        }
    });
    return new RealmAsyncTaskImpl(authenticateRequest, networkPoolExecutor);
}
Also used : RealmAsyncTaskImpl(io.realm.internal.async.RealmAsyncTaskImpl) Handler(android.os.Handler) ThreadPoolExecutor(java.util.concurrent.ThreadPoolExecutor) URISyntaxException(java.net.URISyntaxException) JSONException(org.json.JSONException) MalformedURLException(java.net.MalformedURLException)

Example 2 with RealmAsyncTaskImpl

use of io.realm.internal.async.RealmAsyncTaskImpl in project realm-java by realm.

the class RealmCache method doCreateRealmOrGetFromCacheAsync.

private synchronized <T extends BaseRealm> RealmAsyncTask doCreateRealmOrGetFromCacheAsync(RealmConfiguration configuration, BaseRealm.InstanceCallback<T> callback, Class<T> realmClass) {
    Capabilities capabilities = new AndroidCapabilities();
    capabilities.checkCanDeliverNotification(ASYNC_NOT_ALLOWED_MSG);
    // noinspection ConstantConditions
    if (callback == null) {
        throw new IllegalArgumentException(ASYNC_CALLBACK_NULL_MSG);
    }
    // If there is no Realm file it means that we need to sync the initial remote data in the worker thread.
    if (configuration.isSyncConfiguration() && !configuration.realmExists()) {
        pendingRealmFileCreation.add(configuration.getPath());
    }
    // Always create a Realm instance in the background thread even when there are instances existing on current
    // thread. This to ensure that onSuccess will always be called in the following event loop but not current one.
    CreateRealmRunnable<T> createRealmRunnable = new CreateRealmRunnable<T>(new AndroidRealmNotifier(null, capabilities), configuration, callback, realmClass);
    Future<?> future = BaseRealm.asyncTaskExecutor.submitTransaction(createRealmRunnable);
    createRealmRunnable.setFuture(future);
    // For Realms using Async Open on the server, we need to create the session right away
    // in order to interact with it in a imperative way, e.g. by attaching download progress
    // listeners
    ObjectServerFacade.getSyncFacadeIfPossible().createNativeSyncSession(configuration);
    return new RealmAsyncTaskImpl(future, BaseRealm.asyncTaskExecutor);
}
Also used : RealmAsyncTaskImpl(io.realm.internal.async.RealmAsyncTaskImpl) AndroidCapabilities(io.realm.internal.android.AndroidCapabilities) Capabilities(io.realm.internal.Capabilities) AndroidRealmNotifier(io.realm.internal.android.AndroidRealmNotifier) AndroidCapabilities(io.realm.internal.android.AndroidCapabilities)

Example 3 with RealmAsyncTaskImpl

use of io.realm.internal.async.RealmAsyncTaskImpl in project realm-java by realm.

the class DynamicRealm method executeTransactionAsync.

/**
 * Similar to {@link #executeTransactionAsync(Transaction)}, but also accepts an OnSuccess and OnError callbacks.
 *
 * @param transaction {@link Transaction} to execute.
 * @param onSuccess callback invoked when the transaction succeeds.
 * @param onError callback invoked when the transaction fails.
 * @return a {@link RealmAsyncTask} representing a cancellable task.
 * @throws IllegalArgumentException if the {@code transaction} is {@code null}, or if the realm is opened from
 * another thread.
 */
public RealmAsyncTask executeTransactionAsync(final Transaction transaction, @Nullable final Transaction.OnSuccess onSuccess, @Nullable final Transaction.OnError onError) {
    checkIfValid();
    // noinspection ConstantConditions
    if (transaction == null) {
        throw new IllegalArgumentException("Transaction should not be null");
    }
    if (isFrozen()) {
        throw new IllegalStateException("Write transactions on a frozen Realm is not allowed.");
    }
    // Avoid to call canDeliverNotification() in bg thread.
    final boolean canDeliverNotification = sharedRealm.capabilities.canDeliverNotification();
    // the results.
    if ((onSuccess != null || onError != null)) {
        sharedRealm.capabilities.checkCanDeliverNotification("Callback cannot be delivered on current thread.");
    }
    // We need to use the same configuration to open a background OsSharedRealm (i.e Realm)
    // to perform the transaction
    final RealmConfiguration realmConfiguration = getConfiguration();
    // We need to deliver the callback even if the Realm is closed. So acquire a reference to the notifier here.
    final RealmNotifier realmNotifier = sharedRealm.realmNotifier;
    final Future<?> pendingTransaction = asyncTaskExecutor.submitTransaction(new Runnable() {

        @Override
        public void run() {
            if (Thread.currentThread().isInterrupted()) {
                return;
            }
            OsSharedRealm.VersionID versionID = null;
            Throwable exception = null;
            final DynamicRealm bgRealm = DynamicRealm.getInstance(realmConfiguration);
            bgRealm.beginTransaction();
            try {
                transaction.execute(bgRealm);
                if (Thread.currentThread().isInterrupted()) {
                    return;
                }
                bgRealm.commitTransaction();
                // The bgRealm needs to be closed before post event to caller's handler to avoid concurrency
                // problem. This is currently guaranteed by posting callbacks later below.
                versionID = bgRealm.sharedRealm.getVersionID();
            } catch (final Throwable e) {
                exception = e;
            } finally {
                try {
                    if (bgRealm.isInTransaction()) {
                        bgRealm.cancelTransaction();
                    }
                } finally {
                    bgRealm.close();
                }
            }
            final Throwable backgroundException = exception;
            final OsSharedRealm.VersionID backgroundVersionID = versionID;
            // Cannot be interrupted anymore.
            if (canDeliverNotification) {
                if (backgroundVersionID != null && onSuccess != null) {
                    realmNotifier.post(new Runnable() {

                        @Override
                        public void run() {
                            if (isClosed()) {
                                // The caller Realm is closed. Just call the onSuccess. Since the new created Realm
                                // cannot be behind the background one.
                                onSuccess.onSuccess();
                                return;
                            }
                            if (sharedRealm.getVersionID().compareTo(backgroundVersionID) < 0) {
                                sharedRealm.realmNotifier.addTransactionCallback(new Runnable() {

                                    @Override
                                    public void run() {
                                        onSuccess.onSuccess();
                                    }
                                });
                            } else {
                                onSuccess.onSuccess();
                            }
                        }
                    });
                } else if (backgroundException != null) {
                    realmNotifier.post(new Runnable() {

                        @Override
                        public void run() {
                            if (onError != null) {
                                onError.onError(backgroundException);
                            } else {
                                throw new RealmException("Async transaction failed", backgroundException);
                            }
                        }
                    });
                }
            } else {
                if (backgroundException != null) {
                    // Throw in the worker thread since the caller thread cannot get notifications.
                    throw new RealmException("Async transaction failed", backgroundException);
                }
            }
        }
    });
    return new RealmAsyncTaskImpl(pendingTransaction, asyncTaskExecutor);
}
Also used : RealmAsyncTaskImpl(io.realm.internal.async.RealmAsyncTaskImpl) RealmException(io.realm.exceptions.RealmException) RealmNotifier(io.realm.internal.RealmNotifier)

Example 4 with RealmAsyncTaskImpl

use of io.realm.internal.async.RealmAsyncTaskImpl in project realm-java by realm.

the class SyncSession method scheduleRefreshAccessToken.

private void scheduleRefreshAccessToken(final AuthenticationServer authServer, long expireDateInMs) {
    // calculate the delay time before which we should refresh the access_token,
    // we adjust to 10 second to proactively refresh the access_token before the session
    // hit the expire date on the token
    long refreshAfter = expireDateInMs - System.currentTimeMillis() - REFRESH_MARGIN_DELAY;
    if (refreshAfter < 0) {
        // Token already expired
        RealmLog.debug("Expires time already reached for the access token, refresh as soon as possible");
        // we avoid refreshing directly to avoid an edge case where the client clock is ahead
        // of the server, causing all access_token received from the server to be always
        // expired, we will flood the server with refresh token requests then, so adding
        // a bit of delay is the best effort in this case.
        refreshAfter = REFRESH_MARGIN_DELAY;
    }
    RealmLog.debug("Scheduling an access_token refresh in " + (refreshAfter) + " milliseconds");
    if (refreshTokenTask != null) {
        refreshTokenTask.cancel();
    }
    ScheduledFuture<?> task = REFRESH_TOKENS_EXECUTOR.schedule(new Runnable() {

        @Override
        public void run() {
            if (!isClosed && !Thread.currentThread().isInterrupted()) {
                refreshAccessToken(authServer);
            }
        }
    }, refreshAfter, TimeUnit.MILLISECONDS);
    refreshTokenTask = new RealmAsyncTaskImpl(task, REFRESH_TOKENS_EXECUTOR);
}
Also used : RealmAsyncTaskImpl(io.realm.internal.async.RealmAsyncTaskImpl)

Example 5 with RealmAsyncTaskImpl

use of io.realm.internal.async.RealmAsyncTaskImpl in project realm-java by realm.

the class SyncSession method authenticateRealm.

// Authenticate by getting access tokens for the specific Realm
private void authenticateRealm(final AuthenticationServer authServer) {
    if (networkRequest != null) {
        networkRequest.cancel();
    }
    clearScheduledAccessTokenRefresh();
    // Authenticate in a background thread. This allows incremental backoff and retries in a safe manner.
    Future<?> task = SyncManager.NETWORK_POOL_EXECUTOR.submit(new ExponentialBackoffTask<AuthenticateResponse>() {

        @Override
        protected AuthenticateResponse execute() {
            if (!isClosed && !Thread.currentThread().isInterrupted()) {
                return authServer.loginToRealm(//refresh token in fact
                getUser().getAccessToken(), configuration.getServerUrl(), getUser().getSyncUser().getAuthenticationUrl());
            }
            return null;
        }

        @Override
        protected void onSuccess(AuthenticateResponse response) {
            RealmLog.debug("Session[%s]: Access token acquired", configuration.getPath());
            if (!isClosed && !Thread.currentThread().isInterrupted()) {
                ObjectServerUser.AccessDescription desc = new ObjectServerUser.AccessDescription(response.getAccessToken(), configuration.getPath(), configuration.shouldDeleteRealmOnLogout());
                getUser().getSyncUser().addRealm(configuration.getServerUrl(), desc);
                // schedule a token refresh before it expires
                if (nativeRefreshAccessToken(configuration.getPath(), getUser().getSyncUser().getAccessToken(configuration.getServerUrl()).value(), configuration.getServerUrl().toString())) {
                    scheduleRefreshAccessToken(authServer, response.getAccessToken().expiresMs());
                } else {
                    // token not applied, no refresh will be scheduled
                    onGoingAccessTokenQuery.set(false);
                }
            }
        }

        @Override
        protected void onError(AuthenticateResponse response) {
            onGoingAccessTokenQuery.set(false);
            RealmLog.debug("Session[%s]: Failed to get access token (%d)", configuration.getPath(), response.getError().getErrorCode());
            if (!isClosed && !Thread.currentThread().isInterrupted()) {
                errorHandler.onError(SyncSession.this, response.getError());
            }
        }
    });
    networkRequest = new RealmAsyncTaskImpl(task, SyncManager.NETWORK_POOL_EXECUTOR);
}
Also used : AuthenticateResponse(io.realm.internal.network.AuthenticateResponse) RealmAsyncTaskImpl(io.realm.internal.async.RealmAsyncTaskImpl) ObjectServerUser(io.realm.internal.objectserver.ObjectServerUser)

Aggregations

RealmAsyncTaskImpl (io.realm.internal.async.RealmAsyncTaskImpl)7 RealmException (io.realm.exceptions.RealmException)2 RealmNotifier (io.realm.internal.RealmNotifier)2 AuthenticateResponse (io.realm.internal.network.AuthenticateResponse)2 ObjectServerUser (io.realm.internal.objectserver.ObjectServerUser)2 Handler (android.os.Handler)1 Capabilities (io.realm.internal.Capabilities)1 OsSharedRealm (io.realm.internal.OsSharedRealm)1 AndroidCapabilities (io.realm.internal.android.AndroidCapabilities)1 AndroidRealmNotifier (io.realm.internal.android.AndroidRealmNotifier)1 MalformedURLException (java.net.MalformedURLException)1 URISyntaxException (java.net.URISyntaxException)1 ThreadPoolExecutor (java.util.concurrent.ThreadPoolExecutor)1 JSONException (org.json.JSONException)1