HttpTask.java

/*
 * Decompiled with CFR 0_132.
 * 
 * Could not load the following classes:
 *  android.text.TextUtils
 */
package org.xutils.http;

import android.text.TextUtils;
import java.io.Closeable;
import java.io.File;
import java.lang.ref.WeakReference;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicInteger;
import org.xutils.common.Callback;
import org.xutils.common.task.AbsTask;
import org.xutils.common.task.Priority;
import org.xutils.common.task.PriorityExecutor;
import org.xutils.common.util.IOUtil;
import org.xutils.common.util.LogUtil;
import org.xutils.common.util.ParameterizedTypeUtil;
import org.xutils.ex.HttpException;
import org.xutils.ex.HttpRedirectException;
import org.xutils.http.HttpMethod;
import org.xutils.http.ProgressHandler;
import org.xutils.http.RequestParams;
import org.xutils.http.RequestTrackerWrapper;
import org.xutils.http.app.HttpRetryHandler;
import org.xutils.http.app.RedirectHandler;
import org.xutils.http.app.RequestInterceptListener;
import org.xutils.http.app.RequestTracker;
import org.xutils.http.request.UriRequest;
import org.xutils.http.request.UriRequestFactory;
import org.xutils.x;

public class HttpTask<ResultType>
extends AbsTask<ResultType>
implements ProgressHandler {
    private RequestParams params;
    private UriRequest request;
    private HttpTask<ResultType> requestWorker;
    private final Executor executor;
    private volatile boolean hasException = false;
    private final Callback.CommonCallback<ResultType> callback;
    private Object rawResult = null;
    private volatile Boolean trustCache = null;
    private final Object cacheLock = new Object();
    private Callback.CacheCallback<ResultType> cacheCallback;
    private Callback.PrepareCallback prepareCallback;
    private Callback.ProgressCallback progressCallback;
    private RequestInterceptListener requestInterceptListener;
    private RequestTracker tracker;
    private Type loadType;
    private static final int MAX_FILE_LOAD_WORKER = 3;
    private static final AtomicInteger sCurrFileLoadCount = new AtomicInteger(0);
    private static final HashMap<String, WeakReference<HttpTask<?>>> DOWNLOAD_TASK = new HashMap(1);
    private static final PriorityExecutor HTTP_EXECUTOR = new PriorityExecutor(5, true);
    private static final PriorityExecutor CACHE_EXECUTOR = new PriorityExecutor(5, true);
    private static final int FLAG_REQUEST_CREATED = 1;
    private static final int FLAG_CACHE = 2;
    private static final int FLAG_PROGRESS = 3;
    private long lastUpdateTime;
    private long loadingUpdateMaxTimeSpan = 300L;

    public HttpTask(RequestParams params, Callback.Cancelable cancelHandler, Callback.CommonCallback<ResultType> callback) {
        RequestTracker customTracker;
        super(cancelHandler);
        assert (params != null);
        assert (callback != null);
        this.params = params;
        this.callback = callback;
        if (callback instanceof Callback.CacheCallback) {
            this.cacheCallback = (Callback.CacheCallback)callback;
        }
        if (callback instanceof Callback.PrepareCallback) {
            this.prepareCallback = (Callback.PrepareCallback)callback;
        }
        if (callback instanceof Callback.ProgressCallback) {
            this.progressCallback = (Callback.ProgressCallback)callback;
        }
        if (callback instanceof RequestInterceptListener) {
            this.requestInterceptListener = (RequestInterceptListener)((Object)callback);
        }
        if ((customTracker = params.getRequestTracker()) == null) {
            customTracker = callback instanceof RequestTracker ? (RequestTracker)((Object)callback) : UriRequestFactory.getDefaultTracker();
        }
        if (customTracker != null) {
            this.tracker = new RequestTrackerWrapper(customTracker);
        }
        this.executor = params.getExecutor() != null ? params.getExecutor() : (this.cacheCallback != null ? CACHE_EXECUTOR : HTTP_EXECUTOR);
    }

    private void resolveLoadType() {
        Class<?> callBackType = this.callback.getClass();
        this.loadType = this.callback instanceof Callback.TypedCallback ? ((Callback.TypedCallback)this.callback).getLoadType() : (this.callback instanceof Callback.PrepareCallback ? ParameterizedTypeUtil.getParameterizedType(callBackType, Callback.PrepareCallback.class, 0) : ParameterizedTypeUtil.getParameterizedType(callBackType, Callback.CommonCallback.class, 0));
    }

    private UriRequest createNewRequest() throws Throwable {
        this.params.init();
        UriRequest result = UriRequestFactory.getUriRequest(this.params, this.loadType);
        result.setCallingClassLoader(this.callback.getClass().getClassLoader());
        result.setProgressHandler(this);
        this.loadingUpdateMaxTimeSpan = this.params.getLoadingUpdateMaxTimeSpan();
        this.update(1, result);
        return result;
    }

    /*
     * WARNING - Removed try catching itself - possible behaviour change.
     */
    private void checkDownloadTask() {
        if (File.class == this.loadType) {
            HashMap<String, WeakReference<HttpTask<?>>> hashMap = DOWNLOAD_TASK;
            synchronized (hashMap) {
                String downloadTaskKey = this.params.getSaveFilePath();
                if (!TextUtils.isEmpty((CharSequence)downloadTaskKey)) {
                    WeakReference<HttpTask<?>> taskRef = DOWNLOAD_TASK.get(downloadTaskKey);
                    if (taskRef != null) {
                        HttpTask<?> task = taskRef.get();
                        if (task != null) {
                            task.cancel();
                            HttpTask.super.closeRequestSync();
                        }
                        DOWNLOAD_TASK.remove(downloadTaskKey);
                    }
                    DOWNLOAD_TASK.put(downloadTaskKey, new WeakReference<HttpTask>(this));
                }
                if (DOWNLOAD_TASK.size() > 3) {
                    Iterator<Map.Entry<String, WeakReference<HttpTask<?>>>> entryItr = DOWNLOAD_TASK.entrySet().iterator();
                    while (entryItr.hasNext()) {
                        Map.Entry<String, WeakReference<HttpTask<?>>> next = entryItr.next();
                        WeakReference<HttpTask<?>> value = next.getValue();
                        if (value != null && value.get() != null) continue;
                        entryItr.remove();
                    }
                }
            }
        }
    }

    /*
     * WARNING - Removed try catching itself - possible behaviour change.
     */
    @Override
    protected ResultType doBackground() throws Throwable {
        if (this.isCancelled()) {
            throw new Callback.CancelledException("cancelled before request");
        }
        Object result = null;
        this.resolveLoadType();
        this.request = this.createNewRequest();
        this.checkDownloadTask();
        boolean retry = true;
        int retryCount = 0;
        Throwable exception = null;
        HttpRetryHandler retryHandler = this.params.getHttpRetryHandler();
        if (retryHandler == null) {
            retryHandler = new HttpRetryHandler();
        }
        retryHandler.setMaxRetryCount(this.params.getMaxRetryCount());
        if (this.isCancelled()) {
            throw new Callback.CancelledException("cancelled before request");
        }
        Object cacheResult = null;
        if (this.cacheCallback != null && HttpMethod.permitsCache(this.params.getMethod())) {
            try {
                this.clearRawResult();
                LogUtil.d("load cache: " + this.request.getRequestUri());
                this.rawResult = this.request.loadResultFromCache();
            }
            catch (Throwable ex) {
                LogUtil.w("load disk cache error", ex);
            }
            if (this.isCancelled()) {
                this.clearRawResult();
                throw new Callback.CancelledException("cancelled before request");
            }
            if (this.rawResult != null) {
                if (this.prepareCallback != null) {
                    try {
                        cacheResult = this.prepareCallback.prepare(this.rawResult);
                    }
                    catch (Throwable ex) {
                        cacheResult = null;
                        LogUtil.w("prepare disk cache error", ex);
                    }
                    finally {
                        this.clearRawResult();
                    }
                } else {
                    cacheResult = this.rawResult;
                }
                if (this.isCancelled()) {
                    throw new Callback.CancelledException("cancelled before request");
                }
                if (cacheResult != null) {
                    this.update(2, cacheResult);
                    Object ex = this.cacheLock;
                    synchronized (ex) {
                        while (this.trustCache == null) {
                            try {
                                this.cacheLock.wait();
                            }
                            catch (InterruptedException iex2) {
                                throw new Callback.CancelledException("cancelled before request");
                            }
                            catch (Throwable iex2) {
                            }
                        }
                    }
                    if (this.trustCache.booleanValue()) {
                        return null;
                    }
                }
            }
        }
        if (this.trustCache == null) {
            this.trustCache = false;
        }
        if (cacheResult == null) {
            this.request.clearCacheHeader();
        }
        if (this.callback instanceof Callback.ProxyCacheCallback && ((Callback.ProxyCacheCallback)this.callback).onlyCache()) {
            return null;
        }
        retry = true;
        while (retry) {
            retry = false;
            try {
                if (this.isCancelled()) {
                    throw new Callback.CancelledException("cancelled before request");
                }
                this.request.close();
                try {
                    this.clearRawResult();
                    LogUtil.d("load: " + this.request.getRequestUri());
                    this.requestWorker = new RequestWorker();
                    this.requestWorker.request();
                    if (this.requestWorker.ex != null) {
                        throw this.requestWorker.ex;
                    }
                    this.rawResult = this.requestWorker.result;
                }
                catch (Throwable ex) {
                    this.clearRawResult();
                    if (this.isCancelled()) {
                        throw new Callback.CancelledException("cancelled during request");
                    }
                    throw ex;
                }
                if (this.prepareCallback != null) {
                    if (this.isCancelled()) {
                        throw new Callback.CancelledException("cancelled before request");
                    }
                    try {
                        result = this.prepareCallback.prepare(this.rawResult);
                    }
                    finally {
                        this.clearRawResult();
                    }
                } else {
                    result = this.rawResult;
                }
                if (this.cacheCallback != null && HttpMethod.permitsCache(this.params.getMethod())) {
                    this.request.save2Cache();
                }
                if (!this.isCancelled()) continue;
                throw new Callback.CancelledException("cancelled after request");
            }
            catch (HttpRedirectException redirectEx) {
                retry = true;
                LogUtil.w("Http Redirect:" + this.params.getUri());
            }
            catch (Throwable ex) {
                switch (this.request.getResponseCode()) {
                    case 204: 
                    case 205: 
                    case 304: {
                        return null;
                    }
                }
                exception = ex;
                if (this.isCancelled() && !(exception instanceof Callback.CancelledException)) {
                    exception = new Callback.CancelledException("canceled by user");
                }
                retry = retryHandler.canRetry(this.request, exception, ++retryCount);
            }
        }
        if (exception != null && result == null && !this.trustCache.booleanValue()) {
            this.hasException = true;
            throw exception;
        }
        return (ResultType)result;
    }

    /*
     * WARNING - Removed try catching itself - possible behaviour change.
     */
    @Override
    protected /* varargs */ void onUpdate(int flag, Object ... args) {
        switch (flag) {
            case 1: {
                if (this.tracker == null) break;
                this.tracker.onRequestCreated((UriRequest)args[0]);
                break;
            }
            case 2: {
                Object object = this.cacheLock;
                synchronized (object) {
                    try {
                        Object result = args[0];
                        if (this.tracker != null) {
                            this.tracker.onCache(this.request, result);
                        }
                        this.trustCache = this.cacheCallback.onCache(result);
                    }
                    catch (Throwable ex) {
                        this.trustCache = false;
                        this.callback.onError(ex, true);
                    }
                    finally {
                        this.cacheLock.notifyAll();
                    }
                    break;
                }
            }
            case 3: {
                if (this.progressCallback == null || args.length != 3) break;
                try {
                    this.progressCallback.onLoading(((Number)args[0]).longValue(), ((Number)args[1]).longValue(), (Boolean)args[2]);
                    break;
                }
                catch (Throwable ex) {
                    this.callback.onError(ex, true);
                    break;
                }
            }
        }
    }

    @Override
    protected void onWaiting() {
        if (this.tracker != null) {
            this.tracker.onWaiting(this.params);
        }
        if (this.progressCallback != null) {
            this.progressCallback.onWaiting();
        }
    }

    @Override
    protected void onStarted() {
        if (this.tracker != null) {
            this.tracker.onStart(this.params);
        }
        if (this.progressCallback != null) {
            this.progressCallback.onStarted();
        }
    }

    @Override
    protected void onSuccess(ResultType result) {
        if (this.hasException) {
            return;
        }
        if (this.tracker != null) {
            this.tracker.onSuccess(this.request, result);
        }
        this.callback.onSuccess(result);
    }

    @Override
    protected void onError(Throwable ex, boolean isCallbackError) {
        if (this.tracker != null) {
            this.tracker.onError(this.request, ex, isCallbackError);
        }
        this.callback.onError(ex, isCallbackError);
    }

    @Override
    protected void onCancelled(Callback.CancelledException cex) {
        if (this.tracker != null) {
            this.tracker.onCancelled(this.request);
        }
        this.callback.onCancelled(cex);
    }

    @Override
    protected void onFinished() {
        if (this.tracker != null) {
            this.tracker.onFinished(this.request);
        }
        x.task().run(new Runnable(){

            @Override
            public void run() {
                HttpTask.this.closeRequestSync();
            }
        });
        this.callback.onFinished();
    }

    private void clearRawResult() {
        if (this.rawResult instanceof Closeable) {
            IOUtil.closeQuietly((Closeable)this.rawResult);
        }
        this.rawResult = null;
    }

    @Override
    protected void cancelWorks() {
        x.task().run(new Runnable(){

            @Override
            public void run() {
                HttpTask.this.closeRequestSync();
            }
        });
    }

    @Override
    protected boolean isCancelFast() {
        return this.params.isCancelFast();
    }

    private void closeRequestSync() {
        this.clearRawResult();
        IOUtil.closeQuietly(this.request);
    }

    @Override
    public Executor getExecutor() {
        return this.executor;
    }

    @Override
    public Priority getPriority() {
        return this.params.getPriority();
    }

    @Override
    public boolean updateProgress(long total, long current, boolean forceUpdateUI) {
        if (this.isCancelled() || this.isFinished()) {
            return false;
        }
        if (this.progressCallback != null && this.request != null && total > 0L) {
            if (total < current) {
                total = current;
            }
            if (forceUpdateUI) {
                this.lastUpdateTime = System.currentTimeMillis();
                this.update(3, total, current, this.request.isLoading());
            } else {
                long currTime = System.currentTimeMillis();
                if (currTime - this.lastUpdateTime >= this.loadingUpdateMaxTimeSpan) {
                    this.lastUpdateTime = currTime;
                    this.update(3, total, current, this.request.isLoading());
                }
            }
        }
        return !this.isCancelled() && !this.isFinished();
    }

    public String toString() {
        return this.params.toString();
    }

    private final class RequestWorker {
        Object result;
        Throwable ex;

        private RequestWorker() {
        }

        /*
         * WARNING - Removed try catching itself - possible behaviour change.
         */
        public void request() {
            block31 : {
                try {
                    boolean interrupted = false;
                    if (File.class == HttpTask.this.loadType) {
                        AtomicInteger atomicInteger = sCurrFileLoadCount;
                        synchronized (atomicInteger) {
                            while (sCurrFileLoadCount.get() >= 3 && !HttpTask.this.isCancelled()) {
                                try {
                                    sCurrFileLoadCount.wait(10L);
                                }
                                catch (InterruptedException iex2) {
                                    interrupted = true;
                                    break;
                                }
                                catch (Throwable iex2) {
                                }
                            }
                        }
                        sCurrFileLoadCount.incrementAndGet();
                    }
                    if (interrupted || HttpTask.this.isCancelled()) {
                        throw new Callback.CancelledException("cancelled before request" + (interrupted ? "(interrupted)" : ""));
                    }
                    try {
                        HttpTask.this.request.setRequestInterceptListener(HttpTask.this.requestInterceptListener);
                        this.result = HttpTask.this.request.loadResult();
                    }
                    catch (Throwable ex) {
                        this.ex = ex;
                    }
                    if (this.ex != null) {
                        throw this.ex;
                    }
                }
                catch (Throwable ex) {
                    HttpException httpEx;
                    int errorCode;
                    RedirectHandler redirectHandler;
                    this.ex = ex;
                    if (!(ex instanceof HttpException) || (errorCode = (httpEx = (HttpException)ex).getCode()) != 301 && errorCode != 302 || (redirectHandler = HttpTask.this.params.getRedirectHandler()) == null) break block31;
                    try {
                        RequestParams redirectParams = redirectHandler.getRedirectParams(HttpTask.this.request);
                        if (redirectParams != null) {
                            if (redirectParams.getMethod() == null) {
                                redirectParams.setMethod(HttpTask.this.params.getMethod());
                            }
                            HttpTask.this.params = redirectParams;
                            HttpTask.this.request = HttpTask.this.createNewRequest();
                            this.ex = new HttpRedirectException(errorCode, httpEx.getMessage(), httpEx.getResult());
                        }
                    }
                    catch (Throwable throwable) {
                        this.ex = ex;
                    }
                }
                finally {
                    if (File.class == HttpTask.this.loadType) {
                        AtomicInteger interrupted = sCurrFileLoadCount;
                        synchronized (interrupted) {
                            sCurrFileLoadCount.decrementAndGet();
                            sCurrFileLoadCount.notifyAll();
                        }
                    }
                }
            }
        }
    }

}