[MINDEXER-174] Simplify and tidy up SMO (#262)

Simplidy and tidy up

---

https://issues.apache.org/jira/browse/MINDEXER-174
diff --git a/search-backend-smo/src/main/filtered-resources/smo-version.properties b/search-backend-smo/src/main/filtered-resources/org/apache/maven/search/backend/smo/internal/smo-version.properties
similarity index 100%
rename from search-backend-smo/src/main/filtered-resources/smo-version.properties
rename to search-backend-smo/src/main/filtered-resources/org/apache/maven/search/backend/smo/internal/smo-version.properties
diff --git a/search-backend-smo/src/main/java/org/apache/maven/search/backend/smo/SmoSearchBackendFactory.java b/search-backend-smo/src/main/java/org/apache/maven/search/backend/smo/SmoSearchBackendFactory.java
index ea28ce6..4456caa 100644
--- a/search-backend-smo/src/main/java/org/apache/maven/search/backend/smo/SmoSearchBackendFactory.java
+++ b/search-backend-smo/src/main/java/org/apache/maven/search/backend/smo/SmoSearchBackendFactory.java
@@ -48,7 +48,7 @@
     public SmoSearchBackend create( String backendId,
                                     String repositoryId,
                                     String smoUri,
-                                    SmoSearchTransportSupport transportSupport )
+                                    SmoSearchTransport transportSupport )
     {
         return new SmoSearchBackendImpl( backendId, repositoryId, smoUri, transportSupport );
     }
diff --git a/search-backend-smo/src/main/java/org/apache/maven/search/backend/smo/SmoSearchTransport.java b/search-backend-smo/src/main/java/org/apache/maven/search/backend/smo/SmoSearchTransport.java
new file mode 100644
index 0000000..bda64ce
--- /dev/null
+++ b/search-backend-smo/src/main/java/org/apache/maven/search/backend/smo/SmoSearchTransport.java
@@ -0,0 +1,37 @@
+package org.apache.maven.search.backend.smo;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.
+ */
+
+import java.io.IOException;
+import java.util.Map;
+
+/**
+ * A trivial "transport abstraction" to make possible pluggable implementations.
+ */
+public interface SmoSearchTransport
+{
+    /**
+     * This method should issue a HTTP GET requests using {@code serviceUri} and return body payload as {@link String}
+     * ONLY if the response was HTTP 200 Ok and there was a payload returned by service. In any other case, it should
+     * throw, never return {@code null}. The payload is expected to be {@code application/json}, so client may add
+     * headers to request. Also, the payload is expected to be "relatively small" that may be enforced.
+     */
+    String fetch( String serviceUri, Map<String, String> headers ) throws IOException;
+}
diff --git a/search-backend-smo/src/main/java/org/apache/maven/search/backend/smo/SmoSearchTransportSupport.java b/search-backend-smo/src/main/java/org/apache/maven/search/backend/smo/SmoSearchTransportSupport.java
deleted file mode 100644
index 16fc2ba..0000000
--- a/search-backend-smo/src/main/java/org/apache/maven/search/backend/smo/SmoSearchTransportSupport.java
+++ /dev/null
@@ -1,81 +0,0 @@
-package org.apache.maven.search.backend.smo;
-
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you 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.
- */
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.util.Properties;
-
-import org.apache.maven.search.SearchRequest;
-
-/**
- * A trivial "transport abstraction" to make possible pluggable implementations.
- */
-public abstract class SmoSearchTransportSupport
-{
-    private final String clientVersion;
-
-    public SmoSearchTransportSupport()
-    {
-        this.clientVersion = discoverVersion();
-    }
-
-    private String discoverVersion()
-    {
-        Properties properties = new Properties();
-        InputStream inputStream = getClass().getClassLoader().getResourceAsStream( "smo-version.properties" );
-        if ( inputStream != null )
-        {
-            try ( InputStream is = inputStream )
-            {
-                properties.load( is );
-            }
-            catch ( IOException e )
-            {
-                // fall through
-            }
-        }
-        return properties.getProperty( "version", "unknown" );
-    }
-
-    /**
-     * Exposes this backend version, for example to be used in HTTP {@code User-Agent} string, never {@code null}.
-     */
-    protected String getClientVersion()
-    {
-        return clientVersion;
-    }
-
-    /**
-     * Exposes full HTTP {@code User-Agent} string ready to be used by HTTP clients, never {@code null}.
-     */
-    protected String getUserAgent()
-    {
-        return "Apache Search SMO/" + getClientVersion();
-    }
-
-    /**
-     * This method should issue a HTTP GET requests using {@code serviceUri} and return body payload as {@link String}
-     * ONLY if the response was HTTP 200 Ok and there was a payload returned by service. In any other case, it should
-     * throw, never return {@code null}. The payload is expected to be {@code application/json}, so client may add
-     * headers to request. Also, the payload is expected to be "relatively small".
-     */
-    public abstract String fetch( SearchRequest searchRequest, String serviceUri ) throws IOException;
-}
diff --git a/search-backend-smo/src/main/java/org/apache/maven/search/backend/smo/internal/SmoSearchBackendImpl.java b/search-backend-smo/src/main/java/org/apache/maven/search/backend/smo/internal/SmoSearchBackendImpl.java
index 5c350cc..be504ef 100644
--- a/search-backend-smo/src/main/java/org/apache/maven/search/backend/smo/internal/SmoSearchBackendImpl.java
+++ b/search-backend-smo/src/main/java/org/apache/maven/search/backend/smo/internal/SmoSearchBackendImpl.java
@@ -20,6 +20,7 @@
  */
 
 import java.io.IOException;
+import java.io.InputStream;
 import java.io.UnsupportedEncodingException;
 import java.net.URLEncoder;
 import java.nio.charset.StandardCharsets;
@@ -29,6 +30,7 @@
 import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Properties;
 
 import com.google.gson.JsonArray;
 import com.google.gson.JsonElement;
@@ -40,7 +42,7 @@
 import org.apache.maven.search.SearchRequest;
 import org.apache.maven.search.backend.smo.SmoSearchBackend;
 import org.apache.maven.search.backend.smo.SmoSearchResponse;
-import org.apache.maven.search.backend.smo.SmoSearchTransportSupport;
+import org.apache.maven.search.backend.smo.SmoSearchTransport;
 import org.apache.maven.search.request.BooleanQuery;
 import org.apache.maven.search.request.Field;
 import org.apache.maven.search.request.FieldQuery;
@@ -70,17 +72,43 @@
 
     private final String smoUri;
 
-    private final SmoSearchTransportSupport transportSupport;
+    private final SmoSearchTransport transportSupport;
+
+    private final Map<String, String> commonHeaders;
 
     /**
      * Creates a customized instance of SMO backend, like an in-house instances of SMO or different IDs.
      */
     public SmoSearchBackendImpl( String backendId, String repositoryId, String smoUri,
-                                 SmoSearchTransportSupport transportSupport )
+                                 SmoSearchTransport transportSupport )
     {
         super( backendId, repositoryId );
         this.smoUri = requireNonNull( smoUri );
         this.transportSupport = requireNonNull( transportSupport );
+
+        this.commonHeaders = new HashMap<>();
+        this.commonHeaders.put( "User-Agent", "Apache-Maven-Search-SMO/" + discoverVersion() + " "
+                + transportSupport.getClass().getSimpleName() );
+        this.commonHeaders.put( "Accept", "application/json" );
+    }
+
+    private String discoverVersion()
+    {
+        Properties properties = new Properties();
+        InputStream inputStream = getClass().getClassLoader().getResourceAsStream(
+                "org/apache/maven/search/backend/smo/internal/smo-version.properties" );
+        if ( inputStream != null )
+        {
+            try ( InputStream is = inputStream )
+            {
+                properties.load( is );
+            }
+            catch ( IOException e )
+            {
+                // fall through
+            }
+        }
+        return properties.getProperty( "version", "unknown" );
     }
 
     @Override
@@ -93,14 +121,14 @@
     public SmoSearchResponse search( SearchRequest searchRequest ) throws IOException
     {
         String searchUri = toURI( searchRequest );
-        String payload = transportSupport.fetch( searchRequest, searchUri );
+        String payload = transportSupport.fetch( searchUri, commonHeaders );
         JsonObject raw = JsonParser.parseString( payload ).getAsJsonObject();
         List<Record> page = new ArrayList<>( searchRequest.getPaging().getPageSize() );
         int totalHits = populateFromRaw( raw, page );
         return new SmoSearchResponseImpl( searchRequest, totalHits, page, searchUri, payload );
     }
 
-    private String toURI( SearchRequest searchRequest ) throws UnsupportedEncodingException
+    private String toURI( SearchRequest searchRequest )
     {
         Paging paging = searchRequest.getPaging();
         HashSet<Field> searchedFields = new HashSet<>();
@@ -115,7 +143,7 @@
         return smoUri + "?q=" + smoQuery;
     }
 
-    private String toSMOQuery( HashSet<Field> searchedFields, Query query ) throws UnsupportedEncodingException
+    private String toSMOQuery( HashSet<Field> searchedFields, Query query )
     {
         if ( query instanceof BooleanQuery.And )
         {
diff --git a/search-backend-smo/src/main/java/org/apache/maven/search/backend/smo/internal/SmoSearchTransportSupplier.java b/search-backend-smo/src/main/java/org/apache/maven/search/backend/smo/internal/SmoSearchTransportSupplier.java
index 15922cc..c4a8081 100644
--- a/search-backend-smo/src/main/java/org/apache/maven/search/backend/smo/internal/SmoSearchTransportSupplier.java
+++ b/search-backend-smo/src/main/java/org/apache/maven/search/backend/smo/internal/SmoSearchTransportSupplier.java
@@ -21,15 +21,15 @@
 
 import java.util.function.Supplier;
 
-import org.apache.maven.search.backend.smo.SmoSearchTransportSupport;
+import org.apache.maven.search.backend.smo.SmoSearchTransport;
 
 /**
  * Transport supplier.
  */
-public class SmoSearchTransportSupplier implements Supplier<SmoSearchTransportSupport>
+public class SmoSearchTransportSupplier implements Supplier<SmoSearchTransport>
 {
     @Override
-    public SmoSearchTransportSupport get()
+    public SmoSearchTransport get()
     {
         return new UrlConnectionSmoSearchTransport();
     }
diff --git a/search-backend-smo/src/main/java/org/apache/maven/search/backend/smo/internal/UrlConnectionSmoSearchTransport.java b/search-backend-smo/src/main/java/org/apache/maven/search/backend/smo/internal/UrlConnectionSmoSearchTransport.java
index 312f9a3..4bdb143 100644
--- a/search-backend-smo/src/main/java/org/apache/maven/search/backend/smo/internal/UrlConnectionSmoSearchTransport.java
+++ b/search-backend-smo/src/main/java/org/apache/maven/search/backend/smo/internal/UrlConnectionSmoSearchTransport.java
@@ -24,23 +24,25 @@
 import java.net.HttpURLConnection;
 import java.net.URL;
 import java.nio.charset.StandardCharsets;
+import java.util.Map;
 import java.util.Scanner;
 
-import org.apache.maven.search.SearchRequest;
-import org.apache.maven.search.backend.smo.SmoSearchTransportSupport;
+import org.apache.maven.search.backend.smo.SmoSearchTransport;
 
 /**
  * {@link java.net.HttpURLConnection} backed transport.
  */
-public class UrlConnectionSmoSearchTransport extends SmoSearchTransportSupport
+public class UrlConnectionSmoSearchTransport implements SmoSearchTransport
 {
     @Override
-    public String fetch( SearchRequest searchRequest, String serviceUri ) throws IOException
+    public String fetch( String serviceUri, Map<String, String> headers ) throws IOException
     {
         HttpURLConnection httpConnection = (HttpURLConnection) new URL( serviceUri ).openConnection();
         httpConnection.setInstanceFollowRedirects( false );
-        httpConnection.setRequestProperty( "User-Agent", getUserAgent() );
-        httpConnection.setRequestProperty( "Accept", "application/json" );
+        for ( Map.Entry<String, String> entry : headers.entrySet() )
+        {
+            httpConnection.setRequestProperty( entry.getKey(), entry.getValue() );
+        }
         int httpCode = httpConnection.getResponseCode();
         if ( httpCode == HttpURLConnection.HTTP_OK )
         {
diff --git a/search-backend-smo/src/main/java11/org/apache/maven/search/backend/smo/internal/Java11HttpClientSmoSearchTransport.java b/search-backend-smo/src/main/java11/org/apache/maven/search/backend/smo/internal/Java11HttpClientSmoSearchTransport.java
index 0b45143..381151c 100644
--- a/search-backend-smo/src/main/java11/org/apache/maven/search/backend/smo/internal/Java11HttpClientSmoSearchTransport.java
+++ b/search-backend-smo/src/main/java11/org/apache/maven/search/backend/smo/internal/Java11HttpClientSmoSearchTransport.java
@@ -25,26 +25,26 @@
 import java.net.http.HttpClient;
 import java.net.http.HttpRequest;
 import java.net.http.HttpResponse;
+import java.util.Map;
 
-import org.apache.maven.search.SearchRequest;
-import org.apache.maven.search.backend.smo.SmoSearchTransportSupport;
+import org.apache.maven.search.backend.smo.SmoSearchTransport;
 
 /**
  * Java 11 {@link HttpClient} backed transport.
  */
-public class Java11HttpClientSmoSearchTransport extends SmoSearchTransportSupport
+public class Java11HttpClientSmoSearchTransport implements SmoSearchTransport
 {
     private final HttpClient client = HttpClient.newBuilder().followRedirects( HttpClient.Redirect.NEVER ).build();
 
     @Override
-    public String fetch( SearchRequest searchRequest, String serviceUri ) throws IOException
+    public String fetch( String serviceUri, Map<String, String> headers ) throws IOException
     {
-        HttpRequest request = HttpRequest.newBuilder()
-                .uri( URI.create( serviceUri ) )
-                .header( "User-Agent", getUserAgent() )
-                .header( "Accept", "application/json" )
-                .GET()
-                .build();
+        HttpRequest.Builder builder = HttpRequest.newBuilder().uri( URI.create( serviceUri ) ).GET();
+        for ( Map.Entry<String, String> header : headers.entrySet() )
+        {
+            builder.header( header.getKey(), header.getValue() );
+        }
+        HttpRequest request = builder.build();
         try
         {
             HttpResponse<String> response = client.send( request, HttpResponse.BodyHandlers.ofString() );
diff --git a/search-backend-smo/src/main/java11/org/apache/maven/search/backend/smo/internal/SmoSearchTransportSupplier.java b/search-backend-smo/src/main/java11/org/apache/maven/search/backend/smo/internal/SmoSearchTransportSupplier.java
index 08327be..e12b175 100644
--- a/search-backend-smo/src/main/java11/org/apache/maven/search/backend/smo/internal/SmoSearchTransportSupplier.java
+++ b/search-backend-smo/src/main/java11/org/apache/maven/search/backend/smo/internal/SmoSearchTransportSupplier.java
@@ -21,15 +21,15 @@
 
 import java.util.function.Supplier;
 
-import org.apache.maven.search.backend.smo.SmoSearchTransportSupport;
+import org.apache.maven.search.backend.smo.SmoSearchTransport;
 
 /**
  * Transport supplier.
  */
-public class SmoSearchTransportSupplier implements Supplier<SmoSearchTransportSupport>
+public class SmoSearchTransportSupplier implements Supplier<SmoSearchTransport>
 {
     @Override
-    public SmoSearchTransportSupport get()
+    public SmoSearchTransport get()
     {
         return new Java11HttpClientSmoSearchTransport();
     }