userdata retrieval via json pointer

Change-Id: I58baf039958570ebaeb07afad7279b9424c62ece
diff --git a/src/main/java/de/ids_mannheim/korap/user/DataFactory.java b/src/main/java/de/ids_mannheim/korap/user/DataFactory.java
new file mode 100644
index 0000000..be6f02f
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/user/DataFactory.java
@@ -0,0 +1,222 @@
+package de.ids_mannheim.korap.user;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ArrayNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import de.ids_mannheim.korap.exceptions.KustvaktException;
+import de.ids_mannheim.korap.exceptions.StatusCodes;
+import de.ids_mannheim.korap.interfaces.db.UserDataDbIface;
+import de.ids_mannheim.korap.utils.JsonUtils;
+
+import java.util.*;
+
+/**
+ * @author hanl
+ * @date 27/01/2016
+ */
+public abstract class DataFactory {
+
+    private static final Map<Class<? extends Userdata>, UserDataDbIface> instances = new HashMap<>();
+
+    private static DataFactory factory;
+
+
+    private DataFactory () {}
+
+
+    public static DataFactory getFactory () {
+        if (factory == null)
+            factory = new DefaultFactory();
+        return factory;
+    }
+
+
+    /**
+     * if data string null, returns an empty data holding object
+     * 
+     * @param data
+     * @return
+     */
+    public abstract Object convertData (String data);
+
+
+    public abstract int size (Object data);
+
+
+    public abstract Set<String> keys (Object data);
+
+
+    public abstract Collection<Object> values (Object data);
+
+
+    @Deprecated
+    public abstract Map<String, Object> fields (Object data);
+
+
+    public abstract Object getValue (Object data, String pointer);
+
+
+    public abstract boolean addValue (Object data, String field, Object value);
+
+
+    public abstract boolean removeValue (Object data, String field);
+
+
+    public abstract String toStringValue (Object data);
+
+
+    public boolean checkDataType (Object data) {
+        throw new RuntimeException("Wrong data type for factory setting!");
+    }
+
+
+    /**
+     * updates data1 with values from data2
+     * 
+     * @param data1
+     *            data object that needs update
+     * @param data2
+     *            values that update data1
+     * @return
+     */
+    public abstract Object merge (Object data1, Object data2);
+
+
+
+    private static class DefaultFactory extends DataFactory {
+
+        @Override
+        public Object convertData (String data) {
+            if (data == null)
+                return JsonUtils.createObjectNode();
+            return JsonUtils.readTree(data);
+        }
+
+
+        @Override
+        public int size (Object data) {
+            if (checkDataType(data))
+                return ((JsonNode) data).size();
+            return -1;
+        }
+
+
+        @Override
+        public Set<String> keys (Object data) {
+            Set<String> keys = new HashSet<>();
+            if (checkDataType(data) && ((JsonNode) data).isObject()) {
+                Iterator it = ((JsonNode) data).fieldNames();
+                while (it.hasNext())
+                    keys.add((String) it.next());
+            }
+            return keys;
+        }
+
+
+        @Override
+        public Collection<Object> values (Object data) {
+            return new HashSet<>();
+        }
+
+
+        @Override
+        public Map<String, Object> fields (Object data) {
+            return new HashMap<>();
+        }
+
+
+        @Override
+        public Object getValue (Object data, String key) {
+            if (checkDataType(data)) {
+                JsonNode value;
+                if (key.startsWith("/"))
+                    value = ((JsonNode) data).at(key);
+                else
+                    value = ((JsonNode) data).path(key);
+
+                if (value.canConvertToInt())
+                    return value.asInt();
+                else if (value.isBoolean())
+                    return value.asBoolean();
+                else if (value.isTextual())
+                    return value.asText();
+            }
+            return null;
+        }
+
+
+        //fixme: test that this works with different types
+        @Override
+        public boolean addValue (Object data, String field, Object value) {
+            if (checkDataType(data)) {
+                if (((JsonNode) data).isObject()) {
+                    ObjectNode node = (ObjectNode) data;
+                    if (value instanceof String)
+                        node.put(field, (String) value);
+                    if (value instanceof Boolean)
+                        node.put(field, (Boolean) value);
+                    if (value instanceof Integer)
+                        node.put(field, (Integer) value);
+                    if (value instanceof JsonNode)
+                        node.put(field, (JsonNode) value);
+                    return true;
+                }
+                else if (((JsonNode) data).isArray()) {
+                    ArrayNode node = (ArrayNode) data;
+                    if (value instanceof String)
+                        node.add((String) value);
+                    if (value instanceof Boolean)
+                        node.add((Boolean) value);
+                    if (value instanceof Integer)
+                        node.add((Integer) value);
+                    return true;
+                }
+            }
+            return false;
+        }
+
+
+        @Override
+        public boolean removeValue (Object data, String field) {
+            if (checkDataType(data) && ((JsonNode) data).isObject()) {
+                ObjectNode node = (ObjectNode) data;
+                node.remove(field);
+                return true;
+            }
+            return false;
+        }
+
+
+        @Override
+        public String toStringValue (Object data) {
+            if (data instanceof JsonNode)
+                return JsonUtils.toJSON(data);
+            return data.toString();
+        }
+
+
+        @Override
+        public boolean checkDataType (Object data) {
+            if (!(data instanceof JsonNode))
+                super.checkDataType(data);
+            return true;
+        }
+
+
+        @Override
+        public Object merge (Object data1, Object data2) {
+            if (checkDataType(data1) && checkDataType(data2)) {
+                if (((JsonNode) data1).isObject()
+                        && ((JsonNode) data2).isObject()) {
+                    ((ObjectNode) data1).putAll((ObjectNode) data2);
+                }
+                else if (((JsonNode) data1).isArray()
+                        && ((JsonNode) data2).isArray()) {
+                    ((ArrayNode) data1).addAll((ArrayNode) data2);
+                }
+            }
+            return data1;
+        }
+
+    }
+}
diff --git a/src/main/java/de/ids_mannheim/korap/user/GenericUserData.java b/src/main/java/de/ids_mannheim/korap/user/GenericUserData.java
new file mode 100644
index 0000000..cf254dd
--- /dev/null
+++ b/src/main/java/de/ids_mannheim/korap/user/GenericUserData.java
@@ -0,0 +1,24 @@
+package de.ids_mannheim.korap.user;
+
+/**
+ * Created by hanl on 07.06.16.
+ */
+public class GenericUserData extends Userdata {
+
+
+    public GenericUserData () {
+        super(-1);
+    }
+
+
+    @Override
+    public String[] requiredFields () {
+        return new String[0];
+    }
+
+
+    @Override
+    public String[] defaultFields () {
+        return new String[0];
+    }
+}
diff --git a/src/test/java/de/ids_mannheim/korap/config/BeanInjectTest.java b/src/test/java/de/ids_mannheim/korap/config/BeanInjectTest.java
new file mode 100644
index 0000000..cd2f480
--- /dev/null
+++ b/src/test/java/de/ids_mannheim/korap/config/BeanInjectTest.java
@@ -0,0 +1,58 @@
+package de.ids_mannheim.korap.config;
+
+import de.ids_mannheim.korap.handlers.DocumentDao;
+import de.ids_mannheim.korap.handlers.ResourceDao;
+import de.ids_mannheim.korap.handlers.UserDetailsDao;
+import de.ids_mannheim.korap.handlers.UserSettingsDao;
+import de.ids_mannheim.korap.resources.Document;
+import de.ids_mannheim.korap.resources.KustvaktResource;
+import de.ids_mannheim.korap.user.UserDetails;
+import de.ids_mannheim.korap.user.UserSettings;
+import org.junit.Test;
+import org.springframework.aop.support.AopUtils;
+
+import java.util.Collection;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+/**
+ * Created by hanl on 03.06.16.
+ */
+public class BeanInjectTest {
+
+
+
+    @Test
+    public void testUserBeans () {
+        BeansFactory.loadClasspathContext("default-config.xml");
+        Collection coll = BeansFactory.getKustvaktContext()
+                .getUserDataProviders();
+        assertFalse(coll.isEmpty());
+        Object o = BeansFactory.getTypeFactory().getTypeInterfaceBean(coll,
+                UserSettings.class);
+        assertEquals(UserSettingsDao.class, AopUtils.getTargetClass(o));
+
+        o = BeansFactory.getTypeFactory().getTypeInterfaceBean(coll,
+                UserDetails.class);
+        assertEquals(UserDetailsDao.class, AopUtils.getTargetClass(o));
+        BeansFactory.closeApplication();
+    }
+
+
+    @Test
+    public void testResourceBeans () {
+        BeansFactory.loadClasspathContext("default-config.xml");
+        Collection coll = BeansFactory.getKustvaktContext()
+                .getResourceProviders();
+        assertFalse(coll.isEmpty());
+        Object o = BeansFactory.getTypeFactory().getTypeInterfaceBean(coll,
+                Document.class);
+        assertEquals(DocumentDao.class, AopUtils.getTargetClass(o));
+
+        o = BeansFactory.getTypeFactory().getTypeInterfaceBean(coll,
+                KustvaktResource.class);
+        assertEquals(ResourceDao.class, AopUtils.getTargetClass(o));
+        BeansFactory.closeApplication();
+    }
+}