diff options
Diffstat (limited to 'main/src/cgeo/geocaching/connector/oc/OkapiClient.java')
| -rw-r--r-- | main/src/cgeo/geocaching/connector/oc/OkapiClient.java | 130 |
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; + } + } } |
