com.concentricsky.android.khanacademy.data.remote.KAEntityFetcherTask.java Source code

Java tutorial

Introduction

Here is the source code for com.concentricsky.android.khanacademy.data.remote.KAEntityFetcherTask.java

Source

/*
Viewer for Khan Academy
Copyright (C) 2012 Concentric Sky, Inc.
    
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
    
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.
    
You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.concentricsky.android.khanacademy.data.remote;

import oauth.signpost.OAuthConsumer;

import org.springframework.http.converter.json.replacement.MappingJacksonHttpMessageConverter;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.ResourceAccessException;
import org.springframework.web.client.RestTemplate;

import android.os.AsyncTask;

import com.concentricsky.android.khanacademy.data.db.ModelBase;
import com.concentricsky.android.khanacademy.util.Log;
import com.fasterxml.jackson.databind.ObjectMapper;

/**
 * A task that makes a single API call, serializes the result, and passes it to onPostExecute.
 * 
 * I toyed with making this generic to return the correct type, but there is no clean place
 * to catch any resulting exception if the api call returns an unexpected type. Best leave
 * the casting to the caller.
 * 
 * @author austinlally
 *
 */
public abstract class KAEntityFetcherTask<T extends ModelBase> extends AsyncTask<Void, Integer, T> {

    public final String LOG_TAG = getClass().getName();
    private String url;
    private OAuthConsumer consumer;

    protected Exception exception;

    public KAEntityFetcherTask(String url) {
        this.url = url;
    }

    public KAEntityFetcherTask(String url, OAuthConsumer consumer) {
        this(url);
        this.consumer = consumer;
    }

    @Override
    protected T doInBackground(Void... arg0) {
        // call  API and fetch an entity tree (commonly the tree rooted at the root topic)

        RestTemplate restTemplate = new RestTemplate();
        if (consumer != null) {
            restTemplate.setRequestFactory(new SpringRequestFactory(consumer));
        }

        // TODO : Set up stream parsing.

        //      RequestCallback callback = new RequestCallback() {
        //
        //         public void doWithRequest(ClientHttpRequest request)
        //               throws IOException {
        //            // TODO Auto-generated method stub
        //            
        //         }
        //         
        //      };
        //      
        //      ResponseExtractor<T> extractor = new ResponseExtractor<T>() {
        //
        //         public T extractData(ClientHttpResponse response)
        //               throws IOException {
        //            
        //            InputStream stream = response.getBody();
        //            
        //            
        //            return null;
        //         }
        //         
        //      };
        //      
        //      restTemplate.execute(url, HttpMethod.GET, requestCallback, responseExtractor)

        // Provide a converter to the restTemplate to get automagic json --> pojo deserialization.
        // Provide a mapper to the converter so we can register the custom Video deserializer. Otherwise, the default ObjectMapper would do fine.
        ObjectMapper mapper = new ObjectMapper();
        mapper.registerModule(new VideoDeserializerModule());
        MappingJacksonHttpMessageConverter converter = new MappingJacksonHttpMessageConverter();
        converter.setObjectMapper(mapper);
        restTemplate.getMessageConverters().add(converter);

        ModelBase entity = null;
        try {
            entity = restTemplate.getForObject(this.url, ModelBase.class);
        } catch (HttpClientErrorException e) {
            e.printStackTrace();
            exception = e;
            // meanwhile, entity is null, so we let that return naturally.
        } catch (ResourceAccessException e) {
            // This one happens on Nexus 7 if we have set a SpringRequestFactory but get no Auth challenge.
            // org.springframework.web.client.ResourceAccessException: I/O error: No authentication challenges found; nested exception is java.io.IOException: No authentication challenges found
            e.printStackTrace();
            Log.e(LOG_TAG, "url was " + url);
            exception = e;
        }

        T result;
        try {
            result = (T) entity;
        } catch (ClassCastException e) {
            e.printStackTrace();
            exception = e;
            result = null;
        }

        Log.d(LOG_TAG, "Response received. Returning entity.");
        return result;
    }

    /**
     * Called with the result of the api call. Subclasses should override this 
     * method to handle the result. If result is null, it means the api call
     * returned an unexpected object type, and the exception is available on 
     * this.exception.
     * 
     * @param result The return of the api call.
     */
    @Override
    protected abstract void onPostExecute(T result);

}