package com.qubling.sidekick.fetch.cpan;
import java.io.IOException;
import java.nio.charset.UnsupportedCharsetException;
import java.util.HashMap;
import java.util.Map;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONTokener;
import android.util.Log;
import com.qubling.sidekick.fetch.LimitedFetcher;
import com.qubling.sidekick.instance.Instance;
import com.qubling.sidekick.model.Model;
import com.qubling.sidekick.util.HttpUtils;
import com.qubling.sidekick.util.StringTemplate;
public abstract class CPANQueryFetcher<SomeInstance extends Instance<SomeInstance>>
extends CPANFetcher<SomeInstance> implements LimitedFetcher<SomeInstance> {
/**
* An enumeration of search types on MetaCPAN.
*
* @author sterling
*
*/
public enum SearchSection {
AUTHOR ("v0/author/_search"),
FAVORITE ("v0/favorite/_search"),
FILE ("v0/file/_search"),
RATING ("v0/rating/_search"),
RELEASE ("v0/release/_search");
private String path;
SearchSection(String path) {
this.path = path;
}
public String getPath() {
return path;
}
}
public static final int DEFAULT_SIZE = 10;
public static final int DEFAULT_FROM = 0;
private final SearchSection searchSection;
private final String searchTemplate;
private int size = DEFAULT_SIZE;
private int from = DEFAULT_FROM;
public CPANQueryFetcher(Model<SomeInstance> model, SearchSection searchSection, String searchTemplate) {
super(model);
this.searchSection = searchSection;
this.searchTemplate = searchTemplate + ".json";
}
protected void execute() {
// Log.d("CPANQueryFetcher", "START execute()");
if (!shouldCompleteRequest()) {
// Log.d("CPANQueryFetcher", "Quitting execute() because shouldCompleteRequest() is false");
return;
}
HashMap<String, Object> variables = new HashMap<String, Object>();
variables.put("from", from);
variables.put("size", size);
prepareRequest(variables);
// Log.d("CPANQueryFetcher", "Setup variables by calling prepareRequest()");
JSONObject searchResponse = makeMetaCPANRequest(variables);
try {
consumeResponse(searchResponse);
}
// TODO Notify BugSense if this happens...
catch (JSONException e) {
Log.e("CPANQueryFetcher", "Error while reading JSON during query: " + e.getMessage(), e);
}
// Log.d("CPANQueryFetcher", "END execute()");
}
protected abstract boolean shouldCompleteRequest();
protected abstract void prepareRequest(Map<String, Object> variables);
protected abstract void consumeResponse(JSONObject searchResponse) throws JSONException;
private JSONObject makeMetaCPANRequest(Map<String, Object> variables) {
// Log.d("CPANQueryFetcher", "START makeMetaCPANRequest()");
StringTemplate templater = new StringTemplate(getContext());
String json = templater.processTemplate(searchTemplate, variables);
// Log.d("CPANQueryFetcher", "REQ " + searchSection.getPath() + ": " + json);
try {
// Setup the REST API request
HttpPost req = new HttpPost(METACPAN_API_URL + searchSection.getPath());
req.setEntity(new StringEntity(json));
// Make the request
HttpResponse res = getHttpClient().execute(req);
// Read the content
String content = HttpUtils.slurpContent(res);
// Log.d("CPANQueryFetcher", "RES " + searchSection.getPath() + ": " + content);
// Parse the response into JSON and return it
Object parsedContent = new JSONTokener(content).nextValue();
if (parsedContent instanceof JSONObject) {
return (JSONObject) parsedContent;
}
else {
// TODO Show an alert dialog or toast when this happens
Log.e("CPANQueryFetcher", "Unexpected JSON content: " + parsedContent);
return null;
}
}
catch (UnsupportedCharsetException e) {
// TODO Show an alert dialog if this should ever happen
Log.e("CPANQueryFetcher", e.toString());
}
catch (IOException e) {
// TODO Show an alert dialog if this should ever happen
Log.e("CPANQueryFetcher", e.toString());
}
catch (JSONException e) {
// TODO Show an alert dialog if this should ever happen
Log.e("CPANQueryFetcher", e.toString());
}
// Log.d("CPANQueryFetcher", "END makeMetaCPANRequest()");
return null;
}
public int getSize() {
return size;
}
public void setSize(int size) {
this.size = size;
}
public int getFrom() {
return from;
}
public void setFrom(int from) {
this.from = from;
}
public SearchSection getSearchSection() {
return searchSection;
}
public String getSearchTemplate() {
return searchTemplate;
}
@Override
public String toString() {
return getModel() + ":CPANQueryFetcher(" + searchSection + ";" + searchTemplate.hashCode() + ")";
}
}