Implemented searching option using a network endpoint.

Change-Id: I1a35d482f0df49fc1acaef9aca027eb2fa551401
diff --git a/lite/Changes b/lite/Changes
index d9554fa..9460dd9 100644
--- a/lite/Changes
+++ b/lite/Changes
@@ -1,5 +1,9 @@
 # version 0.68
 
+2022-06-03 
+ - Implemented searching option using a network endpoint
+
+
 # version 0.67
 
 # version 0.66
diff --git a/lite/src/main/resources/lite-config.xml b/lite/src/main/resources/lite-config.xml
index 3e7aacd..a914f95 100644
--- a/lite/src/main/resources/lite-config.xml
+++ b/lite/src/main/resources/lite-config.xml
@@ -137,10 +137,12 @@
 	<bean id="annotationParser" class="de.ids_mannheim.korap.annotation.AnnotationParser"
 		scope="singleton" />
 
-	<!-- Krill -->
+	<!-- Search Engine -->
 	<bean id="search_krill" class="de.ids_mannheim.korap.web.SearchKrill">
 		<constructor-arg value="${krill.indexDir}" />
 	</bean>
+	<bean id="search_network" class="de.ids_mannheim.korap.web.SearchNetworkEndpoint"/>
+	
 
 	<!-- Filters -->
 	<!-- <bean id="APIVersionFilter" class="de.ids_mannheim.korap.web.APIVersionFilter"
diff --git a/lite/src/test/java/de/ids_mannheim/korap/web/service/LiteSearchPipeTest.java b/lite/src/test/java/de/ids_mannheim/korap/web/service/LiteSearchPipeTest.java
index 38e5f21..ac69a61 100644
--- a/lite/src/test/java/de/ids_mannheim/korap/web/service/LiteSearchPipeTest.java
+++ b/lite/src/test/java/de/ids_mannheim/korap/web/service/LiteSearchPipeTest.java
@@ -37,8 +37,9 @@
     private ClientAndServer mockServer;
     private MockServerClient mockClient;
 
+    private int port = 6070;
     private String pipeJson, pipeWithParamJson;
-    private String glemmUri = "http://localhost:1080/glemm";
+    private String glemmUri = "http://localhost:"+port+"/glemm";
 
     public LiteSearchPipeTest () throws IOException{
         pipeJson = IOUtils.toString(
@@ -54,7 +55,7 @@
 
     @Before
     public void startMockServer () {
-        mockServer = startClientAndServer(1080);
+        mockServer = startClientAndServer(port);
         mockClient = new MockServerClient("localhost", mockServer.getPort());
     }
 
@@ -74,7 +75,7 @@
                                 "application/json; charset=utf-8"))
                         .withBody("{test}").withStatusCode(200));
 
-        URL url = new URL("http://localhost:1080/test");
+        URL url = new URL("http://localhost:"+port+"/test");
         HttpURLConnection connection = (HttpURLConnection) url.openConnection();
         connection.setRequestMethod("POST");
         connection.setRequestProperty("Content-Type",
@@ -226,7 +227,7 @@
                 .when(request().withMethod("POST").withPath("/non-json-pipe"))
                 .respond(response().withStatusCode(415));
 
-        String pipeUri = "http://localhost:1080/non-json-pipe";
+        String pipeUri = "http://localhost:"+port+"/non-json-pipe";
 
         ClientResponse response = resource().path(API_VERSION).path("search")
                 .queryParam("q", "[orth=der]").queryParam("ql", "poliqarp")
@@ -280,7 +281,7 @@
                         .withHeaders(new Header("Content-Type",
                                 "application/json; charset=utf-8")));
 
-        String pipeUri = "http://localhost:1080/invalid-response";
+        String pipeUri = "http://localhost:"+port+"/invalid-response";
         ClientResponse response = resource().path(API_VERSION).path("search")
                 .queryParam("q", "[orth=der]").queryParam("ql", "poliqarp")
                 .queryParam("pipes", pipeUri).get(ClientResponse.class);
@@ -304,7 +305,7 @@
                                 new Header("Accept", "application/json")))
                 .respond(response().withBody("blah").withStatusCode(200));
 
-        String pipeUri = "http://localhost:1080/plain-text";
+        String pipeUri = "http://localhost:"+port+"/plain-text";
         ClientResponse response = resource().path(API_VERSION).path("search")
                 .queryParam("q", "[orth=der]").queryParam("ql", "poliqarp")
                 .queryParam("pipes", pipeUri).get(ClientResponse.class);
diff --git a/lite/src/test/java/de/ids_mannheim/korap/web/service/SearchNetworkEndpointTest.java b/lite/src/test/java/de/ids_mannheim/korap/web/service/SearchNetworkEndpointTest.java
new file mode 100644
index 0000000..c00084d
--- /dev/null
+++ b/lite/src/test/java/de/ids_mannheim/korap/web/service/SearchNetworkEndpointTest.java
@@ -0,0 +1,123 @@
+package de.ids_mannheim.korap.web.service;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockserver.integration.ClientAndServer.startClientAndServer;
+import static org.mockserver.model.HttpRequest.request;
+import static org.mockserver.model.HttpResponse.response;
+
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.nio.charset.StandardCharsets;
+
+import org.apache.commons.io.IOUtils;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.mockserver.client.MockServerClient;
+import org.mockserver.integration.ClientAndServer;
+import org.mockserver.model.Header;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.sun.jersey.api.client.ClientResponse;
+
+import de.ids_mannheim.korap.config.KustvaktConfiguration;
+import de.ids_mannheim.korap.config.LiteJerseyTest;
+import de.ids_mannheim.korap.exceptions.KustvaktException;
+import de.ids_mannheim.korap.exceptions.StatusCodes;
+import de.ids_mannheim.korap.utils.JsonUtils;
+
+public class SearchNetworkEndpointTest extends LiteJerseyTest {
+
+    @Autowired
+    private KustvaktConfiguration config;
+
+    private ClientAndServer mockServer;
+    private MockServerClient mockClient;
+
+    private int port = 6080;
+    private String searchResult;
+    private String endpointURL = "http://localhost:"+port+"/searchEndpoint";
+
+    public SearchNetworkEndpointTest () throws IOException {
+        searchResult = IOUtils.toString(
+                ClassLoader.getSystemResourceAsStream(
+                        "network-output/search-result.jsonld"),
+                StandardCharsets.UTF_8);
+    }
+
+
+    @Before
+    public void startMockServer () {
+        mockServer = startClientAndServer(port);
+        mockClient = new MockServerClient("localhost", mockServer.getPort());
+    }
+
+
+    @After
+    public void stopMockServer () {
+        mockServer.stop();
+    }
+
+
+    @Test
+    public void testSearchNetwork ()
+            throws IOException, KustvaktException, URISyntaxException {
+        config.setNetworkEndpointURL(endpointURL);
+        mockClient.reset()
+                .when(request().withMethod("POST").withPath("/searchEndpoint")
+                        .withHeaders(
+                                new Header("Content-Type",
+                                        "application/json; charset=utf-8"),
+                                new Header("Accept", "application/json")))
+                .respond(response()
+                        .withHeader(new Header("Content-Type",
+                                "application/json; charset=utf-8"))
+                        .withBody(searchResult).withStatusCode(200));
+
+        ClientResponse response = resource().path(API_VERSION).path("search")
+                .queryParam("q", "[orth=der]").queryParam("ql", "poliqarp")
+                .queryParam("engine", "network").get(ClientResponse.class);
+
+        assertEquals(ClientResponse.Status.OK.getStatusCode(),
+                response.getStatus());
+
+        String entity = response.getEntity(String.class);
+        JsonNode node = JsonUtils.readTree(entity);
+
+        assertEquals(2, node.at("/matches").size());
+    }
+
+
+    @Test
+    public void testSearchWithUnknownURL ()
+            throws IOException, KustvaktException {
+        config.setNetworkEndpointURL("http://localhost:1040/search");
+        ClientResponse response = resource().path(API_VERSION).path("search")
+                .queryParam("q", "[orth=der]").queryParam("ql", "poliqarp")
+                .queryParam("engine", "network").get(ClientResponse.class);
+        
+        String entity = response.getEntity(String.class);
+        JsonNode node = JsonUtils.readTree(entity);
+        assertEquals(StatusCodes.SEARCH_NETWORK_ENDPOINT_FAILED,
+                node.at("/errors/0/0").asInt());
+        assertEquals(ClientResponse.Status.BAD_REQUEST.getStatusCode(),
+                response.getStatus());
+    }
+    
+    @Test
+    public void testSearchWithUnknownHost () throws KustvaktException {
+        config.setNetworkEndpointURL("http://search.com");
+        
+        ClientResponse response = resource().path(API_VERSION).path("search")
+                .queryParam("q", "[orth=der]").queryParam("ql", "poliqarp")
+                .queryParam("engine", "network").get(ClientResponse.class);
+
+        String entity = response.getEntity(String.class);
+        JsonNode node = JsonUtils.readTree(entity);
+        assertEquals(StatusCodes.SEARCH_NETWORK_ENDPOINT_FAILED,
+                node.at("/errors/0/0").asInt());
+        assertEquals(ClientResponse.Status.BAD_REQUEST.getStatusCode(),
+                response.getStatus());
+    }
+}
diff --git a/lite/src/test/resources/test-config.xml b/lite/src/test/resources/test-config.xml
index 6eec95f..b3f508e 100644
--- a/lite/src/test/resources/test-config.xml
+++ b/lite/src/test/resources/test-config.xml
@@ -128,10 +128,12 @@
 		<property name="dataSource" ref="sqliteDataSource" />
 	</bean>
 
-	<!-- Krill -->
+	<!-- Search Engine -->
 	<bean id="search_krill" class="de.ids_mannheim.korap.web.SearchKrill">
 		<constructor-arg value="${krill.indexDir}" />
 	</bean>
+	<bean id="search_network" class="de.ids_mannheim.korap.web.SearchNetworkEndpoint"/>
+	
 
 	<!-- Filters -->
 	<!-- <bean id="APIVersionFilter" class="de.ids_mannheim.korap.web.APIVersionFilter"