Merge "Added support for unrestricted corpus statistics"
diff --git a/core/pom.xml b/core/pom.xml
index de109cc..3e09cee 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -80,13 +80,13 @@
 				rest tests -->
 			<!-- <plugin>
 				<groupId>org.apache.maven.plugins</groupId>
-				<artifactId>maven-jar-plugin</artifactId>
-				<version>3.0.2</version>
+				<artifactId>maven-source-plugin</artifactId>
+				<version>3.0.1</version>
 				<executions>
 					<execution>
-						<phase>package</phase>
+						<id>attach-sources</id>
 						<goals>
-							<goal>test-jar</goal>
+							<goal>jar</goal>
 						</goals>
 					</execution>
 				</executions>
@@ -183,12 +183,29 @@
 			<version>${jersey.version}</version>
 			<scope>test</scope>
 		</dependency>
+		<!-- EM: Logging -->
 		<dependency>
-			<groupId>org.slf4j</groupId>
-			<artifactId>slf4j-log4j12</artifactId>
-			<version>1.7.25</version>
+			<groupId>org.apache.logging.log4j</groupId>
+			<artifactId>log4j-api</artifactId>
+			<version>2.11.0</version>
 		</dependency>
 		<dependency>
+			<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>
+		</dependency>
+		
+		<dependency>
 			<groupId>junit</groupId>
 			<artifactId>junit</artifactId>
 			<version>4.12</version>
@@ -212,6 +229,22 @@
 					<groupId>org.eclipse.jetty</groupId>
 					<artifactId>jetty-servlet</artifactId>
 				</exclusion>
+				<exclusion>
+					<groupId>org.slf4j</groupId>
+					<artifactId>slf4j-api</artifactId>
+				</exclusion>
+				<exclusion>
+					<groupId>org.slf4j</groupId>
+					<artifactId>slf4j-log4j12</artifactId>
+				</exclusion>
+				<exclusion>
+					<groupId>log4j</groupId>
+					<artifactId>log4j</artifactId>
+				</exclusion>
+				<exclusion>
+					<groupId>log4j</groupId>
+					<artifactId>apache-log4j-extras</artifactId>
+				</exclusion>
 			</exclusions>
 		</dependency>
 
@@ -221,8 +254,6 @@
 			<version>3.21.0</version>
 		</dependency>
 
-		
-
 		<dependency>
 			<groupId>org.apache.commons</groupId>
 			<artifactId>commons-dbcp2</artifactId>
@@ -240,7 +271,7 @@
 			<artifactId>jbcrypt</artifactId>
 			<version>0.4</version>
 		</dependency>
-		
+
 		<dependency>
 			<groupId>de.ids_mannheim.korap</groupId>
 			<artifactId>Krill</artifactId>
@@ -250,6 +281,18 @@
 					<groupId>org.xerial</groupId>
 					<artifactId>sqlite-jdbc</artifactId>
 				</exclusion>
+				<exclusion>
+					<groupId>org.slf4j</groupId>
+					<artifactId>slf4j-log4j12</artifactId>
+				</exclusion>
+				<exclusion>
+					<groupId>org.apache.logging.log4j</groupId>
+					<artifactId>log4j-slf4j-impl</artifactId>
+				</exclusion>
+				<exclusion>
+					<groupId>org.slf4j</groupId>
+					<artifactId>jul-to-slf4j</artifactId>
+				</exclusion>
 			</exclusions>
 		</dependency>
 		<dependency>
@@ -318,7 +361,7 @@
 			<artifactId>commons-collections</artifactId>
 			<version>3.2.2</version>
 		</dependency>
-		
+
 		<!-- jetty -->
 		<dependency>
 			<groupId>org.eclipse.jetty</groupId>
@@ -335,7 +378,7 @@
 			<artifactId>jetty-webapp</artifactId>
 			<version>${jetty.version}</version>
 		</dependency>
-		
+
 		<dependency>
 			<groupId>asm</groupId>
 			<artifactId>asm</artifactId>
diff --git a/core/src/main/java/de/ids_mannheim/korap/config/ConfigLoader.java b/core/src/main/java/de/ids_mannheim/korap/config/ConfigLoader.java
index 855417c..9fcc3bd 100644
--- a/core/src/main/java/de/ids_mannheim/korap/config/ConfigLoader.java
+++ b/core/src/main/java/de/ids_mannheim/korap/config/ConfigLoader.java
@@ -1,20 +1,20 @@
 package de.ids_mannheim.korap.config;
 
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.util.Properties;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
 /**
  * Created by hanl on 08.06.16.
  */
 public class ConfigLoader {
 
-    private static final Logger jlog = LoggerFactory.getLogger(ConfigLoader.class);
+    private static final Logger jlog = LogManager.getLogger(ConfigLoader.class);
 
 
     private ConfigLoader () {}
diff --git a/core/src/main/java/de/ids_mannheim/korap/config/KustvaktConfiguration.java b/core/src/main/java/de/ids_mannheim/korap/config/KustvaktConfiguration.java
index c3e45c2..b4c1bdd 100644
--- a/core/src/main/java/de/ids_mannheim/korap/config/KustvaktConfiguration.java
+++ b/core/src/main/java/de/ids_mannheim/korap/config/KustvaktConfiguration.java
@@ -4,18 +4,16 @@
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
-import java.net.URISyntaxException;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Properties;
 
-import org.apache.log4j.PropertyConfigurator;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+//import org.apache.logging.log4j.PropertyConfigurator;
 
-import de.ids_mannheim.korap.exceptions.KustvaktException;
 import de.ids_mannheim.korap.utils.TimeUtils;
 import lombok.Getter;
 
@@ -33,7 +31,7 @@
     public static final Map<String, Object> KUSTVAKT_USER = new HashMap<>();
 
     private static final Logger jlog =
-            LoggerFactory.getLogger(KustvaktConfiguration.class);
+            LogManager.getLogger(KustvaktConfiguration.class);
     private String indexDir;
     private int port;
     // todo: make exclusive so that the containg languages can really
@@ -198,54 +196,54 @@
 
 
     public static void loadLogger () {
-        InputStream stream = ConfigLoader.loadConfigStream("log4j.properties");
-        PropertyConfigurator.configure(stream);
+//        InputStream stream = ConfigLoader.loadConfigStream("log4j.properties");
+//        PropertyConfigurator.configure(stream);
         jlog.info("Done loading logging framework Log4j!");
     }
 
 
 
-    @Deprecated
-    public static void loadLog4jLogger () {
-        /** loadSubTypes log4j configuration file programmatically */
-        Properties log4j = new Properties();
-        try {
-            File f = new File(System.getProperty("user.dir"),
-                    "log4j.properties");
-            if (f.exists()) {
-                log4j.load(new FileInputStream(f));
-                PropertyConfigurator.configure(log4j);
-                jlog.info(
-                        "using local logging properties file ({}) to configure logging system",
-                        "./log4j.properties");
-                return;
-            }
-        }
-        catch (Exception e) {
-            // do nothing
-        }
-        loadClassLogger();
-    }
+//    @Deprecated
+//    public static void loadLog4jLogger () {
+//        /** loadSubTypes log4j configuration file programmatically */
+//        Properties log4j = new Properties();
+//        try {
+//            File f = new File(System.getProperty("user.dir"),
+//                    "log4j.properties");
+//            if (f.exists()) {
+//                log4j.load(new FileInputStream(f));
+//                PropertyConfigurator.configure(log4j);
+//                jlog.info(
+//                        "using local logging properties file ({}) to configure logging system",
+//                        "./log4j.properties");
+//                return;
+//            }
+//        }
+//        catch (Exception e) {
+//            // do nothing
+//        }
+//        loadClassLogger();
+//    }
 
 
-    @Deprecated
-    private static void loadClassLogger () {
-        Properties log4j = new Properties();
-        jlog.info(
-                "using class path logging properties file to configure logging system");
-
-        try {
-            log4j.load(KustvaktConfiguration.class.getClassLoader()
-                    .getResourceAsStream("log4j.properties"));
-        }
-        catch (IOException e) {
-            // do nothing
-        }
-
-        PropertyConfigurator.configure(log4j);
-        jlog.warn(
-                "No logger properties detected. Using default logger properties");
-    }
+//    @Deprecated
+//    private static void loadClassLogger () {
+//        Properties log4j = new Properties();
+//        jlog.info(
+//                "using class path logging properties file to configure logging system");
+//
+//        try {
+//            log4j.load(KustvaktConfiguration.class.getClassLoader()
+//                    .getResourceAsStream("log4j.properties"));
+//        }
+//        catch (IOException e) {
+//            // do nothing
+//        }
+//
+//        PropertyConfigurator.configure(log4j);
+//        jlog.warn(
+//                "No logger properties detected. Using default logger properties");
+//    }
 
     public enum BACKENDS {
         NEO4J, LUCENE
diff --git a/core/src/main/java/de/ids_mannheim/korap/exceptions/ServiceException.java b/core/src/main/java/de/ids_mannheim/korap/exceptions/ServiceException.java
index 9e615f3..99ddebe 100644
--- a/core/src/main/java/de/ids_mannheim/korap/exceptions/ServiceException.java
+++ b/core/src/main/java/de/ids_mannheim/korap/exceptions/ServiceException.java
@@ -4,13 +4,14 @@
 import lombok.AccessLevel;
 import lombok.Getter;
 import lombok.Setter;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
 /**
  * @author hanl
  * @date 08/04/2015
@@ -22,7 +23,7 @@
 public class ServiceException extends Exception {
 
     protected List<AuditRecord> records = new ArrayList<>();
-    private static final Logger jlog = LoggerFactory
+    private static final Logger jlog = LogManager
             .getLogger(ServiceException.class);
 
     private int status;
diff --git a/core/src/main/java/de/ids_mannheim/korap/interfaces/defaults/ApacheValidator.java b/core/src/main/java/de/ids_mannheim/korap/interfaces/defaults/ApacheValidator.java
index 1b9477a..e78cd0c 100644
--- a/core/src/main/java/de/ids_mannheim/korap/interfaces/defaults/ApacheValidator.java
+++ b/core/src/main/java/de/ids_mannheim/korap/interfaces/defaults/ApacheValidator.java
@@ -8,8 +8,8 @@
 import de.ids_mannheim.korap.web.utils.KustvaktMap;
 import org.apache.commons.validator.routines.*;
 import org.apache.commons.validator.routines.RegexValidator;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 
 import java.io.IOException;
 import java.util.*;
@@ -19,7 +19,7 @@
  */
 public class ApacheValidator implements ValidatorIface {
 
-    private static Logger jlog = LoggerFactory.getLogger(ApacheValidator.class);
+    private static Logger jlog = LogManager.getLogger(ApacheValidator.class);
 
     private static final String STRING_PATTERN = "^[\\.;:,&\\|@\\[\\]\\=\\*\\/\\/_()\\-0-9\\p{L}\\p{Space}]{0,1024}$";
 
@@ -117,8 +117,8 @@
             else
                 return this.isValid(input, "string");
         }
-        jlog.debug("validating entry '{}' of type '{}': {}", input, type,
-                valid ? "Is valid!" : "Is not valid!");
+        jlog.debug("validating entry "+input+" of type "+type+": "+ (
+                valid ? "Is valid!" : "Is not valid!"));
         return valid;
     }
 }
diff --git a/core/src/main/java/de/ids_mannheim/korap/resource/rewrite/RewriteHandler.java b/core/src/main/java/de/ids_mannheim/korap/resource/rewrite/RewriteHandler.java
index fe98402..592a144 100644
--- a/core/src/main/java/de/ids_mannheim/korap/resource/rewrite/RewriteHandler.java
+++ b/core/src/main/java/de/ids_mannheim/korap/resource/rewrite/RewriteHandler.java
@@ -8,8 +8,8 @@
 import java.util.Map;
 import java.util.Set;
 
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.springframework.beans.factory.annotation.Autowired;
 
 import com.fasterxml.jackson.databind.JsonNode;
@@ -30,7 +30,7 @@
 public class RewriteHandler{
     //implements BeanInjectable {
 
-    private static Logger jlog = LoggerFactory.getLogger(RewriteHandler.class);
+    private static Logger jlog = LogManager.getLogger(RewriteHandler.class);
     private Collection<RewriteTask.IterableRewritePath> node_processors;
     private Collection<RewriteTask.RewriteKoralToken> token_node_processors;
     private Collection<RewriteTask> query_processors;
@@ -208,7 +208,7 @@
 
 
         private JsonNode start (boolean result) throws KustvaktException {
-            jlog.debug("Running rewrite process on query {}", root);
+            jlog.debug("Running rewrite process on query "+ root);
             if (root != null) {
                 Iterator<Map.Entry<String, JsonNode>> it = root.fields();
                 while (it.hasNext()) {
diff --git a/core/src/main/java/de/ids_mannheim/korap/user/KorAPUser.java b/core/src/main/java/de/ids_mannheim/korap/user/KorAPUser.java
index 9c544f6..d25097f 100644
--- a/core/src/main/java/de/ids_mannheim/korap/user/KorAPUser.java
+++ b/core/src/main/java/de/ids_mannheim/korap/user/KorAPUser.java
@@ -1,14 +1,15 @@
 package de.ids_mannheim.korap.user;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
 import lombok.Getter;
 import lombok.Setter;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 @Getter
 @Setter
 public class KorAPUser extends User {
-    private static Logger jlog = LoggerFactory.getLogger(KorAPUser.class);
+    private static Logger jlog = LogManager.getLogger(KorAPUser.class);
     private static final long serialVersionUID = -7108308497625884584L;
 
     //fixme: accountlink to shibboleth account
diff --git a/core/src/main/java/de/ids_mannheim/korap/utils/KustvaktLogger.java b/core/src/main/java/de/ids_mannheim/korap/utils/KustvaktLogger.java
deleted file mode 100644
index e75db81..0000000
--- a/core/src/main/java/de/ids_mannheim/korap/utils/KustvaktLogger.java
+++ /dev/null
@@ -1,431 +0,0 @@
-package de.ids_mannheim.korap.utils;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.slf4j.Marker;
-
-/**
- * @author hanl
- * @date 28/03/2014
- */
-
-@Deprecated
-public class KustvaktLogger implements Logger {
-    // debugging flag, info, warn, error will always be logged though!
-    public static boolean DEBUG = false;
-
-    public static final String ERROR_LOG = "errorLog";
-    public static final String SECURITY_LOG = "securityLog";
-
-    public static final KustvaktLogger QUERY_LOGGER = KustvaktLogger
-            .getLogger("ql");
-
-    private Logger log;
-
-
-    public static KustvaktLogger getLogger (Class cl) {
-        return new KustvaktLogger(LoggerFactory.getLogger(cl));
-    }
-
-
-    public static KustvaktLogger getLogger (String name) {
-        return new KustvaktLogger(LoggerFactory.getLogger(name));
-
-    }
-
-
-    private KustvaktLogger (Logger log) {
-        this.log = log;
-    }
-
-
-    @Override
-    public String getName () {
-        return log.getName();
-    }
-
-
-    @Override
-    public boolean isTraceEnabled () {
-        return log.isTraceEnabled();
-    }
-
-
-    @Override
-    public void trace (String s) {
-        if (DEBUG)
-            this.log.trace(s);
-
-    }
-
-
-    @Override
-    public void trace (String s, Object o) {
-        if (DEBUG)
-            this.log.trace(s, o);
-    }
-
-
-    @Override
-    public void trace (String s, Object o, Object o2) {
-        if (DEBUG)
-            this.log.trace(s, o, o2);
-    }
-
-
-    @Override
-    public void trace (String s, Object ... objects) {
-        if (DEBUG)
-            this.log.trace(s, objects);
-    }
-
-
-    @Override
-    public void trace (String s, Throwable throwable) {
-        if (DEBUG)
-            this.log.trace(s, throwable);
-    }
-
-
-    @Override
-    public boolean isTraceEnabled (Marker marker) {
-        if (DEBUG)
-            return this.log.isTraceEnabled();
-        return false;
-    }
-
-
-    @Override
-    public void trace (Marker marker, String s) {
-        if (DEBUG)
-            this.log.trace(marker, s);
-    }
-
-
-    @Override
-    public void trace (Marker marker, String s, Object o) {
-        if (DEBUG)
-            this.log.trace(marker, s, o);
-    }
-
-
-    @Override
-    public void trace (Marker marker, String s, Object o, Object o2) {
-        if (DEBUG)
-            this.log.trace(marker, s, o, o2);
-    }
-
-
-    @Override
-    public void trace (Marker marker, String s, Object ... objects) {
-        if (DEBUG)
-            this.log.trace(marker, s, objects);
-    }
-
-
-    @Override
-    public void trace (Marker marker, String s, Throwable throwable) {
-        if (DEBUG)
-            this.log.trace(marker, s, throwable);
-    }
-
-
-    @Override
-    public boolean isDebugEnabled () {
-        if (DEBUG)
-            return true;
-        return false;
-    }
-
-
-    @Override
-    public void debug (String s) {
-        if (DEBUG)
-            this.log.debug(s);
-    }
-
-
-    @Override
-    public void debug (String s, Object o) {
-        if (DEBUG)
-            this.log.debug(s, o);
-    }
-
-
-    @Override
-    public void debug (String s, Object o, Object o2) {
-        if (DEBUG)
-            this.log.debug(s, o, o2);
-    }
-
-
-    @Override
-    public void debug (String s, Object ... objects) {
-        if (DEBUG)
-            this.log.debug(s);
-    }
-
-
-    @Override
-    public void debug (String s, Throwable throwable) {
-        if (DEBUG)
-            this.log.debug(s, throwable);
-    }
-
-
-    @Override
-    public boolean isDebugEnabled (Marker marker) {
-        return this.log.isDebugEnabled(marker);
-    }
-
-
-    @Override
-    public void debug (Marker marker, String s) {
-        if (DEBUG)
-            this.log.debug(marker, s);
-    }
-
-
-    @Override
-    public void debug (Marker marker, String s, Object o) {
-        if (DEBUG)
-            this.log.debug(marker, s, o);
-    }
-
-
-    @Override
-    public void debug (Marker marker, String s, Object o, Object o2) {
-        if (DEBUG)
-            this.log.debug(marker, s, o, o2);
-    }
-
-
-    @Override
-    public void debug (Marker marker, String s, Object ... objects) {
-        if (DEBUG)
-            this.log.debug(marker, s, objects);
-    }
-
-
-    @Override
-    public void debug (Marker marker, String s, Throwable throwable) {
-        if (DEBUG)
-            this.log.debug(marker, s, throwable);
-    }
-
-
-    @Override
-    public boolean isInfoEnabled () {
-        return this.log.isInfoEnabled();
-    }
-
-
-    @Override
-    public void info (String s) {
-        this.log.info(s);
-    }
-
-
-    @Override
-    public void info (String s, Object o) {
-        this.log.info(s, o);
-    }
-
-
-    @Override
-    public void info (String s, Object o, Object o2) {
-        this.log.info(s, o, o2);
-    }
-
-
-    @Override
-    public void info (String s, Object ... objects) {
-        this.log.info(s, objects);
-    }
-
-
-    @Override
-    public void info (String s, Throwable throwable) {
-        this.log.info(s, throwable);
-    }
-
-
-    @Override
-    public boolean isInfoEnabled (Marker marker) {
-        return this.log.isInfoEnabled(marker);
-    }
-
-
-    @Override
-    public void info (Marker marker, String s) {
-        this.log.info(marker, s);
-    }
-
-
-    @Override
-    public void info (Marker marker, String s, Object o) {
-        this.log.info(marker, s, o);
-    }
-
-
-    @Override
-    public void info (Marker marker, String s, Object o, Object o2) {
-        this.log.info(marker, s, o, o2);
-    }
-
-
-    @Override
-    public void info (Marker marker, String s, Object ... objects) {
-        this.log.info(marker, s, objects);
-    }
-
-
-    @Override
-    public void info (Marker marker, String s, Throwable throwable) {
-        this.log.info(marker, s, throwable);
-    }
-
-
-    @Override
-    public boolean isWarnEnabled () {
-        return this.log.isWarnEnabled();
-    }
-
-
-    @Override
-    public void warn (String s) {
-        this.log.warn(s);
-    }
-
-
-    @Override
-    public void warn (String s, Object o) {
-        this.log.warn(s, o);
-    }
-
-
-    @Override
-    public void warn (String s, Object ... objects) {
-        this.log.warn(s, objects);
-    }
-
-
-    @Override
-    public void warn (String s, Object o, Object o2) {
-        this.log.warn(s, o, o2);
-    }
-
-
-    @Override
-    public void warn (String s, Throwable throwable) {
-        this.log.warn(s, throwable);
-    }
-
-
-    @Override
-    public boolean isWarnEnabled (Marker marker) {
-        return this.log.isTraceEnabled(marker);
-    }
-
-
-    @Override
-    public void warn (Marker marker, String s) {
-        this.log.warn(marker, s);
-    }
-
-
-    @Override
-    public void warn (Marker marker, String s, Object o) {
-        this.log.warn(marker, s, o);
-    }
-
-
-    @Override
-    public void warn (Marker marker, String s, Object o, Object o2) {
-        this.log.warn(marker, s, o, o2);
-    }
-
-
-    @Override
-    public void warn (Marker marker, String s, Object ... objects) {
-        this.log.warn(marker, s, objects);
-    }
-
-
-    @Override
-    public void warn (Marker marker, String s, Throwable throwable) {
-        this.log.warn(marker, s, throwable);
-    }
-
-
-    @Override
-    public boolean isErrorEnabled () {
-        return this.log.isErrorEnabled();
-    }
-
-
-    @Override
-    public void error (String s) {
-        this.log.error(s);
-    }
-
-
-    @Override
-    public void error (String s, Object o) {
-        this.log.error(s, o);
-    }
-
-
-    @Override
-    public void error (String s, Object o, Object o2) {
-        this.log.error(s, o, o2);
-    }
-
-
-    @Override
-    public void error (String s, Object ... objects) {
-        this.log.error(s, objects);
-    }
-
-
-    @Override
-    public void error (String s, Throwable throwable) {
-        this.log.error(s, throwable);
-    }
-
-
-    @Override
-    public boolean isErrorEnabled (Marker marker) {
-        return this.log.isErrorEnabled(marker);
-    }
-
-
-    @Override
-    public void error (Marker marker, String s) {
-        this.log.error(marker, s);
-    }
-
-
-    @Override
-    public void error (Marker marker, String s, Object o) {
-        this.log.error(marker, s, o);
-    }
-
-
-    @Override
-    public void error (Marker marker, String s, Object o, Object o2) {
-        this.log.error(marker, s, o, o2);
-    }
-
-
-    @Override
-    public void error (Marker marker, String s, Object ... objects) {
-        this.log.error(marker, s, objects);
-    }
-
-
-    @Override
-    public void error (Marker marker, String s, Throwable throwable) {
-        this.log.error(marker, s, throwable);
-    }
-}
diff --git a/core/src/main/java/de/ids_mannheim/korap/utils/StringUtils.java b/core/src/main/java/de/ids_mannheim/korap/utils/StringUtils.java
index 5aa6a5e..99c9578 100644
--- a/core/src/main/java/de/ids_mannheim/korap/utils/StringUtils.java
+++ b/core/src/main/java/de/ids_mannheim/korap/utils/StringUtils.java
@@ -1,15 +1,15 @@
 package de.ids_mannheim.korap.utils;
 
 import org.apache.commons.lang.StringEscapeUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
 import java.util.*;
 
 public class StringUtils {
-    private final static Logger jlog = LoggerFactory
+    private final static Logger jlog = LogManager
             .getLogger(StringUtils.class);
 
     private static final String SEP = ";";
diff --git a/core/src/main/java/de/ids_mannheim/korap/utils/TimeUtils.java b/core/src/main/java/de/ids_mannheim/korap/utils/TimeUtils.java
index cac76bb..cd0a1ca 100644
--- a/core/src/main/java/de/ids_mannheim/korap/utils/TimeUtils.java
+++ b/core/src/main/java/de/ids_mannheim/korap/utils/TimeUtils.java
@@ -1,13 +1,13 @@
 package de.ids_mannheim.korap.utils;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.joda.time.DateTime;
 import org.joda.time.DateTimeZone;
 import org.joda.time.LocalDate;
 import org.joda.time.format.DateTimeFormat;
 import org.joda.time.format.DateTimeFormatter;
 import org.joda.time.format.ISODateTimeFormat;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 import java.math.BigDecimal;
 import java.math.RoundingMode;
@@ -30,7 +30,7 @@
     private static DateTimeFormatter dtf = DateTimeFormat
             .forPattern("dd/MM/yyyy");
     private static final DateTimeZone dtz = DateTimeZone.forID("Europe/Berlin");
-    private static Logger jlog = LoggerFactory.getLogger(TimeUtils.class);
+    private static Logger jlog = LogManager.getLogger(TimeUtils.class);
 
 
     public static int convertTimeToSeconds (String expirationVal) {
@@ -38,7 +38,7 @@
         int finIndex = expirationVal.length() - 1;
         char entity = expirationVal.charAt(finIndex);
         int returnSec = Integer.valueOf(expirationVal.substring(0, finIndex));
-        jlog.debug("setting time value to {} with time in {}", returnSec,
+        jlog.debug("setting time value to "+returnSec+" with time in "+
                 entity);
         switch (entity) {
             case 'D':
diff --git a/core/src/main/java/de/ids_mannheim/korap/web/SearchKrill.java b/core/src/main/java/de/ids_mannheim/korap/web/SearchKrill.java
index 231e782..4317308 100644
--- a/core/src/main/java/de/ids_mannheim/korap/web/SearchKrill.java
+++ b/core/src/main/java/de/ids_mannheim/korap/web/SearchKrill.java
@@ -8,9 +8,9 @@
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.lucene.store.MMapDirectory;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 import de.ids_mannheim.korap.Krill;
 import de.ids_mannheim.korap.KrillCollection;
@@ -29,7 +29,7 @@
  * @author Nils Diewald
  */
 public class SearchKrill {
-    private final static Logger jlog = LoggerFactory
+    private final static Logger jlog = LogManager
             .getLogger(SearchKrill.class);
 
     // Temporary - shouldn't be here.
@@ -59,7 +59,7 @@
             };
         }
         catch (IOException e) {
-            jlog.error("Unable to loadSubTypes index: {}", e.getMessage());
+            jlog.error("Unable to loadSubTypes index:"+ e.getMessage());
         };
     };
 
diff --git a/full/Changes b/full/Changes
index d3d8dab..9e6e09e 100644
--- a/full/Changes
+++ b/full/Changes
@@ -1,5 +1,5 @@
 version 0.60.4
-03/07/2018
+04/07/2018
     - implemented OAuth2 authorization code request with OpenID Authentication (margaretha)
     - enabled OAuth2 authorization without OpenID authentication using Nimbus library (margaretha)
     - implemented response handler for OpenID authentication errors in authorization requests (margaretha)
@@ -17,6 +17,8 @@
     - updated client registration requirement to allow desktop applications (margaretha)
     - fixed RSA key configuration (margaretha)
     - merged OAuth2 client deregistration controllers (margaretha)
+    - fixed OAuth2 client unique URL-hashcode (margaretha)
+    - migrated logging to log4j 2 and adapted java.util.logging to log4j(margaretha)
     
 version 0.60.3
 06/06/2018
diff --git a/full/pom.xml b/full/pom.xml
index db4c3e2..9f0b6cd 100644
--- a/full/pom.xml
+++ b/full/pom.xml
@@ -32,9 +32,6 @@
 		<testResources>
 			<testResource>
 				<directory>src/test/resources</directory>
-				<!-- <filtering>true</filtering> <includes> <include>**/*.key</include> 
-					<include>**/*.token</include> <include>**/*.xml</include> <include>**/*.conf</include> 
-					<include>**/*.info</include> <include>**/*.properties</include> </includes> -->
 			</testResource>
 			<testResource>
 				<directory>src/main/resources</directory>
@@ -86,9 +83,11 @@
 					<reuseForks>false</reuseForks>
 					<forkCount>2</forkCount>
 					<threadCount>4</threadCount>
-					<argLine>-Xmx512m -XX:MaxPermSize=256m</argLine>
+					<argLine>-Xmx512m -XX:MaxPermSize=256m 
+						-Djava.util.logging.manager=org.apache.logging.log4j.jul.LogManager</argLine>
 					<excludes>
 						<exclude>de/ids_mannheim/korap/authentication/*.java</exclude>
+						<exclude>de/ids_mannheim/korap/web/controller/TokenExpiryTest.java</exclude>
 					</excludes>
 					<includes>
 						<include>de/ids_mannheim/korap/**/*.java</include>
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 1c22fea..a399c5f 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
@@ -12,8 +12,8 @@
 import javax.ws.rs.core.HttpHeaders;
 import javax.ws.rs.core.MultivaluedMap;
 
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.springframework.beans.factory.annotation.Autowired;
 
 // import com.novell.ldap.*; search() funktioniert nicht korrekt, ausgewechselt gegen unboundID's Bibliothek 20.04.17/FB
@@ -62,7 +62,7 @@
  */
 public class KustvaktAuthenticationManager extends AuthenticationManagerIface {
 
-	private static Logger jlog = LoggerFactory.getLogger(KustvaktAuthenticationManager.class);
+	private static Logger jlog = LogManager.getLogger(KustvaktAuthenticationManager.class);
 	private EncryptionIface crypto;
 	private EntityHandlerIface entHandler;
 	@Autowired
@@ -233,7 +233,7 @@
 	    {
 	    	// to be absolutely sure:
 	    	user.setCorpusAccess(User.CorpusAccess.FREE);
-	    	jlog.debug("setAccessAndLocation: DemoUser: location=%s, access=%s.\n", user.locationtoString(), user.accesstoString());
+	    	jlog.debug("setAccessAndLocation: DemoUser: location="+user.locationtoString()+" access="+ user.accesstoString());
 	     	return;
 	    }
 		
@@ -266,7 +266,7 @@
 			user.setLocation(location);
 			user.setCorpusAccess(corpusAccess);
 	    	
-	    	jlog.debug("setAccessAndLocation: KorAPUser: location=%s, access=%s.\n", user.locationtoString(), user.accesstoString());
+	    	jlog.debug("setAccessAndLocation: KorAPUser: location="+user.locationtoString()+", access="+ user.accesstoString());
 
 		}
 	} // getAccess
@@ -371,9 +371,9 @@
 				URIParam param = (URIParam) user.getField(URIParam.class);
 
 				if (param.hasValues()) {
-					jlog.debug("Account is not yet activated for user '{}'", user.getUsername());
+					jlog.debug("Account is not yet activated for user '"+user.getUsername()+"'" );
 					if (TimeUtils.getNow().isAfter(param.getUriExpiration())) {
-						jlog.error("URI token is expired. Deleting account for user {}", user.getUsername());
+						jlog.error("URI token is expired. Deleting account for user "+ user.getUsername());
 						deleteAccount(user);
 						throw new WrappedException(
 								new KustvaktException(unknown.getId(), StatusCodes.EXPIRED,
@@ -384,7 +384,7 @@
 							new KustvaktException(unknown.getId(), StatusCodes.ACCOUNT_NOT_CONFIRMED),
 							StatusCodes.LOGIN_FAILED, username);
 				}
-				jlog.error("ACCESS DENIED: account not active for '{}'", unknown.getUsername());
+				jlog.error("ACCESS DENIED: account not active for '"+unknown.getUsername()+"'");
 				throw new WrappedException(new KustvaktException(unknown.getId(), StatusCodes.ACCOUNT_DEACTIVATED),
 						StatusCodes.LOGIN_FAILED, username);
 			}
@@ -434,8 +434,7 @@
 			int ret = LdapAuth3.login(username, password, config.getLdapConfig());
 			System.out.printf("Debug: autenticationIdM: Ldap.login(%s) returns: %d.\n", username, ret);
 			if (ret != LdapAuth3.LDAP_AUTH_ROK) {
-				jlog.error("LdapAuth3.login(username='{}') returns '{}'='{}'!", username, ret,
-						LdapAuth3.getErrMessage(ret));
+				jlog.error("LdapAuth3.login(username='"+username+"') returns '"+ret+"'='"+LdapAuth3.getErrMessage(ret)+"'!");
 
 				// mask exception to disable user guessing in possible attacks
 				/*
@@ -448,7 +447,7 @@
 			}
 		} catch (LDAPException e) {
 
-			jlog.error("Error: username='{}' -> '{}'!", username, e);
+			jlog.error("Error: username='"+username+"' -> '"+e+"'!");
 			// mask exception to disable user guessing in possible attacks
 			/*
 			 * by Hanl: throw new WrappedException(new
@@ -540,11 +539,11 @@
 		try {
 			user = entHandler.getAccount(username);
 		} catch (EmptyResultException e) {
-			jlog.debug("user does not exist ({})", username);
+			jlog.debug("user does not exist: "+ username);
 			return false;
 
 		} catch (KustvaktException e) {
-			jlog.error("KorAPException", e.string());
+			jlog.error("KorAPException "+ e.string());
 			return false;
 			// throw new KustvaktException(username,
 			// StatusCodes.ILLEGAL_ARGUMENT,
@@ -590,7 +589,7 @@
 
 		KorAPUser u = (KorAPUser) user;
 		u.setAccountLocked(true);
-		jlog.info("locking account for user: {}", user.getUsername());
+		jlog.info("locking account for user: "+ user.getUsername());
 		entHandler.updateAccount(u);
 	}
 
@@ -628,7 +627,7 @@
 			validator.validateEntry(username, Attributes.USERNAME);
 			validator.validateEntry(newPassphrase, Attributes.PASSWORD);
 		} catch (KustvaktException e) {
-			jlog.error("Error: {}", e.string());
+			jlog.error("Error: "+ e.string());
 			throw new WrappedException(
 					new KustvaktException(username, StatusCodes.ILLEGAL_ARGUMENT, "password invalid", newPassphrase),
 					StatusCodes.PASSWORD_RESET_FAILED, username, newPassphrase);
@@ -649,14 +648,14 @@
 					new KustvaktException(username, StatusCodes.EXPIRED, "URI fragment expired", uriFragment),
 					StatusCodes.PASSWORD_RESET_FAILED, username, uriFragment);
 		else if (result == 1)
-			jlog.info("successfully reset password for user {}", username);
+			jlog.info("successfully reset password for user "+ username);
 	}
 
 	public void confirmRegistration(String uriFragment, String username) throws KustvaktException {
 		try {
 			validator.validateEntry(username, Attributes.USERNAME);
 		} catch (KustvaktException e) {
-			jlog.error("Error: {}", e.string());
+			jlog.error("Error: "+ e.string());
 			throw new WrappedException(e, StatusCodes.ACCOUNT_CONFIRMATION_FAILED, username, uriFragment);
 		}
 		int r = entHandler.activateAccount(username, uriFragment);
@@ -672,7 +671,7 @@
 			throw new WrappedException(new KustvaktException(user.getId(), StatusCodes.EXPIRED),
 					StatusCodes.ACCOUNT_CONFIRMATION_FAILED, username, uriFragment);
 		} else if (r == 1)
-			jlog.info("successfully confirmed user registration for user {}", username);
+			jlog.info("successfully confirmed user registration for user "+ username);
 		// register successful audit!
 	}
 
@@ -727,7 +726,7 @@
 			UserSettings settings = new UserSettings();
 			settings.read(safeMap, true);
 
-			jlog.info("Creating new user account for user {}", user.getUsername());
+			jlog.info("Creating new user account for user "+ user.getUsername());
 			entHandler.createAccount(user);
 //			if (user.isSystemAdmin() && user instanceof KorAPUser) {
 //				adminDao.addAccount(user);
@@ -744,7 +743,7 @@
 			assert dao != null;
 			dao.store(settings);
 		} catch (KustvaktException e) {
-			jlog.error("Error: {}", e.string());
+			jlog.error("Error: "+ e.string());
 			throw new WrappedException(e, StatusCodes.CREATE_ACCOUNT_FAILED, user.toString());
 		}
 
@@ -754,7 +753,7 @@
 
 	// todo:
 	private ShibbolethUser createShibbUserAccount(Map<String, Object> attributes) throws KustvaktException {
-		jlog.debug("creating shibboleth user account for user attr: {}", attributes);
+		jlog.debug("creating shibboleth user account for user attr: "+ attributes);
 		Map<String, Object> safeMap = validator.validateMap(attributes);
 
 		// todo eppn non-unique.join with idp or use persistent_id as username
@@ -841,7 +840,7 @@
 			try {
 				result = entHandler.updateAccount(user) > 0;
 			} catch (KustvaktException e) {
-				jlog.error("Error: {}", e.string());
+				jlog.error("Error: "+ e.string());
 				throw new WrappedException(e, StatusCodes.UPDATE_ACCOUNT_FAILED);
 			}
 		}
@@ -861,7 +860,7 @@
 			try {
 				result = entHandler.deleteAccount(user.getId()) > 0;
 			} catch (KustvaktException e) {
-				jlog.error("Error: {}", e.string());
+				jlog.error("Error: "+ e.string());
 				throw new WrappedException(e, StatusCodes.DELETE_ACCOUNT_FAILED);
 			}
 		}
@@ -906,7 +905,7 @@
 		try {
 			entHandler.updateAccount(user);
 		} catch (KustvaktException e) {
-			jlog.error("Error ", e.string());
+			jlog.error("Error "+ e.string());
 			throw new WrappedException(e, StatusCodes.PASSWORD_RESET_FAILED);
 		}
 		return new Object[] { uritoken, TimeUtils.format(param.getUriExpiration()) };
@@ -927,7 +926,7 @@
 						clazz.getSimpleName());
 			return data;
 		} catch (KustvaktException e) {
-			jlog.error("Error during user data retrieval: {}", e.getEntity());
+			jlog.error("Error during user data retrieval: "+ e.getEntity());
 			throw new WrappedException(e, StatusCodes.GET_ACCOUNT_FAILED);
 		}
 	}
@@ -942,7 +941,7 @@
 			if (dao != null)
 				dao.update(data);
 		} catch (KustvaktException e) {
-			jlog.error("Error during update of user data!", e.getEntity());
+			jlog.error("Error during update of user data! "+ e.getEntity());
 			throw new WrappedException(e, StatusCodes.UPDATE_ACCOUNT_FAILED);
 		}
 	}
diff --git a/full/src/main/java/de/ids_mannheim/korap/authentication/LoginCounter.java b/full/src/main/java/de/ids_mannheim/korap/authentication/LoginCounter.java
index 60289ce..7da50b6 100644
--- a/full/src/main/java/de/ids_mannheim/korap/authentication/LoginCounter.java
+++ b/full/src/main/java/de/ids_mannheim/korap/authentication/LoginCounter.java
@@ -2,20 +2,21 @@
 
 import de.ids_mannheim.korap.config.KustvaktConfiguration;
 import de.ids_mannheim.korap.utils.TimeUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 import java.util.Arrays;
 import java.util.HashMap;
 import java.util.Map;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
 /**
  * @author hanl
  * @date 11/11/2014
  */
 public class LoginCounter {
 
-    private static Logger jlog = LoggerFactory.getLogger(LoginCounter.class);
+    private static Logger jlog = LogManager.getLogger(LoginCounter.class);
     private final Map<String, Long[]> failedLogins;
     private KustvaktConfiguration config;
 
@@ -45,7 +46,7 @@
         set[1] = expires;
 
         failedLogins.put(username, set);
-        jlog.warn("user failed to login ({}) ",
+        jlog.warn("user failed to login "+
                 Arrays.asList(failedLogins.get(username)));
     }
 
diff --git a/full/src/main/java/de/ids_mannheim/korap/authentication/SessionAuthentication.java b/full/src/main/java/de/ids_mannheim/korap/authentication/SessionAuthentication.java
index 23e83c3..1bb4c6d 100644
--- a/full/src/main/java/de/ids_mannheim/korap/authentication/SessionAuthentication.java
+++ b/full/src/main/java/de/ids_mannheim/korap/authentication/SessionAuthentication.java
@@ -10,9 +10,10 @@
 import de.ids_mannheim.korap.config.Attributes;
 import de.ids_mannheim.korap.user.User;
 import de.ids_mannheim.korap.utils.TimeUtils;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.joda.time.DateTime;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 import java.util.Map;
 import java.util.concurrent.ScheduledThreadPoolExecutor;
@@ -27,7 +28,7 @@
  */
 public class SessionAuthentication implements AuthenticationIface {
 
-    private static final Logger jlog = LoggerFactory
+    private static final Logger jlog = LogManager
             .getLogger(SessionAuthentication.class);
     public static SessionFactory sessions;
     private ScheduledThreadPoolExecutor scheduled;
@@ -52,7 +53,7 @@
     @Override
     public TokenContext getTokenContext(String authenticationToken)
             throws KustvaktException {
-        jlog.debug("retrieving user session for user '{}'", authenticationToken);
+        jlog.debug("retrieving user session for user "+ authenticationToken);
         return this.sessions.getSession(authenticationToken);
     }
 
diff --git a/full/src/main/java/de/ids_mannheim/korap/authentication/SessionFactory.java b/full/src/main/java/de/ids_mannheim/korap/authentication/SessionFactory.java
index 7292ad0..6d425c2 100644
--- a/full/src/main/java/de/ids_mannheim/korap/authentication/SessionFactory.java
+++ b/full/src/main/java/de/ids_mannheim/korap/authentication/SessionFactory.java
@@ -6,9 +6,10 @@
 import de.ids_mannheim.korap.user.DemoUser;
 import de.ids_mannheim.korap.utils.ConcurrentMultiMap;
 import de.ids_mannheim.korap.utils.TimeUtils;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.joda.time.DateTime;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 import org.springframework.cache.annotation.CacheEvict;
 import org.springframework.cache.annotation.Cacheable;
 
@@ -31,7 +32,7 @@
 //todo: use simple ehcache!
 public class SessionFactory implements Runnable {
 
-    private static Logger jlog = LoggerFactory.getLogger(SessionFactory.class);
+    private static Logger jlog = LogManager.getLogger(SessionFactory.class);
 
     public static ConcurrentMap<String, TokenContext> sessionsObject;
     public static ConcurrentMap<String, DateTime> timeCheck;
@@ -42,7 +43,7 @@
 
 
     public SessionFactory (boolean multipleEnabled, int inactive) {
-        jlog.debug("allow multiple sessions per user: '{}'", multipleEnabled);
+        jlog.debug("allow multiple sessions per user: "+ multipleEnabled);
         this.multipleEnabled = multipleEnabled;
         this.inactive = inactive;
         this.sessionsObject = new ConcurrentHashMap<>();
@@ -62,7 +63,7 @@
     // todo: remove this!
     @Cacheable("session")
     public TokenContext getSession (String token) throws KustvaktException {
-        jlog.debug("logged in users: {}", loggedInRecord);
+        jlog.debug("logged in users: "+ loggedInRecord);
         TokenContext context = sessionsObject.get(token);
         if (context != null) {
             // fixme: set context to respecitve expiratin interval and return context. handler checks expiration later!
@@ -137,7 +138,7 @@
                 return true;
             }
             else
-                jlog.debug("user with token {} has an invalid session", token);
+                jlog.debug("user with token "+token+" has an invalid session");
         }
         return false;
     }
@@ -153,7 +154,7 @@
         for (Entry<String, DateTime> entry : timeCheck.entrySet()) {
             if (!isUserSessionValid(entry.getKey())) {
                 TokenContext user = sessionsObject.get(entry.getKey());
-                jlog.trace("removing user session for user {}",
+                jlog.trace("removing user session for user "+
                         user.getUsername());
                 inactive.add(user.getUsername());
                 removeSession(entry.getKey());
@@ -161,7 +162,7 @@
         }
         // fixme: not doing anything!
         if (inactive.size() > 0)
-            jlog.trace("removing inactive user session for users '{}' ",
+            jlog.trace("removing inactive user session for users "+
                     inactive);
     }
 
@@ -173,6 +174,6 @@
     public void run () {
         timeoutMaintenance();
         if (loggedInRecord.size() > 0)
-            jlog.debug("logged users: {}", loggedInRecord.toString());
+            jlog.debug("logged users: "+ loggedInRecord.toString());
     }
 }
diff --git a/full/src/main/java/de/ids_mannheim/korap/cache/ResourceCache.java b/full/src/main/java/de/ids_mannheim/korap/cache/ResourceCache.java
index da3e40f..8e5871c 100644
--- a/full/src/main/java/de/ids_mannheim/korap/cache/ResourceCache.java
+++ b/full/src/main/java/de/ids_mannheim/korap/cache/ResourceCache.java
@@ -11,11 +11,12 @@
 import de.ids_mannheim.korap.user.User;
 import net.sf.ehcache.CacheManager;
 import net.sf.ehcache.Element;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 import java.util.Collection;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+
 /**
  * @author hanl
  * @date 23/03/2014
@@ -31,7 +32,7 @@
 @SuppressWarnings("all")
 public class ResourceCache extends KustvaktCacheable {
 
-    private static Logger jlog = LoggerFactory.getLogger(ResourceCache.class);
+    private static Logger jlog = LogManager.getLogger(ResourceCache.class);
 
     public ResourceCache () {
         super("resources", "key:resources");
diff --git a/full/src/main/java/de/ids_mannheim/korap/encryption/KustvaktEncryption.java b/full/src/main/java/de/ids_mannheim/korap/encryption/KustvaktEncryption.java
index b73a524..2ae1a32 100644
--- a/full/src/main/java/de/ids_mannheim/korap/encryption/KustvaktEncryption.java
+++ b/full/src/main/java/de/ids_mannheim/korap/encryption/KustvaktEncryption.java
@@ -8,9 +8,9 @@
 import org.apache.commons.codec.EncoderException;
 import org.apache.commons.codec.binary.Base64;
 import org.apache.commons.lang.RandomStringUtils;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.mindrot.jbcrypt.BCrypt;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 import de.ids_mannheim.korap.config.FullConfiguration;
 import de.ids_mannheim.korap.interfaces.EncryptionIface;
@@ -18,7 +18,7 @@
 public class KustvaktEncryption implements EncryptionIface {
 
     private static final String ALGORITHM = "SHA-256";
-    private static Logger jlog = LoggerFactory
+    private static Logger jlog = LogManager
             .getLogger(KustvaktEncryption.class);
 
     private final FullConfiguration config;
@@ -83,7 +83,7 @@
                 hashString = bcryptHash(input, salt);
                 break;
             default:
-                jlog.warn("Invalid value: {}", config.getEncryption());
+                jlog.warn("Invalid value: "+ config.getEncryption());
                 break;
         }
         return hashString;
diff --git a/full/src/main/java/de/ids_mannheim/korap/handlers/BatchBuilder.java b/full/src/main/java/de/ids_mannheim/korap/handlers/BatchBuilder.java
index 0a83118..bdc622d 100644
--- a/full/src/main/java/de/ids_mannheim/korap/handlers/BatchBuilder.java
+++ b/full/src/main/java/de/ids_mannheim/korap/handlers/BatchBuilder.java
@@ -1,7 +1,7 @@
 package de.ids_mannheim.korap.handlers;
 
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.springframework.dao.DataAccessException;
 import org.springframework.jdbc.core.JdbcOperations;
 import org.springframework.jdbc.core.RowMapper;
@@ -21,7 +21,7 @@
     private static final int SMALL_MEDIUM_BATCH = 6;
     private static final int MEDIUM_BATCH = 8;
     private static final int LARGE_BATCH = 12;
-    private Logger log = LoggerFactory.getLogger(BatchBuilder.class);
+    private Logger log = LogManager.getLogger(BatchBuilder.class);
 
     private JdbcOperations operations;
 
diff --git a/full/src/main/java/de/ids_mannheim/korap/handlers/EntityDao.java b/full/src/main/java/de/ids_mannheim/korap/handlers/EntityDao.java
index fd7fdc2..ffc35e5 100644
--- a/full/src/main/java/de/ids_mannheim/korap/handlers/EntityDao.java
+++ b/full/src/main/java/de/ids_mannheim/korap/handlers/EntityDao.java
@@ -6,8 +6,8 @@
 import java.util.List;
 import java.util.Map;
 
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.springframework.dao.DataAccessException;
 import org.springframework.dao.DuplicateKeyException;
 import org.springframework.dao.EmptyResultDataAccessException;
@@ -41,7 +41,7 @@
  */
 public class EntityDao implements EntityHandlerIface, KustvaktBaseDaoInterface {
 
-    private static Logger jlog = LoggerFactory.getLogger(EntityDao.class);
+    private static Logger jlog = LogManager.getLogger(EntityDao.class);
     private NamedParameterJdbcTemplate jdbcTemplate;
 
 
@@ -67,7 +67,7 @@
             return user;
         	}
         catch (EmptyResultDataAccessException ae) {
-            jlog.warn("No user found for name '{}'", username);
+            jlog.warn("No user found for name "+ username);
         	}
         catch (DataAccessException e) {
             jlog.warn("Could not retrieve user for name: " + username, e);
@@ -261,7 +261,7 @@
             user.setId(holder.getKey().intValue());
         }
         catch (DuplicateKeyException e) {
-            jlog.error("Could not create user account with username: {}",
+            jlog.error("Could not create user account with username: "+
                     user.getUsername());
             throw new DatabaseException(e, user.getUsername(), "korap_users",
                     StatusCodes.DB_ENTRY_EXISTS, "Username exists.",
diff --git a/full/src/main/java/de/ids_mannheim/korap/handlers/OAuthDb.java b/full/src/main/java/de/ids_mannheim/korap/handlers/OAuthDb.java
index 04736b0..a1ae65c 100644
--- a/full/src/main/java/de/ids_mannheim/korap/handlers/OAuthDb.java
+++ b/full/src/main/java/de/ids_mannheim/korap/handlers/OAuthDb.java
@@ -1,36 +1,37 @@
 package de.ids_mannheim.korap.handlers;
 
-import de.ids_mannheim.korap.config.ClientInfo;
-import de.ids_mannheim.korap.constant.TokenType;
-import de.ids_mannheim.korap.exceptions.KustvaktException;
-import de.ids_mannheim.korap.exceptions.StatusCodes;
-import de.ids_mannheim.korap.exceptions.DatabaseException;
-import de.ids_mannheim.korap.interfaces.db.PersistenceClient;
-import de.ids_mannheim.korap.security.context.TokenContext;
-import de.ids_mannheim.korap.config.Attributes;
-import de.ids_mannheim.korap.user.User;
-import de.ids_mannheim.korap.utils.BooleanUtils;
-import de.ids_mannheim.korap.utils.TimeUtils;
-import edu.emory.mathcs.backport.java.util.Collections;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Timestamp;
+import java.util.List;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.springframework.dao.DataAccessException;
 import org.springframework.dao.EmptyResultDataAccessException;
 import org.springframework.jdbc.core.RowMapper;
 import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
 import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
 
-import java.sql.ResultSet;
-import java.sql.SQLException;
-import java.sql.Timestamp;
-import java.util.List;
+import de.ids_mannheim.korap.config.Attributes;
+import de.ids_mannheim.korap.config.ClientInfo;
+import de.ids_mannheim.korap.constant.TokenType;
+import de.ids_mannheim.korap.exceptions.DatabaseException;
+import de.ids_mannheim.korap.exceptions.KustvaktException;
+import de.ids_mannheim.korap.exceptions.StatusCodes;
+import de.ids_mannheim.korap.interfaces.db.PersistenceClient;
+import de.ids_mannheim.korap.security.context.TokenContext;
+import de.ids_mannheim.korap.user.User;
+import de.ids_mannheim.korap.utils.BooleanUtils;
+import de.ids_mannheim.korap.utils.TimeUtils;
+import edu.emory.mathcs.backport.java.util.Collections;
 
 /**
  * Created by hanl on 7/14/14.
  */
 public class OAuthDb {
 
-    private static final Logger jlog = LoggerFactory.getLogger(OAuthDb.class);
+    private static final Logger jlog = LogManager.getLogger(OAuthDb.class);
     private NamedParameterJdbcTemplate jdbcTemplate;
 
 
@@ -64,7 +65,7 @@
                     });
         }
         catch (EmptyResultDataAccessException ex) {
-            jlog.error("'{}' client found", clientid, ex.fillInStackTrace());
+            jlog.error(clientid+" client found "+ ex.fillInStackTrace());
             return null;
         }
     }
@@ -98,7 +99,7 @@
             this.jdbcTemplate.update(tokens, source);
         }
         catch (DataAccessException e) {
-            jlog.error("authorization could not be revoked for user '{}'",
+            jlog.error("authorization could not be revoked for user "+
                     user.getUsername());
             return false;
         }
@@ -126,7 +127,7 @@
         }
         catch (DataAccessException e) {
             e.printStackTrace();
-            jlog.error("token '{}' could not be added for user '{}'", token,
+            jlog.error("token "+token+" could not be added for user "+ 
                     userid);
             return false;
         }
@@ -144,11 +145,11 @@
             return this.jdbcTemplate.queryForObject(sql, s, String.class);
         }
         catch (EmptyResultDataAccessException ex) {
-            jlog.error("no token found for user '{}'", userid);
+            jlog.error("no token found for user "+ userid);
             return null;
         }
         catch (DataAccessException ex) {
-            jlog.error("token retrieval failed for user '{}'", userid);
+            jlog.error("token retrieval failed for user "+ userid);
             return null;
         }
     }
@@ -219,12 +220,12 @@
             return context;
         }
         catch (EmptyResultDataAccessException ee) {
-            jlog.error("no context found for token '{}'", token);
+            jlog.error("no context found for token "+ token);
             revokeToken(token);
             throw new KustvaktException(StatusCodes.EXPIRED, "token", token);
         }
         catch (DataAccessException e) {
-            jlog.error("token context retrieval failed for '{}'", token);
+            jlog.error("token context retrieval failed for "+ token);
             throw new KustvaktException(StatusCodes.ILLEGAL_ARGUMENT,
                     "invalid token", token);
         }
@@ -246,7 +247,7 @@
         }
         catch (DataAccessException e) {
             e.printStackTrace();
-            jlog.error("removing client '{}' failed", info.getClient_id());
+            jlog.error("removing client "+info.getClient_id()+" failed");
             throw new DatabaseException(new KustvaktException(user.getId(),
                     StatusCodes.ILLEGAL_ARGUMENT, "arguments given not valid",
                     info.toJSON()), StatusCodes.CLIENT_DEREGISTRATION_FAILED,
@@ -272,7 +273,7 @@
         }
         catch (DataAccessException e) {
             e.printStackTrace();
-            jlog.error("registering client '{}' failed", info.getClient_id());
+            jlog.error("registering client "+info.getClient_id()+" failed");
             throw new DatabaseException(new KustvaktException(user.getId(),
                     StatusCodes.ILLEGAL_ARGUMENT, "arguments given not valid",
                     info.toJSON()), StatusCodes.CLIENT_REGISTRATION_FAILED,
diff --git a/full/src/main/java/de/ids_mannheim/korap/handlers/ResourceDao.java b/full/src/main/java/de/ids_mannheim/korap/handlers/ResourceDao.java
index 1bbabae..9cf7165 100644
--- a/full/src/main/java/de/ids_mannheim/korap/handlers/ResourceDao.java
+++ b/full/src/main/java/de/ids_mannheim/korap/handlers/ResourceDao.java
@@ -4,8 +4,8 @@
 import java.util.HashMap;
 import java.util.List;
 
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.springframework.dao.DataAccessException;
 import org.springframework.dao.IncorrectResultSizeDataAccessException;
 import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
@@ -31,7 +31,7 @@
 public class ResourceDao<T extends KustvaktResource>
         implements ResourceOperationIface<T> {
 
-    private static Logger log = LoggerFactory.getLogger(ResourceDao.class);
+    private static Logger log = LogManager.getLogger(ResourceDao.class);
     protected final NamedParameterJdbcTemplate jdbcTemplate;
 
 
diff --git a/full/src/main/java/de/ids_mannheim/korap/handlers/UserSettingsDao.java b/full/src/main/java/de/ids_mannheim/korap/handlers/UserSettingsDao.java
index dbd3c25..ba2f927 100644
--- a/full/src/main/java/de/ids_mannheim/korap/handlers/UserSettingsDao.java
+++ b/full/src/main/java/de/ids_mannheim/korap/handlers/UserSettingsDao.java
@@ -7,8 +7,9 @@
 import de.ids_mannheim.korap.interfaces.db.UserDataDbIface;
 import de.ids_mannheim.korap.user.User;
 import de.ids_mannheim.korap.user.UserSettings;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.springframework.dao.DataAccessException;
 import org.springframework.dao.EmptyResultDataAccessException;
 import org.springframework.jdbc.core.RowMapper;
@@ -26,7 +27,7 @@
  */
 public class UserSettingsDao implements UserDataDbIface<UserSettings> {
 
-    private static final Logger jlog = LoggerFactory
+    private static final Logger jlog = LogManager
             .getLogger(UserSettingsDao.class);
 
     private final NamedParameterJdbcTemplate jdbcTemplate;
@@ -52,7 +53,7 @@
             return id;
         }
         catch (DataAccessException e) {
-            jlog.error("couldn't store data in db for user with id '{}'",
+            jlog.error("couldn't store data in db for user with id "+
                     data.getUserId());
             return -1;
         }
diff --git a/full/src/main/java/de/ids_mannheim/korap/oauth2/dao/OAuth2ClientDao.java b/full/src/main/java/de/ids_mannheim/korap/oauth2/dao/OAuth2ClientDao.java
index 89f2d49..78c438c 100644
--- a/full/src/main/java/de/ids_mannheim/korap/oauth2/dao/OAuth2ClientDao.java
+++ b/full/src/main/java/de/ids_mannheim/korap/oauth2/dao/OAuth2ClientDao.java
@@ -15,6 +15,7 @@
 import de.ids_mannheim.korap.exceptions.StatusCodes;
 import de.ids_mannheim.korap.oauth2.constant.OAuth2ClientType;
 import de.ids_mannheim.korap.oauth2.entity.OAuth2Client;
+import de.ids_mannheim.korap.oauth2.entity.OAuth2ClientUrl;
 import de.ids_mannheim.korap.oauth2.entity.OAuth2Client_;
 import de.ids_mannheim.korap.utils.ParameterChecker;
 
@@ -44,8 +45,12 @@
         client.setSecret(secretHashcode);
         client.setType(type);
         client.setNative(isNative);
-        client.setUrl(url);
-        client.setUrlHashCode(urlHashCode);
+        if (urlHashCode != 0) {
+            OAuth2ClientUrl clientUrl = new OAuth2ClientUrl();
+            clientUrl.setUrl(url);
+            clientUrl.setUrlHashCode(urlHashCode);
+            client.setClientUrl(clientUrl);
+        }
         client.setRedirectURI(redirectURI);
         client.setRegisteredBy(registeredBy);
         client.setDescription(description);
diff --git a/full/src/main/java/de/ids_mannheim/korap/oauth2/entity/OAuth2Client.java b/full/src/main/java/de/ids_mannheim/korap/oauth2/entity/OAuth2Client.java
index 17f0cb4..0fb0688 100644
--- a/full/src/main/java/de/ids_mannheim/korap/oauth2/entity/OAuth2Client.java
+++ b/full/src/main/java/de/ids_mannheim/korap/oauth2/entity/OAuth2Client.java
@@ -1,10 +1,14 @@
 package de.ids_mannheim.korap.oauth2.entity;
 
+import javax.persistence.CascadeType;
 import javax.persistence.Column;
 import javax.persistence.Entity;
 import javax.persistence.EnumType;
 import javax.persistence.Enumerated;
+import javax.persistence.FetchType;
 import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.OneToOne;
 import javax.persistence.Table;
 
 import de.ids_mannheim.korap.oauth2.constant.OAuth2ClientType;
@@ -30,20 +34,21 @@
     private OAuth2ClientType type;
     @Column(name = "native")
     private boolean isNative;
-    private String url;
-    @Column(name = "url_hashcode")
-    private int urlHashCode;
     @Column(name = "redirect_uri")
     private String redirectURI;
     @Column(name = "registered_by")
     private String registeredBy;
     private String description;
 
+    @OneToOne(fetch = FetchType.LAZY, cascade=CascadeType.ALL)
+    @JoinColumn(name = "url_id")
+    private OAuth2ClientUrl clientUrl;
+
     @Override
     public String toString () {
         return "id=" + id + ", name=" + name + ", secret=" + secret + ", type="
-                + type + ", isNative=" + isNative + ", url=" + url
-                + ", redirectURI=" + redirectURI + ", registeredBy="
-                + registeredBy + ", description=" + description;
+                + type + ", isNative=" + isNative + ", redirectURI="
+                + redirectURI + ", registeredBy=" + registeredBy
+                + ", description=" + description;
     }
 }
diff --git a/full/src/main/java/de/ids_mannheim/korap/oauth2/entity/OAuth2ClientUrl.java b/full/src/main/java/de/ids_mannheim/korap/oauth2/entity/OAuth2ClientUrl.java
new file mode 100644
index 0000000..3396d0b
--- /dev/null
+++ b/full/src/main/java/de/ids_mannheim/korap/oauth2/entity/OAuth2ClientUrl.java
@@ -0,0 +1,30 @@
+package de.ids_mannheim.korap.oauth2.entity;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Table;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @author margaretha
+ *
+ */
+@Getter
+@Setter
+@Entity
+@Table(name = "oauth2_client_url")
+public class OAuth2ClientUrl {
+
+    @Id
+    @Column(name = "url_hashcode")
+    private int urlHashCode;
+    private String url;
+
+    @Override
+    public String toString () {
+        return "url_hashcode="+urlHashCode+", url=" + url;
+    }
+}
diff --git a/full/src/main/java/de/ids_mannheim/korap/oauth2/service/OAuth2AuthorizationService.java b/full/src/main/java/de/ids_mannheim/korap/oauth2/service/OAuth2AuthorizationService.java
index 638415b..ed47976 100644
--- a/full/src/main/java/de/ids_mannheim/korap/oauth2/service/OAuth2AuthorizationService.java
+++ b/full/src/main/java/de/ids_mannheim/korap/oauth2/service/OAuth2AuthorizationService.java
@@ -3,8 +3,8 @@
 import java.time.ZonedDateTime;
 import java.util.Set;
 
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
@@ -21,7 +21,7 @@
 public class OAuth2AuthorizationService {
 
     private static Logger jlog =
-            LoggerFactory.getLogger(OAuth2AuthorizationService.class);
+            LogManager.getLogger(OAuth2AuthorizationService.class);
 
     @Autowired
     protected OAuth2ClientService clientService;
diff --git a/full/src/main/java/de/ids_mannheim/korap/oauth2/service/OAuth2ClientService.java b/full/src/main/java/de/ids_mannheim/korap/oauth2/service/OAuth2ClientService.java
index 20c6f02..6d61e02 100644
--- a/full/src/main/java/de/ids_mannheim/korap/oauth2/service/OAuth2ClientService.java
+++ b/full/src/main/java/de/ids_mannheim/korap/oauth2/service/OAuth2ClientService.java
@@ -42,9 +42,6 @@
 @Service
 public class OAuth2ClientService {
 
-    // private Logger jlog =
-    // Logger.getLogger(OAuth2ClientService.class);
-
     @Autowired
     private OAuth2ClientDao clientDao;
     @Autowired
@@ -111,12 +108,12 @@
             while ((cause = cause.getCause()) != null
                     && !cause.equals(lastCause)) {
                 if (cause instanceof SQLException) {
-                    throw new KustvaktException(
-                            StatusCodes.CLIENT_REGISTRATION_FAILED,
-                            cause.getMessage(), OAuth2Error.INVALID_REQUEST);
+                    break;
                 }
                 lastCause = cause;
             }
+            throw new KustvaktException(StatusCodes.CLIENT_REGISTRATION_FAILED,
+                    cause.getMessage(), OAuth2Error.INVALID_REQUEST);
         }
 
         return new OAuth2ClientDto(id, secret);
diff --git a/full/src/main/java/de/ids_mannheim/korap/rewrite/CollectionRewrite.java b/full/src/main/java/de/ids_mannheim/korap/rewrite/CollectionRewrite.java
index 1ab70a3..08c252f 100644
--- a/full/src/main/java/de/ids_mannheim/korap/rewrite/CollectionRewrite.java
+++ b/full/src/main/java/de/ids_mannheim/korap/rewrite/CollectionRewrite.java
@@ -4,8 +4,8 @@
 import java.util.ArrayList;
 import java.util.List;
 
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 
 import com.fasterxml.jackson.databind.JsonNode;
 import com.google.common.collect.Lists;
@@ -49,7 +49,7 @@
 public class CollectionRewrite implements RewriteTask.RewriteQuery {
 
     private static Logger jlog =
-            LoggerFactory.getLogger(CollectionRewrite.class);
+            LogManager.getLogger(CollectionRewrite.class);
 
     public CollectionRewrite () {
         super();
diff --git a/full/src/main/java/de/ids_mannheim/korap/service/AnnotationService.java b/full/src/main/java/de/ids_mannheim/korap/service/AnnotationService.java
index a2acc05..bbe6850 100644
--- a/full/src/main/java/de/ids_mannheim/korap/service/AnnotationService.java
+++ b/full/src/main/java/de/ids_mannheim/korap/service/AnnotationService.java
@@ -3,8 +3,8 @@
 import java.util.ArrayList;
 import java.util.List;
 
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
@@ -26,7 +26,7 @@
 public class AnnotationService {
 
     private static Logger jlog =
-            LoggerFactory.getLogger(AnnotationService.class);
+            LogManager.getLogger(AnnotationService.class);
 
     @Autowired
     private AnnotationDao annotationDao;
diff --git a/full/src/main/java/de/ids_mannheim/korap/service/MailService.java b/full/src/main/java/de/ids_mannheim/korap/service/MailService.java
index 37b216d..7ad24dd 100644
--- a/full/src/main/java/de/ids_mannheim/korap/service/MailService.java
+++ b/full/src/main/java/de/ids_mannheim/korap/service/MailService.java
@@ -6,11 +6,11 @@
 import javax.mail.internet.InternetAddress;
 import javax.mail.internet.MimeMessage;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.apache.velocity.VelocityContext;
 import org.apache.velocity.app.VelocityEngine;
 import org.apache.velocity.context.Context;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.mail.javamail.JavaMailSender;
 import org.springframework.mail.javamail.MimeMessageHelper;
@@ -23,8 +23,10 @@
 import de.ids_mannheim.korap.user.User;
 import de.ids_mannheim.korap.utils.ParameterChecker;
 
-/** Manages mail related services, such as sending group member invitations 
- * per email.  
+/**
+ * Manages mail related services, such as sending group member
+ * invitations
+ * per email.
  * 
  * @author margaretha
  *
@@ -32,7 +34,7 @@
 @Service
 public class MailService {
 
-    private static Logger jlog = LoggerFactory.getLogger(MailService.class);
+    private static Logger jlog = LogManager.getLogger(MailService.class);
 
     @Autowired
     private AuthenticationManagerIface authManager;
@@ -49,7 +51,7 @@
         ParameterChecker.checkStringValue(inviteeName, "inviteeName");
         ParameterChecker.checkStringValue(groupName, "groupName");
         ParameterChecker.checkStringValue(inviter, "inviter");
-        
+
         MimeMessagePreparator preparator = new MimeMessagePreparator() {
 
             public void prepare (MimeMessage mimeMessage) throws Exception {
diff --git a/full/src/main/java/de/ids_mannheim/korap/service/ResourceService.java b/full/src/main/java/de/ids_mannheim/korap/service/ResourceService.java
index b079e9c..ed68fc9 100644
--- a/full/src/main/java/de/ids_mannheim/korap/service/ResourceService.java
+++ b/full/src/main/java/de/ids_mannheim/korap/service/ResourceService.java
@@ -2,8 +2,8 @@
 
 import java.util.List;
 
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
@@ -21,7 +21,7 @@
 @Service
 public class ResourceService {
 
-    private static Logger jlog = LoggerFactory.getLogger(ResourceService.class);
+    private static Logger jlog = LogManager.getLogger(ResourceService.class);
 
     @Autowired
     private ResourceDao resourceDao;
diff --git a/full/src/main/java/de/ids_mannheim/korap/service/UserGroupService.java b/full/src/main/java/de/ids_mannheim/korap/service/UserGroupService.java
index e8fc312..fdcc4ab 100644
--- a/full/src/main/java/de/ids_mannheim/korap/service/UserGroupService.java
+++ b/full/src/main/java/de/ids_mannheim/korap/service/UserGroupService.java
@@ -8,8 +8,8 @@
 import java.util.List;
 import java.util.Set;
 
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
@@ -43,7 +43,7 @@
 public class UserGroupService {
 
     private static Logger jlog =
-            LoggerFactory.getLogger(UserGroupService.class);
+            LogManager.getLogger(UserGroupService.class);
     @Autowired
     private UserGroupDao userGroupDao;
     @Autowired
diff --git a/full/src/main/java/de/ids_mannheim/korap/service/VirtualCorpusService.java b/full/src/main/java/de/ids_mannheim/korap/service/VirtualCorpusService.java
index 5835d92..5375aad 100644
--- a/full/src/main/java/de/ids_mannheim/korap/service/VirtualCorpusService.java
+++ b/full/src/main/java/de/ids_mannheim/korap/service/VirtualCorpusService.java
@@ -5,8 +5,8 @@
 import java.util.Iterator;
 import java.util.List;
 
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
@@ -50,7 +50,7 @@
 public class VirtualCorpusService {
 
     private static Logger jlog =
-            LoggerFactory.getLogger(VirtualCorpusService.class);
+            LogManager.getLogger(VirtualCorpusService.class);
 
     @Autowired
     private VirtualCorpusDao vcDao;
diff --git a/full/src/main/java/de/ids_mannheim/korap/web/controller/AdminController.java b/full/src/main/java/de/ids_mannheim/korap/web/controller/AdminController.java
index 1b37937..f97356a 100644
--- a/full/src/main/java/de/ids_mannheim/korap/web/controller/AdminController.java
+++ b/full/src/main/java/de/ids_mannheim/korap/web/controller/AdminController.java
@@ -11,9 +11,9 @@
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.joda.time.DateTime;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Controller;
 
@@ -44,7 +44,7 @@
 @Produces(MediaType.APPLICATION_JSON + ";charset=utf-8")
 public class AdminController {
 
-    private static Logger jlog = LoggerFactory.getLogger(AdminController.class);
+    private static Logger jlog = LogManager.getLogger(AdminController.class);
     @Autowired
     private AuditingIface auditingController;
 
diff --git a/full/src/main/java/de/ids_mannheim/korap/web/controller/AuthenticationController.java b/full/src/main/java/de/ids_mannheim/korap/web/controller/AuthenticationController.java
index 6e7c012..9c01fa5 100644
--- a/full/src/main/java/de/ids_mannheim/korap/web/controller/AuthenticationController.java
+++ b/full/src/main/java/de/ids_mannheim/korap/web/controller/AuthenticationController.java
@@ -8,7 +8,6 @@
 import java.util.Locale;
 import java.util.Map;
 
-import javax.servlet.http.HttpServletResponse;
 import javax.ws.rs.Consumes;
 import javax.ws.rs.GET;
 import javax.ws.rs.HeaderParam;
@@ -23,7 +22,8 @@
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.SecurityContext;
 
-import org.slf4j.Logger;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Controller;
 
@@ -41,10 +41,8 @@
 import de.ids_mannheim.korap.exceptions.StatusCodes;
 import de.ids_mannheim.korap.interfaces.AuthenticationManagerIface;
 import de.ids_mannheim.korap.security.context.TokenContext;
-import de.ids_mannheim.korap.user.KorAPUser;
 import de.ids_mannheim.korap.user.User;
 import de.ids_mannheim.korap.utils.JsonUtils;
-import de.ids_mannheim.korap.utils.KustvaktLogger;
 import de.ids_mannheim.korap.utils.ServiceInfo;
 import de.ids_mannheim.korap.web.KustvaktResponseHandler;
 import de.ids_mannheim.korap.web.filter.AuthenticationFilter;
@@ -75,7 +73,7 @@
     //todo: bootstrap function to transmit certain default configuration settings and examples (example user queries,
     // default usersettings, etc.)
     private static Logger jlog =
-            KustvaktLogger.getLogger(AuthenticationController.class);
+            LogManager.getLogger(AuthenticationController.class);
 
     @Autowired
     private AuthenticationManagerIface controller;
@@ -415,7 +413,7 @@
             controller.logout(context);
         }
         catch (KustvaktException e) {
-            jlog.error("Logout Exception: {}", e.string());
+            jlog.error("Logout Exception:"+ e.string());
             throw kustvaktResponseHandler.throwit(e);
         }
         return Response.ok().build();
diff --git a/full/src/main/java/de/ids_mannheim/korap/web/controller/DocumentController.java b/full/src/main/java/de/ids_mannheim/korap/web/controller/DocumentController.java
index 79ee0e3..1620d6c 100644
--- a/full/src/main/java/de/ids_mannheim/korap/web/controller/DocumentController.java
+++ b/full/src/main/java/de/ids_mannheim/korap/web/controller/DocumentController.java
@@ -11,8 +11,8 @@
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Controller;
 
@@ -43,7 +43,7 @@
     private KustvaktResponseHandler kustvaktResponseHandler;
 
     private static Logger jlog =
-            LoggerFactory.getLogger(DocumentController.class);
+            LogManager.getLogger(DocumentController.class);
     private DocumentDao documentDao;
 
 
diff --git a/full/src/main/java/de/ids_mannheim/korap/web/controller/KustvaktController.java b/full/src/main/java/de/ids_mannheim/korap/web/controller/KustvaktController.java
index 32663f5..6619f0d 100644
--- a/full/src/main/java/de/ids_mannheim/korap/web/controller/KustvaktController.java
+++ b/full/src/main/java/de/ids_mannheim/korap/web/controller/KustvaktController.java
@@ -1,21 +1,20 @@
 package de.ids_mannheim.korap.web.controller;
 
-import de.ids_mannheim.korap.exceptions.KustvaktException;
-import de.ids_mannheim.korap.server.KustvaktServer;
-import de.ids_mannheim.korap.utils.JsonUtils;
-import de.ids_mannheim.korap.utils.ServiceInfo;
-import de.ids_mannheim.korap.web.CoreResponseHandler;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Autowired;
+import java.util.HashMap;
+import java.util.Map;
 
 import javax.ws.rs.Path;
 import javax.ws.rs.Produces;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
-import java.util.HashMap;
-import java.util.Map;
+
+import org.springframework.beans.factory.annotation.Autowired;
+
+import de.ids_mannheim.korap.exceptions.KustvaktException;
+import de.ids_mannheim.korap.server.KustvaktServer;
+import de.ids_mannheim.korap.utils.JsonUtils;
+import de.ids_mannheim.korap.utils.ServiceInfo;
+import de.ids_mannheim.korap.web.CoreResponseHandler;
 
 /**
  * Created by hanl on 29.04.16.
@@ -24,7 +23,6 @@
 @Produces(MediaType.APPLICATION_JSON + ";charset=utf-8")
 public class KustvaktController {
 
-    private static Logger jlog = LoggerFactory.getLogger(UserController.class);
     @Autowired
     private CoreResponseHandler kustvaktResponseHandler;
 
diff --git a/full/src/main/java/de/ids_mannheim/korap/web/controller/SearchController.java b/full/src/main/java/de/ids_mannheim/korap/web/controller/SearchController.java
index 830a76f..0b345cb 100644
--- a/full/src/main/java/de/ids_mannheim/korap/web/controller/SearchController.java
+++ b/full/src/main/java/de/ids_mannheim/korap/web/controller/SearchController.java
@@ -24,8 +24,8 @@
 import javax.ws.rs.core.SecurityContext;
 import javax.ws.rs.core.UriBuilder;
 
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Controller;
 import org.springframework.web.bind.annotation.RequestMapping;
@@ -54,7 +54,6 @@
 import de.ids_mannheim.korap.user.User.CorpusAccess;
 import de.ids_mannheim.korap.utils.JsonUtils;
 import de.ids_mannheim.korap.utils.KoralCollectionQueryBuilder;
-import de.ids_mannheim.korap.utils.KustvaktLogger;
 import de.ids_mannheim.korap.utils.StringUtils;
 import de.ids_mannheim.korap.web.ClientsHandler;
 import de.ids_mannheim.korap.web.CoreResponseHandler;
@@ -79,7 +78,7 @@
 public class SearchController {
 
     private static Logger jlog =
-            LoggerFactory.getLogger(SearchController.class);
+            LogManager.getLogger(SearchController.class);
 
     @Autowired
     private CoreResponseHandler kustvaktResponseHandler;
@@ -401,11 +400,11 @@
         catch (KustvaktException e) {
             throw kustvaktResponseHandler.throwit(e);
         }
-        jlog.info("Serialized search: {}", jsonld);
+        jlog.info("Serialized search: "+ jsonld);
 
         String result = searchKrill.search(jsonld);
         // todo: logging
-        KustvaktLogger.QUERY_LOGGER.trace("The result set: {}", result);
+        jlog.trace("The result set: "+ result);
         return Response.ok(result).build();
     }
 
@@ -432,7 +431,7 @@
             //            System.out.printf("Debug: /search/: location=%s, access='%s'.\n", user.locationtoString(), user.accesstoString());
         }
         catch (KustvaktException e) {
-            jlog.error("Failed retrieving user in the search service: {}",
+            jlog.error("Failed retrieving user in the search service: "+
                     e.string());
             throw kustvaktResponseHandler.throwit(e);
         }
@@ -448,7 +447,7 @@
         String query;
         try {
             query = this.processor.processQuery(serializer.toJSON(), user);
-            jlog.info("the serialized query {}", query);
+            jlog.info("the serialized query "+ query);
         }
         catch (KustvaktException e) {
             throw kustvaktResponseHandler.throwit(e);
@@ -486,7 +485,7 @@
         else {
             result = searchKrill.search(query);
         }
-        KustvaktLogger.QUERY_LOGGER.trace("The result set: {}", result);
+        jlog.trace("The result set: "+ result);
         return result;
 
     }
@@ -509,7 +508,7 @@
             return this.graphDBhandler.getResponse(map, "distKwic");
         }
         catch (KustvaktException e) {
-            jlog.error("Failed searching in Neo4J: {}", e.string());
+            jlog.error("Failed searching in Neo4J: "+ e.string());
             throw kustvaktResponseHandler.throwit(e);
         }
 
@@ -534,7 +533,7 @@
             user = controller.getUser(c.getUsername());
         }
         catch (KustvaktException e) {
-            jlog.error("Exception encountered: {}", e.string());
+            jlog.error("Exception encountered: "+ e.string());
             throw kustvaktResponseHandler.throwit(e);
         }
 
@@ -597,7 +596,7 @@
                     user.locationtoString(), user.accesstoString());
         }
         catch (KustvaktException e) {
-            jlog.error("Failed getting user in the matchInfo service: {}",
+            jlog.error("Failed getting user in the matchInfo service: "+
                     e.string());
             throw kustvaktResponseHandler.throwit(e);
         }
diff --git a/full/src/main/java/de/ids_mannheim/korap/web/controller/StatisticController.java b/full/src/main/java/de/ids_mannheim/korap/web/controller/StatisticController.java
index 65d30bd..f389ea5 100644
--- a/full/src/main/java/de/ids_mannheim/korap/web/controller/StatisticController.java
+++ b/full/src/main/java/de/ids_mannheim/korap/web/controller/StatisticController.java
@@ -11,8 +11,8 @@
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.SecurityContext;
 
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Controller;
 
@@ -42,7 +42,7 @@
 
 
     private static Logger jlog =
-            LoggerFactory.getLogger(StatisticController.class);
+            LogManager.getLogger(StatisticController.class);
     @Autowired
     private CoreResponseHandler kustvaktResponseHandler;
     @Autowired
diff --git a/full/src/main/java/de/ids_mannheim/korap/web/controller/UserController.java b/full/src/main/java/de/ids_mannheim/korap/web/controller/UserController.java
index ed9f97a..00a852b 100644
--- a/full/src/main/java/de/ids_mannheim/korap/web/controller/UserController.java
+++ b/full/src/main/java/de/ids_mannheim/korap/web/controller/UserController.java
@@ -26,8 +26,8 @@
 import javax.ws.rs.core.UriBuilder;
 import javax.ws.rs.core.UriInfo;
 
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Controller;
 
@@ -73,7 +73,7 @@
     @Autowired
     private KustvaktResponseHandler kustvaktResponseHandler;
 
-    private static Logger jlog = LoggerFactory.getLogger(UserController.class);
+    private static Logger jlog = LogManager.getLogger(UserController.class);
     @Autowired
     private AuthenticationManagerIface controller;
 
@@ -113,7 +113,7 @@
                             uri.getUriFragment())
                     .queryParam(Attributes.QUERY_PARAM_USER,
                             user.getUsername());
-            jlog.info("registration was successful for user '{}'",
+            jlog.info("registration was successful for user "+
                     user.getUsername());
             Map<String, Object> object = new HashMap<String, Object>();
             object.put("confirm_uri", uriBuilder.build());
@@ -226,7 +226,7 @@
                     .append(username);
         }
         catch (KustvaktException e) {
-            jlog.error("Eoxception encountered!", e.string());
+            jlog.error("Eoxception encountered! "+ e.string());
             throw kustvaktResponseHandler.throwit(e);
         }
 
@@ -364,7 +364,7 @@
                 result = data.serialize();
         }
         catch (KustvaktException e) {
-            jlog.error("Exception encountered: {}", e.string());
+            jlog.error("Exception encountered: "+ e.string());
             throw kustvaktResponseHandler.throwit(e);
         }
         return Response.ok(result).build();
diff --git a/full/src/main/java/de/ids_mannheim/korap/web/filter/PiwikFilter.java b/full/src/main/java/de/ids_mannheim/korap/web/filter/PiwikFilter.java
index abf2eb9..4567896 100644
--- a/full/src/main/java/de/ids_mannheim/korap/web/filter/PiwikFilter.java
+++ b/full/src/main/java/de/ids_mannheim/korap/web/filter/PiwikFilter.java
@@ -1,5 +1,22 @@
 package de.ids_mannheim.korap.web.filter;
 
+import java.security.SecureRandom;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.Random;
+
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.core.UriBuilder;
+import javax.ws.rs.ext.Provider;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
 import com.sun.jersey.api.client.Client;
 import com.sun.jersey.api.client.WebResource;
 import com.sun.jersey.api.client.config.ClientConfig;
@@ -10,23 +27,15 @@
 import com.sun.jersey.spi.container.ContainerRequestFilter;
 import com.sun.jersey.spi.container.ContainerResponseFilter;
 import com.sun.jersey.spi.container.ResourceFilter;
+
 import de.ids_mannheim.korap.config.Attributes;
-import de.ids_mannheim.korap.config.BeansFactory;
 import de.ids_mannheim.korap.exceptions.KustvaktException;
 import de.ids_mannheim.korap.interfaces.AuthenticationManagerIface;
 import de.ids_mannheim.korap.security.context.TokenContext;
-import de.ids_mannheim.korap.user.*;
+import de.ids_mannheim.korap.user.User;
+import de.ids_mannheim.korap.user.UserSettings;
+import de.ids_mannheim.korap.user.Userdata;
 import net.minidev.json.JSONArray;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Component;
-
-import javax.ws.rs.core.MultivaluedMap;
-import javax.ws.rs.core.UriBuilder;
-import javax.ws.rs.ext.Provider;
-import java.security.SecureRandom;
-import java.util.*;
 
 /**
  * @author hanl
@@ -39,7 +48,7 @@
     private WebResource service;
     //    private static final String SERVICE = "http://localhost:8888";
     private static final String SERVICE = "http://10.0.10.13";
-    private static Logger jlog = LoggerFactory.getLogger(PiwikFilter.class);
+    private static Logger jlog = LogManager.getLogger(PiwikFilter.class);
     public static boolean ENABLED = false;
     private Map<String, String> customVars;
     @Autowired
diff --git a/full/src/main/resources/db/insert/V3.5__insert_oauth2_clients.sql b/full/src/main/resources/db/insert/V3.5__insert_oauth2_clients.sql
index c330c92..dd55405 100644
--- a/full/src/main/resources/db/insert/V3.5__insert_oauth2_clients.sql
+++ b/full/src/main/resources/db/insert/V3.5__insert_oauth2_clients.sql
@@ -1,41 +1,52 @@
 -- test clients
 
+INSERT INTO oauth2_client_url(url,url_hashcode)
+VALUES("http://korap.ids-mannheim.de/confidential", 2087150261);
+
 -- plain secret value is "secret"
-INSERT INTO oauth2_client(id,name,secret,type,native, url,url_hashcode,
+INSERT INTO oauth2_client(id,name,secret,type,native,url_id,
   redirect_uri,registered_by, description) 
 VALUES ("fCBbQkAyYzI4NzUxMg","test confidential client",
   "$2a$08$vi1FbuN3p6GcI1tSxMAoeuIYL8Yw3j6A8wJthaN8ZboVnrQaTwLPq",
-  "CONFIDENTIAL", 1, "http://korap.ids-mannheim.de/confidential", 2087150261, 
+  "CONFIDENTIAL", 1, 2087150261,
   "https://korap.ids-mannheim.de/confidential/redirect", "system",
   "This is a test native confidential client.");
+
   
+INSERT INTO oauth2_client_url(url,url_hashcode)
+VALUES("http://third.party.com/confidential", 1712550103);
+
 -- plain secret value is "secret"
-INSERT INTO oauth2_client(id,name,secret,type,native,url,url_hashcode,
+INSERT INTO oauth2_client(id,name,secret,type,native,url_id,
   redirect_uri,registered_by, description) 
 VALUES ("9aHsGW6QflV13ixNpez","test non native confidential client",
   "$2a$08$vi1FbuN3p6GcI1tSxMAoeuIYL8Yw3j6A8wJthaN8ZboVnrQaTwLPq",
-  "CONFIDENTIAL", 0, "http://third.party.com/confidential", 1712550103, 
+  "CONFIDENTIAL", 0, 1712550103,
   "https://third.party.com/confidential/redirect", "system",
   "This is a test nonnative confidential client.");
+
   
-INSERT INTO oauth2_client(id,name,secret,type,native,url,url_hashcode,
+INSERT INTO oauth2_client_url(url,url_hashcode)
+VALUES("http://third.party.client.com", -2137275617);
+
+INSERT INTO oauth2_client(id,name,secret,type,native,url_id,
   redirect_uri, registered_by, description) 
 VALUES ("8bIDtZnH6NvRkW2Fq","third party client",null,
-  "PUBLIC", 0,"http://third.party.client.com", -2137275617,
+  "PUBLIC", 0, -2137275617,
   "https://third.party.client.com/redirect","system",
   "This is a test nonnative public client.");
+
   
-INSERT INTO oauth2_client(id,name,secret,type,native,url,url_hashcode,
+INSERT INTO oauth2_client_url(url,url_hashcode)
+VALUES("http://korap.ids-mannheim.de/public", 1360724310); 
+  
+INSERT INTO oauth2_client(id,name,secret,type,native,url_id,
   redirect_uri, registered_by, description) 
 VALUES ("iBr3LsTCxOj7D2o0A5m","test public client",null,
-  "PUBLIC", 1, "http://korap.ids-mannheim.de/public", 1360724310,
+  "PUBLIC", 1, 1360724310,
   "https://korap.ids-mannheim.de/public/redirect","system", 
   "This is a test native public client."); 
-  
-  
-INSERT INTO oauth2_access_token(token,user_id, user_auth_time)
-VALUES("249c64a77f40e2b5504982cc5521b596","dory","2018-05-30 16:24:10");
 
 INSERT INTO oauth2_access_token(token,user_id,created_date, user_auth_time)
 VALUES("fia0123ikBWn931470H8s5gRqx7Moc4p","marlin","2018-05-30 16:25:50",
-"2018-05-30 16:23:10");
+"2018-05-30 16:23:10");
\ No newline at end of file
diff --git a/full/src/main/resources/db/new-mysql/V1.4__oauth2_tables.sql b/full/src/main/resources/db/new-mysql/V1.4__oauth2_tables.sql
index 98e3c7b..234df42 100644
--- a/full/src/main/resources/db/new-mysql/V1.4__oauth2_tables.sql
+++ b/full/src/main/resources/db/new-mysql/V1.4__oauth2_tables.sql
@@ -1,5 +1,10 @@
 -- EM: modified from Michael Hanl version
 
+CREATE TABLE IF NOT EXISTS oauth2_client_url (
+	url_hashcode INTEGER PRIMARY KEY NOT NULL,	
+	url TEXT DEFAULT NULL	
+);
+
 -- oauth2 db tables
 CREATE TABLE IF NOT EXISTS oauth2_client (
 	id VARCHAR(100) PRIMARY KEY NOT NULL,
@@ -7,12 +12,12 @@
 	secret VARCHAR(200) DEFAULT NULL,
 	type VARCHAR(200) NOT NULL,
 	native BOOLEAN DEFAULT FALSE,
-	url TEXT DEFAULT NULL,
-	url_hashcode INTEGER,
 	redirect_uri TEXT DEFAULT NULL,
 	description VARCHAR(250) NOT NULL,
 	registered_by VARCHAR(100) NOT NULL,
-	UNIQUE INDEX unique_url(url_hashcode)
+	url_id INTEGER,
+	FOREIGN KEY (url_id)
+	   REFERENCES oauth2_client_url(url_hashcode)
 );
 
 CREATE TABLE IF NOT EXISTS oauth2_authorization (
@@ -24,7 +29,7 @@
 	created_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
 	is_revoked BOOLEAN DEFAULT 0,
 	total_attempts INTEGER DEFAULT 0,
-	user_auth_time TIMESTAMP NOT NULL,
+	user_auth_time TIMESTAMP NULL,
 	nonce TEXT DEFAULT NULL,
 	FOREIGN KEY (client_id)
 	   REFERENCES oauth2_client(id),
@@ -54,7 +59,7 @@
 	created_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
 	is_revoked BOOLEAN DEFAULT 0,
 	total_attempts INTEGER DEFAULT 0,
-	user_auth_time TIMESTAMP NOT NULL,
+	user_auth_time TIMESTAMP NULL,
 	FOREIGN KEY (authorization_id)
 	   REFERENCES oauth2_authorization(id)
 );
diff --git a/full/src/main/resources/db/new-sqlite/V1.4__oauth2_tables.sql b/full/src/main/resources/db/new-sqlite/V1.4__oauth2_tables.sql
index e6506cd..f227752 100644
--- a/full/src/main/resources/db/new-sqlite/V1.4__oauth2_tables.sql
+++ b/full/src/main/resources/db/new-sqlite/V1.4__oauth2_tables.sql
@@ -1,5 +1,10 @@
 -- EM: modified from Michael Hanl version
 
+CREATE TABLE IF NOT EXISTS oauth2_client_url (
+	url_hashcode INTEGER PRIMARY KEY NOT NULL,	
+	url TEXT DEFAULT NULL	
+);
+
 -- oauth2 db tables
 CREATE TABLE IF NOT EXISTS oauth2_client (
 	id VARCHAR(100) PRIMARY KEY NOT NULL,
@@ -7,15 +12,15 @@
 	secret VARCHAR(255) DEFAULT NULL,
 	type VARCHAR(255) NOT NULL,
 	native BOOLEAN DEFAULT FALSE,
-	url TEXT DEFAULT NULL,
-	url_hashcode INTEGER,
 	redirect_uri TEXT DEFAULT NULL,
 	description VARCHAR(255) NOT NULL,
-	registered_by VARCHAR(100) NOT NULL
+	registered_by VARCHAR(100) NOT NULL,
+	url_id INTEGER,
+	FOREIGN KEY (url_id)
+	   REFERENCES oauth2_client_url(url_hashcode)
 );
 
 CREATE UNIQUE INDEX client_id_index on oauth2_client(id);
-CREATE UNIQUE INDEX client_url_index on oauth2_client(url_hashcode);
 
 CREATE TABLE IF NOT EXISTS oauth2_authorization (
 	id INTEGER PRIMARY KEY AUTOINCREMENT,
diff --git a/full/src/main/resources/db/new-sqlite/V1.5__oauth2_triggers.sql b/full/src/main/resources/db/new-sqlite/V1.5__oauth2_triggers.sql
index c55d659..d62e4df 100644
--- a/full/src/main/resources/db/new-sqlite/V1.5__oauth2_triggers.sql
+++ b/full/src/main/resources/db/new-sqlite/V1.5__oauth2_triggers.sql
@@ -5,7 +5,7 @@
       WHERE rowid = new.rowid;
      END;
 
-CREATE TRIGGER insert_access_token_date BEFORE INSERT ON oauth2_access_token
+CREATE TRIGGER insert_access_token_date AFTER INSERT ON oauth2_access_token
      BEGIN
       UPDATE oauth2_access_token
       SET created_date = DATETIME('now', 'localtime')  
diff --git a/full/src/main/resources/log4j.properties b/full/src/main/resources/log4j.properties
deleted file mode 100644
index c747b68..0000000
--- a/full/src/main/resources/log4j.properties
+++ /dev/null
@@ -1,40 +0,0 @@
-
-# Root logger option
-#log4j.threshold=ALL
-log4j.rootLogger=ERROR, stdout, debugLog
-log4j.logger.log=ERROR, errorLog
-
-#log4j.logger.de.ids_mannheim.korap.web.controller.AuthenticationController = debug, debugLog, stdout
-#log4j.logger.de.ids_mannheim.korap.service.UserGroupService= debug, stdout, debugLog
-#log4j.logger.de.ids_mannheim.korap.rewrite.CollectionRewrite= debug, stdout, debugLog
-#log4j.logger.de.ids_mannheim.korap.service.MailService= debug, stdout, debugLog
-
-# Direct log messages to stdout
-log4j.appender.stdout=org.apache.log4j.ConsoleAppender
-log4j.appender.stdout.Target=System.out
-log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
-log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd, HH:mm:ss} %C{6} - %M%n %-5p: %m%n
-
-log4j.appender.errorLog=org.apache.log4j.RollingFileAppender
-log4j.appender.errorLog.layout=org.apache.log4j.PatternLayout
-log4j.appender.errorLog.layout.ConversionPattern=%d{MMM dd, yyyy HH:mm:ss} %C{6} - %M %n %-5p: %m%n
-log4j.appender.errorLog.File=./logs/errors.log
-
-log4j.appender.policyLog=org.apache.log4j.RollingFileAppender
-log4j.appender.policyLog.layout=org.apache.log4j.PatternLayout
-log4j.appender.policyLog.layout.ConversionPattern=%d{MMM dd, yyyy HH:mm:ss} %C{6} - %M %n %-5p: %m%n
-log4j.appender.policyLog.File=./logs/policies.log
-
-log4j.appender.authLog=org.apache.log4j.RollingFileAppender
-log4j.appender.authLog.layout=org.apache.log4j.PatternLayout
-log4j.appender.authLog.layout.ConversionPattern=%d{MMM dd, yyyy HH:mm:ss} %C{6} - %M %n %-5p: %m%n
-log4j.appender.authLog.File=./logs/auth.log
-
-log4j.appender.debugLog=org.apache.log4j.RollingFileAppender
-log4j.appender.debugLog.layout=org.apache.log4j.PatternLayout
-log4j.appender.debugLog.layout.ConversionPattern=%d{MMM dd, yyyy HH:mm:ss} %C{6} - %M %n %-5p: %m%n
-log4j.appender.debugLog.File=./logs/logging.log
-
-
-log4j.logger.de.ids_mannheim.korap.security.ac = ERROR, policyLog
-log4j.logger.de.ids_mannheim.korap.authentication = ERROR, authLog
\ No newline at end of file
diff --git a/full/src/main/resources/log4j2.properties b/full/src/main/resources/log4j2.properties
new file mode 100644
index 0000000..1038fe2
--- /dev/null
+++ b/full/src/main/resources/log4j2.properties
@@ -0,0 +1,29 @@
+appenders = console, file
+appender.console.type = Console
+appender.console.name = STDOUT
+appender.console.layout.type = PatternLayout
+appender.console.layout.pattern = %d{yyyy-MM-dd, HH:mm:ss} %C{6} - %M%n %-5p: %m%n
+
+appender.file.type = File
+appender.file.name = ERRORLOG
+appender.file.fileName=./logs/errors.log
+appender.file.layout.type=PatternLayout
+appender.file.layout.pattern= %d{yyyy-MM-dd, HH:mm:ss} %C{6} - %M%n %-5p: %m%n
+
+rootLogger.level = error
+rootLogger.appenderRefs = stdout
+rootLogger.appenderRef.stdout.ref = STDOUT
+
+#loggers=file
+#logger.file.name=de.ids_mannheim.korap
+#logger.file.level = error
+#logger.file.appenderRefs = file
+#logger.file.appenderRef.file.ref = ERRORLOG
+#logger.file.additivity=true
+
+#loggers=file
+#logger.file.name=com.sun.jersey.test.framework.spi.container
+#logger.file.level = info
+#logger.file.appenderRefs = file
+#logger.file.appenderRef.file.ref = ERRORLOG
+#logger.file.additivity=false
\ No newline at end of file
diff --git a/full/src/test/java/de/ids_mannheim/korap/config/BeanConfigBaseTest.java b/full/src/test/java/de/ids_mannheim/korap/config/BeanConfigBaseTest.java
index a625556..b69cecf 100644
--- a/full/src/test/java/de/ids_mannheim/korap/config/BeanConfigBaseTest.java
+++ b/full/src/test/java/de/ids_mannheim/korap/config/BeanConfigBaseTest.java
@@ -2,7 +2,8 @@
 
 import static org.junit.Assert.assertNotNull;
 
-import org.apache.log4j.Logger;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.junit.runner.RunWith;
 import org.junit.runner.notification.RunNotifier;
 import org.junit.runners.model.InitializationError;
@@ -26,7 +27,7 @@
 @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS)
 public abstract class BeanConfigBaseTest {
 
-    private static Logger jlog = Logger.getLogger(BeanConfigBaseTest.class);
+    private static Logger jlog = LogManager.getLogger(BeanConfigBaseTest.class);
     @Autowired
     protected ApplicationContext context;
     
diff --git a/full/src/test/java/de/ids_mannheim/korap/config/BeanConfigTest.java b/full/src/test/java/de/ids_mannheim/korap/config/BeanConfigTest.java
index 7603c18..2268d87 100644
--- a/full/src/test/java/de/ids_mannheim/korap/config/BeanConfigTest.java
+++ b/full/src/test/java/de/ids_mannheim/korap/config/BeanConfigTest.java
@@ -2,7 +2,8 @@
 
 import static org.junit.Assert.assertNotNull;
 
-import org.apache.log4j.Logger;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.junit.runner.RunWith;
 import org.junit.runner.notification.RunNotifier;
 import org.junit.runners.model.InitializationError;
@@ -25,7 +26,7 @@
 @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS)
 public abstract class BeanConfigTest {
 
-    private static Logger jlog = Logger.getLogger(BeanConfigTest.class);
+    private static Logger jlog = LogManager.getLogger(BeanConfigTest.class);
     @Autowired
     protected ApplicationContext context;
 
diff --git a/full/src/test/java/de/ids_mannheim/korap/dao/VirtualCorpusDaoTest.java b/full/src/test/java/de/ids_mannheim/korap/dao/VirtualCorpusDaoTest.java
index 022f56c..3b97caa 100644
--- a/full/src/test/java/de/ids_mannheim/korap/dao/VirtualCorpusDaoTest.java
+++ b/full/src/test/java/de/ids_mannheim/korap/dao/VirtualCorpusDaoTest.java
@@ -4,7 +4,6 @@
 
 import java.util.Iterator;
 import java.util.List;
-import java.util.Set;
 
 import org.junit.Rule;
 import org.junit.Test;
diff --git a/full/src/test/java/de/ids_mannheim/korap/misc/CollectionQueryBuilderTest.java b/full/src/test/java/de/ids_mannheim/korap/misc/CollectionQueryBuilderTest.java
index 3142330..87469ac 100644
--- a/full/src/test/java/de/ids_mannheim/korap/misc/CollectionQueryBuilderTest.java
+++ b/full/src/test/java/de/ids_mannheim/korap/misc/CollectionQueryBuilderTest.java
@@ -227,7 +227,7 @@
         KoralCollectionQueryBuilder test = new KoralCollectionQueryBuilder();
         test.with("corpusSigle=WPD");
         String json = test.toJSON();
-        System.out.println(json);
+//        System.out.println(json);
         //JsonNode node = (JsonNode) test.rebaseCollection(null);
         //node = b.mergeWith(node);
         //assertNotNull(node);
@@ -249,7 +249,7 @@
         // operator is not supposed to be here!
         test.and().with("corpusSigle=WPD");
         String json = test.toJSON();
-        System.out.println(json);
+//        System.out.println(json);
         //JsonNode node = (JsonNode) test.rebaseCollection(null);
         //node = b.mergeWith(node);
         //assertNotNull(node);
@@ -335,7 +335,7 @@
         builder.setBaseQuery(resource.getData());
         builder.or().with("pubPlace=Mannheim");
 
-        System.out.println("query " + builder.toJSON());
+//        System.out.println("query " + builder.toJSON());
         // todo: assertions
     }
 
@@ -354,7 +354,7 @@
         builder.setBaseQuery(resource.getData());
         builder.or().with("pubPlace=Mannheim");
 
-        System.out.println("query " + builder.toJSON());
+//        System.out.println("query " + builder.toJSON());
         // todo: assertions
     }
 
diff --git a/full/src/test/java/de/ids_mannheim/korap/web/controller/KustvaktCoreRestTest.java b/full/src/test/java/de/ids_mannheim/korap/web/controller/KustvaktCoreRestTest.java
index 324ed0e..77f85bf 100644
--- a/full/src/test/java/de/ids_mannheim/korap/web/controller/KustvaktCoreRestTest.java
+++ b/full/src/test/java/de/ids_mannheim/korap/web/controller/KustvaktCoreRestTest.java
@@ -36,7 +36,7 @@
                 .path("search").queryParam("q", "[base=Wort]")
                 .queryParam("ql", "poliqarp").get(ClientResponse.class);
         //        System.out.println("_______________________________________________");
-                System.out.println(response.getEntity(String.class));
+//                System.out.println(response.getEntity(String.class));
         assert ClientResponse.Status.OK.getStatusCode() == response.getStatus();
     }
 
diff --git a/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2AccessTokenTest.java b/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2AccessTokenTest.java
index 07344fd..8126843 100644
--- a/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2AccessTokenTest.java
+++ b/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2AccessTokenTest.java
@@ -3,18 +3,18 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 
-import java.io.BufferedReader;
 import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
 
-import org.junit.BeforeClass;
+import javax.ws.rs.core.MultivaluedMap;
+
+import org.apache.http.entity.ContentType;
 import org.junit.Test;
 
 import com.fasterxml.jackson.databind.JsonNode;
 import com.google.common.net.HttpHeaders;
 import com.sun.jersey.api.client.ClientResponse;
 import com.sun.jersey.api.client.ClientResponse.Status;
+import com.sun.jersey.core.util.MultivaluedMapImpl;
 
 import de.ids_mannheim.korap.config.Attributes;
 import de.ids_mannheim.korap.config.SpringJerseyTest;
@@ -24,15 +24,29 @@
 
 public class OAuth2AccessTokenTest extends SpringJerseyTest {
 
-    // test access token for username: dory
-    // see:
-    // full/src/main/resources/db/insert/V3.5__insert_oauth2_clients.sql
-    private static String testAccessToken = "249c64a77f40e2b5504982cc5521b596";
+
+    private String requestToken () throws KustvaktException {
+        MultivaluedMap<String, String> form = new MultivaluedMapImpl();
+        form.add("grant_type", "password");
+        form.add("client_id", "fCBbQkAyYzI4NzUxMg");
+        form.add("client_secret", "secret");
+        form.add("username", "dory");
+        form.add("password", "password");
+
+        ClientResponse response = resource().path("oauth2").path("token")
+                .header(HttpHeaders.CONTENT_TYPE,
+                        ContentType.APPLICATION_FORM_URLENCODED)
+                .entity(form).post(ClientResponse.class);
+
+        String entity = response.getEntity(String.class);
+        JsonNode node = JsonUtils.readTree(entity);
+        return node.at("/access_token").asText();
+    }
 
     @Test
     public void testListVC () throws KustvaktException {
         ClientResponse response = resource().path("vc").path("list")
-                .header(Attributes.AUTHORIZATION, "Bearer " + testAccessToken)
+                .header(Attributes.AUTHORIZATION, "Bearer " + requestToken())
                 .get(ClientResponse.class);
 
         assertEquals(Status.OK.getStatusCode(), response.getStatus());
@@ -46,7 +60,7 @@
             throws KustvaktException, IOException {
         ClientResponse response = resource().path("search")
                 .queryParam("q", "Wasser").queryParam("ql", "poliqarp")
-                .header(Attributes.AUTHORIZATION, "Bearer " + testAccessToken)
+                .header(Attributes.AUTHORIZATION, "Bearer " + requestToken())
                 .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")
                 .get(ClientResponse.class);
 
@@ -78,24 +92,4 @@
         assertEquals("Access token is not found",
                 node.at("/errors/0/1").asText());
     }
-
-    @Test
-    public void testSearchWithExpiredToken ()
-            throws KustvaktException, IOException {
-        ClientResponse response = resource().path("search")
-                .queryParam("q", "Wasser").queryParam("ql", "poliqarp")
-                .header(Attributes.AUTHORIZATION,
-                        "Bearer fia0123ikBWn931470H8s5gRqx7Moc4p")
-                .get(ClientResponse.class);
-
-        String ent = response.getEntity(String.class);
-
-        assertEquals(ClientResponse.Status.UNAUTHORIZED.getStatusCode(),
-                response.getStatus());
-
-        JsonNode node = JsonUtils.readTree(ent);
-        assertEquals(StatusCodes.EXPIRED, node.at("/errors/0/0").asInt());
-        assertEquals("Access token is expired",
-                node.at("/errors/0/1").asText());
-    }
 }
diff --git a/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2ClientControllerTest.java b/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2ClientControllerTest.java
index 4f13ad9..c742d1d 100644
--- a/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2ClientControllerTest.java
+++ b/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2ClientControllerTest.java
@@ -248,7 +248,6 @@
                 .delete(ClientResponse.class);
 
         String entity = response.getEntity(String.class);
-        System.out.println(entity);
         assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
 
         JsonNode node = JsonUtils.readTree(entity);
@@ -274,7 +273,6 @@
                 .entity(form).delete(ClientResponse.class);
 
         String entity = response.getEntity(String.class);
-        System.out.println(entity);
         assertEquals(Status.UNAUTHORIZED.getStatusCode(), response.getStatus());
 
         JsonNode node = JsonUtils.readTree(entity);
diff --git a/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2OpenIdControllerTest.java b/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2OpenIdControllerTest.java
index efdab41..a5e84d3 100644
--- a/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2OpenIdControllerTest.java
+++ b/full/src/test/java/de/ids_mannheim/korap/web/controller/OAuth2OpenIdControllerTest.java
@@ -13,7 +13,6 @@
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.MultivaluedMap;
 
-import org.apache.http.HttpStatus;
 import org.apache.http.entity.ContentType;
 import org.apache.oltu.oauth2.common.message.types.TokenType;
 import org.junit.Test;
@@ -41,7 +40,6 @@
 import de.ids_mannheim.korap.config.FullConfiguration;
 import de.ids_mannheim.korap.config.SpringJerseyTest;
 import de.ids_mannheim.korap.exceptions.KustvaktException;
-import de.ids_mannheim.korap.exceptions.StatusCodes;
 import de.ids_mannheim.korap.oauth2.constant.OAuth2Error;
 import de.ids_mannheim.korap.utils.JsonUtils;
 
@@ -106,6 +104,8 @@
         assertEquals("thisIsMyState", params.getFirst("state"));
     }
 
+    
+
     private void testRequestAuthorizationCodeWithoutOpenID (
             MultivaluedMap<String, String> form, String redirectUri)
             throws KustvaktException {
@@ -257,36 +257,6 @@
     }
 
     @Test
-    public void testRequestAuthorizationCodeAuthenticationTooOld ()
-            throws KustvaktException {
-        MultivaluedMap<String, String> form = new MultivaluedMapImpl();
-        form.add("response_type", "code");
-        form.add("client_id", "fCBbQkAyYzI4NzUxMg");
-        form.add("redirect_uri", redirectUri);
-        form.add("scope", "openid");
-        form.add("max_age", "1800");
-
-        ClientResponse response =
-                resource().path("oauth2").path("openid").path("authorize")
-                        .header(Attributes.AUTHORIZATION,
-                                "Bearer 249c64a77f40e2b5504982cc5521b596")
-                        .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")
-                        .header(HttpHeaders.CONTENT_TYPE,
-                                ContentType.APPLICATION_FORM_URLENCODED)
-                        .entity(form).post(ClientResponse.class);
-
-        assertEquals(HttpStatus.SC_UNAUTHORIZED, response.getStatus());
-        String entity = response.getEntity(String.class);
-        JsonNode node = JsonUtils.readTree(entity);
-        assertEquals(StatusCodes.USER_REAUTHENTICATION_REQUIRED,
-                node.at("/errors/0/0").asInt());
-        assertEquals(
-                "User reauthentication is required because the authentication "
-                        + "time is too old according to max_age",
-                node.at("/errors/0/1").asText());
-    }
-
-    @Test
     public void testRequestAccessTokenWithAuthorizationCode ()
             throws KustvaktException, ParseException, InvalidKeySpecException,
             NoSuchAlgorithmException, JOSEException {
@@ -403,7 +373,7 @@
         ClientResponse tokenResponse = sendTokenRequest(tokenForm);
         String entity = tokenResponse.getEntity(String.class);
         System.out.println(entity);
-        
+
         JsonNode node = JsonUtils.readTree(entity);
         assertNotNull(node.at("/access_token").asText());
         assertNotNull(node.at("/refresh_token").asText());
diff --git a/full/src/test/java/de/ids_mannheim/korap/web/controller/TokenExpiryTest.java b/full/src/test/java/de/ids_mannheim/korap/web/controller/TokenExpiryTest.java
new file mode 100644
index 0000000..3985fd6
--- /dev/null
+++ b/full/src/test/java/de/ids_mannheim/korap/web/controller/TokenExpiryTest.java
@@ -0,0 +1,104 @@
+package de.ids_mannheim.korap.web.controller;
+
+import static org.junit.Assert.assertEquals;
+
+import java.io.IOException;
+
+import javax.ws.rs.core.MultivaluedMap;
+
+import org.apache.http.HttpStatus;
+import org.apache.http.entity.ContentType;
+import org.junit.Test;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.google.common.net.HttpHeaders;
+import com.sun.jersey.api.client.ClientResponse;
+import com.sun.jersey.core.util.MultivaluedMapImpl;
+
+import de.ids_mannheim.korap.config.Attributes;
+import de.ids_mannheim.korap.config.SpringJerseyTest;
+import de.ids_mannheim.korap.exceptions.KustvaktException;
+import de.ids_mannheim.korap.exceptions.StatusCodes;
+import de.ids_mannheim.korap.utils.JsonUtils;
+
+public class TokenExpiryTest extends SpringJerseyTest {
+
+    @Test
+    public void requestToken ()
+            throws KustvaktException, InterruptedException, IOException {
+        MultivaluedMap<String, String> form = new MultivaluedMapImpl();
+        form.add("grant_type", "password");
+        form.add("client_id", "fCBbQkAyYzI4NzUxMg");
+        form.add("client_secret", "secret");
+        form.add("username", "dory");
+        form.add("password", "password");
+
+        ClientResponse response = resource().path("oauth2").path("token")
+                .header(HttpHeaders.CONTENT_TYPE,
+                        ContentType.APPLICATION_FORM_URLENCODED)
+                .entity(form).post(ClientResponse.class);
+
+        String entity = response.getEntity(String.class);
+        JsonNode node = JsonUtils.readTree(entity);
+        String token = node.at("/access_token").asText();
+
+        Thread.sleep(1000);
+
+        testRequestAuthorizationCodeAuthenticationTooOld(token);
+        
+        Thread.sleep(1500);
+        testSearchWithExpiredToken(token);
+    }
+
+    // not possible to store expired token in the test database,
+    // because sqlite needs a trigger after INSERT to
+    // oauth_access_token to store created_date. Before INSERT trigger
+    // does not work.
+    private void testSearchWithExpiredToken (String token)
+            throws KustvaktException, IOException {
+        ClientResponse response = resource().path("search")
+                .queryParam("q", "Wasser").queryParam("ql", "poliqarp")
+                .header(Attributes.AUTHORIZATION, "Bearer " + token)
+                .get(ClientResponse.class);
+
+        String ent = response.getEntity(String.class);
+
+        assertEquals(ClientResponse.Status.UNAUTHORIZED.getStatusCode(),
+                response.getStatus());
+
+        JsonNode node = JsonUtils.readTree(ent);
+        assertEquals(StatusCodes.EXPIRED, node.at("/errors/0/0").asInt());
+        assertEquals("Access token is expired",
+                node.at("/errors/0/1").asText());
+    }
+
+    // cannot be tested dynamically
+    private void testRequestAuthorizationCodeAuthenticationTooOld (String token)
+            throws KustvaktException {
+        MultivaluedMap<String, String> form = new MultivaluedMapImpl();
+        form.add("response_type", "code");
+        form.add("client_id", "fCBbQkAyYzI4NzUxMg");
+        form.add("redirect_uri",
+                "https://korap.ids-mannheim.de/confidential/redirect");
+        form.add("scope", "openid");
+        form.add("max_age", "1");
+
+        ClientResponse response =
+                resource().path("oauth2").path("openid").path("authorize")
+                        .header(Attributes.AUTHORIZATION, "Bearer " + token)
+                        .header(HttpHeaders.X_FORWARDED_FOR, "149.27.0.32")
+                        .header(HttpHeaders.CONTENT_TYPE,
+                                ContentType.APPLICATION_FORM_URLENCODED)
+                        .entity(form).post(ClientResponse.class);
+
+        assertEquals(HttpStatus.SC_UNAUTHORIZED, response.getStatus());
+        String entity = response.getEntity(String.class);
+        JsonNode node = JsonUtils.readTree(entity);
+        assertEquals(StatusCodes.USER_REAUTHENTICATION_REQUIRED,
+                node.at("/errors/0/0").asInt());
+        assertEquals(
+                "User reauthentication is required because the authentication "
+                        + "time is too old according to max_age",
+                node.at("/errors/0/1").asText());
+    }
+}
diff --git a/full/src/test/java/de/ids_mannheim/korap/web/controller/UserGroupControllerAdminTest.java b/full/src/test/java/de/ids_mannheim/korap/web/controller/UserGroupControllerAdminTest.java
index af9f4ff..2af5234 100644
--- a/full/src/test/java/de/ids_mannheim/korap/web/controller/UserGroupControllerAdminTest.java
+++ b/full/src/test/java/de/ids_mannheim/korap/web/controller/UserGroupControllerAdminTest.java
@@ -14,8 +14,8 @@
 import com.sun.jersey.api.client.ClientHandlerException;
 import com.sun.jersey.api.client.ClientResponse;
 import com.sun.jersey.api.client.ClientResponse.Status;
-import com.sun.jersey.core.util.MultivaluedMapImpl;
 import com.sun.jersey.api.client.UniformInterfaceException;
+import com.sun.jersey.core.util.MultivaluedMapImpl;
 
 import de.ids_mannheim.korap.authentication.http.HttpAuthorizationHandler;
 import de.ids_mannheim.korap.config.Attributes;
@@ -66,7 +66,7 @@
 
         assertEquals(Status.OK.getStatusCode(), response.getStatus());
         String entity = response.getEntity(String.class);
-        //        System.out.println(entity);
+        // System.out.println(entity);
         JsonNode node = JsonUtils.readTree(entity);
         assertEquals(3, node.size());
     }
@@ -84,7 +84,7 @@
 
         assertEquals(Status.OK.getStatusCode(), response.getStatus());
         String entity = response.getEntity(String.class);
-        //        System.out.println(entity);
+        // System.out.println(entity);
         JsonNode node = JsonUtils.readTree(entity);
         assertEquals(2, node.size());
     }
@@ -119,9 +119,16 @@
 
         assertEquals(Status.OK.getStatusCode(), response.getStatus());
         String entity = response.getEntity(String.class);
-
         JsonNode node = JsonUtils.readTree(entity);
         assertEquals(4, node.size());
+
+        boolean containsHiddenStatus = false;
+        for (int i = 0; i < node.size(); i++) {
+            if (node.get(i).at("/status").asText().equals("HIDDEN")) {
+                containsHiddenStatus = true;
+            }
+        }
+        assertEquals(true, containsHiddenStatus);
     }
 
     @Test
@@ -278,7 +285,7 @@
     private void testDeleteGroup (String groupId)
             throws UniformInterfaceException, ClientHandlerException,
             KustvaktException {
-        //delete group
+        // delete group
         ClientResponse response = resource().path("group").path("delete")
                 .queryParam("groupId", groupId)
                 .header(Attributes.AUTHORIZATION,
@@ -308,7 +315,7 @@
                 .delete(ClientResponse.class);
 
         assertEquals(Status.OK.getStatusCode(), response.getStatus());
-        
+
         // check group member
         JsonNode node = listGroup(testUsername);
         node = node.get(0);
diff --git a/full/src/test/resources/kustvakt-test.conf b/full/src/test/resources/kustvakt-test.conf
index b135ca7..8416b6a 100644
--- a/full/src/test/resources/kustvakt-test.conf
+++ b/full/src/test/resources/kustvakt-test.conf
@@ -81,8 +81,8 @@
 
 ## token expiration time
 security.longTokenTTL = 1D
-security.tokenTTL = 9S
-security.shortTokenTTL = 5S
+security.tokenTTL = 2S
+security.shortTokenTTL = 1S
 
 ## specifies the user data field that is used to salt user passwords
 security.passcode.salt=salt
diff --git a/full/src/test/resources/test-expired.token b/full/src/test/resources/test-expired.token
deleted file mode 100644
index 5d49da3..0000000
--- a/full/src/test/resources/test-expired.token
+++ /dev/null
@@ -1 +0,0 @@
-eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ0ZXN0VXNlciIsImlzcyI6Imh0dHA6XC9cL2tvcmFwLmlkcy1tYW5uaGVpbS5kZSIsImV4cCI6MTUyODMwMzE5OX0.rmEFpdm8-_iyHGb2tEaJbKBoceiZwnyodixWhyLrU9w
\ No newline at end of file
diff --git a/full/src/test/resources/test-hibernate.properties b/full/src/test/resources/test-hibernate.properties
index 76c9add..161b737 100644
--- a/full/src/test/resources/test-hibernate.properties
+++ b/full/src/test/resources/test-hibernate.properties
@@ -1,6 +1,6 @@
 hibernate.dialect=org.hibernate.dialect.MySQLDialect
 hibernate.hbm2ddl.auto=none
-hibernate.show_sql=true
+hibernate.show_sql=false
 hibernate.cache.use_query_cache=false
 hibernate.cache.use_second_level_cache=false
 hibernate.cache.provider=org.hibernate.cache.EhCacheProvider
diff --git a/lite/src/main/java/de/ids_mannheim/korap/web/service/lite/LiteService.java b/lite/src/main/java/de/ids_mannheim/korap/web/service/lite/LiteService.java
index 5463738..3a384d5 100644
--- a/lite/src/main/java/de/ids_mannheim/korap/web/service/lite/LiteService.java
+++ b/lite/src/main/java/de/ids_mannheim/korap/web/service/lite/LiteService.java
@@ -17,8 +17,8 @@
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriBuilder;
 
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Controller;
 
@@ -55,7 +55,7 @@
 @Produces(MediaType.APPLICATION_JSON + ";charset=utf-8")
 public class LiteService {
 
-    private static Logger jlog = LoggerFactory.getLogger(LiteService.class);
+    private static Logger jlog = LogManager.getLogger(LiteService.class);
 
     @Autowired
     CoreResponseHandler kustvaktResponseHandler;
@@ -145,10 +145,10 @@
             throw kustvaktResponseHandler.throwit(e);
         }
         // todo: should be possible to add the meta part to the query serialization
-        jlog.info("Serialized search: {}", jsonld);
+        jlog.info("Serialized search: "+jsonld);
         try {
             String result = searchKrill.search(jsonld);
-            jlog.debug("The result set: {}", result);
+            jlog.debug("The result set: "+result);
             return Response.ok(result).build();
         }
         catch (Exception e) {
@@ -188,7 +188,7 @@
         catch (KustvaktException e) {
             throw kustvaktResponseHandler.throwit(e);
         }
-        jlog.info("the serialized query {}", query);
+        jlog.info("the serialized query "+ query);
 
         // This may not work with the the KoralQuery
         if (eng.equals(KustvaktConfiguration.BACKENDS.NEO4J)) {
@@ -209,7 +209,7 @@
         }
         else
             result = searchKrill.search(query);
-        jlog.debug("The result set: {}", result);
+        jlog.debug("The result set: "+ result);
         return Response.ok(result).build();
     }
 
@@ -290,7 +290,7 @@
             throw kustvaktResponseHandler.throwit(500, e.getMessage(), null);
         }
 
-        jlog.debug("The result set: {}", result);
+        jlog.debug("The result set: "+ result);
         return Response.ok(result).build();
     }
 
diff --git a/lite/src/main/resources/log4j.properties b/lite/src/main/resources/log4j.properties
deleted file mode 100644
index 5d769fb..0000000
--- a/lite/src/main/resources/log4j.properties
+++ /dev/null
@@ -1,35 +0,0 @@
-
-# Root logger option
-#log4j.threshold=ALL
-log4j.rootLogger=error, stdout, debugLog
-log4j.logger.log=ERROR, errorLog
-
-# Direct log messages to stdout
-log4j.appender.stdout=org.apache.log4j.ConsoleAppender
-log4j.appender.stdout.Target=System.out
-log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
-log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd, HH:mm:ss} %C{6} - %M%n %-5p: %m%n
-
-log4j.appender.errorLog=org.apache.log4j.RollingFileAppender
-log4j.appender.errorLog.layout=org.apache.log4j.PatternLayout
-log4j.appender.errorLog.layout.ConversionPattern=%d{MMM dd, yyyy HH:mm:ss} %C{6} - %M %n %-5p: %m%n
-log4j.appender.errorLog.File=./logs/errors.log
-
-log4j.appender.policyLog=org.apache.log4j.RollingFileAppender
-log4j.appender.policyLog.layout=org.apache.log4j.PatternLayout
-log4j.appender.policyLog.layout.ConversionPattern=%d{MMM dd, yyyy HH:mm:ss} %C{6} - %M %n %-5p: %m%n
-log4j.appender.policyLog.File=./logs/policies.log
-
-log4j.appender.authLog=org.apache.log4j.RollingFileAppender
-log4j.appender.authLog.layout=org.apache.log4j.PatternLayout
-log4j.appender.authLog.layout.ConversionPattern=%d{MMM dd, yyyy HH:mm:ss} %C{6} - %M %n %-5p: %m%n
-log4j.appender.authLog.File=./logs/auth.log
-
-log4j.appender.debugLog=org.apache.log4j.RollingFileAppender
-log4j.appender.debugLog.layout=org.apache.log4j.PatternLayout
-log4j.appender.debugLog.layout.ConversionPattern=%d{MMM dd, yyyy HH:mm:ss} %C{6} - %M %n %-5p: %m%n
-log4j.appender.debugLog.File=./logs/logging.log
-
-
-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
diff --git a/lite/src/main/resources/log4j2.properties b/lite/src/main/resources/log4j2.properties
new file mode 100644
index 0000000..6692040
--- /dev/null
+++ b/lite/src/main/resources/log4j2.properties
@@ -0,0 +1,21 @@
+appenders = console, file
+appender.console.type = Console
+appender.console.name = STDOUT
+appender.console.layout.type = PatternLayout
+appender.console.layout.pattern = %d{yyyy-MM-dd, HH:mm:ss} %C{6} - %M%n %-5p: %m%n
+
+appender.file.type = File
+appender.file.name = ERRORLOG
+appender.file.fileName=./logs/errors.log
+appender.file.layout.type=PatternLayout
+appender.file.layout.pattern= %d{yyyy-MM-dd, HH:mm:ss} %C{6} - %M%n %-5p: %m%n
+
+rootLogger.level = error
+rootLogger.appenderRefs = stdout
+rootLogger.appenderRef.stdout.ref = STDOUT
+
+#loggers=file
+#logger.file.name=de.ids_mannheim.korap
+#logger.file.level = error
+#logger.file.appenderRefs = file
+#logger.file.appenderRef.file.ref = ERRORLOG
\ No newline at end of file