user data factory pattern
diff --git a/src/main/java/de/ids_mannheim/korap/interfaces/AuthenticationManagerIface.java b/src/main/java/de/ids_mannheim/korap/interfaces/AuthenticationManagerIface.java
index ccc79d8..a6cf827 100644
--- a/src/main/java/de/ids_mannheim/korap/interfaces/AuthenticationManagerIface.java
+++ b/src/main/java/de/ids_mannheim/korap/interfaces/AuthenticationManagerIface.java
@@ -1,10 +1,7 @@
 package de.ids_mannheim.korap.interfaces;
 
 import de.ids_mannheim.korap.exceptions.KustvaktException;
-import de.ids_mannheim.korap.user.TokenContext;
-import de.ids_mannheim.korap.user.User;
-import de.ids_mannheim.korap.user.UserDetails;
-import de.ids_mannheim.korap.user.UserSettings;
+import de.ids_mannheim.korap.user.*;
 
 import java.util.HashMap;
 import java.util.Map;
@@ -57,10 +54,15 @@
     public abstract User createUserAccount(Map attributes,
             boolean confirmation_required) throws KustvaktException;
 
-//    public abstract boolean updateAccount(User user) throws KustvaktException;
+    //    public abstract boolean updateAccount(User user) throws KustvaktException;
 
     public abstract boolean deleteAccount(User user) throws KustvaktException;
 
+    public abstract <T extends Userdata> T getUserData(User user,
+            Class<T> clazz) throws KustvaktException;
+
+    public abstract void updateUserData(Userdata data) throws KustvaktException;
+
     public abstract UserDetails getUserDetails(User user)
             throws KustvaktException;
 
diff --git a/src/main/java/de/ids_mannheim/korap/security/auth/KustvaktAuthenticationManager.java b/src/main/java/de/ids_mannheim/korap/security/auth/KustvaktAuthenticationManager.java
index 306eade..8cd65eb 100644
--- a/src/main/java/de/ids_mannheim/korap/security/auth/KustvaktAuthenticationManager.java
+++ b/src/main/java/de/ids_mannheim/korap/security/auth/KustvaktAuthenticationManager.java
@@ -146,6 +146,7 @@
         return user;
     }
 
+    // todo: dont use annotations for caching
     @CachePut(value = "users", key = "#user.getUsername()")
     public TokenContext createTokenContext(User user, Map<String, String> attr,
             String provider_key) throws KustvaktException {
@@ -153,7 +154,7 @@
                 Attributes.API_AUTHENTICATION);
 
         if (attr.get(Attributes.SCOPES) != null)
-            this.getUserDetails(user);
+            this.getUserData(user, Userdetails2.class);
 
         TokenContext context = provider.createUserSession(user, attr);
         if (context == null)
@@ -634,7 +635,7 @@
                     username), StatusCodes.PASSWORD_RESET_FAILED, username);
         }
 
-        getUserDetails(ident);
+        this.getUserData(ident, Userdetails2.class);
         KorAPUser user = (KorAPUser) ident;
         if (!mail.equals(user.getDetails().getEmail()))
             //            throw new NotAuthorizedException(StatusCodes.ILLEGAL_ARGUMENT,
@@ -694,12 +695,14 @@
         }
     }
 
+    @Override
     public <T extends Userdata> T getUserData(User user, Class<T> clazz) {
         UserDataDbIface<T> dao = UserdataFactory.getDaoInstance(clazz);
         return dao.get(user);
     }
 
     //todo: cache userdata outside of the user object!
+    @Override
     public void updateUserData(Userdata data) {
         UserDataDbIface dao = UserdataFactory.getDaoInstance(data.getClass());
         dao.update(data);
diff --git a/src/main/java/de/ids_mannheim/korap/user/User.java b/src/main/java/de/ids_mannheim/korap/user/User.java
index 0806d2e..5cc1403 100644
--- a/src/main/java/de/ids_mannheim/korap/user/User.java
+++ b/src/main/java/de/ids_mannheim/korap/user/User.java
@@ -31,7 +31,7 @@
     private UserDetails details;
     private List<UserQuery> queries;
 
-    private List<? extends Userdata> userdata;
+    private List<Userdata> userdata;
 
     protected User() {
         this.fields = new ParamFields();
@@ -73,6 +73,17 @@
         }
     }
 
+    public void addUserData(Userdata data) {
+        if (data != null) {
+            for (Userdata d : this.userdata) {
+                // already has an object of that type!
+                if (d.getClass().equals(data.getClass()))
+                    return;
+            }
+            userdata.add(data);
+        }
+    }
+
     @Deprecated
     public void setDetails(UserDetails details) {
         if (details != null)
diff --git a/src/main/java/de/ids_mannheim/korap/user/Userdata.java b/src/main/java/de/ids_mannheim/korap/user/Userdata.java
index 1ffdfe1..42d8247 100644
--- a/src/main/java/de/ids_mannheim/korap/user/Userdata.java
+++ b/src/main/java/de/ids_mannheim/korap/user/Userdata.java
@@ -57,7 +57,17 @@
     }
 
     public boolean isValid() {
-        return this.missing(this.fields).isEmpty() && this.userID != -1;
+        //        return this.missing(this.fields).isEmpty() && this.userID != -1;
+        return validationReturn().length == 0;
+    }
+
+    public String[] validationReturn() {
+        StringBuilder b = new StringBuilder();
+        Set<String> m = missing(this.fields);
+        for (String k : m) {
+            b.append(k).append(";");
+        }
+        return b.toString().split(";");
     }
 
     public Set<String> keys() {
@@ -74,6 +84,17 @@
             this.fields.putAll(m);
     }
 
+    public void update(Userdata other) {
+        if (other != null && this.getClass().equals(other.getClass())) {
+            if (!other.isValid()) {
+                throw new RuntimeException(
+                        "User data object not valid. Missing fields: "
+                                + missing(this.fields));
+            }
+            this.fields.putAll(other.fields);
+        }
+    }
+
     public String data() {
         return JsonUtils.toJSON(this.fields);
     }
@@ -84,5 +105,4 @@
 
     public abstract String[] requiredFields();
 
-
 }
diff --git a/src/main/java/de/ids_mannheim/korap/web/service/full/AuthService.java b/src/main/java/de/ids_mannheim/korap/web/service/full/AuthService.java
index f53c816..05f3c53 100644
--- a/src/main/java/de/ids_mannheim/korap/web/service/full/AuthService.java
+++ b/src/main/java/de/ids_mannheim/korap/web/service/full/AuthService.java
@@ -7,10 +7,7 @@
 import de.ids_mannheim.korap.exceptions.StatusCodes;
 import de.ids_mannheim.korap.interfaces.AuthenticationManagerIface;
 import de.ids_mannheim.korap.security.auth.BasicHttpAuth;
-import de.ids_mannheim.korap.user.Attributes;
-import de.ids_mannheim.korap.user.TokenContext;
-import de.ids_mannheim.korap.user.User;
-import de.ids_mannheim.korap.user.UserSettings;
+import de.ids_mannheim.korap.user.*;
 import de.ids_mannheim.korap.utils.JsonUtils;
 import de.ids_mannheim.korap.utils.KustvaktLogger;
 import de.ids_mannheim.korap.utils.ServiceVersion;
@@ -118,7 +115,9 @@
         TokenContext context;
         try {
             User user = controller.authenticate(0, values[0], values[1], attr);
-            this.controller.getUserDetails(user);
+            Userdata data = this.controller
+                    .getUserData(user, Userdetails2.class);
+            user.addUserData(data);
             context = controller.createTokenContext(user, attr,
                     Attributes.API_AUTHENTICATION);
         }catch (KustvaktException e) {
diff --git a/src/main/java/de/ids_mannheim/korap/web/service/full/OAuthService.java b/src/main/java/de/ids_mannheim/korap/web/service/full/OAuthService.java
index 11fc0b3..9e85bbf 100644
--- a/src/main/java/de/ids_mannheim/korap/web/service/full/OAuthService.java
+++ b/src/main/java/de/ids_mannheim/korap/web/service/full/OAuthService.java
@@ -8,9 +8,7 @@
 import de.ids_mannheim.korap.handlers.OAuth2Handler;
 import de.ids_mannheim.korap.interfaces.AuthenticationManagerIface;
 import de.ids_mannheim.korap.interfaces.EncryptionIface;
-import de.ids_mannheim.korap.user.Attributes;
-import de.ids_mannheim.korap.user.TokenContext;
-import de.ids_mannheim.korap.user.User;
+import de.ids_mannheim.korap.user.*;
 import de.ids_mannheim.korap.utils.JsonUtils;
 import de.ids_mannheim.korap.utils.StringUtils;
 import de.ids_mannheim.korap.web.KustvaktServer;
@@ -127,7 +125,9 @@
         User user;
         try {
             user = this.controller.getUser(ctx.getUsername());
-            this.controller.getUserDetails(user);
+            Userdata data = this.controller
+                    .getUserData(user, Userdetails2.class);
+            user.addUserData(data);
             Set<String> base_scope = StringUtils.toSet(scopes, " ");
             base_scope.retainAll(StringUtils.toSet(scopes));
             scopes = StringUtils.toString(base_scope);
@@ -136,8 +136,8 @@
         }
         // json format with scope callback parameter
         // todo: add other scopes as well!
-        return Response.ok(JsonUtils.toJSON(Scopes
-                .mapScopes(scopes, user.getDetails()))).build();
+        return Response.ok(JsonUtils
+                .toJSON(Scopes.mapScopes(scopes, user.getDetails()))).build();
     }
 
     @GET
@@ -198,7 +198,9 @@
 
             try {
                 user = controller.getUser(c.getUsername());
-                controller.getUserDetails(user);
+                Userdata data = controller
+                        .getUserData(user, Userdetails2.class);
+                user.addUserData(data);
             }catch (KustvaktException e) {
                 throw KustvaktResponseHandler.throwit(e);
             }
@@ -540,7 +542,10 @@
                         user = controller
                                 .authenticate(0, oauthRequest.getUsername(),
                                         oauthRequest.getPassword(), attr);
-                    controller.getUserDetails(user);
+                    Userdata data = controller
+                            .getUserData(user, Userdetails2.class);
+                    user.addUserData(data);
+
                     attr.put(Attributes.CLIENT_SECRET,
                             oauthRequest.getClientSecret());
                     TokenContext c = controller.createTokenContext(user, attr,
diff --git a/src/main/java/de/ids_mannheim/korap/web/service/full/UserService.java b/src/main/java/de/ids_mannheim/korap/web/service/full/UserService.java
index d76d02f..b342e84 100644
--- a/src/main/java/de/ids_mannheim/korap/web/service/full/UserService.java
+++ b/src/main/java/de/ids_mannheim/korap/web/service/full/UserService.java
@@ -220,7 +220,10 @@
         User user;
         try {
             user = controller.getUser(ctx.getUsername());
-            controller.getUserDetails(user);
+            Userdata data = controller
+                    .getUserData(user, Userdetails2.class);
+            user.addUserData(data);
+
             Set<String> base_scope = StringUtils.toSet(scopes, " ");
             if (scopes != null)
                 base_scope.retainAll(StringUtils.toSet(scopes));
@@ -297,7 +300,10 @@
         User user;
         try {
             user = controller.getUser(ctx.getUsername());
-            controller.getUserDetails(user);
+            Userdata data = controller
+                    .getUserData(user, Userdetails2.class);
+            user.addUserData(data);
+
         }catch (KustvaktException e) {
             jlog.error("Exception encountered!", e);
             throw KustvaktResponseHandler.throwit(e);
diff --git a/src/test/java/UserdataTest.java b/src/test/java/UserdataTest.java
index a10a480..ea47a99 100644
--- a/src/test/java/UserdataTest.java
+++ b/src/test/java/UserdataTest.java
@@ -59,6 +59,18 @@
     }
 
     @Test
+    public void testDataValidation() {
+        Userdata data = new Userdetails2(1);
+        data.addField(Attributes.COUNTRY, "Germany");
+
+        String[] req = data.requiredFields();
+        String[] r = data.validationReturn();
+        assert r.length > 0;
+        assert r.length == req.length;
+        assert !data.isValid();
+    }
+
+    @Test
     public void testUserdatafactory() {
         UserDataDbIface dao = UserdataFactory
                 .getDaoInstance(Userdetails2.class);