retrofit.MagnetCall.java Source code

Java tutorial

Introduction

Here is the source code for retrofit.MagnetCall.java

Source

/*
 * Copyright (c) 2015 Magnet Systems, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package retrofit;

import android.util.Log;
import com.magnet.max.android.auth.AuthTokenProvider;
import com.magnet.max.android.connectivity.ConnectivityManager;
import com.magnet.max.android.rest.CacheOptions;
import com.magnet.max.android.rest.CallOptions;
import com.magnet.max.android.rest.ReliableCallOptions;
import com.magnet.max.android.rest.RequestManager;
import com.magnet.max.android.rest.qos.Condition;
import com.squareup.okhttp.CacheControl;
import com.squareup.okhttp.Request;
import java.util.Set;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;

public class MagnetCall<T> {
    private static final String TAG = MagnetCall.class.getSimpleName();

    private final Call<T> call;
    private final AuthTokenProvider authTokenProvider;
    private final RequestManager requestManager;
    private final Executor callbackExecutor;

    private boolean executed;

    public MagnetCall(Call<T> call, AuthTokenProvider authTokenProvider, RequestManager requestManager,
            Executor callbackExecutor) {
        this.call = call;
        this.authTokenProvider = authTokenProvider;
        this.requestManager = requestManager;
        this.callbackExecutor = callbackExecutor;
    }

    public void executeInBackground() {
        executeInBackground(null);
    }

    public void executeInBackground(CacheOptions options) {
        execute(options, null);
    }

    public void executeEventually() {
        executeEventually(null);
    }

    public void executeEventually(ReliableCallOptions options) {
        execute(null, null != options ? options : ReliableCallOptions.DEFAULT);
    }

    private void execute(CacheOptions cacheOptions, ReliableCallOptions reliableOptions) {
        synchronized (this) {
            if (this.executed) {
                throw new IllegalStateException("Already executed");
            }

            this.executed = true;
        }

        CallOptions options = null;
        if (null != cacheOptions) {
            options = new CallOptions(cacheOptions);
        } else if (null != reliableOptions) {
            options = new CallOptions(reliableOptions);
        }

        OkHttpCall<T> okHttpCall = (OkHttpCall<T>) call;
        Callback<T> callback = extractAndRemoveCallback(okHttpCall);
        //Wrap callback in main thread executor
        Callback<T> callbackInMainThread = new ExecutorCallback<>(callbackExecutor, callback);

        Request request = okHttpCall.getRequest(null);

        if (null != reliableOptions) {
            Set<Condition> failedPrerequisites = reliableOptions.unsatisfiedConditions(true);
            if (!failedPrerequisites.isEmpty()) {
                StringBuilder sb = new StringBuilder("Prerequisite(s) not met : ");
                for (Condition p : failedPrerequisites) {
                    sb.append(p.toString()).append(",");
                }
                sb.append(")");

                requestManager.saveReliableRequest(request, call, callbackInMainThread, reliableOptions,
                        sb.toString());
                return;
            }
        }

        if (null != options) {
            requestManager.saveRequestOptions(request, options);
        }

        if (isCallReady(request, options)) {
            call.enqueue(callbackInMainThread);
        } else {
            Log.i(TAG, "Request " + request.urlString() + " is not ready, added into pending queue");
            requestManager.savePendingCall(call, callbackInMainThread, options);
        }
    }

    public void cancel() {
        call.cancel();
    }

    /**
     * Extract the callback in the last argument and remove it from OkHttpCall
     * @param okHttpCall
     * @return
     */
    private Callback<T> extractAndRemoveCallback(OkHttpCall okHttpCall) {
        Object[] args = okHttpCall.getArgs();
        Callback<T> callback = null;
        if (null != args && args.length > 0 && args[args.length - 1] instanceof Callback) {
            callback = (Callback<T>) args[args.length - 1];
            Object[] actualArgs = new Object[args.length - 1];
            System.arraycopy(args, 0, actualArgs, 0, args.length - 1);
            okHttpCall.setArgs(actualArgs);
        }
        if (null == callback) {
            throw new IllegalArgumentException("Last argument should be Callback");
        }

        return callback;
    }

    private CacheControl getCacheControl(CacheOptions options) {
        if (null != options) {
            if (Boolean.TRUE == options.isAlwaysUseCacheIfOffline() || options.getMaxCacheAge() > 0) {
                CacheControl.Builder builder = new CacheControl.Builder();
                // Always return from cache if offline
                if (Boolean.TRUE == options.isAlwaysUseCacheIfOffline()) {
                    if (ConnectivityManager.getInstance()
                            .getConnectivityStatus() == ConnectivityManager.TYPE_NOT_CONNECTED) {
                        builder.onlyIfCached().maxAge(Integer.MAX_VALUE, TimeUnit.SECONDS).build();
                    }
                }
                if (options.getMaxCacheAge() > 0) { // Return from cache if it's not expired
                    builder.maxAge(options.getMaxCacheAge(), TimeUnit.SECONDS);
                }

                return builder.build();
            }
        } else {

        }

        return null;
    }

    private boolean isCallReady(Request request, CallOptions options) {
        return authTokenProvider.isAuthReady(request);
    }

    static final class ExecutorCallback<T> implements Callback<T> {
        private final Executor callbackExecutor;
        private final Callback<T> delegate;

        ExecutorCallback(Executor callbackExecutor, Callback<T> delegate) {
            this.callbackExecutor = callbackExecutor;
            this.delegate = delegate;
        }

        @Override
        public void onResponse(final Response<T> response) {
            callbackExecutor.execute(new Runnable() {
                @Override
                public void run() {
                    delegate.onResponse(response);
                }
            });
        }

        @Override
        public void onFailure(final Throwable t) {
            callbackExecutor.execute(new Runnable() {
                @Override
                public void run() {
                    delegate.onFailure(t);
                }
            });
        }
    }
}