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

Change-Id: I29e34b51ae71aaf98e59d206d54f8c640824ef2e
diff --git a/.gitignore b/.gitignore
index f993ee1..cbec024 100644
--- a/.gitignore
+++ b/.gitignore
@@ -11,9 +11,6 @@
 .*
 !.gitignore
 
-
-/src/main/resources
-
 # /src/main/antlr/cosmas/
 /src/main/antlr/cosmas/c2ps_regex.g
 
diff --git a/Changes b/Changes
index 9ec1522..4edfab6 100644
--- a/Changes
+++ b/Changes
@@ -1,5 +1,7 @@
 0.33 2019-01-08
     - Added debug flags (margaretha)
+    - [bugfix] Fixed poliqarp layer bug (#52; margaretha)
+    - Replaced log4j with log4j2 (margaretha)
     
 0.32 2018-12-13
     - [bugfix] Support verbatim string queries (#57; diewald).
diff --git a/pom.xml b/pom.xml
index 7d5a151..5129347 100644
--- a/pom.xml
+++ b/pom.xml
@@ -108,24 +108,35 @@
 			<version>1.12</version>
 		</dependency>
 		<dependency>
-			<groupId>log4j</groupId>
-			<artifactId>log4j</artifactId>
-			<version>1.2.17</version>
+			<groupId>org.apache.logging.log4j</groupId>
+			<artifactId>log4j-api</artifactId>
+			<version>2.11.0</version>
 		</dependency>
 		<dependency>
-			<groupId>log4j</groupId>
-			<artifactId>apache-log4j-extras</artifactId>
-			<version>1.2.17</version>
+			<groupId>org.apache.logging.log4j</groupId>
+			<artifactId>log4j-core</artifactId>
+			<version>2.11.0</version>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.logging.log4j</groupId>
+			<artifactId>log4j-slf4j-impl</artifactId>
+			<version>2.11.0</version>
+		</dependency>
+		<dependency>
+			<groupId>org.apache.logging.log4j</groupId>
+			<artifactId>log4j-jul</artifactId>
+			<version>2.11.0</version>
+			<exclusions>
+				<exclusion>
+					<groupId>org.slf4j</groupId>
+					<artifactId>slf4j-api</artifactId>
+				</exclusion>
+			</exclusions>
 		</dependency>
 		<dependency>
 			<groupId>org.slf4j</groupId>
 			<artifactId>slf4j-api</artifactId>
-			<version>1.7.5</version>
-		</dependency>
-		<dependency>
-			<groupId>org.slf4j</groupId>
-			<artifactId>slf4j-log4j12</artifactId>
-			<version>1.7.5</version>
+			<version>1.7.25</version>
 		</dependency>
 		<dependency>
 			<groupId>eu.clarin.sru.fcs</groupId>
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";