/*
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);
}