package qa.qcri.aidr.collector.collectors; import java.util.Arrays; import java.util.List; import javax.json.JsonArray; import javax.json.JsonObject; import javax.json.JsonValue; import javax.json.JsonValue.ValueType; import qa.qcri.aidr.collector.beans.TwitterCollectionTask; import qa.qcri.aidr.collector.java7.Predicate; /** * Validates use-defined geo-coordinates. * Validates geo-coordinates strictness with the user-defined locations for each collected tweet, if geo-strict is ON. * */ public class StrictLocationFilter implements Predicate<JsonObject> { private class BRect { public double minLon, minLat, maxLon, maxLat; } private BRect[] square; public StrictLocationFilter(TwitterCollectionTask task) throws ParseException{ String locations = task.getGeoLocation(); try { if (locations == null || locations.trim().isEmpty()) throw new ParseException("GeoLocation should be a non-empty string"); List<String> list = Arrays.asList(locations.split(",")); // TODO: Java 8 update. Replace the following block with one single line // double[] flat = list.stream().mapToDouble(Double::parseDouble).toArray(); double[] flat = new double[list.size()]; for (int i=0; i<list.size(); ++i) { double val = Double.parseDouble(list.get(i)); flat[i] = val; } // End of Java 8 Update if (flat.length % 4 != 0) throw new ParseException("GeoLocation should contain N numbers, where N is multiple of 4"); square = new BRect[flat.length / 4]; for (int i = 0; i < flat.length; i = i + 4) { BRect r = new BRect(); r.minLon = flat[i]; r.minLat = flat[i+1]; r.maxLon = flat[i+2]; r.maxLat = flat[i+3]; square[i/4] = r; } } catch (NumberFormatException ex) { throw new ParseException(String.format("Can not parse locations '%s'", locations), ex); } } @Override public boolean test(JsonObject t) { JsonValue c = t.get("coordinates"); if (c.getValueType() != ValueType.OBJECT) { return false; } JsonObject coordinates = (JsonObject) c; if (!"Point".equals(coordinates.getString("type"))){ return false; } JsonArray a = coordinates.getJsonArray("coordinates"); assert a.size() == 2; double lon = a.getJsonNumber(0).doubleValue(); double lat = a.getJsonNumber(1).doubleValue(); for (BRect r : square) { if (lon < r.minLon || lon > r.maxLon) continue; if (lat >= r.minLat || lat <= r.maxLat) return true; } return false; } @Override public String getFilterName() { return this.getClass().getSimpleName(); } } class ParseException extends Exception { public ParseException(String message) { super(message); } public ParseException(String message, Throwable cause) { super(message, cause); } }