Fix for producteev api errors by a smart retry algorithm.

pull/14/head
Tim Su 14 years ago
parent cb7fe75ee2
commit adbc132c02

@ -4,7 +4,7 @@
<booleanAttribute key="ch.zork.quicklaunch" value="true"/>
<stringAttribute key="ch.zork.quicklaunch.icon" value="14.gif"/>
<intAttribute key="ch.zork.quicklaunch.index" value="0"/>
<stringAttribute key="ch.zork.quicklaunch.mode" value="debug"/>
<stringAttribute key="ch.zork.quicklaunch.mode" value="run"/>
<intAttribute key="com.android.ide.eclipse.adt.action" value="0"/>
<stringAttribute key="com.android.ide.eclipse.adt.commandline" value="-scale 0.7"/>
<intAttribute key="com.android.ide.eclipse.adt.delay" value="0"/>

@ -420,6 +420,7 @@ public abstract class UserTask<Params, Progress, Result> {
@SuppressWarnings("unchecked")
@Override
public void handleMessage(Message msg) {
@SuppressWarnings("rawtypes")
UserTaskResult result = (UserTaskResult) msg.obj;
switch (msg.what) {
case MESSAGE_POST_RESULT:

@ -0,0 +1,18 @@
package com.todoroo.astrid.producteev.api;
/**
* Exception that is thrown when an authentication exception occurs and users
* need to sign in
*
* @author timsu
*
*/
public class ApiAuthenticationException extends ApiServiceException {
private static final long serialVersionUID = 1696103465107607150L;
public ApiAuthenticationException(String detailMessage) {
super(detailMessage);
}
}

@ -0,0 +1,18 @@
package com.todoroo.astrid.producteev.api;
/**
* Exception that wraps a 403 exception
*
* @author timsu
*
*/
public class ApiSignatureException extends ApiServiceException {
private static final long serialVersionUID = 4320984373933L;
public ApiSignatureException(String detailMessage) {
super(detailMessage);
}
}

@ -3,6 +3,8 @@ package com.todoroo.astrid.producteev.api;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import android.text.Html;
import com.todoroo.andlib.utility.DateUtilities;
/**
@ -58,4 +60,12 @@ public final class ApiUtilities {
}
}
/**
* Unescape a Producteev string
* @param string
* @return
*/
public static String decode(String string) {
return Html.fromHtml(string).toString();
}
}

@ -13,8 +13,6 @@ import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import com.todoroo.andlib.service.RestClient;
@SuppressWarnings("nls")
public class ProducteevInvoker {
@ -319,7 +317,7 @@ public class ProducteevInvoker {
// --- invocation
private final RestClient restClient = new ProducteevRestClient();
private final ProducteevRestClient restClient = new ProducteevRestClient();
/**
* Invokes authenticated method using HTTP GET. Will retry after re-authenticating if service exception encountered
@ -334,19 +332,28 @@ public class ProducteevInvoker {
throws IOException, ApiServiceException {
try {
String request = createFetchUrl(method, getParameters);
String response;
String response = null;
try {
response = restClient.get(request);
} catch (ApiServiceException e) {
String oldToken = getToken();
System.err.println("PDV: retrying due to exception: " + e);
authenticate(retryEmail, retryPassword);
for(int i = 0; i < getParameters.length; i++)
if(oldToken.equals(getParameters[i]))
getParameters[i] = getToken();
request = createFetchUrl(method, getParameters);
response = restClient.get(request);
} catch (ApiSignatureException e) {
// clear cookies, get new token, retry
for(int retry = 0; retry < 2; retry++) {
String oldToken = token;
restClient.reset();
authenticate(retryEmail, retryPassword);
for(int i = 0; i < getParameters.length; i++)
if(oldToken.equals(getParameters[i])) {
getParameters[i] = getToken();
}
request = createFetchUrl(method, getParameters);
try {
response = restClient.get(request);
} catch (ApiSignatureException newException) {
//
}
}
if(response == null)
throw e;
}
if(response.startsWith("DEBUG MESSAGE")) {
System.err.println(response);
@ -369,13 +376,14 @@ public class ProducteevInvoker {
* Name/Value pairs. Values will be URL encoded.
* @return response object
*/
private JSONObject invokeGet(String method, Object... getParameters)
throws IOException, ApiServiceException {
JSONObject invokeGet(String method, Object... getParameters) throws IOException, ApiServiceException {
try {
String request = createFetchUrl(method, getParameters);
String response = restClient.get(request);
if(response.startsWith("DEBUG MESSAGE"))
throw new ApiServiceException(response);
if(response.startsWith("DEBUG MESSAGE")) {
System.err.println(response);
return new JSONObject();
}
return new JSONObject(response);
} catch (JSONException e) {
throw new ApiResponseParseException(e);
@ -392,7 +400,7 @@ public class ProducteevInvoker {
* @throws UnsupportedEncodingException
* @throws NoSuchAlgorithmException
*/
public String createFetchUrl(String method, Object... getParameters) throws UnsupportedEncodingException, NoSuchAlgorithmException {
String createFetchUrl(String method, Object... getParameters) throws UnsupportedEncodingException, NoSuchAlgorithmException {
TreeMap<String, Object> treeMap = new TreeMap<String, Object>();
for(int i = 0; i < getParameters.length; i += 2)
treeMap.put(getParameters[i].toString(), getParameters[i+1]);

@ -92,7 +92,13 @@ public class ProducteevRestClient implements RestClient {
try {
JSONObject errorObject = new JSONObject(body).getJSONObject("error"); //$NON-NLS-1$
String errorMessage = errorObject.getString("message"); //$NON-NLS-1$
error= new ApiServiceException(errorMessage);
if(statusCode == 403)
error = new ApiSignatureException(errorMessage);
else if(statusCode == 401)
error = new ApiAuthenticationException(errorMessage);
else
error = new ApiServiceException(errorMessage);
} catch (Exception e) {
error = new ApiServiceException(response.getStatusLine() +
"\n" + body); //$NON-NLS-1$
@ -158,4 +164,11 @@ public class ProducteevRestClient implements RestClient {
}
}
/**
* Destroy and re-create http client
*/
public void reset() {
httpClient = null;
}
}

@ -41,7 +41,7 @@ public class ProducteevNote {
Metadata metadata = new Metadata();
metadata.setValue(Metadata.KEY, METADATA_KEY);
metadata.setValue(ID, note.optLong("id_note"));
metadata.setValue(MESSAGE, note.optString("message"));
metadata.setValue(MESSAGE, ApiUtilities.decode(note.optString("message")));
metadata.setValue(CREATED, ApiUtilities.producteevToUnixTime(
note.optString("time_create"), 0));
return metadata;

@ -281,7 +281,7 @@ public class ProducteevSyncProvider extends SyncProvider<ProducteevTaskContainer
if(remoteTask.has("task"))
remoteTask = remoteTask.getJSONObject("task");
task.setValue(Task.TITLE, remoteTask.getString("title"));
task.setValue(Task.TITLE, ApiUtilities.decode(remoteTask.getString("title")));
task.setValue(Task.CREATION_DATE, ApiUtilities.producteevToUnixTime(remoteTask.getString("time_created"), 0));
task.setValue(Task.COMPLETION_DATE, remoteTask.getInt("status") == 2 ? DateUtilities.now() : 0);
task.setValue(Task.DELETION_DATE, remoteTask.getInt("deleted") == 1 ? DateUtilities.now() : 0);
@ -298,7 +298,7 @@ public class ProducteevSyncProvider extends SyncProvider<ProducteevTaskContainer
Metadata tagData = new Metadata();
tagData.setValue(Metadata.KEY, TagService.KEY);
tagData.setValue(TagService.TAG, label.getString("title"));
tagData.setValue(TagService.TAG, ApiUtilities.decode(label.getString("title")));
metadata.add(tagData);
}
@ -381,7 +381,7 @@ public class ProducteevSyncProvider extends SyncProvider<ProducteevTaskContainer
for(String label : toAdd) {
if(!labelMap.containsKey(label)) {
JSONObject result = invoker.labelsCreate(defaultDashboard, label).getJSONObject("label");
labelMap.put(result.getString("title"), result.getLong("id_label"));
labelMap.put(ApiUtilities.decode(result.getString("title")), result.getLong("id_label"));
}
invoker.tasksSetLabel(idTask, labelMap.get(label));
}
@ -543,7 +543,7 @@ public class ProducteevSyncProvider extends SyncProvider<ProducteevTaskContainer
private void readLabels(JSONArray labels) throws JSONException, ApiServiceException, IOException {
for(int i = 0; i < labels.length(); i++) {
JSONObject label = labels.getJSONObject(i).getJSONObject("label");
labelMap.put(label.getString("title"), label.getLong("id_label"));
labelMap.put(ApiUtilities.decode(label.getString("title")), label.getLong("id_label"));
}
}

Loading…
Cancel
Save