<commit_before>package org.edx.mobile.http;

import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;

import org.edx.mobile.util.images.ErrorUtils;
import org.edx.mobile.view.common.TaskMessageCallback;
import org.edx.mobile.view.common.TaskProgressCallback;

import java.io.IOException;

import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import roboguice.RoboGuice;

/**
 * Generic abstract implementation of Retrofit's
 * {@link retrofit2.Callback} interface, that takes care of delivering
 * status and error information to the proper callbacks. It also
 * provides (and delegates to) a simpler callback interface for
 * subclasses, stripping out unnecessary parameters, and redirecting
 * all responses with error codes to the failure callback method (as it
 * used to be in the implementation in Retrofit 1).
 *
 * @param <T> The successful response body type.
 */
public abstract class ErrorHandlingCallback<T> implements Callback<T> {
    /**
     * A Context for resolving the error message strings.
     */
    @NonNull
    private final Context context;

    /**
     * The trigger for initiating the call. This is used to determine the type of error message to
     * deliver.
     */
    @NonNull
    private final CallTrigger callTrigger;

    /**
     * The callback to invoke on start and finish of the request.
     */
    @Nullable
    private final TaskProgressCallback progressCallback;

    /**
     * The callback to invoke for delivering any error messages.
     */
    @Nullable
    private final TaskMessageCallback messageCallback;

    /**
     * Create a new instance of this class.
     *
     * @param context A Context for resolving the error message strings. Note that for convenience,
     *                this will be checked to determine whether it's implementing any of the
     *                callback interfaces, and will be registered as such if so. If this is not the
     *                desired outcome, then one of the alternative constructors should be used
     *                instead, with the relevant callback parameters explicitly passed as null (this
     *                may require casting the null in case of ambiguity when using a constructor
     *                that only sets one callback explicitly).
     * @param callTrigger The trigger for initiating the call. This is used to determine the type of
     *                    error message to deliver.
     */
    public ErrorHandlingCallback(@NonNull final Context context,
                                 @NonNull final CallTrigger callTrigger) {
        this(context, callTrigger,
                context instanceof TaskProgressCallback ? (TaskProgressCallback) context : null,
                context instanceof TaskMessageCallback ? (TaskMessageCallback) context : null);
    }

    /**
     * Create a new instance of this class.
     *
     * @param context A Context for resolving the error message strings. Note that for convenience,
     *                this will be checked to determine whether it's implementing the
     *                {@link TaskMessageCallback} interface, and will be registered as such if so.
     *                If this is not the desired outcome, then the other constructor should be used
     *                that takes this callback parameter, and it should be explicitly set as null.
     * @param callTrigger The trigger for initiating the call. This is used to determine the type of
     *                    error message to deliver.
     * @param progressCallback The callback to invoke on start and finish of the request. Note that
     *                         since no callback method in this class is invoked upon request
     *                         initiation, it assumes that it's being initiated immediately, and
     *                         thus invokes that start callback immediately as well.
     */
    public ErrorHandlingCallback(@NonNull final Context context,
                                 @NonNull final CallTrigger callTrigger,
                                 @Nullable final TaskProgressCallback progressCallback) {
        this(context, callTrigger,
                progressCallback,
                context instanceof TaskMessageCallback ? (TaskMessageCallback) context : null);
    }

    /**
     * Create a new instance of this class.
     *
     * @param context A Context for resolving the error message strings. Note that for convenience,
     *                this will be checked to determine whether it's implementing the
     *                {@link TaskProgressCallback} interface, and will be registered as such if so.
     *                If this is not the desired outcome, then the other constructor should be used
     *                that takes this callback parameter, and it should be explicitly set as null.
     * @param callTrigger The trigger for initiating the call. This is used to determine the type of
     *                    error message to deliver.
     * @param messageCallback The callback to invoke for delivering any error messages.
     */
    public ErrorHandlingCallback(@NonNull final Context context,
                                 @NonNull final CallTrigger callTrigger,
                                 @Nullable final TaskMessageCallback messageCallback) {
        this(context, callTrigger,
                context instanceof TaskProgressCallback ? (TaskProgressCallback) context : null,
                messageCallback);
    }

    /**
     * Create a new instance of this class.
     *
     * @param context A Context for resolving the error message strings.
     * @param callTrigger The trigger for initiating the call. This is used to determine the type of
     *                    error message to deliver.
     * @param progressCallback The callback to invoke on start and finish of the request. Note that
     *                         since no callback method in this class is invoked upon request
     *                         initiation, it assumes that it's being initiated immediately, and
     *                         thus invokes that start callback immediately as well.
     * @param messageCallback The callback to invoke for delivering any error messages.
     */
    public ErrorHandlingCallback(@NonNull final Context context,
                                 @NonNull final CallTrigger callTrigger,
                                 @Nullable final TaskProgressCallback progressCallback,
                                 @Nullable final TaskMessageCallback messageCallback) {
        this.context = context;
        this.callTrigger = callTrigger;
        this.progressCallback = progressCallback;
        this.messageCallback = messageCallback;
        // For the convenience of subclasses
        RoboGuice.injectMembers(context, this);
        if (progressCallback != null) {
            progressCallback.startProcess();
        }
    }

    /**
     * The original callback method invoked by Retrofit upon receiving an HTTP response. This method
     * definition provides extra information that's not needed by most individual callback
     * implementations, and is also invoked when HTTP error status codes are encountered (forcing
     * the implementation to manually check for success in each case). Therefore this implementation
     * delegates to {@link #onResponse(Object)} in the case where it receives a successful HTTP
     * status code, and to {@link #onFailure(Call, Throwable)} otherwise, passing an instance of
     * {@link HttpResponseStatusException} with the relevant error status code. This method is
     * declared as final, as subclasses are meant to be implementing the abstract
     * {@link #onResponse(Object)} method instead of this one.
     * <p>
     * This implementation takes care of invoking the callback for request process completion.
     *
     * @param call The Call object that was used to enqueue the request.
     * @param response The HTTP response data.
     */
    @Override
    public final void onResponse(@NonNull Call<T> call, @NonNull Response<T> response) {
        if (!response.isSuccessful()) {
            onFailure(call, new HttpResponseStatusException(response.code()));
        } else {
            if (progressCallback != null) {
                progressCallback.finishProcess();
            }
            onResponse(response.body());
        }
    }

    /**
     * The original callback method invoked by Retrofit upon failure to receive an HTTP response,
     * whether due to encountering a network error while waiting for the response, or some other
     * unexpected error while constructing the request or processing the response. It's also invoked
     * by the {@link #onResponse(Call, Response)} implementation when it receives an HTTP error
     * status code. However, this method definition provides extra information that's not needed by
     * most individual callback implementation, so this implementation only delegates to
     * {@link #onFailure(Throwable)}.
     * <p>
     * This implementation takes care of delivering the appropriate error message to it's registered
     * callback, and invoking the callback for request process completion. It should only be
     * overridden if the subclass wants to handle or control these actions itself; otherwise
     * subclasses should override the empty {@link #onFailure(Throwable)} callback method instead.
     *
     * @param call The Call object that was used to enqueue the request.
     * @param error An {@link IOException} if the request failed due to a network failure, an
     *              {HttpResponseStatusException} if the failure was due to receiving an error code,
     *              or any {@link Throwable} implementation if one was thrown unexpectedly while
     *              creating the request or processing the response.
     */
    @Override
    public void onFailure(@NonNull Call<T> call, @NonNull Throwable error) {
        if (progressCallback != null) {
            progressCallback.finishProcess();
        }
        if (messageCallback != null) {
            messageCallback.onMessage(callTrigger.getMessageType(),
                    ErrorUtils.getErrorMessage(error, context));
        }
        onFailure(error);
    }

    /**
     * Callback method for a successful HTTP response.
     *
     * @param responseBody The response body, converted to an instance of it's associated Java
     *                     class.
     */
    protected abstract void onResponse(@NonNull final T responseBody);

    /**
     * Callback method for when the HTTP response was not received successfully, whether due to a
     * network failure, receiving an HTTP error status code, or encountering an unexpected exception
     * or error during the request creation or response processing phase.
     *
     * @param error An {@link IOException} if the request failed due to a network failure, an
     *              {HttpResponseStatusException} if the failure was due to receiving an error code,
     *              or any {@link Throwable} implementation if one was thrown unexpectedly while<commit_msg>Fix Retrofit call cancellation triggering error<commit_after>package org.edx.mobile.http;

import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;

import org.edx.mobile.util.images.ErrorUtils;
import org.edx.mobile.view.common.TaskMessageCallback;
import org.edx.mobile.view.common.TaskProgressCallback;

import java.io.IOException;

import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
import roboguice.RoboGuice;

/**
 * Generic abstract implementation of Retrofit's
 * {@link retrofit2.Callback} interface, that takes care of delivering
 * status and error information to the proper callbacks. It also
 * provides (and delegates to) a simpler callback interface for
 * subclasses, stripping out unnecessary parameters, and redirecting
 * all responses with error codes to the failure callback method (as it
 * used to be in the implementation in Retrofit 1).
 *
 * @param <T> The successful response body type.
 */
public abstract class ErrorHandlingCallback<T> implements Callback<T> {
    /**
     * A Context for resolving the error message strings.
     */
    @NonNull
    private final Context context;

    /**
     * The trigger for initiating the call. This is used to determine the type of error message to
     * deliver.
     */
    @NonNull
    private final CallTrigger callTrigger;

    /**
     * The callback to invoke on start and finish of the request.
     */
    @Nullable
    private final TaskProgressCallback progressCallback;

    /**
     * The callback to invoke for delivering any error messages.
     */
    @Nullable
    private final TaskMessageCallback messageCallback;

    /**
     * Create a new instance of this class.
     *
     * @param context A Context for resolving the error message strings. Note that for convenience,
     *                this will be checked to determine whether it's implementing any of the
     *                callback interfaces, and will be registered as such if so. If this is not the
     *                desired outcome, then one of the alternative constructors should be used
     *                instead, with the relevant callback parameters explicitly passed as null (this
     *                may require casting the null in case of ambiguity when using a constructor
     *                that only sets one callback explicitly).
     * @param callTrigger The trigger for initiating the call. This is used to determine the type of
     *                    error message to deliver.
     */
    public ErrorHandlingCallback(@NonNull final Context context,
                                 @NonNull final CallTrigger callTrigger) {
        this(context, callTrigger,
                context instanceof TaskProgressCallback ? (TaskProgressCallback) context : null,
                context instanceof TaskMessageCallback ? (TaskMessageCallback) context : null);
    }

    /**
     * Create a new instance of this class.
     *
     * @param context A Context for resolving the error message strings. Note that for convenience,
     *                this will be checked to determine whether it's implementing the
     *                {@link TaskMessageCallback} interface, and will be registered as such if so.
     *                If this is not the desired outcome, then the other constructor should be used
     *                that takes this callback parameter, and it should be explicitly set as null.
     * @param callTrigger The trigger for initiating the call. This is used to determine the type of
     *                    error message to deliver.
     * @param progressCallback The callback to invoke on start and finish of the request. Note that
     *                         since no callback method in this class is invoked upon request
     *                         initiation, it assumes that it's being initiated immediately, and
     *                         thus invokes that start callback immediately as well.
     */
    public ErrorHandlingCallback(@NonNull final Context context,
                                 @NonNull final CallTrigger callTrigger,
                                 @Nullable final TaskProgressCallback progressCallback) {
        this(context, callTrigger,
                progressCallback,
                context instanceof TaskMessageCallback ? (TaskMessageCallback) context : null);
    }

    /**
     * Create a new instance of this class.
     *
     * @param context A Context for resolving the error message strings. Note that for convenience,
     *                this will be checked to determine whether it's implementing the
     *                {@link TaskProgressCallback} interface, and will be registered as such if so.
     *                If this is not the desired outcome, then the other constructor should be used
     *                that takes this callback parameter, and it should be explicitly set as null.
     * @param callTrigger The trigger for initiating the call. This is used to determine the type of
     *                    error message to deliver.
     * @param messageCallback The callback to invoke for delivering any error messages.
     */
    public ErrorHandlingCallback(@NonNull final Context context,
                                 @NonNull final CallTrigger callTrigger,
                                 @Nullable final TaskMessageCallback messageCallback) {
        this(context, callTrigger,
                context instanceof TaskProgressCallback ? (TaskProgressCallback) context : null,
                messageCallback);
    }

    /**
     * Create a new instance of this class.
     *
     * @param context A Context for resolving the error message strings.
     * @param callTrigger The trigger for initiating the call. This is used to determine the type of
     *                    error message to deliver.
     * @param progressCallback The callback to invoke on start and finish of the request. Note that
     *                         since no callback method in this class is invoked upon request
     *                         initiation, it assumes that it's being initiated immediately, and
     *                         thus invokes that start callback immediately as well.
     * @param messageCallback The callback to invoke for delivering any error messages.
     */
    public ErrorHandlingCallback(@NonNull final Context context,
                                 @NonNull final CallTrigger callTrigger,
                                 @Nullable final TaskProgressCallback progressCallback,
                                 @Nullable final TaskMessageCallback messageCallback) {
        this.context = context;
        this.callTrigger = callTrigger;
        this.progressCallback = progressCallback;
        this.messageCallback = messageCallback;
        // For the convenience of subclasses
        RoboGuice.injectMembers(context, this);
        if (progressCallback != null) {
            progressCallback.startProcess();
        }
    }

    /**
     * The original callback method invoked by Retrofit upon receiving an HTTP response. This method
     * definition provides extra information that's not needed by most individual callback
     * implementations, and is also invoked when HTTP error status codes are encountered (forcing
     * the implementation to manually check for success in each case). Therefore this implementation
     * delegates to {@link #onResponse(Object)} in the case where it receives a successful HTTP
     * status code, and to {@link #onFailure(Call, Throwable)} otherwise, passing an instance of
     * {@link HttpResponseStatusException} with the relevant error status code. This method is
     * declared as final, as subclasses are meant to be implementing the abstract
     * {@link #onResponse(Object)} method instead of this one.
     * <p>
     * This implementation takes care of invoking the callback for request process completion.
     *
     * @param call The Call object that was used to enqueue the request.
     * @param response The HTTP response data.
     */
    @Override
    public final void onResponse(@NonNull Call<T> call, @NonNull Response<T> response) {
        if (!response.isSuccessful()) {
            onFailure(call, new HttpResponseStatusException(response.code()));
        } else {
            if (progressCallback != null) {
                progressCallback.finishProcess();
            }
            onResponse(response.body());
        }
    }

    /**
     * The original callback method invoked by Retrofit upon failure to receive an HTTP response,
     * whether due to encountering a network error while waiting for the response, or some other
     * unexpected error while constructing the request or processing the response. It's also invoked
     * by the {@link #onResponse(Call, Response)} implementation when it receives an HTTP error
     * status code. However, this method definition provides extra information that's not needed by
     * most individual callback implementation, so this implementation only delegates to
     * {@link #onFailure(Throwable)}.
     * <p>
     * This implementation takes care of delivering the appropriate error message to it's registered
     * callback, and invoking the callback for request process completion. It should only be
     * overridden if the subclass wants to handle or control these actions itself; otherwise
     * subclasses should override the empty {@link #onFailure(Throwable)} callback method instead.
     *
     * @param call The Call object that was used to enqueue the request.
     * @param error An {@link IOException} if the request failed due to a network failure, an
     *              {HttpResponseStatusException} if the failure was due to receiving an error code,
     *              or any {@link Throwable} implementation if one was thrown unexpectedly while
     *              creating the request or processing the response.
     */
    @Override
    public void onFailure(@NonNull Call<T> call, @NonNull Throwable error) {
        if (progressCallback != null) {
            progressCallback.finishProcess();
        }
        if (messageCallback != null && !call.isCanceled()) {
            messageCallback.onMessage(callTrigger.getMessageType(),
                    ErrorUtils.getErrorMessage(error, context));
        }
        onFailure(error);
    }

    /**
     * Callback method for a successful HTTP response.
     *
     * @param responseBody The response body, converted to an instance of it's associated Java
     *                     class.
     */
    protected abstract void onResponse(@NonNull final T responseBody);

    /**
     * Callback method for when the HTTP response was not received successfully, whether due to a
     * network failure, receiving an HTTP error status code, or encountering an unexpected exception
     * or error during the request creation or response processing phase.
     *
     * @param error An {@link IOException} if the request failed due to a network failure, an
     *              {HttpResponseStatusException} if the failure was due to receiving an error code,
     *              or any {@link Throwable} implementation if one was thrown unexpectedly while
{'fraction_non_alphanumeric': 0.05501733179272954, 'fraction_numerical': 0.00044440494178295264, 'mean_word_length': 2.4193891505850176, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 19, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 16, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '260703', 'n_tokens_mistral': 4926, 'n_tokens_neox': 4801, 'n_words': 2333}