Added statistics tests and handled errors from a KoralQuery processor.

Change-Id: I859655d13c40d75550406b43c56420b571d8488c
diff --git a/src/main/java/de/ids_mannheim/korap/exceptions/StatusCodes.java b/src/main/java/de/ids_mannheim/korap/exceptions/StatusCodes.java
index b30a915..e611f4e 100644
--- a/src/main/java/de/ids_mannheim/korap/exceptions/StatusCodes.java
+++ b/src/main/java/de/ids_mannheim/korap/exceptions/StatusCodes.java
@@ -31,6 +31,7 @@
      */
 
     public static final int NO_QUERY = 301;
+    public static final int SERIALIZATION_FAILED = 302;
 
 
     /**
@@ -40,7 +41,7 @@
     // fixme: use unsupported resource and include type in return message
     public static final int POLICY_ERROR_DEFAULT = 400;
     public static final int UNSUPPORTED_RESOURCE = 402;
-    public static final int FAILED_REWRITE = 403;
+    public static final int REWRITE_FAILED = 403;
     //public static final int UNSUPPORTED_FOUNDRY = 403;
     //public static final int UNSUPPORTED_CORPUS = 404;
     //public static final int UNSUPPORTED_LAYER = 405;
diff --git a/src/main/java/de/ids_mannheim/korap/utils/KoralCollectionQueryBuilder.java b/src/main/java/de/ids_mannheim/korap/utils/KoralCollectionQueryBuilder.java
index 811c227..d2671be 100644
--- a/src/main/java/de/ids_mannheim/korap/utils/KoralCollectionQueryBuilder.java
+++ b/src/main/java/de/ids_mannheim/korap/utils/KoralCollectionQueryBuilder.java
@@ -1,19 +1,22 @@
 package de.ids_mannheim.korap.utils;
 
+import java.util.List;
+
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.node.ArrayNode;
 import com.fasterxml.jackson.databind.node.ObjectNode;
-import de.ids_mannheim.korap.query.serialize.CollectionQueryProcessor;
-import edu.emory.mathcs.backport.java.util.Arrays;
 
-import java.io.IOError;
-import java.util.Map;
+import de.ids_mannheim.korap.exceptions.StatusCodes;
+import de.ids_mannheim.korap.query.serialize.CollectionQueryProcessor;
+import de.ids_mannheim.korap.response.Notifications;
+import de.ids_mannheim.korap.web.utils.KustvaktResponseHandler;
+import edu.emory.mathcs.backport.java.util.Arrays;
 
 /**
  * convenience builder class for collection query
  * 
- * @author hanl
- * @date 16/09/2014
+ * @author hanl, margaretha
+ * @date 29/06/2017
  */
 public class KoralCollectionQueryBuilder {
 
@@ -98,7 +101,7 @@
     }
 
 
-    public Object rebaseCollection () {
+    public Object rebaseCollection (){
         if (this.builder.length() == 0 && this.base == null)
             return null;
 
@@ -107,6 +110,21 @@
             CollectionQueryProcessor tree = new CollectionQueryProcessor(
                     this.verbose);
             tree.process(this.builder.toString());
+            if (tree.getErrors().size() > 0){
+                Notifications notif = new Notifications();
+                int code; 
+                for (List<Object> e : tree.getErrors()){
+                    code = (int) e.get(0);
+                    if (e.get(1) instanceof String){
+                        notif.addError(code, (String) e.get(1));
+                    }
+                    else{
+                        notif.addError(code, (String[]) e.get(1));
+                    }
+                }
+                
+                throw KustvaktResponseHandler.throwit(StatusCodes.SERIALIZATION_FAILED,notif.toJsonString());
+            }
             request = JsonUtils.valueToTree(tree.getRequestMap());
         }
 
diff --git a/src/main/java/de/ids_mannheim/korap/web/service/full/ResourceService.java b/src/main/java/de/ids_mannheim/korap/web/service/full/ResourceService.java
index 9b559fb..8d35f95 100644
--- a/src/main/java/de/ids_mannheim/korap/web/service/full/ResourceService.java
+++ b/src/main/java/de/ids_mannheim/korap/web/service/full/ResourceService.java
@@ -753,24 +753,34 @@
         }
     }
 
-
-    @POST
-    @Path("stats")
-    public Response getStats (@Context SecurityContext context,
-            @Context Locale locale, String json) {
+    // EM: changed method POST to GET
+    @GET
+    @Path("statistics")
+    public Response getStatistics (@Context SecurityContext context,
+            @Context Locale locale, @QueryParam("collectionQuery") 
+            String collectionQuery) {
+        
+        if (collectionQuery == null || collectionQuery.isEmpty()){
+         throw KustvaktResponseHandler.throwit(new KustvaktException(
+                 StatusCodes.MISSING_ARGUMENT, "Parameter collectionQuery is missing.", 
+                 "collectionQuery"));
+        }
+        
+        
         KoralCollectionQueryBuilder builder = new KoralCollectionQueryBuilder();
-        builder.with(json);
-        String stats = searchKrill.getStatistics(builder.toJSON());
-
+        builder.with(collectionQuery);
+        String json = builder.toJSON();
+        
+        String stats = searchKrill.getStatistics(json);
         if (stats.contains("-1"))
             throw KustvaktResponseHandler.throwit(StatusCodes.NO_VALUE_FOUND);
-
+        jlog.debug("Stats: "+stats);
         return Response.ok(stats).build();
     }
 
-
+    // EM: what is child?
     @GET
-    @Path("{type}/{id}/{child}/stats")
+    @Path("{type}/{id}/{child}/statistics")
     public Response getStatisticsbyIdChild (@Context SecurityContext context,
             @Context Locale locale, @PathParam("type") String type,
             @PathParam("id") String id, @PathParam("child") String child) {
@@ -983,32 +993,32 @@
             KoralCollectionQueryBuilder cquery = new KoralCollectionQueryBuilder();
             cquery.setBaseQuery(base);
 
-            cachetmp = ResourceFactory.getCachedCollection(cquery.toJSON());
+            try {
+                cachetmp = ResourceFactory.getCachedCollection(cquery.toJSON());
 
-            // see if collection was cached!
-            VirtualCollection tmp = resourceHandler.getCache(cachetmp.getId(),
-                    VirtualCollection.class);
-            // if not cached, fill with stats values
-            if (tmp == null) {
-                String stats = searchKrill.getStatistics(cquery.toJSON());
-                cachetmp.setStats(JsonUtils.readSimple(stats, Map.class));
-            }
-
-            if (!cache) {
-                collection = ResourceFactory.getPermanentCollection(cachetmp,
-                        name, description);
-                vals = collection.toMap();
-                try {
-                    resourceHandler.storeResources(user, collection);
+                // see if collection was cached!
+                VirtualCollection tmp = resourceHandler.getCache(cachetmp.getId(),
+                        VirtualCollection.class);
+                // if not cached, fill with stats values
+                if (tmp == null) {
+                    String stats = searchKrill.getStatistics(cquery.toJSON());
+                    cachetmp.setStats(JsonUtils.readSimple(stats, Map.class));
                 }
-                catch (KustvaktException e) {
-                    jlog.error("Exception encountered: {}", e.string());
-                    throw KustvaktResponseHandler.throwit(e);
+            
+                if (!cache) {
+                    collection = ResourceFactory.getPermanentCollection(cachetmp,
+                            name, description);
+                    vals = collection.toMap();
+                        resourceHandler.storeResources(user, collection);
                 }
+                else {
+                    resourceHandler.cache(cachetmp);
+                    vals = cachetmp.toMap();
+                }
+            
             }
-            else {
-                resourceHandler.cache(cachetmp);
-                vals = cachetmp.toMap();
+            catch (KustvaktException e) {
+                throw KustvaktResponseHandler.throwit(e);
             }
         }
         return Response.ok(JsonUtils.toJSON(vals)).build();
diff --git a/src/main/java/de/ids_mannheim/korap/web/service/light/LightService.java b/src/main/java/de/ids_mannheim/korap/web/service/light/LightService.java
index c9785f4..a422904 100644
--- a/src/main/java/de/ids_mannheim/korap/web/service/light/LightService.java
+++ b/src/main/java/de/ids_mannheim/korap/web/service/light/LightService.java
@@ -20,12 +20,15 @@
 import org.slf4j.LoggerFactory;
 
 import javax.ws.rs.*;
+import javax.ws.rs.core.Context;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.MultivaluedMap;
 import javax.ws.rs.core.Response;
+import javax.ws.rs.core.SecurityContext;
 import javax.ws.rs.core.UriBuilder;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Locale;
 import java.util.Set;
 
 /**
@@ -274,22 +277,39 @@
     }
 
 
-    //todo: switch to new serialization
-    @POST
-    @Path("stats")
-    public Response getStats (String json) {
+//    //todo: switch to new serialization
+//    @POST
+//    @Path("stats")
+//    public Response getStats (String json) {
+//        KoralCollectionQueryBuilder builder = new KoralCollectionQueryBuilder();
+//        builder.with(json);
+//
+//        // todo: policy override in extension!
+//        String stats = searchKrill.getStatistics(builder.toJSON());
+//        if (stats.contains("-1"))
+//            throw KustvaktResponseHandler.throwit(StatusCodes.NO_VALUE_FOUND);
+//
+//        return Response.ok(stats).build();
+//    }
+    
+    @GET
+    @Path("statistics")
+    public Response getStatistics (@QueryParam("collectionQuery") 
+            String collectionQuery) {
+        
         KoralCollectionQueryBuilder builder = new KoralCollectionQueryBuilder();
-        builder.with(json);
-
-        // todo: policy override in extension!
-        String stats = searchKrill.getStatistics(builder.toJSON());
+        builder.with(collectionQuery);
+        String json = builder.toJSON();
+        
+        String stats = searchKrill.getStatistics(json);
         if (stats.contains("-1"))
             throw KustvaktResponseHandler.throwit(StatusCodes.NO_VALUE_FOUND);
-
+        jlog.debug("Stats: "+stats);
         return Response.ok(stats).build();
     }
 
 
+
 	/*
 	 * TODO: The problem here is, that the matchinfo path makes no
 	 * distinction between docs and texts - unlike DeReKo, the backend
diff --git a/src/main/java/de/ids_mannheim/korap/web/utils/KustvaktResponseHandler.java b/src/main/java/de/ids_mannheim/korap/web/utils/KustvaktResponseHandler.java
index 086336b..44fb085 100644
--- a/src/main/java/de/ids_mannheim/korap/web/utils/KustvaktResponseHandler.java
+++ b/src/main/java/de/ids_mannheim/korap/web/utils/KustvaktResponseHandler.java
@@ -40,7 +40,6 @@
         return new WebApplicationException(s);
     }
 
-
     public static WebApplicationException throwit (int code) {
         return new WebApplicationException(Response.status(getStatus(code))
                 .entity(buildNotification(code, "", "")).build());
@@ -53,7 +52,11 @@
                 .entity(buildNotification(code, message, entity)).build());
     }
 
-
+    public static WebApplicationException throwit (int code, String notification) {
+        return new WebApplicationException(Response.status(getStatus(code))
+                .entity(notification).build());
+    }
+    
     private static String buildNotification (KustvaktException e) {
         register(e.getRecords());
         return buildNotification(e.getStatusCode(), e.getMessage(),
diff --git a/src/test/java/de/ids_mannheim/korap/web/service/full/KustvaktCoreRestTest.java b/src/test/java/de/ids_mannheim/korap/web/service/full/KustvaktCoreRestTest.java
index b5b30a8..0cf4dcc 100644
--- a/src/test/java/de/ids_mannheim/korap/web/service/full/KustvaktCoreRestTest.java
+++ b/src/test/java/de/ids_mannheim/korap/web/service/full/KustvaktCoreRestTest.java
@@ -1,17 +1,14 @@
 package de.ids_mannheim.korap.web.service.full;
 
-import com.sun.jersey.api.client.ClientResponse;
-import de.ids_mannheim.korap.exceptions.KustvaktException;
-import de.ids_mannheim.korap.query.serialize.CollectionQueryProcessor;
-import de.ids_mannheim.korap.query.serialize.QuerySerializer;
-import de.ids_mannheim.korap.utils.JsonUtils;
-import de.ids_mannheim.korap.web.service.FastJerseyTest;
 import org.junit.BeforeClass;
 import org.junit.Ignore;
 import org.junit.Test;
 
-import java.util.LinkedHashMap;
-import java.util.Map;
+import com.sun.jersey.api.client.ClientResponse;
+
+import de.ids_mannheim.korap.exceptions.KustvaktException;
+import de.ids_mannheim.korap.query.serialize.QuerySerializer;
+import de.ids_mannheim.korap.web.service.FastJerseyTest;
 
 /**
  * @author hanl
@@ -75,35 +72,7 @@
         ClientResponse response = resource().path(getAPIVersion()).get(
                 ClientResponse.class);
     }
-
-
-    //    @Test
-    public void testGetStatsThrowsNoException () {
-        CollectionQueryProcessor pr = new CollectionQueryProcessor();
-        pr.process("corpusSigle=WPD & textClass=Sport");
-        Map map = new LinkedHashMap();
-        map.put("collection", pr.getRequestMap());
-        ClientResponse response = resource().path(getAPIVersion())
-                .path("stats")
-                .post(ClientResponse.class, JsonUtils.toJSON(map));
-        assert ClientResponse.Status.OK.getStatusCode() == response.getStatus();
-    }
-
-
-    @Test
-    @Ignore
-    public void testGetStats2ThrowsNoException () {
-        ClientResponse response = resource().path(getAPIVersion())
-                .path("stats")
-                .post(ClientResponse.class, "creationDate in 1787");
-        String ent = response.getEntity(String.class);
-        assert ClientResponse.Status.OK.getStatusCode() == response.getStatus();
-        //        System.out
-        //                .println("___________________________________________________");
-        //        System.out.println("STATS ENTITY " + ent);
-    }
-
-
+   
     //    @Test
     public void testBuildQueryThrowsNoException () {
         ClientResponse response = resource().path(getAPIVersion())
diff --git a/src/test/java/de/ids_mannheim/korap/web/service/full/KustvaktServerTest.java b/src/test/java/de/ids_mannheim/korap/web/service/full/KustvaktServerTest.java
index a5002c9..6a5674d 100644
--- a/src/test/java/de/ids_mannheim/korap/web/service/full/KustvaktServerTest.java
+++ b/src/test/java/de/ids_mannheim/korap/web/service/full/KustvaktServerTest.java
@@ -5,27 +5,12 @@
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileReader;
 import java.io.IOException;
 import java.io.InputStream;
-import java.io.InputStreamReader;
 import java.net.URI;
 import java.net.URISyntaxException;
-import java.nio.charset.Charset;
-import java.nio.charset.StandardCharsets;
-import java.security.KeyManagementException;
-import java.security.KeyStore;
-import java.security.KeyStoreException;
-import java.security.NoSuchAlgorithmException;
-import java.security.UnrecoverableKeyException;
-import java.security.cert.CertificateException;
-import java.util.List;
 import java.util.UUID;
 
-import javax.net.ssl.SSLContext;
 import javax.ws.rs.core.HttpHeaders;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.MultivaluedMap;
@@ -37,20 +22,13 @@
 import org.apache.http.client.HttpClient;
 import org.apache.http.client.methods.HttpPost;
 import org.apache.http.client.utils.URIBuilder;
-import org.apache.http.config.Registry;
-import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
-import org.apache.http.conn.ssl.SSLContexts;
-import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
 import org.apache.http.entity.StringEntity;
-import org.apache.http.impl.client.DefaultHttpClient;
 import org.apache.http.impl.client.HttpClients;
-import org.eclipse.jetty.util.ssl.SslContextFactory;
 import org.junit.Assert;
 import org.junit.Test;
 
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.ObjectMapper;
-import com.google.common.io.Files;
 import com.sun.jersey.api.client.ClientResponse;
 import com.sun.jersey.core.util.MultivaluedMapImpl;
 
diff --git a/src/test/java/de/ids_mannheim/korap/web/service/full/StatisticsServiceTest.java b/src/test/java/de/ids_mannheim/korap/web/service/full/StatisticsServiceTest.java
new file mode 100644
index 0000000..971817b
--- /dev/null
+++ b/src/test/java/de/ids_mannheim/korap/web/service/full/StatisticsServiceTest.java
@@ -0,0 +1,114 @@
+package de.ids_mannheim.korap.web.service.full;
+
+import java.io.IOException;
+
+import org.junit.BeforeClass;
+import org.junit.Test;
+import static org.junit.Assert.assertEquals;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.sun.jersey.api.client.ClientResponse;
+
+import de.ids_mannheim.korap.exceptions.KustvaktException;
+import de.ids_mannheim.korap.web.service.FastJerseyTest;
+
+/** 
+ * @author margaretha
+ * @date 29/06/2017
+ *
+ */
+public class StatisticsServiceTest extends FastJerseyTest {
+
+    private ObjectMapper mapper = new ObjectMapper();
+
+
+    @Override
+    public void initMethod () throws KustvaktException {
+
+    }
+
+    @BeforeClass
+    public static void configure () {
+//        FastJerseyTest.setPackages("de.ids_mannheim.korap.web.service.light",
+        FastJerseyTest.setPackages("de.ids_mannheim.korap.web.service.full",
+                "de.ids_mannheim.korap.web.utils");
+    }
+
+
+    @Test
+    public void testGetStatisticsWithCollectionQuery1 ()
+            throws JsonProcessingException, IOException {
+        String collectionQuery = "corpusSigle=GOE";
+        ClientResponse response = resource().path(getAPIVersion())
+                .path("statistics")
+                .queryParam("collectionQuery", collectionQuery)
+                .get(ClientResponse.class);
+
+        assert ClientResponse.Status.OK.getStatusCode() == response.getStatus();
+
+        String ent = response.getEntity(String.class);
+        JsonNode node = mapper.readTree(ent);
+        assert node.get("documents").asInt() == 11;
+        assert node.get("tokens").asInt() == 665842;
+    }
+
+
+    @Test
+    public void testGetStatisticsWithCollectionQuery2 ()
+            throws JsonProcessingException, IOException {
+        ClientResponse response = resource().path(getAPIVersion())
+                .path("statistics")
+                .queryParam("collectionQuery", "creationDate since 1810")
+                .get(ClientResponse.class);
+        String ent = response.getEntity(String.class);
+        JsonNode node = mapper.readTree(ent);
+        assert ClientResponse.Status.OK.getStatusCode() == response.getStatus();
+        assert node.get("documents").asInt() == 7;
+        assert node.get("tokens").asInt() == 279402;
+        // EM: why zero?
+        assert node.get("sentences").asInt() == 0;
+        assert node.get("paragraphs").asInt() == 0;
+    }
+
+
+    @Test
+    public void testGetStatisticsWithWrongCollectionQuery ()
+            throws JsonProcessingException, IOException {
+        ClientResponse response = resource().path(getAPIVersion())
+                .path("statistics")
+                .queryParam("collectionQuery", "creationDate geq 1810")
+                .get(ClientResponse.class);
+
+        assert ClientResponse.Status.BAD_REQUEST.getStatusCode() == response
+                .getStatus();
+        String ent = response.getEntity(String.class);
+        JsonNode node = mapper.readTree(ent);
+        assertEquals(node.at("/errors/0/0").asInt(), 302);
+        assertEquals(node.at("/errors/0/1").asText(),
+                "Could not parse query >>> (creationDate geq 1810) <<<.");
+        assertEquals(node.at("/errors/0/2").asText(),
+                "(creationDate geq 1810)");
+    }
+
+
+    @Test
+    public void testGetStatisticsWithWrongCollectionQuery2 ()
+            throws JsonProcessingException, IOException {
+        ClientResponse response = resource().path(getAPIVersion())
+                .path("statistics")
+                .queryParam("collectionQuery", "creationDate >= 1810")
+                .get(ClientResponse.class);
+
+        assertEquals(ClientResponse.Status.BAD_REQUEST.getStatusCode(),
+                response.getStatus());
+        String ent = response.getEntity(String.class);
+        JsonNode node = mapper.readTree(ent);
+        assertEquals(node.at("/errors/0/0").asInt(), 305);
+        assertEquals(node.at("/errors/0/1").asText(),
+                "Operator >= is not acceptable.");
+        assertEquals(node.at("/errors/0/2").asText(), ">=");
+    }
+
+}