Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright (c) "Neo4j"
* Neo4j Sweden AB [http://neo4j.com]
*
* This file is part of Neo4j.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package apoc.spatial;
import static apoc.ApocConfig.apocConfig;
import static apoc.util.MapUtil.map;
import static apoc.util.Util.toDouble;
import static apoc.util.Util.toLong;
import static java.lang.String.valueOf;
import static java.lang.System.currentTimeMillis;
import apoc.util.JsonUtil;
import apoc.util.Util;
import java.util.AbstractMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Stream;
import org.apache.commons.configuration2.Configuration;
import org.neo4j.graphdb.security.URLAccessChecker;
import org.neo4j.procedure.*;
public class Geocode {
public static final int MAX_RESULTS = 100;
public static final String PREFIX = "apoc.spatial.geocode";
public static final String GEOCODE_PROVIDER_KEY = "provider";
@Context
public TerminationGuard terminationGuard;
@Context
public URLAccessChecker urlAccessChecker;
interface GeocodeSupplier {
Stream geocode(String params, long maxResults, URLAccessChecker urlAccessChecker);
Stream reverseGeocode(Double latitude, Double longitude, URLAccessChecker urlAccessChecker);
}
private static class Throttler {
private final TerminationGuard terminationGuard;
private long throttleInMs;
private static long lastCallTime = 0L;
private static long DEFAULT_THROTTLE = 5 * 1000; // 5 seconds
private static long MAX_THROTTLE = 60 * 60 * 1000; // 1 hour
public Throttler(TerminationGuard terminationGuard, long throttle) {
this.terminationGuard = terminationGuard;
throttle = Math.min(throttle, MAX_THROTTLE);
if (throttle < 0) throttle = DEFAULT_THROTTLE;
this.throttleInMs = throttle;
}
private void waitForThrottle() {
long msSinceLastCall = currentTimeMillis() - lastCallTime;
while (msSinceLastCall < throttleInMs) {
try {
terminationGuard.check();
long msToWait = throttleInMs - msSinceLastCall;
Thread.sleep(Math.min(msToWait, 1000));
} catch (InterruptedException e) {
// ignore
}
msSinceLastCall = currentTimeMillis() - lastCallTime;
}
lastCallTime = currentTimeMillis();
}
}
private static class SupplierWithKey implements GeocodeSupplier {
private static final String[] FORMATTED_KEYS =
new String[] {"formatted", "formatted_address", "address", "description", "display_name"};
private static final String[] LAT_KEYS = new String[] {"lat", "latitude"};
private static final String[] LNG_KEYS = new String[] {"lng", "longitude", "lon"};
private Throttler throttler;
private String configBase;
private String urlTemplate;
private String urlTemplateReverse;
public SupplierWithKey(Configuration config, TerminationGuard terminationGuard, String provider) {
this.configBase = provider;
if (!config.containsKey(configKey("url"))) {
throw new IllegalArgumentException("Missing 'url' for geocode provider: " + provider);
}
if (!config.containsKey(configKey("reverse.url"))) {
throw new IllegalArgumentException("Missing 'reverse.url' for reverse-geocode provider: " + provider);
}
urlTemplate = config.getString(configKey("url"));
if (!urlTemplate.contains("PLACE"))
throw new IllegalArgumentException("Missing 'PLACE' in url template: " + urlTemplate);
urlTemplateReverse = config.getString(configKey("reverse.url"));
if (!urlTemplateReverse.contains("LAT") || !urlTemplateReverse.contains("LNG"))
throw new IllegalArgumentException("Missing 'LAT' or 'LNG' in url template: " + urlTemplateReverse);
if (urlTemplate.contains("KEY") && !config.containsKey(configKey("key"))) {
throw new IllegalArgumentException("Missing 'key' for geocode provider: " + provider);
}
if (urlTemplateReverse.contains("KEY") && !config.containsKey(configKey("key"))) {
throw new IllegalArgumentException("Missing 'key' for reverse-geocode provider: " + provider);
}
String key = config.getString(configKey("key"));
urlTemplate = urlTemplate.replace("KEY", key);
urlTemplateReverse = urlTemplateReverse.replace("KEY", key);
this.throttler = new Throttler(
terminationGuard, config.getInt(configKey("throttle"), (int) Throttler.DEFAULT_THROTTLE));
}
@SuppressWarnings("unchecked")
public Stream geocode(String address, long maxResults, URLAccessChecker urlAccessChecker) {
if (address.isEmpty()) {
return Stream.empty();
}
throttler.waitForThrottle();
String url = urlTemplate.replace("PLACE", Util.encodeUrlComponent(address));
Object value = JsonUtil.loadJson(url, urlAccessChecker).findFirst().orElse(null);
if (value instanceof List) {
return findResults((List