Fixed poliqarp layer bug (#52) & replaced log4j with log4j2.

Change-Id: I29e34b51ae71aaf98e59d206d54f8c640824ef2e
diff --git a/src/main/antlr/poliqarpplus/PoliqarpPlusParser.g4 b/src/main/antlr/poliqarpplus/PoliqarpPlusParser.g4
index 1236956..0ba3451 100644
--- a/src/main/antlr/poliqarpplus/PoliqarpPlusParser.g4
+++ b/src/main/antlr/poliqarpplus/PoliqarpPlusParser.g4
@@ -70,6 +70,7 @@
 /* Fields */
 term       
 : NEG* (foundry SLASH)? layer termOp key (COLON value)? flag?
+| NEG* foundry flag layer? termOp key (COLON value)? flag?
 | LRPAREN term RRPAREN
 ;
 
diff --git a/src/main/java/de/ids_mannheim/korap/query/serialize/PoliqarpPlusQueryProcessor.java b/src/main/java/de/ids_mannheim/korap/query/serialize/PoliqarpPlusQueryProcessor.java
index 7bde9bc..7879842 100644
--- a/src/main/java/de/ids_mannheim/korap/query/serialize/PoliqarpPlusQueryProcessor.java
+++ b/src/main/java/de/ids_mannheim/korap/query/serialize/PoliqarpPlusQueryProcessor.java
@@ -867,23 +867,29 @@
             }
             // process possible flags
             if (flagNode != null) {
-                ArrayList<String> flags = new ArrayList<String>();
                 // substring removes leading slash
                 String flag = getNodeCat(flagNode.getChild(0)).substring(1);
-
-                if (flag.contains("i"))
-                    flags.add("flags:caseInsensitive");
-                if (flag.contains("x")) {
-                    if (!isRegex) {
-                        key = QueryUtils.escapeRegexSpecialChars(key);
+                
+                // EM: handling flagnode as layer
+                if (node.getChild(1).equals(flagNode)){
+                    if (layerNode == null) {
+                        term.put("layer", flag);
                     }
-                    // flag 'x' allows submatches:
-                    // overwrite key with appended .*?
-                    term.put("key", ".*?" + key + ".*?"); //
-                    term.put("type", "type:regex");
+                    else{
+                        String layer = (String) term.get("layer");
+                        term.put("layer", flag+layer);
+                    }
+                    
+                    // EM: check for other flags
+                    List<ParseTree> list = getChildrenWithCat(node, "flag");
+                    for (int i=1; i < list.size(); i++){
+                        ParseTree n = list.get(i);
+                        flag = getNodeCat(n.getChild(0)).substring(1);
+                        parseFlag(flag, isRegex, key, term);
+                    }
                 }
-                if (!flags.isEmpty()) {
-                    term.put("flags", flags);
+                else {
+                    term = parseFlag(flag, isRegex, key, term);
                 }
             }
             return term;
@@ -937,6 +943,26 @@
     }
 
 
+    private Map<String, Object> parseFlag (String flag, boolean isRegex,
+            String key, Map<String, Object> term) {
+        ArrayList<String> flags = new ArrayList<String>();
+
+        if (flag.contains("i")) flags.add("flags:caseInsensitive");
+        if (flag.contains("x")) {
+            if (!isRegex) {
+                key = QueryUtils.escapeRegexSpecialChars(key);
+            }
+            // flag 'x' allows submatches:
+            // overwrite key with appended .*?
+            term.put("key", ".*?" + key + ".*?"); //
+            term.put("type", "type:regex");
+        }
+        if (!flags.isEmpty()) {
+            term.put("flags", flags);
+        }
+        return term;
+    }
+    
     /**
      * Puts an object into the operands list of its governing (or
      * "super") object which had been placed on the
@@ -1042,11 +1068,13 @@
         Antlr4DescriptiveErrorListener errorListener = new Antlr4DescriptiveErrorListener(
                 query);
         // Like p. 111
+        CommonTokenStream tokens = null;
         try {
             // Tokenize input data
             ANTLRInputStream input = new ANTLRInputStream(query);
             lexer.setInputStream(input);
-            CommonTokenStream tokens = new CommonTokenStream(lexer);
+            tokens = new CommonTokenStream(lexer);
+            
             parser = new PoliqarpPlusParser(tokens);
 
             // Don't throw out erroneous stuff
diff --git a/src/main/java/de/ids_mannheim/korap/query/serialize/QuerySerializer.java b/src/main/java/de/ids_mannheim/korap/query/serialize/QuerySerializer.java
index 725203b..cba745c 100644
--- a/src/main/java/de/ids_mannheim/korap/query/serialize/QuerySerializer.java
+++ b/src/main/java/de/ids_mannheim/korap/query/serialize/QuerySerializer.java
@@ -7,7 +7,6 @@
 import java.util.List;
 import java.util.Map;
 
-import org.apache.log4j.BasicConfigurator;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -69,7 +68,7 @@
         /*
          * just for testing...
          */
-        BasicConfigurator.configure();
+//        BasicConfigurator.configure();
         QuerySerializer jg = new QuerySerializer();
         int i = 0;
         String[] queries = null;
diff --git a/src/main/resources/log4j2.properties b/src/main/resources/log4j2.properties
new file mode 100644
index 0000000..39a5bf5
--- /dev/null
+++ b/src/main/resources/log4j2.properties
@@ -0,0 +1,8 @@
+appenders = console
+appender.console.type = Console
+appender.console.name = CONSOLE
+appender.console.layout.type = PatternLayout
+appender.console.layout.pattern = %d{yyyy-MM-dd, HH:mm:ss} %C{6} - %M%n %-5p: %m%n
+
+rootLogger.level = error
+rootLogger.appenderRef.stdout.ref = CONSOLE
\ No newline at end of file
diff --git a/src/test/java/de/ids_mannheim/korap/query/test/poliqarpplus/PoliqarpPlusQueryProcessorTest.java b/src/test/java/de/ids_mannheim/korap/query/test/poliqarpplus/PoliqarpPlusQueryProcessorTest.java
index c194f94..13e0e05 100644
--- a/src/test/java/de/ids_mannheim/korap/query/test/poliqarpplus/PoliqarpPlusQueryProcessorTest.java
+++ b/src/test/java/de/ids_mannheim/korap/query/test/poliqarpplus/PoliqarpPlusQueryProcessorTest.java
@@ -29,8 +29,54 @@
     ObjectMapper mapper = new ObjectMapper();
     JsonNode res;
 
+    @Test
+    public void testUnknownLayerLikeCase () throws IOException {
+        query = "[mate/i=Baum]";
+        qs.setQuery(query, "poliqarpplus");
+        res = mapper.readTree(qs.toJSON());
+        assertEquals("i", res.at("/query/wrap/layer").asText());
+        
+        query = "[mate/xi=Baum]";
+        qs.setQuery(query, "poliqarpplus");
+        res = mapper.readTree(qs.toJSON());
+        assertEquals("xi", res.at("/query/wrap/layer").asText());
+        
+        query = "[mate/xib=Baum]";
+        qs.setQuery(query, "poliqarpplus");
+        res = mapper.readTree(qs.toJSON());
+        assertEquals("xib", res.at("/query/wrap/layer").asText());
+    }
+    
+    @Test
+    public void testUnknownLayer () throws IOException {
+        query = "[mate/b=Baum]";
+        qs.setQuery(query, "poliqarpplus");
+        res = mapper.readTree(qs.toJSON());
+        assertEquals("b", res.at("/query/wrap/layer").asText());
+        
+        query = "[mate/bi=Baum]";
+        qs.setQuery(query, "poliqarpplus");
+        res = mapper.readTree(qs.toJSON());
+        assertEquals("bi", res.at("/query/wrap/layer").asText());
+    }
 
     @Test
+    public void testLayerWithFlag () throws IOException {
+        query = "[base=Baum/i]";
+        qs.setQuery(query, "poliqarpplus");
+        res = mapper.readTree(qs.toJSON());
+        assertEquals("lemma", res.at("/query/wrap/layer").asText());
+        assertEquals("flags:caseInsensitive", res.at("/query/wrap/flags/0").asText());
+
+        query = "[mate/x=Baum/i]";
+        qs.setQuery(query, "poliqarpplus");
+        res = mapper.readTree(qs.toJSON());
+        assertEquals("x", res.at("/query/wrap/layer").asText());
+        assertEquals("flags:caseInsensitive", res.at("/query/wrap/flags/0").asText());
+    }
+
+    
+    @Test
     public void testContext () throws JsonProcessingException, IOException {
         query = "foo";
         String contextString = "http://korap.ids-mannheim.de/ns/koral/0.3/context.jsonld";