Fixed rewrite redundancy in collection rewrite.

Change-Id: Id3c4744449064e21f02d682fe62bc07dc6201a6f
diff --git a/core/src/main/java/de/ids_mannheim/korap/resource/rewrite/CollectionRewrite.java b/core/src/main/java/de/ids_mannheim/korap/resource/rewrite/CollectionRewrite.java
index 8937d42..60402ac 100644
--- a/core/src/main/java/de/ids_mannheim/korap/resource/rewrite/CollectionRewrite.java
+++ b/core/src/main/java/de/ids_mannheim/korap/resource/rewrite/CollectionRewrite.java
@@ -17,70 +17,110 @@
 import de.ids_mannheim.korap.query.object.KoralOperation;
 import de.ids_mannheim.korap.resource.rewrite.KoralNode.RewriteIdentifier;
 import de.ids_mannheim.korap.user.User;
+import de.ids_mannheim.korap.user.User.CorpusAccess;
 import de.ids_mannheim.korap.utils.JsonUtils;
 import de.ids_mannheim.korap.utils.KoralCollectionQueryBuilder;
+import edu.emory.mathcs.backport.java.util.Arrays;
 
-/**
+/** CollectionRewrite determines which availability field values are 
+ *  possible for a user with respect to his mean and location of access.
+ *  
+ *  <br/><br/>
+ *  KorAP differentiates 3 kinds of access:
+ *  <ul>
+ *      <li>FREE: without login</li> 
+ *      <li>PUB: login outside IDS network</li> 
+ *      <li>ALL: login within IDS network</li> 
+ *  </ul>
+ *  
+ *  Each of these accesses corresponds to a regular expression of license 
+ *  formats defined in kustvakt.conf. For a given access, only those 
+ *  resources whose availability field matches its regular expression 
+ *  are allowed to be retrieved. 
+ *  
+ *  
  * @author margaretha
- * @date 2 June 2017
- * @last 9 Nov 2017
+ * @last-update 21 Nov 2017
+ * @see CorpusAccess
  */
 public class CollectionRewrite implements RewriteTask.RewriteQuery {
 
-    private static Logger jlog = LoggerFactory
-            .getLogger(CollectionRewrite.class);
+    private static Logger jlog =
+            LoggerFactory.getLogger(CollectionRewrite.class);
 
     public CollectionRewrite () {
         super();
     }
 
-    
-    private List<String> checkAvailability (JsonNode node, List<String> userAvailabilities) {
 
-        if (node.has("operands") && node.at("/operation").asText().equals(KoralOperation.AND.toString())) {
-            ArrayList<JsonNode> operands = Lists
-                    .newArrayList(node.at("/operands").elements());
-            for (int i = 0; i < operands.size(); i++) {
-                userAvailabilities = checkAvailability(operands.get(i), userAvailabilities);
+    private List<String> checkAvailability (JsonNode node,
+            List<String> originalAvailabilities,
+            List<String> updatedAvailabilities, boolean isOperationOr) {
+        try {
+            jlog.debug(JsonUtils.toJSON(node));
+        }
+        catch (KustvaktException e) {
+            e.printStackTrace();
+        }
+
+        if (node.has("operands")) {
+            ArrayList<JsonNode> operands =
+                    Lists.newArrayList(node.at("/operands").elements());
+
+            if (node.at("/operation").asText()
+                    .equals(KoralOperation.AND.toString())) {
+                for (int i = 0; i < operands.size(); i++) {
+                    updatedAvailabilities = checkAvailability(operands.get(i),
+                            originalAvailabilities, updatedAvailabilities,
+                            false);
+                    if (updatedAvailabilities.isEmpty()) break;
+                }
+            }
+            else {
+                for (int i = 0; i < operands.size(); i++) {
+                    updatedAvailabilities = checkAvailability(operands.get(i),
+                            originalAvailabilities, updatedAvailabilities,
+                            true);
+                }
             }
         }
         else if (node.has("key")
                 && node.at("/key").asText().equals("availability")) {
             String queryAvailability = node.at("/value").asText();
             String matchOp = node.at("/match").asText();
-            if (userAvailabilities.contains(queryAvailability) && matchOp.
-                    equals(KoralMatchOperator.EQUALS.toString())){
-                userAvailabilities.remove(queryAvailability);
+            if (originalAvailabilities.contains(queryAvailability)
+                    && matchOp.equals(KoralMatchOperator.EQUALS.toString())) {
+                jlog.debug("REMOVE " + queryAvailability);
+                updatedAvailabilities.remove(queryAvailability);
+            }
+            else if (isOperationOr) {
+                jlog.debug("RESET availabilities");
+                updatedAvailabilities.clear();
+                updatedAvailabilities.addAll(originalAvailabilities);
+                return updatedAvailabilities;
             }
         }
-
-        return userAvailabilities;
+        return updatedAvailabilities;
     }
 
     @Override
     public JsonNode rewriteQuery (KoralNode node, KustvaktConfiguration config,
             User user) throws KustvaktException {
         JsonNode jsonNode = node.rawNode();
-        
+
         List<String> userAvailabilities = new ArrayList<String>();
         switch (user.getCorpusAccess()) {
             case PUB:
                 userAvailabilities.add(config.getFreeOnlyRegex());
                 userAvailabilities.add(config.getPublicOnlyRegex());
-//                builder.with(
-//                        "availability = /CC-BY.*/ | availability = /ACA.*/");
                 break;
             case ALL:
                 userAvailabilities.add(config.getFreeOnlyRegex());
                 userAvailabilities.add(config.getPublicOnlyRegex());
                 userAvailabilities.add(config.getAllOnlyRegex());
-
-//                builder.with("availability = /QAO.*/ | availability = /ACA.*/ |"
-//                        + "  availability = /CC-BY.*/");
                 break;
             case FREE:
                 userAvailabilities.add(config.getFreeOnlyRegex());
-//                builder.with("availability   = /CC-BY.*/");
                 break;
         }
 
@@ -90,9 +130,16 @@
         JsonNode rewrittesNode;
 
         if (jsonNode.has("collection")) {
-            userAvailabilities = checkAvailability(jsonNode.at("/collection"), userAvailabilities);
-            if (!userAvailabilities.isEmpty()){
-                builder.with(buildAvailability(userAvailabilities));
+            List<String> avalabilityCopy =
+                    new ArrayList<String>(userAvailabilities.size());
+            avalabilityCopy.addAll(userAvailabilities);
+            jlog.debug("Availabilities: "
+                    + Arrays.toString(userAvailabilities.toArray()));
+
+            userAvailabilities = checkAvailability(jsonNode.at("/collection"),
+                    avalabilityCopy, userAvailabilities, false);
+            if (!userAvailabilities.isEmpty()) {
+                builder.with(buildAvailability(avalabilityCopy));
                 builder.setBaseQuery(builder.toJSON());
                 rewrittesNode = builder.mergeWith(jsonNode).at("/collection");
                 node.set("collection", rewrittesNode, identifier);
@@ -100,25 +147,25 @@
         }
         else {
             builder.with(buildAvailability(userAvailabilities));
-            rewrittesNode = JsonUtils.readTree(builder.toJSON())
-                    .at("/collection");
+            rewrittesNode =
+                    JsonUtils.readTree(builder.toJSON()).at("/collection");
             node.set("collection", rewrittesNode, identifier);
         }
 
         jlog.info("REWRITES: " + node.at("/collection").toString());
         return node.rawNode();
     }
-    
-    
+
+
     private String buildAvailability (List<String> userAvailabilities) {
         StringBuilder sb = new StringBuilder();
-        for (int i=0; i < userAvailabilities.size()-1; i++){
+        for (int i = 0; i < userAvailabilities.size() - 1; i++) {
             sb.append("availability=/");
             sb.append(userAvailabilities.get(i));
             sb.append("/ | ");
         }
         sb.append("availability=/");
-        sb.append(userAvailabilities.get(userAvailabilities.size()-1));
+        sb.append(userAvailabilities.get(userAvailabilities.size() - 1));
         sb.append("/");
         return sb.toString();
     }
diff --git a/full/src/main/java/de/ids_mannheim/korap/authentication/KustvaktAuthenticationManager.java b/full/src/main/java/de/ids_mannheim/korap/authentication/KustvaktAuthenticationManager.java
index 7ee3506..60c3126 100644
--- a/full/src/main/java/de/ids_mannheim/korap/authentication/KustvaktAuthenticationManager.java
+++ b/full/src/main/java/de/ids_mannheim/korap/authentication/KustvaktAuthenticationManager.java
@@ -231,13 +231,11 @@
 					corpusAccess = CorpusAccess.PUB;
 				}
 				
-				if (DEBUG_LOG == true) {
-					System.out.printf("Debug: X-Forwarded-For : '%s' (%d values) -> %s\n", 
-							Arrays.toString(vals), vals.length, vals[0]);
-					System.out.printf("Debug: X-Forwarded-For : location = %s corpusAccess = %s\n",
-							location == Location.INTERN ? "INTERN" : "EXTERN", corpusAccess == CorpusAccess.ALL ? "ALL"
-									: corpusAccess == CorpusAccess.PUB ? "PUB" : "FREE");
-				}
+			    jlog.debug(String.format("X-Forwarded-For : '%s' (%d values) -> %s\n", 
+						Arrays.toString(vals), vals.length, vals[0]));
+			    jlog.debug(String.format("X-Forwarded-For : location = %s corpusAccess = %s\n",
+						location == Location.INTERN ? "INTERN" : "EXTERN", corpusAccess == CorpusAccess.ALL ? "ALL"
+								: corpusAccess == CorpusAccess.PUB ? "PUB" : "FREE"));
 
 			} catch (UnknownHostException e) {
 				// TODO Auto-generated catch block
diff --git a/full/src/main/resources/log4j.properties b/full/src/main/resources/log4j.properties
index 308c9ca..7f9c1ca 100644
--- a/full/src/main/resources/log4j.properties
+++ b/full/src/main/resources/log4j.properties
@@ -6,7 +6,7 @@
 
 #log4j.logger.de.ids_mannheim.korap.service.VirtualCorpusService = error, debugLog
 #log4j.logger.de.ids_mannheim.korap.web.controller.AuthenticationController = debug, debugLog, stdout
-
+log4j.logger.de.ids_mannheim.korap.resource.rewrite.CollectionRewrite= stdout, debugLog
 
 # Direct log messages to stdout
 log4j.appender.stdout=org.apache.log4j.ConsoleAppender
@@ -36,4 +36,4 @@
 
 
 log4j.logger.de.ids_mannheim.korap.security.ac = ERROR, policyLog
-log4j.logger.de.ids_mannheim.korap.security.auth = ERROR, authLog
\ No newline at end of file
+log4j.logger.de.ids_mannheim.korap.authentication = debug, authLog
\ No newline at end of file
diff --git a/full/src/test/java/de/ids_mannheim/korap/web/service/full/SearchWithAvailabilityTest.java b/full/src/test/java/de/ids_mannheim/korap/web/service/full/SearchWithAvailabilityTest.java
index 7328064..cf19694 100644
--- a/full/src/test/java/de/ids_mannheim/korap/web/service/full/SearchWithAvailabilityTest.java
+++ b/full/src/test/java/de/ids_mannheim/korap/web/service/full/SearchWithAvailabilityTest.java
@@ -64,21 +64,17 @@
                 node.at("/collection/rewrites/0/scope").asText());
     }
 
-    private void checkAndPublicWithoutACA (String json)
+    private void checkAndPublicWithACA (String json)
             throws KustvaktException {
         JsonNode node = JsonUtils.readTree(json);
         assertNotNull(node);
         assertEquals("operation:and",
                 node.at("/collection/operation").asText());
-        assertEquals("match:eq",
-                node.at("/collection/operands/0/match").asText());
-        assertEquals("type:regex",
-                node.at("/collection/operands/0/type").asText());
-        assertEquals("availability",
-                node.at("/collection/operands/0/key").asText());
-        assertEquals("CC-BY.*",
-                node.at("/collection/operands/0/value").asText());
-
+        assertEquals("operation:insertion",
+                node.at("/collection/rewrites/0/operation").asText());
+        assertEquals("availability(PUB)",
+                node.at("/collection/rewrites/0/scope").asText());
+        
         assertEquals("match:eq",
                 node.at("/collection/operands/1/match").asText());
         assertEquals("type:regex",
@@ -86,11 +82,26 @@
         assertEquals("availability",
                 node.at("/collection/operands/1/key").asText());
         assertEquals("ACA.*", node.at("/collection/operands/1/value").asText());
+        
+        node = node.at("/collection/operands/0");
+        assertEquals("match:eq",
+                node.at("/operands/0/match").asText());
+        assertEquals("type:regex",
+                node.at("/operands/0/type").asText());
+        assertEquals("availability",
+                node.at("/operands/0/key").asText());
+        assertEquals("CC-BY.*",
+                node.at("/operands/0/value").asText());
 
-        assertEquals("operation:insertion",
-                node.at("/collection/rewrites/0/operation").asText());
-        assertEquals("availability(PUB)",
-                node.at("/collection/rewrites/0/scope").asText());
+        assertEquals("match:eq",
+                node.at("/operands/1/match").asText());
+        assertEquals("type:regex",
+                node.at("/operands/1/type").asText());
+        assertEquals("availability",
+                node.at("/operands/1/key").asText());
+        assertEquals("ACA.*", node.at("/operands/1/value").asText());
+
+        
     }
 
     private void checkAndAll (String json) throws KustvaktException {
@@ -122,27 +133,39 @@
 
     }
 
-    private void checkAndAllWithoutACA (String json) throws KustvaktException {
+    private void checkAndAllWithACA (String json) throws KustvaktException {
         JsonNode node = JsonUtils.readTree(json);
         assertNotNull(node);
         assertEquals("operation:and",
                 node.at("/collection/operation").asText());
-        assertEquals("match:eq",
-                node.at("/collection/operands/0/operands/0/match").asText());
-        assertEquals("type:regex",
-                node.at("/collection/operands/0/operands/0/type").asText());
-        assertEquals("availability",
-                node.at("/collection/operands/0/operands/0/key").asText());
-        assertEquals("CC-BY.*",
-                node.at("/collection/operands/0/operands/0/value").asText());
-        assertEquals("match:eq",
-                node.at("/collection/operands/0/operands/1/match").asText());
-        assertEquals("QAO.*",
-                node.at("/collection/operands/0/operands/1/value").asText());
         assertEquals("operation:insertion",
                 node.at("/collection/rewrites/0/operation").asText());
         assertEquals("availability(ALL)",
                 node.at("/collection/rewrites/0/scope").asText());
+        
+        assertEquals("match:eq",
+                node.at("/collection/operands/1/match").asText());
+        assertEquals("type:regex",
+                node.at("/collection/operands/1/type").asText());
+        assertEquals("availability",
+                node.at("/collection/operands/1/key").asText());
+        assertEquals("ACA.*", node.at("/collection/operands/1/value").asText());
+        
+        node = node.at("/collection/operands/0");
+        
+        assertEquals("match:eq",
+                node.at("/operands/0/match").asText());
+        assertEquals("type:regex",
+                node.at("/operands/0/type").asText());
+        assertEquals("availability",
+                node.at("/operands/0/key").asText());
+        assertEquals("CC-BY.*",
+                node.at("/operands/0/value").asText());
+        assertEquals("match:eq",
+                node.at("/operands/1/operands/1/match").asText());
+        assertEquals("QAO.*",
+                node.at("/operands/1/operands/1/value").asText());
+        
     }
 
 
@@ -350,7 +373,7 @@
         assertEquals(ClientResponse.Status.OK.getStatusCode(),
                 response.getStatus());
 
-        checkAndPublicWithoutACA(response.getEntity(String.class));
+        checkAndPublicWithACA(response.getEntity(String.class));
     }
 
 
@@ -412,7 +435,7 @@
         assertEquals(ClientResponse.Status.OK.getStatusCode(),
                 response.getStatus());
 
-        checkAndAllWithoutACA(response.getEntity(String.class));
+        checkAndAllWithACA(response.getEntity(String.class));
     }
 
 }