aboutsummaryrefslogtreecommitdiffstats
path: root/main/src/cgeo/geocaching/connector/oc/OkapiClient.java
diff options
context:
space:
mode:
Diffstat (limited to 'main/src/cgeo/geocaching/connector/oc/OkapiClient.java')
-rw-r--r--main/src/cgeo/geocaching/connector/oc/OkapiClient.java130
1 files changed, 93 insertions, 37 deletions
diff --git a/main/src/cgeo/geocaching/connector/oc/OkapiClient.java b/main/src/cgeo/geocaching/connector/oc/OkapiClient.java
index 43ea8ad..24e30e7 100644
--- a/main/src/cgeo/geocaching/connector/oc/OkapiClient.java
+++ b/main/src/cgeo/geocaching/connector/oc/OkapiClient.java
@@ -1,12 +1,12 @@
package cgeo.geocaching.connector.oc;
+import cgeo.geocaching.CgeoApplication;
+import cgeo.geocaching.DataStore;
import cgeo.geocaching.Geocache;
import cgeo.geocaching.Image;
import cgeo.geocaching.LogEntry;
import cgeo.geocaching.R;
import cgeo.geocaching.Waypoint;
-import cgeo.geocaching.cgData;
-import cgeo.geocaching.cgeoapplication;
import cgeo.geocaching.connector.ConnectorFactory;
import cgeo.geocaching.connector.IConnector;
import cgeo.geocaching.connector.LogResult;
@@ -29,9 +29,15 @@ import cgeo.geocaching.network.OAuth;
import cgeo.geocaching.network.Parameters;
import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.utils.Log;
+import cgeo.geocaching.utils.SynchronizedDateFormat;
+
+import ch.boye.httpclientandroidlib.HttpResponse;
import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.time.FastDateFormat;
import org.apache.commons.lang3.tuple.ImmutablePair;
+import org.eclipse.jdt.annotation.NonNull;
+import org.eclipse.jdt.annotation.Nullable;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
@@ -39,7 +45,6 @@ import org.json.JSONObject;
import android.net.Uri;
import java.text.ParseException;
-import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
@@ -56,12 +61,8 @@ final class OkapiClient {
private static final char SEPARATOR = '|';
private static final String SEPARATOR_STRING = Character.toString(SEPARATOR);
- private static final SimpleDateFormat LOG_DATE_FORMAT;
- static {
- LOG_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSZ", Locale.US);
- LOG_DATE_FORMAT.setTimeZone(TimeZone.getTimeZone("UTC"));
- }
- private static final SimpleDateFormat ISO8601DATEFORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.getDefault());
+ private static final FastDateFormat LOG_DATE_FORMAT = FastDateFormat.getInstance("yyyy-MM-dd HH:mm:ss.SSSZ", TimeZone.getTimeZone("UTC"), Locale.US);
+ private static final SynchronizedDateFormat ISO8601DATEFORMAT = new SynchronizedDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.getDefault());
private static final String CACHE_ATTRNAMES = "attrnames";
private static final String WPT_LOCATION = "location";
@@ -81,7 +82,6 @@ final class OkapiClient {
private static final String CACHE_LATEST_LOGS = "latest_logs";
private static final String CACHE_IMAGE_URL = "url";
private static final String CACHE_IMAGE_CAPTION = "caption";
- private static final String CACHE_IMAGE_IS_SPOILER = "is_spoiler";
private static final String CACHE_IMAGES = "images";
private static final String CACHE_HINT = "hint";
private static final String CACHE_DESCRIPTION = "description";
@@ -110,14 +110,15 @@ final class OkapiClient {
// the several realms of possible fields for cache retrieval:
// Core: for livemap requests (L3 - only with level 3 auth)
// Additional: additional fields for full cache (L3 - only for level 3 auth, current - only for connectors with current api)
- private static final String SERVICE_CACHE_CORE_FIELDS = "code|name|location|type|status|difficulty|terrain|size";
+ private static final String SERVICE_CACHE_CORE_FIELDS = "code|name|location|type|status|difficulty|terrain|size|date_hidden";
private static final String SERVICE_CACHE_CORE_L3_FIELDS = "is_found";
- private static final String SERVICE_CACHE_ADDITIONAL_FIELDS = "owner|founds|notfounds|rating|rating_votes|recommendations|description|hint|images|latest_logs|date_hidden|alt_wpts|attrnames|req_passwd";
+ private static final String SERVICE_CACHE_ADDITIONAL_FIELDS = "owner|founds|notfounds|rating|rating_votes|recommendations|description|hint|images|latest_logs|alt_wpts|attrnames|req_passwd";
private static final String SERVICE_CACHE_ADDITIONAL_CURRENT_FIELDS = "gc_code|attribution_note";
private static final String SERVICE_CACHE_ADDITIONAL_L3_FIELDS = "is_watched|my_notes";
- private static final String METHOD_SEARCH_NEAREST = "services/caches/search/nearest";
+ private static final String METHOD_SEARCH_ALL = "services/caches/search/all";
private static final String METHOD_SEARCH_BBOX = "services/caches/search/bbox";
+ private static final String METHOD_SEARCH_NEAREST = "services/caches/search/nearest";
private static final String METHOD_RETRIEVE_CACHES = "services/caches/geocaches";
public static Geocache getCache(final String geoCode) {
@@ -132,13 +133,9 @@ final class OkapiClient {
params.add("fields", getFullFields(ocapiConn));
params.add("attribution_append", "none");
- final JSONObject data = request(ocapiConn, OkapiService.SERVICE_CACHE, params);
-
- if (data == null) {
- return null;
- }
+ final JSONResult result = request(ocapiConn, OkapiService.SERVICE_CACHE, params);
- return parseCache(data);
+ return result.isSuccess ? parseCache(result.data) : null;
}
public static List<Geocache> getCachesAround(final Geopoint center, final OCApiConnector connector) {
@@ -152,12 +149,38 @@ final class OkapiClient {
return requestCaches(connector, params, valueMap);
}
+ public static List<Geocache> getCachesNamed(final Geopoint center, final String namePart, final OCApiConnector connector) {
+ final Map<String, String> valueMap = new LinkedHashMap<String, String>();
+ final Parameters params;
+
+ // search around current position, if there is a position
+ if (center != null) {
+ final String centerString = GeopointFormatter.format(GeopointFormatter.Format.LAT_DECDEGREE_RAW, center) + SEPARATOR + GeopointFormatter.format(GeopointFormatter.Format.LON_DECDEGREE_RAW, center);
+ params = new Parameters("search_method", METHOD_SEARCH_NEAREST);
+ valueMap.put("center", centerString);
+ valueMap.put("limit", "20");
+ }
+ else {
+ params = new Parameters("search_method", METHOD_SEARCH_ALL);
+ valueMap.put("limit", "20");
+ }
+
+ // full wildcard search, maybe we need to change this after some testing and evaluation
+ valueMap.put("name", "*" + namePart + "*");
+ return requestCaches(connector, params, valueMap);
+ }
+
private static List<Geocache> requestCaches(final OCApiConnector connector, final Parameters params, final Map<String, String> valueMap) {
+ // if a global type filter is set, and OKAPI does not know that type, then return an empty list instead of all caches
+ if (Settings.getCacheType() != CacheType.ALL && StringUtils.isBlank(getFilterFromType())) {
+ return Collections.emptyList();
+ }
+
addFilterParams(valueMap, connector);
params.add("search_params", new JSONObject(valueMap).toString());
addRetrieveParams(params, connector);
- final JSONObject data = request(connector, OkapiService.SERVICE_SEARCH_AND_RETRIEVE, params);
+ final JSONObject data = request(connector, OkapiService.SERVICE_SEARCH_AND_RETRIEVE, params).data;
if (data == null) {
return Collections.emptyList();
@@ -166,7 +189,9 @@ final class OkapiClient {
return parseCaches(data);
}
- // Assumes level 3 OAuth
+ /**
+ * Assumes level 3 OAuth.
+ */
public static List<Geocache> getCachesBBox(final Viewport viewport, final OCApiConnector connector) {
if (viewport.getLatitudeSpan() == 0 || viewport.getLongitudeSpan() == 0) {
@@ -188,7 +213,7 @@ final class OkapiClient {
final Parameters params = new Parameters("cache_code", cache.getGeocode());
params.add("watched", watched ? "true" : "false");
- final JSONObject data = request(connector, OkapiService.SERVICE_MARK_CACHE, params);
+ final JSONObject data = request(connector, OkapiService.SERVICE_MARK_CACHE, params).data;
if (data == null) {
return false;
@@ -212,7 +237,7 @@ final class OkapiClient {
params.add("password", logPassword);
}
- final JSONObject data = request(connector, OkapiService.SERVICE_SUBMIT_LOG, params);
+ final JSONObject data = request(connector, OkapiService.SERVICE_SUBMIT_LOG, params).data;
if (data == null) {
return new LogResult(StatusCode.LOG_POST_ERROR, "");
@@ -265,7 +290,7 @@ final class OkapiClient {
parseCoreCache(response, cache);
- cgData.saveCache(cache, EnumSet.of(SaveFlag.SAVE_CACHE));
+ DataStore.saveCache(cache, EnumSet.of(SaveFlag.SAVE_CACHE));
} catch (final JSONException e) {
Log.e("OkapiClient.parseSmallCache", e);
}
@@ -297,7 +322,7 @@ final class OkapiClient {
final StringBuilder description = new StringBuilder(500);
if (!response.isNull("gc_code")) {
final String gccode = response.getString("gc_code");
- description.append(cgeoapplication.getInstance().getResources()
+ description.append(CgeoApplication.getInstance().getResources()
.getString(R.string.cache_listed_on, GCConnector.getInstance().getName()))
.append(": <a href=\"http://coord.info/")
.append(gccode)
@@ -318,13 +343,13 @@ final class OkapiClient {
final JSONObject imageResponse = images.getJSONObject(i);
final String title = imageResponse.getString(CACHE_IMAGE_CAPTION);
final String url = absoluteUrl(imageResponse.getString(CACHE_IMAGE_URL), cache.getGeocode());
+ // all images are added as spoiler images, although OKAPI has spoiler and non spoiler images
cache.addSpoiler(new Image(url, title));
}
}
cache.setAttributes(parseAttributes(response.getJSONArray(CACHE_ATTRNAMES)));
cache.setLogs(parseLogs(response.getJSONArray(CACHE_LATEST_LOGS)));
- cache.setHidden(parseDate(response.getString(CACHE_HIDDEN)));
//TODO: Store license per cache
//cache.setLicense(response.getString("attribution_note"));
cache.setWaypoints(parseWaypoints(response.getJSONArray(CACHE_WPTS)), false);
@@ -338,7 +363,7 @@ final class OkapiClient {
cache.setDetailedUpdatedNow();
// save full detailed caches
- cgData.saveCache(cache, EnumSet.of(SaveFlag.SAVE_DB));
+ DataStore.saveCache(cache, EnumSet.of(SaveFlag.SAVE_DB));
} catch (final JSONException e) {
Log.e("OkapiClient.parseCache", e);
}
@@ -363,6 +388,7 @@ final class OkapiClient {
if (!response.isNull(CACHE_IS_FOUND)) {
cache.setFound(response.getBoolean(CACHE_IS_FOUND));
}
+ cache.setHidden(parseDate(response.getString(CACHE_HIDDEN)));
}
private static String absoluteUrl(final String url, final String geocode) {
@@ -419,6 +445,7 @@ final class OkapiClient {
if (result == null) {
result = new ArrayList<Waypoint>();
}
+ wpt.setPrefix(wpt.getName());
result.add(wpt);
} catch (final JSONException e) {
Log.e("OkapiClient.parseWaypoints", e);
@@ -597,14 +624,15 @@ final class OkapiClient {
return res.toString();
}
- private static JSONObject request(final OCApiConnector connector, final OkapiService service, final Parameters params) {
+ @NonNull
+ private static JSONResult request(final OCApiConnector connector, final OkapiService service, final Parameters params) {
if (connector == null) {
- return null;
+ return new JSONResult(null);
}
final String host = connector.getHost();
if (StringUtils.isBlank(host)) {
- return null;
+ return new JSONResult(null);
}
params.add("langpref", getPreferredLanguage());
@@ -617,7 +645,7 @@ final class OkapiClient {
}
final String uri = "http://" + host + service.methodName;
- return Network.requestJSON(uri, params);
+ return new JSONResult(Network.getRequest(uri, params));
}
private static String getPreferredLanguage() {
@@ -637,7 +665,7 @@ final class OkapiClient {
valueMap.put("found_status", "notfound_only");
}
if (Settings.getCacheType() != CacheType.ALL) {
- valueMap.put("type", getFilterFromType(Settings.getCacheType()));
+ valueMap.put("type", getFilterFromType());
}
}
@@ -647,8 +675,8 @@ final class OkapiClient {
params.add("wrap", "true");
}
- private static String getFilterFromType(final CacheType cacheType) {
- switch (cacheType) {
+ private static String getFilterFromType() {
+ switch (Settings.getCacheType()) {
case EVENT:
return "Event";
case MULTI:
@@ -669,12 +697,16 @@ final class OkapiClient {
public static UserInfo getUserInfo(final OCApiLiveConnector connector) {
final Parameters params = new Parameters("fields", USER_INFO_FIELDS);
- final JSONObject data = request(connector, OkapiService.SERVICE_USER, params);
+ final JSONResult result = request(connector, OkapiService.SERVICE_USER, params);
- if (data == null) {
- return new UserInfo(StringUtils.EMPTY, 0, UserInfoStatus.FAILED);
+ if (!result.isSuccess) {
+ final OkapiError error = new OkapiError(result.data);
+ Log.e("OkapiClient.getUserInfo: error getting user info: '" + error.getMessage() + "'");
+ return new UserInfo(StringUtils.EMPTY, 0, UserInfoStatus.getFromOkapiError(error.getResult()));
}
+ JSONObject data = result.data;
+
String name = StringUtils.EMPTY;
boolean successUserName = false;
@@ -702,4 +734,28 @@ final class OkapiClient {
return new UserInfo(name, finds, successUserName && successFinds ? UserInfoStatus.SUCCESSFUL : UserInfoStatus.FAILED);
}
+ /**
+ * Encapsulates response state and content of an HTTP-request that expects a JSON result. <code>isSuccess</code> is
+ * only true, if the response state was success and <code>data</code> is not null.
+ */
+ private static class JSONResult {
+
+ public final boolean isSuccess;
+ public final JSONObject data;
+
+ public JSONResult(final @Nullable HttpResponse response) {
+ boolean isSuccess = Network.isSuccess(response);
+ final String responseData = Network.getResponseDataAlways(response);
+ JSONObject data = null;
+ if (responseData != null) {
+ try {
+ data = new JSONObject(responseData);
+ } catch (final JSONException e) {
+ Log.w("JSONResult", e);
+ }
+ }
+ this.data = data;
+ this.isSuccess = isSuccess && data != null;
+ }
+ }
}