Added default setting key validation & fixed UserdataTest.

Change-Id: If427a13cf68977ee53579c1286930482dd9bfbeb
diff --git a/core/src/main/java/de/ids_mannheim/korap/config/ContextHolder.java b/core/src/main/java/de/ids_mannheim/korap/config/ContextHolder.java
index 9205c54..99c54ae 100644
--- a/core/src/main/java/de/ids_mannheim/korap/config/ContextHolder.java
+++ b/core/src/main/java/de/ids_mannheim/korap/config/ContextHolder.java
@@ -1,17 +1,13 @@
 package de.ids_mannheim.korap.config;
 
-import java.io.IOException;
 import java.util.Collection;
 
 import org.springframework.beans.factory.NoSuchBeanDefinitionException;
 import org.springframework.context.ApplicationContext;
 
-//import de.ids_mannheim.korap.interfaces.EncryptionIface;
-import de.ids_mannheim.korap.interfaces.ValidatorIface;
 import de.ids_mannheim.korap.interfaces.db.AuditingIface;
 import de.ids_mannheim.korap.interfaces.db.PersistenceClient;
 import de.ids_mannheim.korap.interfaces.db.UserDataDbIface;
-import de.ids_mannheim.korap.interfaces.defaults.ApacheValidator;
 import de.ids_mannheim.korap.web.CoreResponseHandler;
 
 /**
@@ -79,28 +75,22 @@
     }
 
 
+    @Deprecated
     public <T extends KustvaktConfiguration> T getConfiguration () {
         return (T) getBean(KUSTVAKT_CONFIG);
     }
 
 
+    @Deprecated
     public PersistenceClient getPersistenceClient () {
         return getBean(KUSTVAKT_DB);
     }
 
-
+    @Deprecated
     public Collection<UserDataDbIface> getUserDataProviders () {
         return getBean(KUSTVAKT_USERDATA);
     }
 
-    public ValidatorIface getValidator()  {
-        try {
-            return new ApacheValidator();
-        } catch (IOException e) {
-            throw new RuntimeException("validator could not be loaded!");
-        }
-    }
-
     private void close () {
         this.getAuditingProvider().finish();
         this.context = null;
diff --git a/core/src/main/java/de/ids_mannheim/korap/user/DataFactory.java b/core/src/main/java/de/ids_mannheim/korap/user/DataFactory.java
index 888ebb6..21aea9a 100644
--- a/core/src/main/java/de/ids_mannheim/korap/user/DataFactory.java
+++ b/core/src/main/java/de/ids_mannheim/korap/user/DataFactory.java
@@ -13,8 +13,8 @@
 import com.fasterxml.jackson.databind.node.ObjectNode;
 
 import de.ids_mannheim.korap.exceptions.KustvaktException;
-import de.ids_mannheim.korap.interfaces.ValidatorIface;
 import de.ids_mannheim.korap.utils.JsonUtils;
+import de.ids_mannheim.korap.validator.Validator;
 
 /**
  * EM: util class
@@ -52,7 +52,7 @@
 
     public abstract Collection<Object> values (Object data);
 
-    public abstract Object validate(Object data, ValidatorIface validator) throws KustvaktException;
+    public abstract Object validate(Object data, Validator validator) throws KustvaktException;
 
     @Deprecated
     public abstract Map<String, Object> fields (Object data);
@@ -130,7 +130,7 @@
         }
 
         @Override
-        public Object validate(Object data, ValidatorIface validator) throws KustvaktException {
+        public Object validate(Object data, Validator validator) throws KustvaktException {
             if (checkDataType(data) && ((JsonNode) data).isObject()) {
                 try {
                     @SuppressWarnings("unchecked")
diff --git a/core/src/main/java/de/ids_mannheim/korap/user/Userdata.java b/core/src/main/java/de/ids_mannheim/korap/user/Userdata.java
index 2d1693e..e735776 100644
--- a/core/src/main/java/de/ids_mannheim/korap/user/Userdata.java
+++ b/core/src/main/java/de/ids_mannheim/korap/user/Userdata.java
@@ -2,7 +2,7 @@
 
 import de.ids_mannheim.korap.exceptions.KustvaktException;
 import de.ids_mannheim.korap.exceptions.StatusCodes;
-import de.ids_mannheim.korap.interfaces.ValidatorIface;
+import de.ids_mannheim.korap.validator.Validator;
 import lombok.AccessLevel;
 import lombok.Getter;
 import lombok.Setter;
@@ -122,9 +122,10 @@
         dataFactory.addValue(this.data, key, value);
     }
 
-    // EM: not reliable
+    // EM: de.ids_mannheim.korap.interfaces.defaults.ApacheValidator.validateMap(Map<String, Object>)
+    // is not reliable
     // todo: test
-    public void validate (ValidatorIface validator) throws KustvaktException {
+    public void validate (Validator validator) throws KustvaktException {
         dataFactory.validate(this.data, validator);
     }
 
diff --git a/core/src/main/java/de/ids_mannheim/korap/interfaces/defaults/ApacheValidator.java b/core/src/main/java/de/ids_mannheim/korap/validator/ApacheValidator.java
similarity index 91%
rename from core/src/main/java/de/ids_mannheim/korap/interfaces/defaults/ApacheValidator.java
rename to core/src/main/java/de/ids_mannheim/korap/validator/ApacheValidator.java
index 6cc2224..c88a0da 100644
--- a/core/src/main/java/de/ids_mannheim/korap/interfaces/defaults/ApacheValidator.java
+++ b/core/src/main/java/de/ids_mannheim/korap/validator/ApacheValidator.java
@@ -1,23 +1,28 @@
-package de.ids_mannheim.korap.interfaces.defaults;
+package de.ids_mannheim.korap.validator;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import org.apache.commons.validator.routines.DateValidator;
+import org.apache.commons.validator.routines.EmailValidator;
+import org.apache.commons.validator.routines.RegexValidator;
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
 
 import de.ids_mannheim.korap.config.Attributes;
 import de.ids_mannheim.korap.config.ConfigLoader;
 import de.ids_mannheim.korap.exceptions.KustvaktException;
 import de.ids_mannheim.korap.exceptions.StatusCodes;
-import de.ids_mannheim.korap.interfaces.ValidatorIface;
 import de.ids_mannheim.korap.web.utils.KustvaktMap;
-import org.apache.commons.validator.routines.*;
-import org.apache.commons.validator.routines.RegexValidator;
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-
-import java.io.IOException;
-import java.util.*;
 
 /**
  * Created by hanl on 09.06.16.
+ *  
  */
-public class ApacheValidator implements ValidatorIface {
+public class ApacheValidator implements Validator {
 
     private static Logger jlog = LogManager.getLogger(ApacheValidator.class);
 
@@ -91,7 +96,7 @@
     public String validateEntry (String input, String type)
             throws KustvaktException {
         if (!isValid(input, type))
-            throw new KustvaktException(StatusCodes.ILLEGAL_ARGUMENT,
+            throw new KustvaktException(StatusCodes.INVALID_ARGUMENT,
                     "Entry did not validate for type '" + type + "'", input);
         return input;
     }
diff --git a/core/src/main/java/de/ids_mannheim/korap/interfaces/ValidatorIface.java b/core/src/main/java/de/ids_mannheim/korap/validator/Validator.java
similarity index 67%
rename from core/src/main/java/de/ids_mannheim/korap/interfaces/ValidatorIface.java
rename to core/src/main/java/de/ids_mannheim/korap/validator/Validator.java
index e8fb3c6..b20cb3b 100644
--- a/core/src/main/java/de/ids_mannheim/korap/interfaces/ValidatorIface.java
+++ b/core/src/main/java/de/ids_mannheim/korap/validator/Validator.java
@@ -1,13 +1,18 @@
-package de.ids_mannheim.korap.interfaces;
-
-import de.ids_mannheim.korap.exceptions.KustvaktException;
+package de.ids_mannheim.korap.validator;
 
 import java.util.Map;
 
+import org.springframework.stereotype.Component;
+
+import de.ids_mannheim.korap.exceptions.KustvaktException;
+
 /**
+ * EM: made this as a spring component
+ * 
  * Created by hanl on 08.06.16.
  */
-public interface ValidatorIface {
+@Component
+public interface Validator {
 
 
     Map<String, Object> validateMap (Map<String, Object> map) throws KustvaktException;
diff --git a/core/src/main/resources/validation.properties b/core/src/main/resources/validation.properties
index 0a8f4f0..15e09cd 100644
--- a/core/src/main/resources/validation.properties
+++ b/core/src/main/resources/validation.properties
@@ -35,4 +35,8 @@
 #Validator.username=^[A-Za-z_.\\d]{6,15}$ by Hanl
 # 21.04.17/FB
 Validator.username=^[A-Za-z_.\\d]{3,20}$
-Validator.password=^((?=.*\\d)(?=.*[A-Za-z])(?!.*[\\(\\)-]).{8,20})$
\ No newline at end of file
+Validator.password=^((?=.*\\d)(?=.*[A-Za-z])(?!.*[\\(\\)-]).{8,20})$
+
+
+# EM
+Validator.setting=[a-zA-Z0-9_-]+
\ No newline at end of file
diff --git a/full/Changes b/full/Changes
index 0c554ae..6b41749 100644
--- a/full/Changes
+++ b/full/Changes
@@ -24,6 +24,9 @@
 22/01/2019
    - Updated default setting controllers & added tests (margaretha)
    - Added delete key in setting controllers (margaretha)
+23/01/2019
+   - Added default setting key validation (margaretha)
+   - Fixed UserdataTest (margaretha) 
 
 # version 0.61.4
 14/11/2018
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 99b6b52..137812e 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
@@ -1,10 +1,7 @@
 package de.ids_mannheim.korap.authentication;
 
-import java.io.IOException;
-import java.io.UnsupportedEncodingException;
 import java.net.InetAddress;
 import java.net.UnknownHostException;
-import java.security.NoSuchAlgorithmException;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Map;
@@ -35,10 +32,8 @@
 import de.ids_mannheim.korap.exceptions.WrappedException;
 import de.ids_mannheim.korap.interfaces.EncryptionIface;
 import de.ids_mannheim.korap.interfaces.EntityHandlerIface;
-import de.ids_mannheim.korap.interfaces.ValidatorIface;
 import de.ids_mannheim.korap.interfaces.db.AuditingIface;
 import de.ids_mannheim.korap.interfaces.db.UserDataDbIface;
-import de.ids_mannheim.korap.interfaces.defaults.ApacheValidator;
 import de.ids_mannheim.korap.security.context.TokenContext;
 import de.ids_mannheim.korap.user.DemoUser;
 import de.ids_mannheim.korap.user.KorAPUser;
@@ -50,6 +45,7 @@
 import de.ids_mannheim.korap.user.UserSettingProcessor;
 import de.ids_mannheim.korap.user.Userdata;
 import de.ids_mannheim.korap.utils.TimeUtils;
+import de.ids_mannheim.korap.validator.Validator;
 
 /**
  * contains the logic to authentication and registration processes. Uses
@@ -69,9 +65,11 @@
 	private AdminDao adminDao;
 	private AuditingIface auditing;
 	private FullConfiguration config;
+	@Deprecated
 	private Collection userdatadaos;
 	private LoginCounter counter;
-	private ValidatorIface validator;
+	@Autowired
+	private Validator validator;
 	
 	public KustvaktAuthenticationManager(EntityHandlerIface userdb, EncryptionIface crypto,
 			FullConfiguration config, AuditingIface auditer, Collection<UserDataDbIface> userdatadaos) {
@@ -83,11 +81,11 @@
 		this.counter = new LoginCounter(config);
 		this.userdatadaos = userdatadaos;
 		// todo: load via beancontext
-		try {
-			this.validator = new ApacheValidator();
-		} catch (IOException e) {
-			e.printStackTrace();
-		}
+//		try {
+//			this.validator = new ApacheValidator();
+//		} catch (IOException e) {
+//			e.printStackTrace();
+//		}
 	}
 
 	/**
diff --git a/full/src/main/java/de/ids_mannheim/korap/dao/DefaultSettingDao.java b/full/src/main/java/de/ids_mannheim/korap/dao/DefaultSettingDao.java
index 1a60efc..e1239cf 100644
--- a/full/src/main/java/de/ids_mannheim/korap/dao/DefaultSettingDao.java
+++ b/full/src/main/java/de/ids_mannheim/korap/dao/DefaultSettingDao.java
@@ -16,6 +16,13 @@
 import de.ids_mannheim.korap.exceptions.KustvaktException;
 import de.ids_mannheim.korap.utils.ParameterChecker;
 
+/**
+ * DefaultSettingDao manages database queries and transactions
+ * regarding user default setting.
+ * 
+ * @author margaretha
+ *
+ */
 @Transactional
 @Repository
 public class DefaultSettingDao {
diff --git a/full/src/main/java/de/ids_mannheim/korap/service/DefaultSettingService.java b/full/src/main/java/de/ids_mannheim/korap/service/DefaultSettingService.java
index 1aabb9b..bd28723 100644
--- a/full/src/main/java/de/ids_mannheim/korap/service/DefaultSettingService.java
+++ b/full/src/main/java/de/ids_mannheim/korap/service/DefaultSettingService.java
@@ -10,16 +10,23 @@
 import de.ids_mannheim.korap.entity.DefaultSetting;
 import de.ids_mannheim.korap.exceptions.KustvaktException;
 import de.ids_mannheim.korap.exceptions.StatusCodes;
-import de.ids_mannheim.korap.user.DataFactory;
 import de.ids_mannheim.korap.user.UserSettingProcessor;
+import de.ids_mannheim.korap.validator.ApacheValidator;
 
+/**
+ * DefaultSettingService handles all business logic related to user
+ * default setting.
+ * 
+ * @author margaretha
+ *
+ */
 @Service
 public class DefaultSettingService {
 
     @Autowired
     private DefaultSettingDao settingDao;
-
-    public DataFactory dataFactory = DataFactory.getFactory();
+    @Autowired
+    private ApacheValidator validator;
 
     private String verifiyUsername (String username, String contextUsername)
             throws KustvaktException {
@@ -34,14 +41,21 @@
         return username;
     }
 
-    public int handlePutRequest (String username, Map<String, Object> map,
-            String contextUsername) throws KustvaktException {
-        username = verifiyUsername(username, contextUsername);
-
+    private void validateSettingMap (Map<String, Object> map)
+            throws KustvaktException {
         if (map == null || map.isEmpty()) {
             throw new KustvaktException(StatusCodes.INVALID_ARGUMENT,
                     "Entity body is empty. No settings are given.");
         }
+        for (String k : map.keySet()) {
+            validator.validateEntry(k, "setting");
+        }
+    }
+
+    public int handlePutRequest (String username, Map<String, Object> map,
+            String contextUsername) throws KustvaktException {
+        username = verifiyUsername(username, contextUsername);
+        validateSettingMap(map);
 
         UserSettingProcessor processor = new UserSettingProcessor();
         processor.readQuietly(map, false);
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/UserSettingController.java
similarity index 73%
rename from full/src/main/java/de/ids_mannheim/korap/web/controller/UserController.java
rename to full/src/main/java/de/ids_mannheim/korap/web/controller/UserSettingController.java
index 0fba5b7..5f24f00 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/UserSettingController.java
@@ -31,14 +31,19 @@
 import de.ids_mannheim.korap.web.filter.PiwikFilter;
 
 /**
+ * UserSettingController defines web APIs related to user default
+ * setting.
+ * 
+ * All the APIs in this class are only available to logged-in users.
+ * 
  * @author margaretha
  *
  */
 @Controller
-@Path("{version}/{username: ~[a-zA-Z0-9_]+}")
+@Path("{version}/{username: ~[a-zA-Z0-9_]+}/setting")
 @ResourceFilters({ AuthenticationFilter.class, APIVersionFilter.class,
         PiwikFilter.class })
-public class UserController {
+public class UserSettingController {
 
     @Autowired
     private DefaultSettingService settingService;
@@ -47,8 +52,23 @@
     @Autowired
     private OAuth2ScopeService scopeService;
 
+    /**
+     * Creates a default setting of the given username.
+     * The setting inputs should be represented as a pair of keys and
+     * values (a map). The keys must only contains alphabets, numbers,
+     * hypens or underscores.
+     * 
+     * 
+     * @param context
+     *            security context
+     * @param username
+     *            username
+     * @param map
+     *            the default setting
+     * @return status code 201 if a new resource is created, or 200 if
+     *         an existing resource is edited.
+     */
     @PUT
-    @Path("setting")
     @Consumes(MediaType.APPLICATION_JSON)
     @ResourceFilters({ AuthenticationFilter.class, PiwikFilter.class,
             BlockingFilter.class })
@@ -69,8 +89,16 @@
 
     }
 
+    /**
+     * Retrieves the default setting of the given username.
+     * 
+     * @param context
+     *            a security context
+     * @param username
+     *            a username
+     * @return the default setting of the given username
+     */
     @GET
-    @Path("setting")
     @ResourceFilters({ AuthenticationFilter.class, PiwikFilter.class,
             BlockingFilter.class })
     @Produces(MediaType.APPLICATION_JSON + ";charset=utf-8")
@@ -90,12 +118,20 @@
         }
     }
 
+    /**
+     * Deletes an entry of a default setting of a user by the given key.
+     * 
+     * @param context a security context
+     * @param username a username
+     * @param key the key of the default setting entry to be deleted
+     * @return
+     */
     @DELETE
-    @Path("setting/{key}")
+    @Path("{key}")
     @Consumes(MediaType.APPLICATION_JSON)
     @ResourceFilters({ AuthenticationFilter.class, PiwikFilter.class,
             BlockingFilter.class })
-    public Response createDefaultSetting (@Context SecurityContext context,
+    public Response deleteDefaultSettingEntry (@Context SecurityContext context,
             @PathParam("username") String username,
             @PathParam("key") String key) {
 
diff --git a/full/src/main/resources/default-config.xml b/full/src/main/resources/default-config.xml
index d543d53..c8fd658 100644
--- a/full/src/main/resources/default-config.xml
+++ b/full/src/main/resources/default-config.xml
@@ -198,6 +198,9 @@
 	<bean id="search_krill" class="de.ids_mannheim.korap.web.SearchKrill">
 		<constructor-arg value="${krill.indexDir}" />
 	</bean>
+	
+	<!-- Validator -->
+	<bean id="validator" class="de.ids_mannheim.korap.validator.ApacheValidator"/>
 
 	<!-- URLValidator -->
 	<bean id="redirectURIValidator" class="org.apache.commons.validator.routines.UrlValidator">
diff --git a/full/src/test/java/de/ids_mannheim/korap/user/UserdataTest.java b/full/src/test/java/de/ids_mannheim/korap/user/UserdataTest.java
index c97d0a5..970a698 100644
--- a/full/src/test/java/de/ids_mannheim/korap/user/UserdataTest.java
+++ b/full/src/test/java/de/ids_mannheim/korap/user/UserdataTest.java
@@ -3,84 +3,68 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 
-import org.junit.Before;
-import org.junit.Ignore;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
 import org.junit.Test;
 
+import com.fasterxml.jackson.databind.node.ArrayNode;
+
 import de.ids_mannheim.korap.config.Attributes;
-import de.ids_mannheim.korap.config.BeanConfigTest;
-import de.ids_mannheim.korap.config.BeansFactory;
 import de.ids_mannheim.korap.exceptions.KustvaktException;
-import de.ids_mannheim.korap.handlers.UserDetailsDao;
-import de.ids_mannheim.korap.handlers.UserSettingsDao;
-import de.ids_mannheim.korap.interfaces.db.UserDataDbIface;
+import de.ids_mannheim.korap.utils.JsonUtils;
+import de.ids_mannheim.korap.validator.ApacheValidator;
+import edu.emory.mathcs.backport.java.util.Arrays;
 
 /**
- * @author hanl
+ * @author hanl, margaretha
  * @date 27/01/2016
  */
-@Deprecated
-@Ignore
-public class UserdataTest extends BeanConfigTest {
+public class UserdataTest {
 
-    @Before
-    public void clear () {
-        UserDetailsDao dao = new UserDetailsDao(helper().getContext()
-                .getPersistenceClient());
-        UserSettingsDao sdao = new UserSettingsDao(helper().getContext()
-                .getPersistenceClient());
-        assertNotEquals(-1, dao.deleteAll());
-        assertNotEquals(-1, sdao.deleteAll());
+    // EM: added
+    @Test
+    public void testReadEmptyMap () throws KustvaktException {
+        Userdata userData = new UserSettingProcessor();
+        userData.read(new HashMap<>(), false);
+        String jsonSettings = userData.serialize();
+        assertEquals("{}", jsonSettings);
     }
 
-
     @Test
-    public void testDataStore () throws KustvaktException {
-        String val = "value1;value_data";
-        User user = new KorAPUser();
-        user.setId(1);
-        UserDetailsDao dao = new UserDetailsDao(helper().getContext()
-                .getPersistenceClient());
-        UserDetails d = new UserDetails(1);
-        d.setField(Attributes.FIRSTNAME, "first");
-        d.setField(Attributes.LASTNAME, "last");
-        d.setField(Attributes.ADDRESS, "address");
-        d.setField(Attributes.EMAIL, "email");
-        d.setField("key_1", val);
-        assertNotEquals(-1, dao.store(d));
+    public void testReadNullMap () throws KustvaktException {
+        Userdata userData = new UserSettingProcessor();
+        userData.read(null, false);
+        String jsonSettings = userData.serialize();
+        assertEquals("{}", jsonSettings);
     }
 
-
+    // EM: based on MH code, supposedly to validate entries like email
+    // and date. See ApacheValidator
+    //
+    // It has inconsistent behaviors:
+    // throws exceptions when there are invalid entries in a list,
+    // otherwise skips invalid entries and returns a valid map
+    // Moreover, Userdata.validate(ValidatorIface) does not return a
+    // valid map.
+    //
+    // At the moment, validation is not needed for default settings.
     @Test
-    public void testDataGet () throws KustvaktException {
-        String val = "value1;value_data";
-        User user = new KorAPUser();
-        user.setId(1);
-        
-        UserDetailsDao dao = new UserDetailsDao(helper().getContext()
-                .getPersistenceClient());
-        UserDetails d = new UserDetails(1);
-        d.setField(Attributes.FIRSTNAME, "first");
-        d.setField(Attributes.LASTNAME, "last");
-        d.setField(Attributes.ADDRESS, "address");
-        d.setField(Attributes.EMAIL, "email");
-        d.setField("key_1", val);
+    public void testValidateMap () throws IOException, KustvaktException {
 
-        assertNotEquals(-1, dao.store(d));
+        Map<String, Object> map = new HashMap<>();
+        map.put("k1", Arrays.asList(new String[] { "a", "b", "c" }));
+        map.put("k2", Arrays.asList(new Integer[] { 1, 2, 3 }));
 
-        d = dao.get(d.getId());
-        assertNotNull(d);
-        assertEquals(val, d.get("key_1"));
-
-        d = dao.get(user);
-        assertNotNull(d);
-        assertEquals(val, d.get("key_1"));
+        Userdata data = new UserSettingProcessor();
+        data.read(map, false);
+        data.validate(new ApacheValidator());
     }
 
-
+    // EM: below are tests from MH
     @Test
     public void testDataValidation () {
         Userdata data = new UserDetails(1);
@@ -96,7 +80,7 @@
 
     @Test
     public void testSettingsValidation () {
-        Userdata data = new UserSettingProcessor(1);
+        Userdata data = new UserSettingProcessor();
         data.setField(Attributes.FILE_FORMAT_FOR_EXPORT, "export");
 
         String[] req = data.requiredFields();
@@ -105,43 +89,95 @@
         assertEquals(req.length, r.length);
         assertTrue(data.isValid());
     }
+    
+    @Test
+    public void testUserdataRequiredFields () throws KustvaktException {
+        UserDetails details = new UserDetails(-1);
+        Map<String, Object> m = new HashMap<>();
+        m.put(Attributes.FIRSTNAME, "first");
+        m.put(Attributes.LASTNAME, "last");
+        m.put(Attributes.ADDRESS, "address");
+        m.put(Attributes.EMAIL, "email");
+        details.setData(JsonUtils.toJSON(m));
 
+        details.setData(JsonUtils.toJSON(m));
+        String[] missing = details.findMissingFields();
+        assertEquals(0, missing.length);
+    }
 
     @Test
-    public void testUserdataDaoTypefactory () throws KustvaktException {
-        UserDataDbIface dao = BeansFactory.getTypeFactory()
-                .getTypeInterfaceBean(
-                        helper().getContext().getUserDataProviders(),
-                        UserDetails.class);
-        assertNotNull(dao);
-        assertTrue(dao instanceof UserDetailsDao);
+    public void testUserdataDefaultFields () throws KustvaktException {
+        UserSettingProcessor settings = new UserSettingProcessor();
+        Map<String, Object> m = new HashMap<>();
+        m.put(Attributes.DEFAULT_REL_FOUNDRY, "rel_1");
+        m.put(Attributes.DEFAULT_CONST_FOUNDRY, "const_1");
+        m.put(Attributes.DEFAULT_POS_FOUNDRY, "pos_1");
+        m.put(Attributes.DEFAULT_LEMMA_FOUNDRY, "lemma_1");
+        m.put(Attributes.PAGE_LENGTH, 10);
+        m.put(Attributes.QUERY_LANGUAGE, "poliqarp");
+        m.put(Attributes.METADATA_QUERY_EXPERT_MODUS, false);
 
-        dao = BeansFactory.getTypeFactory().getTypeInterfaceBean(
-                helper().getContext().getUserDataProviders(),
-                UserSettingProcessor.class);
-        assertNotNull(dao);
-        assertTrue(dao instanceof UserSettingsDao);
+        settings.read(m, true);
+
+        assertNotEquals(m.size(), settings.size());
+        assertEquals(settings.defaultFields().length, settings.size());
+        assertEquals("rel_1", settings.get(Attributes.DEFAULT_REL_FOUNDRY));
+        assertEquals("pos_1", settings.get(Attributes.DEFAULT_POS_FOUNDRY));
+        assertEquals("lemma_1", settings.get(Attributes.DEFAULT_LEMMA_FOUNDRY));
+        assertEquals("const_1", settings.get(Attributes.DEFAULT_CONST_FOUNDRY));
+        assertEquals(10, settings.get(Attributes.PAGE_LENGTH));
+
     }
 
-    @Deprecated
-    @Test(expected = RuntimeException.class)
-    public void testUserdatafactoryError () throws KustvaktException {
-        BeansFactory.getTypeFactory().getTypeInterfaceBean(
-                helper().getContext().getUserDataProviders(), new Userdata(1) {
-                    @Override
-                    public String[] requiredFields () {
-                        return new String[0];
-                    }
+    @Test(expected = KustvaktException.class)
+    public void testUserDataRequiredFieldsException ()
+            throws KustvaktException {
+        UserDetails details = new UserDetails(-1);
+        Map<String, Object> m = new HashMap<>();
+        m.put(Attributes.FIRSTNAME, "first");
+        m.put(Attributes.LASTNAME, "last");
+        m.put(Attributes.ADDRESS, "address");
 
+        details.setData(JsonUtils.toJSON(m));
+        String[] missing = details.findMissingFields();
 
-                    @Override
-                    public String[] defaultFields () {
-                        return new String[0];
-                    }
-                }.getClass());
+        assertEquals(1, missing.length);
+        assertEquals("email", missing[0]);
+        details.checkRequired();
     }
 
+    @Test
+    public void testUserDataPointerFunction () throws KustvaktException {
+        UserDetails details = new UserDetails(-1);
+        Map<String, Object> m = new HashMap<>();
+        m.put(Attributes.FIRSTNAME, "first");
+        m.put(Attributes.LASTNAME, "last");
+        m.put(Attributes.ADDRESS, "address");
+        m.put(Attributes.EMAIL, "email");
+        details.setData(JsonUtils.toJSON(m));
 
-    @Override
-    public void initMethod () throws KustvaktException {}
+        ArrayNode array = JsonUtils.createArrayNode();
+        array.add(100);
+        array.add("message");
+        details.setField("errors", array);
+
+        assertEquals(100, details.get("/errors/0"));
+        assertEquals("message", details.get("/errors/1"));
+    }
+
+    @Test
+    public void testUserDataUpdate () {
+        UserDetails details = new UserDetails(-1);
+        details.setField(Attributes.FIRSTNAME, "first");
+        details.setField(Attributes.LASTNAME, "last");
+        details.setField(Attributes.ADDRESS, "address");
+        details.setField(Attributes.EMAIL, "email");
+
+        UserDetails details2 = new UserDetails(-1);
+        details2.setField(Attributes.COUNTRY, "Germany");
+        details.update(details2);
+
+        assertEquals("first", details.get(Attributes.FIRSTNAME));
+        assertEquals("Germany", details.get(Attributes.COUNTRY));
+    }
 }
diff --git a/full/src/test/java/de/ids_mannheim/korap/user/UserdataTest2.java b/full/src/test/java/de/ids_mannheim/korap/user/UserdataTest2.java
deleted file mode 100644
index 8364fb9..0000000
--- a/full/src/test/java/de/ids_mannheim/korap/user/UserdataTest2.java
+++ /dev/null
@@ -1,156 +0,0 @@
-package de.ids_mannheim.korap.user;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
-
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.Map;
-
-import org.junit.Test;
-
-import com.fasterxml.jackson.databind.node.ArrayNode;
-
-import de.ids_mannheim.korap.config.Attributes;
-import de.ids_mannheim.korap.exceptions.KustvaktException;
-import de.ids_mannheim.korap.interfaces.defaults.ApacheValidator;
-import de.ids_mannheim.korap.utils.JsonUtils;
-import edu.emory.mathcs.backport.java.util.Arrays;
-
-/**
- * @author margaretha, hanl
- *
- */
-public class UserdataTest2 {
-
-    @Test
-    public void testReadEmptyMap () throws KustvaktException {
-        Userdata userData = new UserSettingProcessor();
-        userData.read(new HashMap<>(), false);
-        String jsonSettings = userData.serialize();
-        assertEquals("{}", jsonSettings);
-    }
-
-    @Test
-    public void testReadNullMap () throws KustvaktException {
-        Userdata userData = new UserSettingProcessor();
-        userData.read(null, false);
-        String jsonSettings = userData.serialize();
-        assertEquals("{}", jsonSettings);
-    }
-
-    // EM: based on MH code, supposedly to validate entries like email
-    // and date. See ApacheValidator
-    //
-    // It has inconsistent behaviors:
-    // throws exceptions when there are invalid entries in a list,
-    // otherwise skips invalid entries and returns a valid map
-    // Moreover, Userdata.validate(ValidatorIface) does not return a
-    // valid map.
-    //
-    // At the moment, validation is not needed for default settings.
-    @Test
-    public void testValidateMap () throws IOException, KustvaktException {
-
-        Map<String, Object> map = new HashMap<>();
-        map.put("k1", Arrays.asList(new String[] { "a", "b", "c" }));
-        map.put("k2", Arrays.asList(new Integer[] { 1, 2, 3 }));
-
-        Userdata data = new UserSettingProcessor();
-        data.read(map, false);
-        data.validate(new ApacheValidator());
-    }
-
-    // EM: below are tests from MH
-
-    @Test
-    public void testUserdataRequiredFields () throws KustvaktException {
-        UserDetails details = new UserDetails(-1);
-        Map<String, Object> m = new HashMap<>();
-        m.put(Attributes.FIRSTNAME, "first");
-        m.put(Attributes.LASTNAME, "last");
-        m.put(Attributes.ADDRESS, "address");
-        m.put(Attributes.EMAIL, "email");
-        details.setData(JsonUtils.toJSON(m));
-
-        details.setData(JsonUtils.toJSON(m));
-        String[] missing = details.findMissingFields();
-        assertEquals(0, missing.length);
-    }
-
-    @Test
-    public void testUserdataDefaultFields () throws KustvaktException {
-        UserSettingProcessor settings = new UserSettingProcessor(-1);
-        Map<String, Object> m = new HashMap<>();
-        m.put(Attributes.DEFAULT_REL_FOUNDRY, "rel_1");
-        m.put(Attributes.DEFAULT_CONST_FOUNDRY, "const_1");
-        m.put(Attributes.DEFAULT_POS_FOUNDRY, "pos_1");
-        m.put(Attributes.DEFAULT_LEMMA_FOUNDRY, "lemma_1");
-        m.put(Attributes.PAGE_LENGTH, 10);
-        m.put(Attributes.QUERY_LANGUAGE, "poliqarp");
-        m.put(Attributes.METADATA_QUERY_EXPERT_MODUS, false);
-
-        settings.read(m, true);
-
-        assertNotEquals(m.size(), settings.size());
-        assertEquals(settings.defaultFields().length, settings.size());
-        assertEquals("rel_1", settings.get(Attributes.DEFAULT_REL_FOUNDRY));
-        assertEquals("pos_1", settings.get(Attributes.DEFAULT_POS_FOUNDRY));
-        assertEquals("lemma_1", settings.get(Attributes.DEFAULT_LEMMA_FOUNDRY));
-        assertEquals("const_1", settings.get(Attributes.DEFAULT_CONST_FOUNDRY));
-        assertEquals(10, settings.get(Attributes.PAGE_LENGTH));
-
-    }
-
-    @Test(expected = KustvaktException.class)
-    public void testUserDataRequiredFieldsException ()
-            throws KustvaktException {
-        UserDetails details = new UserDetails(-1);
-        Map<String, Object> m = new HashMap<>();
-        m.put(Attributes.FIRSTNAME, "first");
-        m.put(Attributes.LASTNAME, "last");
-        m.put(Attributes.ADDRESS, "address");
-
-        details.setData(JsonUtils.toJSON(m));
-        String[] missing = details.findMissingFields();
-
-        assertEquals(1, missing.length);
-        assertEquals("email", missing[0]);
-        details.checkRequired();
-    }
-
-    @Test
-    public void testUserDataPointerFunction () throws KustvaktException {
-        UserDetails details = new UserDetails(-1);
-        Map<String, Object> m = new HashMap<>();
-        m.put(Attributes.FIRSTNAME, "first");
-        m.put(Attributes.LASTNAME, "last");
-        m.put(Attributes.ADDRESS, "address");
-        m.put(Attributes.EMAIL, "email");
-        details.setData(JsonUtils.toJSON(m));
-
-        ArrayNode array = JsonUtils.createArrayNode();
-        array.add(100);
-        array.add("message");
-        details.setField("errors", array);
-
-        assertEquals(100, details.get("/errors/0"));
-        assertEquals("message", details.get("/errors/1"));
-    }
-
-    @Test
-    public void testUserDataUpdate () {
-        UserDetails details = new UserDetails(-1);
-        details.setField(Attributes.FIRSTNAME, "first");
-        details.setField(Attributes.LASTNAME, "last");
-        details.setField(Attributes.ADDRESS, "address");
-        details.setField(Attributes.EMAIL, "email");
-
-        UserDetails details2 = new UserDetails(-1);
-        details2.setField(Attributes.COUNTRY, "Germany");
-        details.update(details2);
-
-        assertEquals("first", details.get(Attributes.FIRSTNAME));
-        assertEquals("Germany", details.get(Attributes.COUNTRY));
-    }
-}
diff --git a/full/src/test/java/de/ids_mannheim/korap/web/controller/UserControllerTest.java b/full/src/test/java/de/ids_mannheim/korap/web/controller/UserSettingControllerTest.java
similarity index 90%
rename from full/src/test/java/de/ids_mannheim/korap/web/controller/UserControllerTest.java
rename to full/src/test/java/de/ids_mannheim/korap/web/controller/UserSettingControllerTest.java
index 69f47df..c3fd0b4 100644
--- a/full/src/test/java/de/ids_mannheim/korap/web/controller/UserControllerTest.java
+++ b/full/src/test/java/de/ids_mannheim/korap/web/controller/UserSettingControllerTest.java
@@ -26,10 +26,10 @@
  * @author margaretha
  *
  */
-public class UserControllerTest extends SpringJerseyTest {
+public class UserSettingControllerTest extends SpringJerseyTest {
 
-    private String username = "~UserControllerTest";
-    private String username2 = "~UserControllerTest2";
+    private String username = "~UserSettingTest";
+    private String username2 = "~UserSettingTest2";
 
     private ClientResponse sendPutRequest (String username,
             Map<String, Object> map) throws KustvaktException {
@@ -80,8 +80,22 @@
                 "author title textSigle availability");
 
         testUpdateSetting(username2);
+        testputRequestInvalidKey();
     }
+    
+    @Test
+    public void testputRequestInvalidKey () throws KustvaktException {
+        Map<String, Object> map = new HashMap<>();
+        map.put("key/", "invalidKey");
 
+        ClientResponse response = sendPutRequest(username2, map);
+        assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatus());
+        
+        JsonNode node = JsonUtils.readTree(response.getEntity(String.class));
+        assertEquals(StatusCodes.INVALID_ARGUMENT, node.at("/errors/0/0").asInt());
+        assertEquals("key/", node.at("/errors/0/2").asText());
+    }
+    
     @Test
     public void testPutDifferentUsername () throws KustvaktException {
         String json = "{\"foundry\":\"opennlp\",\"metadata\":\"author title "
@@ -155,7 +169,7 @@
 
         testRetrieveSettings(username, "malt", 15, "author title");
     }
-
+    
     private void testRetrieveSettings (String username, String foundry,
             int numOfResult, String metadata) throws KustvaktException {
         ClientResponse response = resource().path(API_VERSION).path(username)
diff --git a/full/src/test/resources/test-config.xml b/full/src/test/resources/test-config.xml
index d597eb4..6a19768 100644
--- a/full/src/test/resources/test-config.xml
+++ b/full/src/test/resources/test-config.xml
@@ -181,6 +181,9 @@
 		<constructor-arg value="${krill.indexDir}" />
 	</bean>
 
+	<!-- Validator -->
+	<bean id="validator" class="de.ids_mannheim.korap.validator.ApacheValidator"/>
+	
 	<!-- URLValidator -->
 	<bean id="redirectURIValidator" class="org.apache.commons.validator.routines.UrlValidator">
 		<constructor-arg value="http,https" index="0" />