All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.divide.client.cache.Wrapper Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (C) 2014 Divide.io
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see .
 */

package io.divide.client.cache;

import com.google.gson.*;
import io.divide.shared.transitory.query.Query;
import io.divide.shared.util.ObjectUtils;
import io.divide.shared.util.ReflectionUtils;
import io.divide.shared.transitory.TransientObject;

import java.lang.reflect.Constructor;
import java.lang.reflect.Type;
import java.util.*;

import static io.divide.shared.util.ObjectUtils.*;

//@BoxLength(2048)
public class Wrapper extends HashMap {

    private static final boolean DEBUG = false;

    public Wrapper(){}

    public  Wrapper(B b){
        Key(b.getObjectKey());
        Table(Query.safeTable(b.getObjectType()));

        recursiveSave("user_data", "", b.getUserData());
        recursiveSave("meta_data", "", b.getMetaData());

        if(DEBUG) System.out.println("Table: " + b.getObjectType());
        if(DEBUG) System.out.println("Key: " + b.getObjectKey());
    }

    public String Key() {
        return (String ) this.get("Key");
    }

    public void Key(String value) {
        this.put("Key", value);
    }

    public String Table() {
        return (String ) this.get("Table");
    }

    public void Table(String value) {
        this.put("Table", value);
    }

    private FileInfo recursiveSave(String root, String current, Object object){
        String currentPath;
        if(current!=null && current.length()>0){
            currentPath = root + "." + current;
        } else currentPath = root;
        if(DEBUG) System.out.println("recursiveSave: " + currentPath);
        if(isMap(object)){
            Map m = (Map)object;
            Manifest manifest = new Manifest();
            Set objects = m.entrySet();
            for(Map.Entry e : objects){
                FileInfo coded = recursiveSave(currentPath, String.valueOf(e.getKey()), e.getValue());
                manifest.files.add(coded);
            }
            put("x." + currentPath,manifest.toString());
            if(DEBUG) System.out.println("manifest["+"x." + currentPath+"] " + manifest.toString());
            return new FileInfo('x',null,current);
        }
        else if(isCollection(object)){
            Object[] array = ((Collection) object).toArray(new Object[0]);
            if(DEBUG) System.out.println("SaveC["+currentPath+"=" + array +"]");
            put(currentPath, array);

            return new FileInfo('c',object.getClass(),current);
        }
        else if(isArray(object)){
            Object[] array = (Object[]) object;
            put(currentPath, array);

            return new FileInfo('a',object.getClass(),current);
        }
        else {
            if(DEBUG) System.out.println("Save["+currentPath+"=" + object +"]");
            put(currentPath, object);

            return new FileInfo('n',null,current);
        }
    }

    private void recursiveLoad(String currentPath, Map map){
        if(DEBUG) System.out.println("recursiveLoad: " + currentPath);

        String json = (String) get("x." + currentPath);
        Manifest manifest = Manifest.fromString(json);
        if(DEBUG) System.out.println("Files: " + ObjectUtils.v2c(manifest));

        for(FileInfo file : manifest.files) {
            String path = file.path;
            switch (file.type){
                case 'x' : {
                    recursiveLoad(currentPath + "." + path, map);
                }break;
                case 'a' : {
                    if(DEBUG) System.out.println("Loada["+currentPath+"."+path+"]");
                    Class type = file.clazz;
                    Object[] raw = (Object[]) get(currentPath+"."+path);
                    Object o = type.cast(raw);
                    map.put(path,o);
                }break;
                case 'c' : {
                    if(DEBUG) System.out.println("Loadc["+currentPath+"."+path+"]");
                    Class type = file.clazz;
                    Object[] raw = (Object[]) get(currentPath+"."+path);
//                    Object o = type.cast( v2c(raw) );
                    Object o = v2c(raw);
                    map.put(path,o);
                }break;
                case 'n' : {
                    if(DEBUG) System.out.println("Loadn["+currentPath+"."+path+"]");
                    Object raw = get(currentPath+"."+path);
                    map.put(path,raw);
                }
            }
        }
    }

    private String fromArray(Object o){

        return "";
    }

    private String fromCollection(Object o){

        return "";
    }

    public  B toObject(Class type){
        try {
            Constructor constructor;
            constructor = type.getDeclaredConstructor();
            constructor.setAccessible(true);

            B b = constructor.newInstance();

            Map user_data = (Map) ReflectionUtils.getObjectField(b, TransientObject.USER_DATA);
            Map meta_data = (Map) ReflectionUtils.getObjectField(b, TransientObject.META_DATA);
            user_data.clear();
            meta_data.clear();

            recursiveLoad("user_data",user_data);
            recursiveLoad("meta_data",meta_data);

            return b;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    private static final class Manifest{
        private static Gson gson;
        static {
            gson = new GsonBuilder().registerTypeAdapter(Class.class,new ClassTypeConverter()).create();
        }
        public final List files = new ArrayList();

        @Override
        public String toString(){
            return gson.toJson(this);
        }

        public static Manifest fromString(String string){
            return gson.fromJson(string,Manifest.class);
        }
    }

    private static final class FileInfo{
        public char type;
        public Class clazz;
        public String path;

        public FileInfo(char type, Class clazz, String path){
            this.type = type;
            this.clazz = clazz;
            this.path = path;
        }
    }

    private static class ClassTypeConverter implements JsonSerializer, JsonDeserializer {
        @Override
        public JsonElement serialize(Class src, Type srcType, JsonSerializationContext context) {
            return new JsonPrimitive(src.getName());
        }

        @Override
        public Class deserialize(JsonElement json, Type type, JsonDeserializationContext context)
                throws JsonParseException {
            try {
                return Class.forName(json.getAsString());
            } catch (ClassNotFoundException e) {
                return null;
            }
        }
    }

    @Override
    public String toString(){
        return "Wrapper{" +
                "Table='" + Table() + '\'' +
                "Key='" +   Key() + '\'' +
                '}';    }

}