aboutsummaryrefslogtreecommitdiffstats
path: root/main/src/cgeo/geocaching/gcvote/GCVote.java
diff options
context:
space:
mode:
Diffstat (limited to 'main/src/cgeo/geocaching/gcvote/GCVote.java')
-rw-r--r--main/src/cgeo/geocaching/gcvote/GCVote.java239
1 files changed, 81 insertions, 158 deletions
diff --git a/main/src/cgeo/geocaching/gcvote/GCVote.java b/main/src/cgeo/geocaching/gcvote/GCVote.java
index 8de3edc..2985e89 100644
--- a/main/src/cgeo/geocaching/gcvote/GCVote.java
+++ b/main/src/cgeo/geocaching/gcvote/GCVote.java
@@ -8,13 +8,18 @@ import cgeo.geocaching.network.Parameters;
import cgeo.geocaching.settings.Settings;
import cgeo.geocaching.utils.LeastRecentlyUsedMap;
import cgeo.geocaching.utils.Log;
-import cgeo.geocaching.utils.MatcherWrapper;
+import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
+import org.apache.commons.io.Charsets;
+import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.eclipse.jdt.annotation.NonNull;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserFactory;
+import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -22,17 +27,9 @@ import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
-import java.util.regex.Pattern;
public final class GCVote {
public static final float NO_RATING = 0;
- private static final Pattern PATTERN_LOG_IN = Pattern.compile("loggedIn='([^']+)'", Pattern.CASE_INSENSITIVE);
- private static final Pattern PATTERN_GUID = Pattern.compile("cacheId='([^']+)'", Pattern.CASE_INSENSITIVE);
- private static final Pattern PATTERN_WAYPOINT = Pattern.compile("waypoint='([^']+)'", Pattern.CASE_INSENSITIVE);
- private static final Pattern PATTERN_RATING = Pattern.compile("voteAvg='([0-9.]+)'", Pattern.CASE_INSENSITIVE);
- private static final Pattern PATTERN_VOTES = Pattern.compile("voteCnt='([0-9]+)'", Pattern.CASE_INSENSITIVE);
- private static final Pattern PATTERN_VOTE = Pattern.compile("voteUser='([0-9.]+)'", Pattern.CASE_INSENSITIVE);
- private static final Pattern PATTERN_VOTE_ELEMENT = Pattern.compile("<vote ([^>]+)>", Pattern.CASE_INSENSITIVE);
private static final int MAX_CACHED_RATINGS = 1000;
private static final LeastRecentlyUsedMap<String, GCVoteRating> RATINGS_CACHE = new LeastRecentlyUsedMap.LruCache<>(MAX_CACHED_RATINGS);
@@ -46,10 +43,6 @@ public final class GCVote {
/**
* Get user rating for a given guid or geocode. For a guid first the ratings cache is checked
* before a request to gcvote.com is made.
- *
- * @param guid
- * @param geocode
- * @return
*/
public static GCVoteRating getRating(final String guid, final String geocode) {
if (StringUtils.isNotBlank(guid) && RATINGS_CACHE.containsKey(guid)) {
@@ -66,161 +59,100 @@ public final class GCVote {
/**
* Get user ratings from gcvote.com
- *
- * @param guids
- * @param geocodes
- * @return
*/
+ @NonNull
private static Map<String, GCVoteRating> getRating(final List<String> guids, final List<String> geocodes) {
if (guids == null && geocodes == null) {
- return null;
+ return Collections.emptyMap();
}
- final Map<String, GCVoteRating> ratings = new HashMap<>();
+ final Parameters params = new Parameters("version", "cgeo");
+ final ImmutablePair<String, String> login = Settings.getGCvoteLogin();
+ if (login != null) {
+ params.put("userName", login.left, "password", login.right);
+ }
+ // use guid or gccode for lookup
+ final boolean requestByGuids = CollectionUtils.isNotEmpty(guids);
+ if (requestByGuids) {
+ params.put("cacheIds", StringUtils.join(guids, ','));
+ } else {
+ params.put("waypoints", StringUtils.join(geocodes, ','));
+ }
+ final InputStream response = Network.getResponseStream(Network.getRequest("http://gcvote.com/getVotes.php", params));
+ if (response == null) {
+ return Collections.emptyMap();
+ }
try {
- final Parameters params = new Parameters();
- if (Settings.isLogin()) {
- final ImmutablePair<String, String> login = Settings.getGCvoteLogin();
- if (login != null) {
- params.put("userName", login.left, "password", login.right);
- }
- }
- // use guid or gccode for lookup
- boolean requestByGuids = true;
- if (guids != null && !guids.isEmpty()) {
- params.put("cacheIds", StringUtils.join(guids.toArray(), ','));
- } else {
- params.put("waypoints", StringUtils.join(geocodes.toArray(), ','));
- requestByGuids = false;
- }
- params.put("version", "cgeo");
- final String page = Network.getResponseData(Network.getRequest("http://gcvote.com/getVotes.php", params));
- if (page == null) {
- return null;
- }
-
- final MatcherWrapper matcherVoteElement = new MatcherWrapper(PATTERN_VOTE_ELEMENT, page);
- while (matcherVoteElement.find()) {
- String voteData = matcherVoteElement.group(1);
- if (voteData == null) {
- continue;
- }
-
- String id = null;
- String guid = null;
- final MatcherWrapper matcherGuid = new MatcherWrapper(PATTERN_GUID, voteData);
- if (matcherGuid.find()) {
- if (matcherGuid.groupCount() > 0) {
- guid = matcherGuid.group(1);
- if (requestByGuids) {
- id = guid;
- }
- }
- }
- if (!requestByGuids) {
- final MatcherWrapper matcherWp = new MatcherWrapper(PATTERN_WAYPOINT, voteData);
- if (matcherWp.find()) {
- if (matcherWp.groupCount() > 0) {
- id = matcherWp.group(1);
- }
- }
- }
- if (id == null) {
- continue;
- }
-
- boolean loggedIn = false;
- final MatcherWrapper matcherLoggedIn = new MatcherWrapper(PATTERN_LOG_IN, page);
- if (matcherLoggedIn.find()) {
- if (matcherLoggedIn.groupCount() > 0) {
- if (matcherLoggedIn.group(1).equalsIgnoreCase("true")) {
- loggedIn = true;
- }
- }
- }
-
- float rating = NO_RATING;
- try {
- final MatcherWrapper matcherRating = new MatcherWrapper(PATTERN_RATING, voteData);
- if (matcherRating.find()) {
- rating = Float.parseFloat(matcherRating.group(1));
- }
- } catch (NumberFormatException e) {
- Log.w("GCVote.getRating: Failed to parse rating");
- }
- if (!isValidRating(rating)) {
- continue;
- }
-
- int votes = -1;
- try {
- final MatcherWrapper matcherVotes = new MatcherWrapper(PATTERN_VOTES, voteData);
- if (matcherVotes.find()) {
- votes = Integer.parseInt(matcherVotes.group(1));
- }
- } catch (NumberFormatException e) {
- Log.w("GCVote.getRating: Failed to parse vote count");
- }
- if (votes < 0) {
- continue;
- }
+ return getRatingsFromXMLResponse(response, requestByGuids);
+ } finally {
+ IOUtils.closeQuietly(response);
+ }
+ }
- float myVote = NO_RATING;
- if (loggedIn) {
- try {
- final MatcherWrapper matcherVote = new MatcherWrapper(PATTERN_VOTE, voteData);
- if (matcherVote.find()) {
- myVote = Float.parseFloat(matcherVote.group(1));
- }
- } catch (NumberFormatException e) {
- Log.w("GCVote.getRating: Failed to parse user's vote");
+ static Map<String, GCVoteRating> getRatingsFromXMLResponse(@NonNull final InputStream response, final boolean requestByGuids) {
+ try {
+ final XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
+ final XmlPullParser xpp = factory.newPullParser();
+ xpp.setInput(response, Charsets.UTF_8.name());
+ boolean loggedIn = false;
+ final Map<String, GCVoteRating> ratings = new HashMap<>();
+ int eventType = xpp.getEventType();
+ while (eventType != XmlPullParser.END_DOCUMENT) {
+ if (eventType == XmlPullParser.START_TAG) {
+ final String tagName = xpp.getName();
+ if (StringUtils.equals(tagName, "vote")) {
+ final String id = xpp.getAttributeValue(null, requestByGuids ? "cacheId" : "waypoint");
+ final float myVote = loggedIn ? Float.parseFloat(xpp.getAttributeValue(null, "voteUser")) : 0;
+ final GCVoteRating voteRating = new GCVoteRating(Float.parseFloat(xpp.getAttributeValue(null, "voteAvg")),
+ Integer.parseInt(xpp.getAttributeValue(null, "voteCnt")),
+ myVote);
+ ratings.put(id, voteRating);
+ } else if (StringUtils.equals(tagName, "votes")) {
+ loggedIn = StringUtils.equals(xpp.getAttributeValue(null, "loggedIn"), "true");
}
}
-
- if (StringUtils.isNotBlank(id)) {
- GCVoteRating gcvoteRating = new GCVoteRating(rating, votes, myVote);
- ratings.put(id, gcvoteRating);
- RATINGS_CACHE.put(guid, gcvoteRating);
- }
+ eventType = xpp.next();
}
- } catch (RuntimeException e) {
- Log.e("GCVote.getRating", e);
- }
+ RATINGS_CACHE.putAll(ratings);
+ return ratings;
+ } catch (final Exception e) {
+ Log.e("Cannot parse GC vote result", e);
+ return Collections.emptyMap();
- return ratings;
+ }
}
/**
* Transmit user vote to gcvote.com
*
- * @param cache
- * @param vote
+ * @param cache the geocache (supported by GCVote)
+ * @param rating the rating
* @return {@code true} if the rating was submitted successfully
*/
- public static boolean setRating(final Geocache cache, final float vote) {
+ public static boolean setRating(final Geocache cache, final float rating) {
if (!isVotingPossible(cache)) {
- return false;
+ throw new IllegalArgumentException("voting is not possible for " + cache);
}
- if (!isValidRating(vote)) {
- return false;
+ if (!isValidRating(rating)) {
+ throw new IllegalArgumentException("invalid rating " + rating);
}
final ImmutablePair<String, String> login = Settings.getGCvoteLogin();
- if (login == null) {
- return false;
- }
-
final Parameters params = new Parameters(
"userName", login.left,
"password", login.right,
"cacheId", cache.getGuid(),
- "voteUser", String.format("%.1f", vote).replace(',', '.'),
+ "waypoint", cache.getGeocode(),
+ "voteUser", String.format(Locale.US, "%.1f", rating),
"version", "cgeo");
- final String result = Network.getResponseData(Network.getRequest("http://gcvote.com/setVote.php", params));
-
- return result != null && result.trim().equalsIgnoreCase("ok");
+ final String result = StringUtils.trim(Network.getResponseData(Network.getRequest("http://gcvote.com/setVote.php", params)));
+ if (!StringUtils.equalsIgnoreCase(result, "ok")) {
+ Log.e("GCVote.setRating: could not post rating, answer was " + result);
+ return false;
+ }
+ return true;
}
public static void loadRatings(final @NonNull ArrayList<Geocache> caches) {
@@ -236,34 +168,29 @@ public final class GCVote {
try {
final Map<String, GCVoteRating> ratings = GCVote.getRating(null, geocodes);
- if (MapUtils.isNotEmpty(ratings)) {
- // save found cache coordinates
- for (Geocache cache : caches) {
- if (ratings.containsKey(cache.getGeocode())) {
- GCVoteRating rating = ratings.get(cache.getGeocode());
+ // save found cache coordinates
+ for (final Geocache cache : caches) {
+ if (ratings.containsKey(cache.getGeocode())) {
+ final GCVoteRating rating = ratings.get(cache.getGeocode());
- cache.setRating(rating.getRating());
- cache.setVotes(rating.getVotes());
- cache.setMyVote(rating.getMyVote());
- }
+ cache.setRating(rating.getRating());
+ cache.setVotes(rating.getVotes());
+ cache.setMyVote(rating.getMyVote());
}
}
- } catch (Exception e) {
+ } catch (final Exception e) {
Log.e("GCvote.loadRatings", e);
}
}
/**
* Get geocodes of all the caches, which can be used with GCVote. Non-GC caches will be filtered out.
- *
- * @param caches
- * @return
*/
private static @NonNull
ArrayList<String> getVotableGeocodes(final @NonNull Collection<Geocache> caches) {
final ArrayList<String> geocodes = new ArrayList<>(caches.size());
for (final Geocache cache : caches) {
- String geocode = cache.getGeocode();
+ final String geocode = cache.getGeocode();
if (StringUtils.isNotBlank(geocode) && cache.supportsGCVote()) {
geocodes.add(geocode);
}
@@ -275,11 +202,7 @@ public final class GCVote {
return rating >= MIN_RATING && rating <= MAX_RATING;
}
- public static String getRatingText(final float rating) {
- return String.format(Locale.getDefault(), "%.1f", rating);
- }
-
- public static boolean isVotingPossible(final Geocache cache) {
+ public static boolean isVotingPossible(@NonNull final Geocache cache) {
return Settings.isGCvoteLogin() && StringUtils.isNotBlank(cache.getGuid()) && cache.supportsGCVote();
}
@@ -308,7 +231,7 @@ public final class GCVote {
}
}
- private static String getString(int resId) {
+ private static String getString(final int resId) {
return CgeoApplication.getInstance().getString(resId);
}