com.lillicoder.newsblurry.net.BaseTask.java Source code

Java tutorial

Introduction

Here is the source code for com.lillicoder.newsblurry.net.BaseTask.java

Source

/**
 * Copyright 2012 Scott Weeden-Moody
 *
 * 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 com.lillicoder.newsblurry.net;

import java.io.IOException;

import junit.framework.Assert;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.CookieStore;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.protocol.ClientContext;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;
import org.json.JSONException;
import org.json.JSONObject;

import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.net.http.AndroidHttpClient;
import android.os.AsyncTask;
import android.util.Log;

import com.lillicoder.newsblurry.R;
import com.lillicoder.newsblurry.exception.ApiRequestException;

/**
 * Base {@link AsyncTask} implementation that supports {@link OnTaskCompletedListener} callbacks.
 * When using the class, do not override {@link #onPreExecute()} or {@link #onPostExecute(Object)}
 * since this are overridden to enable listener callbacks.
 * @author lillicoder
 * 
 * @param <Params> Type of the parameters sent to the task upon execution.
 * @param <Progress> Type of the progress units published during the background computation.
 * @param <Result> Type of the result of the background computation.
 */
public abstract class BaseTask<Params, Progress, Result> extends AsyncTask<Params, Progress, Result> {

    private static final String TAG = BaseTask.class.getSimpleName();

    private static final String EXCEPTION_CONNECTION_ERROR = "Unable to get connection, request unsuccessful.";

    private static final String EXCEPTION_HTTP_ERROR = "HTTP error, request unsuccessful.";

    private static final String EXCEPTION_INVALID_CONTEXT_PARAM = "The given Context must not be null.";

    private static final String EXCEPTION_INVALID_LISTENER_PARAM = "The given OnTaskCompletedListener must not be null.";

    private static final String WARNING_FAILED_TO_GET_PACKAGE_INFO = "Failed to get package info for package name %s.";

    protected static final String EXCEPTION_API_REQUEST_FAILED = "Failed to connect and fetch data from NewsBlur.";

    protected static final String EXCEPTION_FAILED_TO_PARAMS = "Failed to get params for this task, will not execute.";

    protected static final String EXCEPTION_FAILED_TO_PARSE_RESPONSE = "Failed to parse the HTTP response.";

    protected static final String EXCEPTION_UNABLE_TO_CREATE_JSON_FROM_RESPONSE = "Unable to create JSON instance from server response, is the received JSON data valid?";

    private Context _context;
    private Exception _exception;
    private OnTaskCompletedListener<Result> _listener;

    /**
     * Instantiates this instance with the given context and task completion listener.
     * @param context {@link Context} for this task.
     * @param listener {@link OnTaskCompletedListener} for this task. This is used for task callback events (e.g. success, failure).
     */
    protected BaseTask(Context context, OnTaskCompletedListener<Result> listener) {
        if (context == null)
            throw new IllegalArgumentException(EXCEPTION_INVALID_CONTEXT_PARAM);

        if (listener == null)
            throw new IllegalArgumentException(EXCEPTION_INVALID_LISTENER_PARAM);

        this._context = context;
        this._listener = listener;
    }

    /**
     * Executes the given {@link HttpGet} using pre-configured
     * defaults. Cookies storage and HTTP context will be provided
     * via {@link #getRequestContext()}. Override this method
     * to provide custom execution control for a request.
     * @param get {@link HttpGet} request to execute.
     * @return {@link HttpResponse} from the executed request.
     * @throws ApiRequestException Thrown in case of an HTTP or connection error,
     *                         or if the request was aborted.
     */
    protected HttpResponse executeWebRequest(HttpGet get) throws ApiRequestException {
        try {
            HttpClient client = AndroidHttpClient.newInstance(this.getUserAgent());
            return client.execute(get, this.getRequestContext());
        } catch (ClientProtocolException e) {
            throw new ApiRequestException(EXCEPTION_HTTP_ERROR, e);
        } catch (IOException e) {
            throw new ApiRequestException(EXCEPTION_CONNECTION_ERROR, e);
        }
    }

    /**
     * Executes the given {@link HttpPost} using pre-configured
     * defaults. Cookies storage and HTTP context will be provided
     * via {@link #getRequestContext()}. Override this method
     * to provide custom execution control for a request.
     * @param get {@link HttpPost} request to execute.
     * @return {@link HttpResponse} from the executed request.
     * @throws ApiRequestException Thrown in case of an HTTP or connection error,
     *                         or if the request was aborted.
     */
    protected HttpResponse executeWebRequest(HttpPost post) throws ApiRequestException {
        try {
            HttpClient client = AndroidHttpClient.newInstance(this.getUserAgent());
            return client.execute(post, this.getRequestContext());
        } catch (ClientProtocolException e) {
            throw new ApiRequestException(EXCEPTION_HTTP_ERROR, e);
        } catch (IOException e) {
            throw new ApiRequestException(EXCEPTION_CONNECTION_ERROR, e);
        }
    }

    /**
     * Gets the context associated with this task.
     * @return {@link Contxt} associated with this task.
     */
    protected Context getContext() {
        return this._context;
    }

    /**
     * Gets the exception generated by this task when execution fails.
     * When this task succeeds or still still running, this value may be <code>null</code>.
     * @return {@link Exception} generated by this task as a result of failure. 
     */
    protected Exception getException() {
        return this._exception;
    }

    /**
     * Gets an {@link HttpContext} instance configured for making
     * web requests. The returned context will have a cookie store
     * attached for persisting cookies created during the request.
     * @return {@link HttpContext} for use with web requests.
     */
    protected HttpContext getRequestContext() {
        HttpContext context = new BasicHttpContext();
        CookieStore cookieStore = new PreferenceCookieStore(this.getContext());
        context.setAttribute(ClientContext.COOKIE_STORE, cookieStore);

        return context;
    }

    /**
     * Gets the user agent string for use with tasks that make web requests.
     * By default this returns the application name and version code.
     * @return User agent string for use with web requests.
     */
    protected String getUserAgent() {
        Context context = this.getContext();
        Assert.assertTrue(context != null);

        String versionName = context.getString(R.string.default_versionName);
        try {
            PackageManager manager = context.getPackageManager();
            PackageInfo info = manager.getPackageInfo(context.getPackageName(), 0);
            versionName = info.versionName;
        } catch (NameNotFoundException e) {
            Log.w(TAG, String.format(WARNING_FAILED_TO_GET_PACKAGE_INFO, context.getPackageName()));
        }

        String userAgentFormat = context.getString(R.string.format_userAgent);
        String appName = context.getString(R.string.app_name);
        return String.format(userAgentFormat, appName, versionName);
    }

    /**
     * Gets the task completion listener associated with this task.
     * @return {@link OnTaskCompletedListener} associated with this task.
     */
    protected OnTaskCompletedListener<Result> getListener() {
        return this._listener;
    }

    @Override
    protected void onPreExecute() {
        OnTaskCompletedListener<Result> listener = this.getListener();
        Assert.assertTrue(listener != null);

        listener.onPreExecute();
    }

    @Override
    protected void onPostExecute(Result result) {
        OnTaskCompletedListener<Result> listener = this.getListener();
        Assert.assertTrue(listener != null);

        Exception exception = this.getException();
        if (exception != null)
            // Exception was set, we task has failed execution.
            listener.onFailure(exception);
        else
            // No exception, task has succeeded.
            listener.onSuccess(result);
    }

    /**
     * Gets the {@link JSONObject} data contained in the given {@link HttpResponse}.
     * @param response {@link HttpResponse} to get JSON data from.
     * @return {@link JSONObject} data contained in the given response.
     * @throws JSONException Thrown when the JSON containing the response data could not be created.
     * @throws IOException Thrown when there is an error parsing the given response.
     */
    protected JSONObject getJsonFromResponse(HttpResponse response) throws JSONException, IOException {
        Assert.assertTrue(response != null);

        HttpEntity responseEntity = response.getEntity();
        String responseText = EntityUtils.toString(responseEntity, "UTF-8");
        return new JSONObject(responseText);
    }

    /**
     * Sets this task's {@link Exception}. When {@link #doInBackground(Object...)}
     * completes, this exception will be reported to this task's
     * {@link OnTaskCompletedListener#onFailure(Exception)} method.
     * @param exception {@link Exception} to set.
     */
    protected void setException(Exception exception) {
        this._exception = exception;
    }

}