/* * Copyright (C) 2014 Divide.io * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ 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<String, Object> { private static final boolean DEBUG = false; public Wrapper(){} public <B extends TransientObject> 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<Map.Entry> 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<String,Object> 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 extends TransientObject> B toObject(Class<B> type){ try { Constructor<B> 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<FileInfo> files = new ArrayList<FileInfo>(); @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<Class>, JsonDeserializer<Class> { @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() + '\'' + '}'; } }