This is an automated email from the ASF dual-hosted git repository.

cstamas pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven-indexer.git


The following commit(s) were added to refs/heads/master by this push:
     new aaf9623  [MINDEXER-254] Add CSC, add hacks circumventing CSC bug and 
make project more open (#425)
aaf9623 is described below

commit aaf962303de22a86a4d47186aacc51e198d795f3
Author: Tamas Cservenak <ta...@cservenak.net>
AuthorDate: Fri May 30 19:04:00 2025 +0200

    [MINDEXER-254] Add CSC, add hacks circumventing CSC bug and make project 
more open (#425)
    
    Adds CSC support, with a hack to support CSC bug re paging. On related 
note, make whole Search API more open and "hackable", that is more accessible 
for client code.
    
    ---
    
    https://issues.apache.org/jira/browse/MINDEXER-253
    https://issues.apache.org/jira/browse/MINDEXER-254
---
 indexer-examples/indexer-examples-spring/pom.xml   |   2 +-
 .../java/org/apache/maven/search/api/Record.java   |  12 +-
 .../org/apache/maven/search/api/SearchRequest.java |   6 +-
 .../maven/search/api/request/BooleanQuery.java     |   8 +-
 .../org/apache/maven/search/api/request/Field.java |   4 +-
 .../maven/search/api/request/FieldQuery.java       |   2 +-
 .../apache/maven/search/api/request/Paging.java    |   6 +-
 .../org/apache/maven/search/api/request/Query.java |   2 +-
 .../search/api/support/SearchBackendSupport.java   |   4 +-
 .../search/api/support/SearchResponseSupport.java  |   6 +-
 .../api/transport/Java11HttpClientTransport.java   |  12 +-
 .../search/backend/remoterepository/Context.java   |   8 +-
 .../backend/remoterepository/RecordFactory.java    |   6 +-
 .../extractor/MavenCentralResponseExtractor.java   |   2 +-
 .../extractor/Nx2ResponseExtractor.java            |   2 +-
 .../RemoteRepositorySearchBackendImpl.java         |  14 +--
 .../RemoteRepositorySearchResponseImpl.java        |   4 +-
 .../backend/smo/SmoSearchBackendFactory.java       |  47 ++++++-
 .../backend/smo/internal/SmoSearchBackendImpl.java |  68 ++++++----
 .../smo/internal/SmoSearchResponseImpl.java        |   4 +-
 .../smo/internal/CscSearchBackendImplTest.java}    |  22 ++--
 .../smo/internal/SmoSearchBackendImplTest.java     | 140 +--------------------
 ...lTest.java => SmoSearchBackendTestSupport.java} |  15 +--
 23 files changed, 161 insertions(+), 235 deletions(-)

diff --git a/indexer-examples/indexer-examples-spring/pom.xml 
b/indexer-examples/indexer-examples-spring/pom.xml
index ec80bf8..97cc893 100644
--- a/indexer-examples/indexer-examples-spring/pom.xml
+++ b/indexer-examples/indexer-examples-spring/pom.xml
@@ -33,7 +33,7 @@ under the License.
   <description>This module contains Maven Indexer usage examples for 
integration with Spring.</description>
 
   <properties>
-    <version.spring>5.3.31</version.spring>
+    <version.spring>5.3.39</version.spring>
   </properties>
 
   <dependencies>
diff --git a/search-api/src/main/java/org/apache/maven/search/api/Record.java 
b/search-api/src/main/java/org/apache/maven/search/api/Record.java
index 53856eb..16b2eef 100644
--- a/search-api/src/main/java/org/apache/maven/search/api/Record.java
+++ b/search-api/src/main/java/org/apache/maven/search/api/Record.java
@@ -29,16 +29,16 @@ import static java.util.Objects.requireNonNull;
 /**
  * A search response record.
  */
-public final class Record {
-    private final String backendId;
+public class Record {
+    protected final String backendId;
 
-    private final String repositoryId;
+    protected final String repositoryId;
 
-    private final String uid;
+    protected final String uid;
 
-    private final Long lastUpdated;
+    protected final Long lastUpdated;
 
-    private final Map<Field, Object> fields;
+    protected final Map<Field, Object> fields;
 
     public Record(String backendId, String repositoryId, String uid, Long 
lastUpdated, Map<Field, Object> fields) {
         this.backendId = requireNonNull(backendId);
diff --git 
a/search-api/src/main/java/org/apache/maven/search/api/SearchRequest.java 
b/search-api/src/main/java/org/apache/maven/search/api/SearchRequest.java
index 64f50da..5f93319 100644
--- a/search-api/src/main/java/org/apache/maven/search/api/SearchRequest.java
+++ b/search-api/src/main/java/org/apache/maven/search/api/SearchRequest.java
@@ -26,10 +26,10 @@ import static java.util.Objects.requireNonNull;
 /**
  * A search request to perform search: defines paging and query.
  */
-public final class SearchRequest {
-    private final Paging paging;
+public class SearchRequest {
+    protected final Paging paging;
 
-    private final Query query;
+    protected final Query query;
 
     /**
      * Creates a request with given {@link Query} instance and default page 
size of 50.
diff --git 
a/search-api/src/main/java/org/apache/maven/search/api/request/BooleanQuery.java
 
b/search-api/src/main/java/org/apache/maven/search/api/request/BooleanQuery.java
index eed6388..f2038e1 100644
--- 
a/search-api/src/main/java/org/apache/maven/search/api/request/BooleanQuery.java
+++ 
b/search-api/src/main/java/org/apache/maven/search/api/request/BooleanQuery.java
@@ -24,9 +24,9 @@ import static java.util.Objects.requireNonNull;
  * Boolean query.
  */
 public abstract class BooleanQuery extends Query {
-    private final Query left;
+    protected final Query left;
 
-    private final Query right;
+    protected final Query right;
 
     protected BooleanQuery(Query left, String op, Query right) {
         super(op);
@@ -53,8 +53,8 @@ public abstract class BooleanQuery extends Query {
         return getLeft() + " " + getValue() + " " + getRight();
     }
 
-    public static final class And extends BooleanQuery {
-        private And(Query left, Query right) {
+    public static class And extends BooleanQuery {
+        protected And(Query left, Query right) {
             super(left, "AND", right);
         }
     }
diff --git 
a/search-api/src/main/java/org/apache/maven/search/api/request/Field.java 
b/search-api/src/main/java/org/apache/maven/search/api/request/Field.java
index 35cf31c..fe47c75 100644
--- a/search-api/src/main/java/org/apache/maven/search/api/request/Field.java
+++ b/search-api/src/main/java/org/apache/maven/search/api/request/Field.java
@@ -28,9 +28,9 @@ import static java.util.Objects.requireNonNull;
  * Field, that is used as key in record.
  */
 public abstract class Field {
-    private final String fieldName;
+    protected final String fieldName;
 
-    private Field(String fieldName) {
+    protected Field(String fieldName) {
         this.fieldName = requireNonNull(fieldName);
     }
 
diff --git 
a/search-api/src/main/java/org/apache/maven/search/api/request/FieldQuery.java 
b/search-api/src/main/java/org/apache/maven/search/api/request/FieldQuery.java
index f108142..906edba 100644
--- 
a/search-api/src/main/java/org/apache/maven/search/api/request/FieldQuery.java
+++ 
b/search-api/src/main/java/org/apache/maven/search/api/request/FieldQuery.java
@@ -24,7 +24,7 @@ import static java.util.Objects.requireNonNull;
  * Field query.
  */
 public class FieldQuery extends Query {
-    private final Field field;
+    protected final Field field;
 
     protected FieldQuery(Field field, String queryString) {
         super(queryString);
diff --git 
a/search-api/src/main/java/org/apache/maven/search/api/request/Paging.java 
b/search-api/src/main/java/org/apache/maven/search/api/request/Paging.java
index 6a60de5..f8f611d 100644
--- a/search-api/src/main/java/org/apache/maven/search/api/request/Paging.java
+++ b/search-api/src/main/java/org/apache/maven/search/api/request/Paging.java
@@ -21,10 +21,10 @@ package org.apache.maven.search.api.request;
 /**
  * Paging.
  */
-public final class Paging {
-    private final int pageSize;
+public class Paging {
+    protected final int pageSize;
 
-    private final int pageOffset;
+    protected final int pageOffset;
 
     /**
      * Creates paging instance with given page size (must be greater than 0) 
and page offset (must be non-negative).
diff --git 
a/search-api/src/main/java/org/apache/maven/search/api/request/Query.java 
b/search-api/src/main/java/org/apache/maven/search/api/request/Query.java
index 1a0dcc2..b13e7aa 100644
--- a/search-api/src/main/java/org/apache/maven/search/api/request/Query.java
+++ b/search-api/src/main/java/org/apache/maven/search/api/request/Query.java
@@ -24,7 +24,7 @@ import static java.util.Objects.requireNonNull;
  * Query.
  */
 public class Query {
-    private final String queryString;
+    protected final String queryString;
 
     protected Query(String queryString) {
         this.queryString = requireNonNull(queryString);
diff --git 
a/search-api/src/main/java/org/apache/maven/search/api/support/SearchBackendSupport.java
 
b/search-api/src/main/java/org/apache/maven/search/api/support/SearchBackendSupport.java
index a306a8f..e2dddce 100644
--- 
a/search-api/src/main/java/org/apache/maven/search/api/support/SearchBackendSupport.java
+++ 
b/search-api/src/main/java/org/apache/maven/search/api/support/SearchBackendSupport.java
@@ -26,9 +26,9 @@ import static java.util.Objects.requireNonNull;
  * A search backend support class.
  */
 public abstract class SearchBackendSupport implements SearchBackend {
-    private final String backendId;
+    protected final String backendId;
 
-    private final String repositoryId;
+    protected final String repositoryId;
 
     protected SearchBackendSupport(String backendId, String repositoryId) {
         this.backendId = requireNonNull(backendId);
diff --git 
a/search-api/src/main/java/org/apache/maven/search/api/support/SearchResponseSupport.java
 
b/search-api/src/main/java/org/apache/maven/search/api/support/SearchResponseSupport.java
index 18317fb..0b30ecc 100644
--- 
a/search-api/src/main/java/org/apache/maven/search/api/support/SearchResponseSupport.java
+++ 
b/search-api/src/main/java/org/apache/maven/search/api/support/SearchResponseSupport.java
@@ -30,11 +30,11 @@ import static java.util.Objects.requireNonNull;
  * A search response support class.
  */
 public abstract class SearchResponseSupport implements SearchResponse {
-    private final SearchRequest searchRequest;
+    protected final SearchRequest searchRequest;
 
-    private final int totalHits;
+    protected final int totalHits;
 
-    private final List<Record> page;
+    protected final List<Record> page;
 
     protected SearchResponseSupport(SearchRequest searchRequest, int 
totalHits, List<Record> page) {
         this.searchRequest = requireNonNull(searchRequest);
diff --git 
a/search-api/src/main/java/org/apache/maven/search/api/transport/Java11HttpClientTransport.java
 
b/search-api/src/main/java/org/apache/maven/search/api/transport/Java11HttpClientTransport.java
index 01c47cd..610b47d 100644
--- 
a/search-api/src/main/java/org/apache/maven/search/api/transport/Java11HttpClientTransport.java
+++ 
b/search-api/src/main/java/org/apache/maven/search/api/transport/Java11HttpClientTransport.java
@@ -35,13 +35,13 @@ import static java.util.Objects.requireNonNull;
  * Java 11 {@link HttpClient} backed transport.
  */
 public class Java11HttpClientTransport implements Transport {
-    private static class ResponseImpl implements Response {
+    protected static class ResponseImpl implements Response {
 
-        private final HttpResponse<?> response;
+        protected final HttpResponse<?> response;
 
-        private final InputStream inputStream;
+        protected final InputStream inputStream;
 
-        private ResponseImpl(HttpResponse<?> response, InputStream 
inputStream) {
+        protected ResponseImpl(HttpResponse<?> response, InputStream 
inputStream) {
             this.response = requireNonNull(response);
             this.inputStream = inputStream;
         }
@@ -77,9 +77,9 @@ public class Java11HttpClientTransport implements Transport {
         }
     }
 
-    private final Duration timeout;
+    protected final Duration timeout;
 
-    private final HttpClient client;
+    protected final HttpClient client;
 
     public Java11HttpClientTransport() {
         this(Duration.ofSeconds(10L));
diff --git 
a/search-backend-remoterepository/src/main/java/org/apache/maven/search/backend/remoterepository/Context.java
 
b/search-backend-remoterepository/src/main/java/org/apache/maven/search/backend/remoterepository/Context.java
index 404f441..5f3a194 100644
--- 
a/search-backend-remoterepository/src/main/java/org/apache/maven/search/backend/remoterepository/Context.java
+++ 
b/search-backend-remoterepository/src/main/java/org/apache/maven/search/backend/remoterepository/Context.java
@@ -33,10 +33,10 @@ import static java.util.Objects.requireNonNull;
 /**
  * Class that "disassembles" the query and populates fields and values and 
exposes them.
  */
-public final class Context {
-    private final SearchRequest searchRequest;
+public class Context {
+    protected final SearchRequest searchRequest;
 
-    private final Map<Field, String> fields;
+    protected final Map<Field, String> fields;
 
     public Context(SearchRequest searchRequest) {
         this.searchRequest = requireNonNull(searchRequest);
@@ -44,7 +44,7 @@ public final class Context {
         populateFields(searchRequest.getQuery());
     }
 
-    private void populateFields(Query query) {
+    protected void populateFields(Query query) {
         if (query instanceof BooleanQuery) {
             populateFields(((BooleanQuery) query).getLeft());
             populateFields(((BooleanQuery) query).getRight());
diff --git 
a/search-backend-remoterepository/src/main/java/org/apache/maven/search/backend/remoterepository/RecordFactory.java
 
b/search-backend-remoterepository/src/main/java/org/apache/maven/search/backend/remoterepository/RecordFactory.java
index 106eb13..705d52d 100644
--- 
a/search-backend-remoterepository/src/main/java/org/apache/maven/search/backend/remoterepository/RecordFactory.java
+++ 
b/search-backend-remoterepository/src/main/java/org/apache/maven/search/backend/remoterepository/RecordFactory.java
@@ -30,9 +30,9 @@ import static java.util.Objects.requireNonNull;
 /**
  * Helper class that creates record instances for provided backend.
  */
-public final class RecordFactory {
+public class RecordFactory {
 
-    private final RemoteRepositorySearchBackend backend;
+    protected final RemoteRepositorySearchBackend backend;
 
     public RecordFactory(RemoteRepositorySearchBackend backend) {
         this.backend = requireNonNull(backend);
@@ -58,7 +58,7 @@ public final class RecordFactory {
         return new Record(backend.getBackendId(), backend.getRepositoryId(), 
null, lastUpdated, result);
     }
 
-    private static void mayPut(Map<Field, Object> result, Field fieldName, 
Object value) {
+    protected static void mayPut(Map<Field, Object> result, Field fieldName, 
Object value) {
         if (value == null) {
             return;
         }
diff --git 
a/search-backend-remoterepository/src/main/java/org/apache/maven/search/backend/remoterepository/extractor/MavenCentralResponseExtractor.java
 
b/search-backend-remoterepository/src/main/java/org/apache/maven/search/backend/remoterepository/extractor/MavenCentralResponseExtractor.java
index 0e39f39..4fed593 100644
--- 
a/search-backend-remoterepository/src/main/java/org/apache/maven/search/backend/remoterepository/extractor/MavenCentralResponseExtractor.java
+++ 
b/search-backend-remoterepository/src/main/java/org/apache/maven/search/backend/remoterepository/extractor/MavenCentralResponseExtractor.java
@@ -35,7 +35,7 @@ public class MavenCentralResponseExtractor extends 
ResponseExtractorSupport {
      * attribute contains name in relative form as {@code "name/"} (followed 
by slash), if name denotes
      * a directory. The trailing slash is removed by this method, if any.
      */
-    private String nameInHref(Element element) {
+    protected String nameInHref(Element element) {
         String name = element.attr("href");
         if (name.endsWith("/")) {
             name = name.substring(0, name.length() - 1);
diff --git 
a/search-backend-remoterepository/src/main/java/org/apache/maven/search/backend/remoterepository/extractor/Nx2ResponseExtractor.java
 
b/search-backend-remoterepository/src/main/java/org/apache/maven/search/backend/remoterepository/extractor/Nx2ResponseExtractor.java
index 9e5eeb5..752db12 100644
--- 
a/search-backend-remoterepository/src/main/java/org/apache/maven/search/backend/remoterepository/extractor/Nx2ResponseExtractor.java
+++ 
b/search-backend-remoterepository/src/main/java/org/apache/maven/search/backend/remoterepository/extractor/Nx2ResponseExtractor.java
@@ -35,7 +35,7 @@ public class Nx2ResponseExtractor extends 
ResponseExtractorSupport {
         return !"Parent Directory".equals(name) && super.accept(name);
     }
 
-    private String name(Element element) {
+    protected String name(Element element) {
         String name = element.text();
         if (name.endsWith("/")) {
             name = name.substring(0, name.length() - 1);
diff --git 
a/search-backend-remoterepository/src/main/java/org/apache/maven/search/backend/remoterepository/internal/RemoteRepositorySearchBackendImpl.java
 
b/search-backend-remoterepository/src/main/java/org/apache/maven/search/backend/remoterepository/internal/RemoteRepositorySearchBackendImpl.java
index 2938008..a1bbfe0 100644
--- 
a/search-backend-remoterepository/src/main/java/org/apache/maven/search/backend/remoterepository/internal/RemoteRepositorySearchBackendImpl.java
+++ 
b/search-backend-remoterepository/src/main/java/org/apache/maven/search/backend/remoterepository/internal/RemoteRepositorySearchBackendImpl.java
@@ -55,13 +55,13 @@ import static java.util.Objects.requireNonNull;
  * (HTML parsing) if needed.
  */
 public class RemoteRepositorySearchBackendImpl extends SearchBackendSupport 
implements RemoteRepositorySearchBackend {
-    private final String baseUri;
+    protected final String baseUri;
 
-    private final Transport transport;
+    protected final Transport transport;
 
-    private final ResponseExtractor responseExtractor;
+    protected final ResponseExtractor responseExtractor;
 
-    private final Map<String, String> commonHeaders;
+    protected final Map<String, String> commonHeaders;
 
     protected enum State {
         G,
@@ -91,7 +91,7 @@ public class RemoteRepositorySearchBackendImpl extends 
SearchBackendSupport impl
                         + transport.getClass().getSimpleName());
     }
 
-    private String discoverVersion() {
+    protected String discoverVersion() {
         Properties properties = new Properties();
         InputStream inputStream = getClass()
                 .getClassLoader()
@@ -214,11 +214,11 @@ public class RemoteRepositorySearchBackendImpl extends 
SearchBackendSupport impl
         return new RemoteRepositorySearchResponseImpl(searchRequest, 
totalHits, page, uri, document);
     }
 
-    private static final DateTimeFormatter RFC7231 = 
DateTimeFormatter.ofPattern(
+    protected static final DateTimeFormatter RFC7231 = 
DateTimeFormatter.ofPattern(
                     "EEE, dd MMM yyyy HH:mm:ss z", Locale.ENGLISH)
             .withZone(ZoneId.of("GMT"));
 
-    private static String readChecksum(InputStream inputStream) throws 
IOException {
+    protected static String readChecksum(InputStream inputStream) throws 
IOException {
         String checksum = "";
         try (BufferedReader br = new BufferedReader(new 
InputStreamReader(inputStream, StandardCharsets.UTF_8), 512)) {
             while (true) {
diff --git 
a/search-backend-remoterepository/src/main/java/org/apache/maven/search/backend/remoterepository/internal/RemoteRepositorySearchResponseImpl.java
 
b/search-backend-remoterepository/src/main/java/org/apache/maven/search/backend/remoterepository/internal/RemoteRepositorySearchResponseImpl.java
index 4970e5f..0835d25 100644
--- 
a/search-backend-remoterepository/src/main/java/org/apache/maven/search/backend/remoterepository/internal/RemoteRepositorySearchResponseImpl.java
+++ 
b/search-backend-remoterepository/src/main/java/org/apache/maven/search/backend/remoterepository/internal/RemoteRepositorySearchResponseImpl.java
@@ -31,8 +31,8 @@ import static java.util.Objects.requireNonNull;
 public class RemoteRepositorySearchResponseImpl extends SearchResponseSupport
         implements RemoteRepositorySearchResponse {
 
-    private final String uri;
-    private final Document document;
+    protected final String uri;
+    protected final Document document;
 
     public RemoteRepositorySearchResponseImpl(
             SearchRequest searchRequest, int totalHits, List<Record> page, 
String uri, Document document) {
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 dcb5679..f10a4e0 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
@@ -26,21 +26,62 @@ import 
org.apache.maven.search.backend.smo.internal.SmoSearchBackendImpl;
  * The SMO search backend factory.
  */
 public final class SmoSearchBackendFactory {
-    public static final String DEFAULT_BACKEND_ID = "central-smo";
+    public static final String SMO_BACKEND_ID = "central-smo";
 
-    public static final String DEFAULT_REPOSITORY_ID = "central";
+    public static final String SMO_REPOSITORY_ID = "central";
 
-    public static final String DEFAULT_SMO_URI = 
"https://search.maven.org/solrsearch/select";;
+    public static final String SMO_SMO_URI = 
"https://search.maven.org/solrsearch/select";;
+
+    public static final String CSC_BACKEND_ID = "central-csc";
+
+    public static final String CSC_REPOSITORY_ID = "central";
+
+    public static final String CSC_SMO_URI = 
"https://central.sonatype.com/solrsearch/select";;
+
+    /**
+     * @deprecated Use SMO_ or CSC_ instead.
+     */
+    @Deprecated
+    public static final String DEFAULT_BACKEND_ID = SMO_BACKEND_ID;
+
+    /**
+     * @deprecated Use SMO_ or CSC_ instead.
+     */
+    @Deprecated
+    public static final String DEFAULT_REPOSITORY_ID = SMO_REPOSITORY_ID;
+
+    /**
+     * @deprecated Use SMO_ or CSC_ instead.
+     */
+    @Deprecated
+    public static final String DEFAULT_SMO_URI = SMO_SMO_URI;
 
     private SmoSearchBackendFactory() {}
 
     /**
      * Creates "default" SMO search backend suitable for most use cases.
+     *
+     * @deprecated Use methods {@link #createSmo()} or {@link #createCsc()} 
instead.
      */
+    @Deprecated
     public static SmoSearchBackend createDefault() {
         return create(DEFAULT_BACKEND_ID, DEFAULT_REPOSITORY_ID, 
DEFAULT_SMO_URI, new Java11HttpClientTransport());
     }
 
+    /**
+     * Creates SMO backend.
+     */
+    public static SmoSearchBackend createSmo() {
+        return create(SMO_BACKEND_ID, SMO_REPOSITORY_ID, SMO_SMO_URI, new 
Java11HttpClientTransport());
+    }
+
+    /**
+     * Creates CSC backend.
+     */
+    public static SmoSearchBackend createCsc() {
+        return create(CSC_BACKEND_ID, CSC_REPOSITORY_ID, CSC_SMO_URI, new 
Java11HttpClientTransport());
+    }
+
     /**
      * Creates SMO search backend using provided parameters.
      */
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 6f8b8b1..8ccb61b 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
@@ -41,17 +41,17 @@ import org.apache.maven.search.api.SearchRequest;
 import org.apache.maven.search.api.request.BooleanQuery;
 import org.apache.maven.search.api.request.Field;
 import org.apache.maven.search.api.request.FieldQuery;
-import org.apache.maven.search.api.request.Paging;
 import org.apache.maven.search.api.request.Query;
 import org.apache.maven.search.api.support.SearchBackendSupport;
 import org.apache.maven.search.api.transport.Transport;
 import org.apache.maven.search.backend.smo.SmoSearchBackend;
+import org.apache.maven.search.backend.smo.SmoSearchBackendFactory;
 import org.apache.maven.search.backend.smo.SmoSearchResponse;
 
 import static java.util.Objects.requireNonNull;
 
 public class SmoSearchBackendImpl extends SearchBackendSupport implements 
SmoSearchBackend {
-    private static final Map<Field, String> FIELD_TRANSLATION;
+    protected static final Map<Field, String> FIELD_TRANSLATION;
 
     static {
         FIELD_TRANSLATION = Map.of(
@@ -73,11 +73,11 @@ public class SmoSearchBackendImpl extends 
SearchBackendSupport implements SmoSea
                 "1");
     }
 
-    private final String smoUri;
+    protected final String smoUri;
 
-    private final Transport transport;
+    protected final Transport transport;
 
-    private final Map<String, String> commonHeaders;
+    protected final Map<String, String> commonHeaders;
 
     /**
      * Creates a customized instance of SMO backend, like an in-house 
instances of SMO or different IDs.
@@ -95,7 +95,7 @@ public class SmoSearchBackendImpl extends 
SearchBackendSupport implements SmoSea
         this.commonHeaders.put("Accept", "application/json");
     }
 
-    private String discoverVersion() {
+    protected String discoverVersion() {
         Properties properties = new Properties();
         InputStream inputStream = getClass()
                 .getClassLoader()
@@ -125,20 +125,44 @@ public class SmoSearchBackendImpl extends 
SearchBackendSupport implements SmoSea
         return new SmoSearchResponseImpl(searchRequest, totalHits, page, 
searchUri, payload);
     }
 
-    private String toURI(SearchRequest searchRequest) {
-        Paging paging = searchRequest.getPaging();
+    protected String toURI(SearchRequest searchRequest) {
         HashSet<Field> searchedFields = new HashSet<>();
         String smoQuery = toSMOQuery(searchedFields, searchRequest.getQuery());
-        smoQuery += "&start=" + paging.getPageSize() * paging.getPageOffset();
-        smoQuery += "&rows=" + paging.getPageSize();
-        smoQuery += "&wt=json";
+        smoQuery += paging(searchRequest, searchedFields);
+        smoQuery += extra(searchRequest, searchedFields);
+        return smoUri + "?q=" + smoQuery;
+    }
+
+    protected String paging(SearchRequest searchRequest, HashSet<Field> 
searchedFields) {
+        if (SmoSearchBackendFactory.CSC_BACKEND_ID.equals(backendId)) {
+            return cscPaging(searchRequest, searchedFields);
+        } else {
+            return smoPaging(searchRequest, searchedFields);
+        }
+    }
+
+    protected String smoPaging(SearchRequest searchRequest, HashSet<Field> 
searchedFields) {
+        return "&start="
+                + searchRequest.getPaging().getPageSize()
+                        * searchRequest.getPaging().getPageOffset() + "&rows="
+                + searchRequest.getPaging().getPageSize();
+    }
+
+    protected String cscPaging(SearchRequest searchRequest, HashSet<Field> 
searchedFields) {
+        // this is a bug in CSC: it should work same as SMO but this is life
+        return "&start=" + searchRequest.getPaging().getPageOffset() + "&rows="
+                + searchRequest.getPaging().getPageSize();
+    }
+
+    protected String extra(SearchRequest searchRequest, HashSet<Field> 
searchedFields) {
+        String extra = "&wt=json";
         if (searchedFields.contains(MAVEN.GROUP_ID) && 
searchedFields.contains(MAVEN.ARTIFACT_ID)) {
-            smoQuery += "&core=gav";
+            extra += "&core=gav";
         }
-        return smoUri + "?q=" + smoQuery;
+        return extra;
     }
 
-    private String fetch(String serviceUri, Map<String, String> headers) 
throws IOException {
+    protected String fetch(String serviceUri, Map<String, String> headers) 
throws IOException {
         try (Transport.Response response = transport.get(serviceUri, headers)) 
{
             if (response.getCode() == HttpURLConnection.HTTP_OK) {
                 return new String(response.getBody().readAllBytes(), 
StandardCharsets.UTF_8);
@@ -148,7 +172,7 @@ public class SmoSearchBackendImpl extends 
SearchBackendSupport implements SmoSea
         }
     }
 
-    private String toSMOQuery(HashSet<Field> searchedFields, Query query) {
+    protected String toSMOQuery(HashSet<Field> searchedFields, Query query) {
         if (query instanceof BooleanQuery.And) {
             BooleanQuery bq = (BooleanQuery) query;
             return toSMOQuery(searchedFields, bq.getLeft()) + "%20AND%20" + 
toSMOQuery(searchedFields, bq.getRight());
@@ -165,11 +189,11 @@ public class SmoSearchBackendImpl extends 
SearchBackendSupport implements SmoSea
         return encodeQueryParameterValue(query.getValue());
     }
 
-    private String encodeQueryParameterValue(String parameterValue) {
+    protected String encodeQueryParameterValue(String parameterValue) {
         return URLEncoder.encode(parameterValue, 
StandardCharsets.UTF_8).replace("+", "%20");
     }
 
-    private int populateFromRaw(JsonObject raw, List<Record> page) {
+    protected int populateFromRaw(JsonObject raw, List<Record> page) {
         JsonObject response = raw.getAsJsonObject("response");
         Number numFound = response.get("numFound").getAsNumber();
 
@@ -180,7 +204,7 @@ public class SmoSearchBackendImpl extends 
SearchBackendSupport implements SmoSea
         return numFound.intValue();
     }
 
-    private Record convert(JsonObject doc) {
+    protected Record convert(JsonObject doc) {
         HashMap<Field, Object> result = new HashMap<>();
 
         mayPut(result, MAVEN.GROUP_ID, mayGet("g", doc));
@@ -214,15 +238,15 @@ public class SmoSearchBackendImpl extends 
SearchBackendSupport implements SmoSea
                 result);
     }
 
-    private static final JsonPrimitive EC_SOURCE_JAR = new 
JsonPrimitive("-sources.jar");
+    protected static final JsonPrimitive EC_SOURCE_JAR = new 
JsonPrimitive("-sources.jar");
 
-    private static final JsonPrimitive EC_JAVADOC_JAR = new 
JsonPrimitive("-javadoc.jar");
+    protected static final JsonPrimitive EC_JAVADOC_JAR = new 
JsonPrimitive("-javadoc.jar");
 
-    private static String mayGet(String field, JsonObject object) {
+    protected static String mayGet(String field, JsonObject object) {
         return object.has(field) ? object.get(field).getAsString() : null;
     }
 
-    private static void mayPut(Map<Field, Object> result, Field fieldName, 
Object value) {
+    protected static void mayPut(Map<Field, Object> result, Field fieldName, 
Object value) {
         if (value == null) {
             return;
         }
diff --git 
a/search-backend-smo/src/main/java/org/apache/maven/search/backend/smo/internal/SmoSearchResponseImpl.java
 
b/search-backend-smo/src/main/java/org/apache/maven/search/backend/smo/internal/SmoSearchResponseImpl.java
index f5cab8d..3e8cb3b 100644
--- 
a/search-backend-smo/src/main/java/org/apache/maven/search/backend/smo/internal/SmoSearchResponseImpl.java
+++ 
b/search-backend-smo/src/main/java/org/apache/maven/search/backend/smo/internal/SmoSearchResponseImpl.java
@@ -28,9 +28,9 @@ import org.apache.maven.search.backend.smo.SmoSearchResponse;
 import static java.util.Objects.requireNonNull;
 
 public class SmoSearchResponseImpl extends SearchResponseSupport implements 
SmoSearchResponse {
-    private final String searchUri;
+    protected final String searchUri;
 
-    private final String rawJsonResponse;
+    protected final String rawJsonResponse;
 
     public SmoSearchResponseImpl(
             SearchRequest searchRequest, int totalHits, List<Record> page, 
String searchUri, String rawJsonResponse) {
diff --git 
a/search-backend-smo/src/main/java/org/apache/maven/search/backend/smo/SmoSearchTransport.java
 
b/search-backend-smo/src/test/java/org/apache/maven/search/backend/smo/internal/CscSearchBackendImplTest.java
similarity index 51%
rename from 
search-backend-smo/src/main/java/org/apache/maven/search/backend/smo/SmoSearchTransport.java
rename to 
search-backend-smo/src/test/java/org/apache/maven/search/backend/smo/internal/CscSearchBackendImplTest.java
index 685ede7..e4f2070 100644
--- 
a/search-backend-smo/src/main/java/org/apache/maven/search/backend/smo/SmoSearchTransport.java
+++ 
b/search-backend-smo/src/test/java/org/apache/maven/search/backend/smo/internal/CscSearchBackendImplTest.java
@@ -16,20 +16,14 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.maven.search.backend.smo;
+package org.apache.maven.search.backend.smo.internal;
 
-import java.io.IOException;
-import java.util.Map;
+import org.apache.maven.search.backend.smo.SmoSearchBackendFactory;
+import org.junit.Ignore;
 
-/**
- * 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;
+@Ignore("This is not a test, is more a showcase")
+public class CscSearchBackendImplTest extends SmoSearchBackendTestSupport {
+    public CscSearchBackendImplTest() {
+        super(SmoSearchBackendFactory.createCsc());
+    }
 }
diff --git 
a/search-backend-smo/src/test/java/org/apache/maven/search/backend/smo/internal/SmoSearchBackendImplTest.java
 
b/search-backend-smo/src/test/java/org/apache/maven/search/backend/smo/internal/SmoSearchBackendImplTest.java
index 20649c5..1116cc2 100644
--- 
a/search-backend-smo/src/test/java/org/apache/maven/search/backend/smo/internal/SmoSearchBackendImplTest.java
+++ 
b/search-backend-smo/src/test/java/org/apache/maven/search/backend/smo/internal/SmoSearchBackendImplTest.java
@@ -18,146 +18,12 @@
  */
 package org.apache.maven.search.backend.smo.internal;
 
-import java.io.IOException;
-import java.time.Instant;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.concurrent.atomic.AtomicInteger;
-
-import org.apache.maven.search.api.MAVEN;
-import org.apache.maven.search.api.Record;
-import org.apache.maven.search.api.SearchRequest;
-import org.apache.maven.search.api.request.BooleanQuery;
-import org.apache.maven.search.api.request.FieldQuery;
-import org.apache.maven.search.api.request.Query;
-import org.apache.maven.search.backend.smo.SmoSearchBackend;
 import org.apache.maven.search.backend.smo.SmoSearchBackendFactory;
-import org.apache.maven.search.backend.smo.SmoSearchResponse;
 import org.junit.Ignore;
-import org.junit.Test;
 
 @Ignore("This is not a test, is more a showcase")
-public class SmoSearchBackendImplTest {
-    private final SmoSearchBackend backend = 
SmoSearchBackendFactory.createDefault();
-
-    private void dumpSingle(AtomicInteger counter, List<Record> page) {
-        for (Record record : page) {
-            StringBuilder sb = new StringBuilder();
-            sb.append(record.getValue(MAVEN.GROUP_ID))
-                    .append(":")
-                    .append(record.getValue(MAVEN.ARTIFACT_ID))
-                    .append(":")
-                    .append(record.getValue(MAVEN.VERSION));
-            if (record.hasField(MAVEN.PACKAGING)) {
-                if (record.hasField(MAVEN.CLASSIFIER)) {
-                    sb.append(":").append(record.getValue(MAVEN.CLASSIFIER));
-                }
-                sb.append(":").append(record.getValue(MAVEN.PACKAGING));
-            }
-
-            List<String> remarks = new ArrayList<>();
-            if (record.getLastUpdated() != null) {
-                remarks.add("lastUpdate=" + 
Instant.ofEpochMilli(record.getLastUpdated()));
-            }
-            if (record.hasField(MAVEN.VERSION_COUNT)) {
-                remarks.add("versionCount=" + 
record.getValue(MAVEN.VERSION_COUNT));
-            }
-            if (record.hasField(MAVEN.HAS_SOURCE)) {
-                remarks.add("hasSource=" + record.getValue(MAVEN.HAS_SOURCE));
-            }
-            if (record.hasField(MAVEN.HAS_JAVADOC)) {
-                remarks.add("hasJavadoc=" + 
record.getValue(MAVEN.HAS_JAVADOC));
-            }
-
-            System.out.print(counter.incrementAndGet() + ". " + sb);
-            if (!remarks.isEmpty()) {
-                System.out.print(" " + remarks);
-            }
-            System.out.println();
-        }
-    }
-
-    private void dumpPage(SmoSearchResponse searchResponse) throws IOException 
{
-        AtomicInteger counter = new AtomicInteger(0);
-        System.out.println(
-                "QUERY: " + 
searchResponse.getSearchRequest().getQuery().toString());
-        System.out.println("URL: " + searchResponse.getSearchUri());
-        dumpSingle(counter, searchResponse.getPage());
-        while (searchResponse.getTotalHits() > 
searchResponse.getCurrentHits()) {
-            System.out.println("NEXT PAGE (size "
-                    + 
searchResponse.getSearchRequest().getPaging().getPageSize() + ")");
-            searchResponse = 
backend.search(searchResponse.getSearchRequest().nextPage());
-            dumpSingle(counter, searchResponse.getPage());
-            if (counter.get() > 50) {
-                System.out.println("ABORTED TO NOT SPAM");
-                break; // do not spam the SMO service
-            }
-        }
-        System.out.println();
-    }
-
-    @Test
-    public void smoke() throws IOException {
-        SearchRequest searchRequest = new SearchRequest(Query.query("smoke"));
-        SmoSearchResponse searchResponse = backend.search(searchRequest);
-        System.out.println("TOTAL HITS: " + searchResponse.getTotalHits());
-        dumpPage(searchResponse);
-    }
-
-    @Test
-    public void g() throws IOException {
-        SearchRequest searchRequest =
-                new SearchRequest(FieldQuery.fieldQuery(MAVEN.GROUP_ID, 
"org.apache.maven.plugins"));
-        SmoSearchResponse searchResponse = backend.search(searchRequest);
-        System.out.println("TOTAL HITS: " + searchResponse.getTotalHits());
-        dumpPage(searchResponse);
-    }
-
-    @Test
-    public void ga() throws IOException {
-        SearchRequest searchRequest = new SearchRequest(BooleanQuery.and(
-                FieldQuery.fieldQuery(MAVEN.GROUP_ID, 
"org.apache.maven.plugins"),
-                FieldQuery.fieldQuery(MAVEN.ARTIFACT_ID, 
"maven-clean-plugin")));
-        SmoSearchResponse searchResponse = backend.search(searchRequest);
-        System.out.println("TOTAL HITS: " + searchResponse.getTotalHits());
-        dumpPage(searchResponse);
-    }
-
-    @Test
-    public void gav() throws IOException {
-        SearchRequest searchRequest = new SearchRequest(BooleanQuery.and(
-                FieldQuery.fieldQuery(MAVEN.GROUP_ID, 
"org.apache.maven.plugins"),
-                FieldQuery.fieldQuery(MAVEN.ARTIFACT_ID, "maven-clean-plugin"),
-                FieldQuery.fieldQuery(MAVEN.VERSION, "3.1.0")));
-        SmoSearchResponse searchResponse = backend.search(searchRequest);
-        System.out.println("TOTAL HITS: " + searchResponse.getTotalHits());
-        dumpPage(searchResponse);
-    }
-
-    @Test
-    public void sha1() throws IOException {
-        SearchRequest searchRequest =
-                new SearchRequest(FieldQuery.fieldQuery(MAVEN.SHA1, 
"8ac9e16d933b6fb43bc7f576336b8f4d7eb5ba12"));
-        SmoSearchResponse searchResponse = backend.search(searchRequest);
-        System.out.println("TOTAL HITS: " + searchResponse.getTotalHits());
-        dumpPage(searchResponse);
-    }
-
-    @Test
-    public void cn() throws IOException {
-        SearchRequest searchRequest =
-                new SearchRequest(FieldQuery.fieldQuery(MAVEN.CLASS_NAME, 
"MavenRepositorySystem"));
-        SmoSearchResponse searchResponse = backend.search(searchRequest);
-        System.out.println("TOTAL HITS: " + searchResponse.getTotalHits());
-        dumpPage(searchResponse);
-    }
-
-    @Test
-    public void fqcn() throws IOException {
-        SearchRequest searchRequest = new SearchRequest(
-                FieldQuery.fieldQuery(MAVEN.FQ_CLASS_NAME, 
"org.apache.maven.bridge.MavenRepositorySystem"));
-        SmoSearchResponse searchResponse = backend.search(searchRequest);
-        System.out.println("TOTAL HITS: " + searchResponse.getTotalHits());
-        dumpPage(searchResponse);
+public class SmoSearchBackendImplTest extends SmoSearchBackendTestSupport {
+    public SmoSearchBackendImplTest() {
+        super(SmoSearchBackendFactory.createSmo());
     }
 }
diff --git 
a/search-backend-smo/src/test/java/org/apache/maven/search/backend/smo/internal/SmoSearchBackendImplTest.java
 
b/search-backend-smo/src/test/java/org/apache/maven/search/backend/smo/internal/SmoSearchBackendTestSupport.java
similarity index 94%
copy from 
search-backend-smo/src/test/java/org/apache/maven/search/backend/smo/internal/SmoSearchBackendImplTest.java
copy to 
search-backend-smo/src/test/java/org/apache/maven/search/backend/smo/internal/SmoSearchBackendTestSupport.java
index 20649c5..c192b18 100644
--- 
a/search-backend-smo/src/test/java/org/apache/maven/search/backend/smo/internal/SmoSearchBackendImplTest.java
+++ 
b/search-backend-smo/src/test/java/org/apache/maven/search/backend/smo/internal/SmoSearchBackendTestSupport.java
@@ -31,16 +31,17 @@ import org.apache.maven.search.api.request.BooleanQuery;
 import org.apache.maven.search.api.request.FieldQuery;
 import org.apache.maven.search.api.request.Query;
 import org.apache.maven.search.backend.smo.SmoSearchBackend;
-import org.apache.maven.search.backend.smo.SmoSearchBackendFactory;
 import org.apache.maven.search.backend.smo.SmoSearchResponse;
-import org.junit.Ignore;
 import org.junit.Test;
 
-@Ignore("This is not a test, is more a showcase")
-public class SmoSearchBackendImplTest {
-    private final SmoSearchBackend backend = 
SmoSearchBackendFactory.createDefault();
+public abstract class SmoSearchBackendTestSupport {
+    protected final SmoSearchBackend backend;
 
-    private void dumpSingle(AtomicInteger counter, List<Record> page) {
+    public SmoSearchBackendTestSupport(SmoSearchBackend backend) {
+        this.backend = backend;
+    }
+
+    protected void dumpSingle(AtomicInteger counter, List<Record> page) {
         for (Record record : page) {
             StringBuilder sb = new StringBuilder();
             sb.append(record.getValue(MAVEN.GROUP_ID))
@@ -77,7 +78,7 @@ public class SmoSearchBackendImplTest {
         }
     }
 
-    private void dumpPage(SmoSearchResponse searchResponse) throws IOException 
{
+    protected void dumpPage(SmoSearchResponse searchResponse) throws 
IOException {
         AtomicInteger counter = new AtomicInteger(0);
         System.out.println(
                 "QUERY: " + 
searchResponse.getSearchRequest().getQuery().toString());


Reply via email to