Browse Source

replace nominatimClient with copied/pacthes version replacing legacy httpClient with okhttp3

Signed-off-by: Andy Scherzinger <info@andy-scherzinger.de>
Andy Scherzinger 4 years ago
parent
commit
f52d7f29d9

+ 4 - 2
app/build.gradle

@@ -294,8 +294,10 @@ dependencies {
     implementation 'com.elyeproj.libraries:loaderviewlibrary:2.0.0'
 
     implementation 'org.osmdroid:osmdroid-android:6.1.10'
-    //noinspection DuplicatePlatformClasses
-    implementation 'fr.dudie:nominatim-api:3.4'
+    implementation ('fr.dudie:nominatim-api:3.4', {
+        //noinspection DuplicatePlatformClasses
+        exclude group: 'org.apache.httpcomponents', module: 'httpclient'
+    })
 
     testImplementation 'junit:junit:4.13.2'
     testImplementation 'org.mockito:mockito-core:3.11.0'

+ 7 - 15
app/src/main/java/com/nextcloud/talk/controllers/GeocodingController.kt

@@ -46,20 +46,14 @@ import com.nextcloud.talk.controllers.util.viewBinding
 import com.nextcloud.talk.databinding.ControllerGeocodingBinding
 import com.nextcloud.talk.utils.bundle.BundleKeys
 import com.nextcloud.talk.utils.database.user.UserUtils
-import fr.dudie.nominatim.client.JsonNominatimClient
+import fr.dudie.nominatim.client.TalkJsonNominatimClient
 import fr.dudie.nominatim.model.Address
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Dispatchers.IO
 import kotlinx.coroutines.Dispatchers.Main
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.withContext
-import org.apache.http.client.HttpClient
-import org.apache.http.conn.ClientConnectionManager
-import org.apache.http.conn.scheme.Scheme
-import org.apache.http.conn.scheme.SchemeRegistry
-import org.apache.http.conn.ssl.SSLSocketFactory
-import org.apache.http.impl.client.DefaultHttpClient
-import org.apache.http.impl.conn.SingleClientConnManager
+import okhttp3.OkHttpClient
 import org.osmdroid.config.Configuration
 import javax.inject.Inject
 
@@ -78,8 +72,11 @@ class GeocodingController(args: Bundle) :
     @Inject
     lateinit var userUtils: UserUtils
 
+    @Inject
+    lateinit var okHttpClient: OkHttpClient
+
     var roomToken: String?
-    var nominatimClient: JsonNominatimClient? = null
+    var nominatimClient: TalkJsonNominatimClient? = null
 
     var searchItem: MenuItem? = null
     var searchView: SearchView? = null
@@ -178,13 +175,9 @@ class GeocodingController(args: Bundle) :
     }
 
     private fun initGeocoder() {
-        val registry = SchemeRegistry()
-        registry.register(Scheme("https", SSLSocketFactory.getSocketFactory(), HTTPS_PORT))
-        val connexionManager: ClientConnectionManager = SingleClientConnManager(null, registry)
-        val httpClient: HttpClient = DefaultHttpClient(connexionManager, null)
         val baseUrl = context!!.getString(R.string.osm_geocoder_url)
         val email = context!!.getString(R.string.osm_geocoder_contact)
-        nominatimClient = JsonNominatimClient(baseUrl, httpClient, email)
+        nominatimClient = TalkJsonNominatimClient(baseUrl, okHttpClient, email)
     }
 
     private fun searchLocation(): Boolean {
@@ -223,6 +216,5 @@ class GeocodingController(args: Bundle) :
 
     companion object {
         private const val TAG = "GeocodingController"
-        private const val HTTPS_PORT: Int = 443
     }
 }

+ 7 - 15
app/src/main/java/com/nextcloud/talk/controllers/LocationPickerController.kt

@@ -57,7 +57,7 @@ import com.nextcloud.talk.utils.DisplayUtils
 import com.nextcloud.talk.utils.bundle.BundleKeys
 import com.nextcloud.talk.utils.bundle.BundleKeys.KEY_ROOM_TOKEN
 import com.nextcloud.talk.utils.database.user.UserUtils
-import fr.dudie.nominatim.client.JsonNominatimClient
+import fr.dudie.nominatim.client.TalkJsonNominatimClient
 import fr.dudie.nominatim.model.Address
 import io.reactivex.Observer
 import io.reactivex.android.schedulers.AndroidSchedulers
@@ -67,13 +67,7 @@ import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.withContext
-import org.apache.http.client.HttpClient
-import org.apache.http.conn.ClientConnectionManager
-import org.apache.http.conn.scheme.Scheme
-import org.apache.http.conn.scheme.SchemeRegistry
-import org.apache.http.conn.ssl.SSLSocketFactory
-import org.apache.http.impl.client.DefaultHttpClient
-import org.apache.http.impl.conn.SingleClientConnManager
+import okhttp3.OkHttpClient
 import org.osmdroid.config.Configuration.getInstance
 import org.osmdroid.events.DelayedMapListener
 import org.osmdroid.events.MapListener
@@ -103,7 +97,10 @@ class LocationPickerController(args: Bundle) :
     @Inject
     lateinit var userUtils: UserUtils
 
-    var nominatimClient: JsonNominatimClient? = null
+    @Inject
+    lateinit var okHttpClient: OkHttpClient
+
+    var nominatimClient: TalkJsonNominatimClient? = null
 
     var roomToken: String?
 
@@ -425,13 +422,9 @@ class LocationPickerController(args: Bundle) :
     }
 
     private fun initGeocoder() {
-        val registry = SchemeRegistry()
-        registry.register(Scheme("https", SSLSocketFactory.getSocketFactory(), HTTPS_PORT))
-        val connexionManager: ClientConnectionManager = SingleClientConnManager(null, registry)
-        val httpClient: HttpClient = DefaultHttpClient(connexionManager, null)
         val baseUrl = context!!.getString(R.string.osm_geocoder_url)
         val email = context!!.getString(R.string.osm_geocoder_contact)
-        nominatimClient = JsonNominatimClient(baseUrl, httpClient, email)
+        nominatimClient = TalkJsonNominatimClient(baseUrl, okHttpClient, email)
     }
 
     private fun searchPlaceNameForCoordinates(lat: Double, lon: Double): Boolean {
@@ -483,6 +476,5 @@ class LocationPickerController(args: Bundle) :
         private const val ZOOM_LEVEL_RECEIVED_RESULT: Double = 14.0
         private const val ZOOM_LEVEL_DEFAULT: Double = 14.0
         private const val GEOCODE_ZERO: Double = 0.0
-        private const val HTTPS_PORT: Int = 443
     }
 }

+ 338 - 0
app/src/main/java/fr/dudie/nominatim/client/TalkJsonNominatimClient.java

@@ -0,0 +1,338 @@
+package fr.dudie.nominatim.client;
+
+/*
+ * [license]
+ * Nominatim Java API client
+ * ~~~~
+ * Copyright (C) 2010 - 2014 Dudie
+ * ~~~~
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Lesser Public License for more details.
+ *
+ * You should have received a copy of the GNU General Lesser Public
+ * License along with this program.  If not, see
+ * <http://www.gnu.org/licenses/lgpl-3.0.html>.
+ * [/license]
+ */
+
+import android.util.Log;
+
+import com.github.filosganga.geogson.gson.GeometryAdapterFactory;
+import com.github.filosganga.geogson.jts.JtsAdapterFactory;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+import com.google.gson.reflect.TypeToken;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.util.ArrayList;
+import java.util.List;
+
+import fr.dudie.nominatim.client.request.NominatimLookupRequest;
+import fr.dudie.nominatim.client.request.NominatimReverseRequest;
+import fr.dudie.nominatim.client.request.NominatimSearchRequest;
+import fr.dudie.nominatim.client.request.paramhelper.OsmType;
+import fr.dudie.nominatim.gson.ArrayOfAddressElementsDeserializer;
+import fr.dudie.nominatim.gson.ArrayOfPolygonPointsDeserializer;
+import fr.dudie.nominatim.gson.BoundingBoxDeserializer;
+import fr.dudie.nominatim.gson.PolygonPointDeserializer;
+import fr.dudie.nominatim.model.Address;
+import fr.dudie.nominatim.model.BoundingBox;
+import fr.dudie.nominatim.model.Element;
+import fr.dudie.nominatim.model.PolygonPoint;
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import okhttp3.Response;
+import okhttp3.ResponseBody;
+
+/**
+ * An implementation of the Nominatim Api Service.
+ *
+ * @author Jérémie Huchet
+ * @author Sunil D S
+ * @author Andy Scherzinger
+ */
+public final class TalkJsonNominatimClient implements NominatimClient {
+    private static final String TAG = "TalkNominationClient";
+
+    /**
+     * The default nominatim base URL.
+     */
+    private static final String DEFAULT_BASE_URL = "https://nominatim.openstreetmap.org/";
+
+    /**
+     * UTF-8 encoding.
+     */
+    public static final String ENCODING_UTF_8 = "UTF-8";
+
+    private final OkHttpClient httpClient;
+
+    /**
+     * Gson instance for Nominatim API calls.
+     */
+    private final Gson gson;
+
+    /**
+     * The url to make search queries.
+     */
+    private final String searchUrl;
+
+    /**
+     * The url for reverse geocoding.
+     */
+    private final String reverseUrl;
+
+    /**
+     * The url for address lookup.
+     */
+    private final String lookupUrl;
+
+    /**
+     * The default search options.
+     */
+    private final NominatimOptions defaults;
+
+    /**
+     * Creates the json nominatim client with the default base URL ({@value #DEFAULT_BASE_URL}.
+     *
+     * @param httpClient an HTTP client
+     * @param email      an email to add in the HTTP requests parameters to "sign" them
+     */
+    public TalkJsonNominatimClient(final OkHttpClient httpClient, final String email) {
+        this(DEFAULT_BASE_URL, httpClient, email, new NominatimOptions());
+    }
+
+    /**
+     * Creates the json nominatim client with the default base URL ({@value #DEFAULT_BASE_URL}.
+     *
+     * @param httpClient an HTTP client
+     * @param email      an email to add in the HTTP requests parameters to "sign" them
+     * @param defaults   defaults options, they override null valued requests options
+     */
+    public TalkJsonNominatimClient(final OkHttpClient httpClient, final String email, final NominatimOptions defaults) {
+        this(DEFAULT_BASE_URL, httpClient, email, defaults);
+    }
+
+    /**
+     * Creates the json nominatim client.
+     *
+     * @param baseUrl    the nominatim server url
+     * @param httpClient an HTTP client
+     * @param email      an email to add in the HTTP requests parameters to "sign" them (see
+     *                   https://wiki.openstreetmap.org/wiki/Nominatim_usage_policy)
+     */
+    public TalkJsonNominatimClient(final String baseUrl, final OkHttpClient httpClient, final String email) {
+        this(baseUrl, httpClient, email, new NominatimOptions());
+    }
+
+    /**
+     * Creates the json nominatim client.
+     *
+     * @param baseUrl    the nominatim server url
+     * @param httpClient an HTTP client
+     * @param email      an email to add in the HTTP requests parameters to "sign" them (see
+     *                   https://wiki.openstreetmap.org/wiki/Nominatim_usage_policy)
+     * @param defaults   defaults options, they override null valued requests options
+     */
+    public TalkJsonNominatimClient(final String baseUrl, final OkHttpClient httpClient, final String email, final NominatimOptions defaults) {
+        String emailEncoded;
+        try {
+            emailEncoded = URLEncoder.encode(email, ENCODING_UTF_8);
+        } catch (UnsupportedEncodingException e) {
+            emailEncoded = email;
+        }
+        this.searchUrl = String.format("%s/search?format=jsonv2&email=%s", baseUrl.replaceAll("/$", ""), emailEncoded);
+        this.reverseUrl = String.format("%s/reverse?format=jsonv2&email=%s", baseUrl.replaceAll("/$", ""), emailEncoded);
+        this.lookupUrl = String.format("%s/lookup?format=json&email=%s", baseUrl.replaceAll("/$", ""), emailEncoded);
+
+        Log.d(TAG, "API search URL: " + searchUrl);
+        Log.d(TAG, "API reverse URL: " + reverseUrl);
+
+        this.defaults = defaults;
+
+        // prepare gson instance
+        final GsonBuilder gsonBuilder = new GsonBuilder();
+
+        gsonBuilder.registerTypeAdapter(Element[].class, new ArrayOfAddressElementsDeserializer());
+        gsonBuilder.registerTypeAdapter(PolygonPoint.class, new PolygonPointDeserializer());
+        gsonBuilder.registerTypeAdapter(PolygonPoint[].class, new ArrayOfPolygonPointsDeserializer());
+        gsonBuilder.registerTypeAdapter(BoundingBox.class, new BoundingBoxDeserializer());
+
+        gsonBuilder.registerTypeAdapterFactory(new JtsAdapterFactory());
+        gsonBuilder.registerTypeAdapterFactory(new GeometryAdapterFactory());
+
+        gson = gsonBuilder.create();
+
+        // prepare httpclient
+        this.httpClient = httpClient;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @see fr.dudie.nominatim.client.NominatimClient#search(fr.dudie.nominatim.client.request.NominatimSearchRequest)
+     */
+    @Override
+    public List<Address> search(final NominatimSearchRequest search) throws IOException {
+
+        defaults.mergeTo(search);
+        final String apiCall = String.format("%s&%s", searchUrl, search.getQueryString());
+        Log.d(TAG, "search url: " + apiCall);
+
+        Request requesthttp = new Request.Builder()
+                .addHeader("accept", "application/json")
+                .url(apiCall)
+                .build();
+
+        Response response = httpClient.newCall(requesthttp).execute();
+        if (response.isSuccessful()) {
+            ResponseBody responseBody = response.body();
+            if (responseBody != null) {
+                return gson.fromJson(responseBody.string(), new TypeToken<List<Address>>() {
+                }.getType());
+            }
+        }
+
+        return new ArrayList<>();
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @see fr.dudie.nominatim.client.NominatimClient#getAddress(fr.dudie.nominatim.client.request.NominatimReverseRequest)
+     */
+    @Override
+    public Address getAddress(final NominatimReverseRequest reverse) throws IOException {
+
+        final String apiCall = String.format("%s&%s", reverseUrl, reverse.getQueryString());
+        Log.d(TAG, "reverse geocoding url: " + apiCall);
+
+        Request requesthttp = new Request.Builder()
+                .addHeader("accept", "application/json")
+                .url(apiCall)
+                .build();
+
+        Response response = httpClient.newCall(requesthttp).execute();
+        if (response.isSuccessful()) {
+            ResponseBody responseBody = response.body();
+            if (responseBody != null) {
+                return gson.fromJson(responseBody.string(), Address.class);
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @see fr.dudie.nominatim.client.NominatimClient#lookupAddress(fr.dudie.nominatim.client.request.NominatimLookupRequest)
+     */
+    @Override
+    public List<Address> lookupAddress(final NominatimLookupRequest lookup) throws IOException {
+
+        final String apiCall = String.format("%s&%s", lookupUrl, lookup.getQueryString());
+        Log.d(TAG, "lookup url: " + apiCall);
+        Request requesthttp = new Request.Builder()
+                .addHeader("accept", "application/json")
+                .url(apiCall)
+                .build();
+
+        Response response = httpClient.newCall(requesthttp).execute();
+        if (response.isSuccessful()) {
+            ResponseBody responseBody = response.body();
+            if (responseBody != null) {
+                return gson.fromJson(responseBody.string(), new TypeToken<List<Address>>() {
+                }.getType());
+            }
+        }
+
+        return new ArrayList<>();
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @see fr.dudie.nominatim.client.NominatimClient#search(java.lang.String)
+     */
+    @Override
+    public List<Address> search(final String query) throws IOException {
+
+        final NominatimSearchRequest q = new NominatimSearchRequest();
+        q.setQuery(query);
+        return this.search(q);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @see fr.dudie.nominatim.client.NominatimClient#getAddress(double, double)
+     */
+    @Override
+    public Address getAddress(final double longitude, final double latitude) throws IOException {
+
+        final NominatimReverseRequest q = new NominatimReverseRequest();
+        q.setQuery(longitude, latitude);
+        return this.getAddress(q);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @see fr.dudie.nominatim.client.NominatimClient#getAddress(double, double, int)
+     */
+    @Override
+    public Address getAddress(final double longitude, final double latitude, final int zoom)
+            throws IOException {
+
+        final NominatimReverseRequest q = new NominatimReverseRequest();
+        q.setQuery(longitude, latitude);
+        q.setZoom(zoom);
+        return this.getAddress(q);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @see fr.dudie.nominatim.client.NominatimClient#getAddress(int, int)
+     */
+    @Override
+    public Address getAddress(final int longitudeE6, final int latitudeE6) throws IOException {
+
+        return this.getAddress((double) (longitudeE6 / 1E6), (double) (latitudeE6 / 1E6));
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @see fr.dudie.nominatim.client.NominatimClient#getAddress(String, long)
+     */
+    @Override
+    public Address getAddress(final String type, final long id) throws IOException {
+
+        final NominatimReverseRequest q = new NominatimReverseRequest();
+        q.setQuery(OsmType.from(type), id);
+        return this.getAddress(q);
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * @see fr.dudie.nominatim.client.NominatimClient#lookupAddress(java.util.List)
+     */
+    @Override
+    public List<Address> lookupAddress(final List<String> typeId) throws IOException {
+
+        final NominatimLookupRequest q = new NominatimLookupRequest();
+        q.setQuery(typeId);
+        return this.lookupAddress(q);
+    }
+}