001 package railo.runtime.functions.conversion; 002 003 import java.util.Iterator; 004 005 import railo.commons.lang.StringUtil; 006 import railo.runtime.PageContext; 007 import railo.runtime.exp.PageException; 008 import railo.runtime.ext.function.Function; 009 import railo.runtime.interpreter.JSONExpressionInterpreter; 010 import railo.runtime.op.Caster; 011 import railo.runtime.type.Array; 012 import railo.runtime.type.ArrayImpl; 013 import railo.runtime.type.Collection; 014 import railo.runtime.type.Collection.Key; 015 import railo.runtime.type.KeyImpl; 016 import railo.runtime.type.List; 017 import railo.runtime.type.QueryImpl; 018 import railo.runtime.type.Struct; 019 020 /** 021 * Decodes Binary Data that are encoded as String 022 */ 023 public final class DeserializeJSON implements Function { 024 025 private static final Key COLUMNS = KeyImpl.intern("COLUMNS"); 026 private static final Key COLUMNLIST = KeyImpl.intern("COLUMNLIST"); 027 private static final Key DATA = KeyImpl.intern("DATA"); 028 private static final Key ROWCOUNT = KeyImpl.intern("ROWCOUNT"); 029 private static final Key RECORDCOUNT = KeyImpl.intern("RECORDCOUNT"); 030 031 public static Object call(PageContext pc, String JSONVar) throws PageException { 032 return call(pc,JSONVar,true); 033 } 034 public static Object call(PageContext pc, String JSONVar,boolean strictMapping) throws PageException { 035 Object result = new JSONExpressionInterpreter().interpret(pc, JSONVar); 036 if(!strictMapping) return toQuery(result); 037 return result; 038 } 039 040 //{"COLUMNS":["AAA","BBB"],"DATA":[["a","b"],["c","d"]]} 041 //{"ROWCOUNT":2,"COLUMNS":["AAA","BBB"],"DATA":{"aaa":["a","c"],"bbb":["b","d"]}} 042 private static Object toQuery(Object obj) throws PageException { 043 if(obj instanceof Struct) { 044 Struct sct=(Struct) obj; 045 Key[] keys = sct.keys(); 046 047 // Columns 048 Key[] columns = null; 049 if(contains(keys,COLUMNS)) 050 columns = toColumns(sct.get(COLUMNS,null)); 051 else if(contains(keys,COLUMNLIST)) 052 columns = toColumnlist(sct.get(COLUMNLIST,null)); 053 054 // rowcount 055 int rowcount = -1; 056 if(contains(keys,ROWCOUNT)) 057 rowcount = toRowCount(sct.get(ROWCOUNT,null)); 058 else if(contains(keys,RECORDCOUNT)) 059 rowcount = toRowCount(sct.get(RECORDCOUNT,null)); 060 061 062 if(columns!=null) { 063 if(keys.length==2 && contains(keys,DATA)) { 064 065 Array[] data = toData(sct.get(DATA,null),columns); 066 if(data!=null) { 067 return new QueryImpl(columns,data,"query"); 068 } 069 } 070 071 else if(keys.length==3 && rowcount!=-1 && contains(keys,DATA)) { 072 Array[] data = toData(sct.get(DATA,null),columns,rowcount); 073 if(data!=null) { 074 return new QueryImpl(columns,data,"query"); 075 } 076 } 077 } 078 return toQuery(sct,keys); 079 } 080 /*else if(obj instanceof Query) { 081 return toQuery((Query) obj); 082 }*/ 083 else if(obj instanceof Collection) { 084 Collection coll=(Collection) obj; 085 return toQuery(coll, coll.keys()); 086 } 087 088 return obj; 089 090 } 091 092 /*private static Object toQuery(Query qry) throws DatabaseException { 093 int rows=qry.getRecordcount(); 094 String[] columns = qry.getColumns(); 095 Object src,trg; 096 for(int row=1;row<=rows;row++) { 097 for(int col=0;col<columns.length;col++) { 098 trg=toQuery(src=qry.getAt(columns[col], row, null)); 099 if(src!=trg) qry.setAtEL(columns[col], row, trg); 100 } 101 } 102 return qry; 103 }*/ 104 105 private static Collection toQuery(Collection coll, Key[] keys) throws PageException { 106 Object src,trg; 107 for(int i=0;i<keys.length;i++) { 108 trg=toQuery(src=coll.get(keys[i],null)); 109 if(src!=trg) coll.setEL(keys[i], trg); 110 } 111 return coll; 112 } 113 114 private static int toRowCount(Object obj) { 115 return Caster.toIntValue(obj,-1); 116 } 117 118 private static Array[] toData(Object obj, Key[] columns, int rowcount) throws PageException { 119 if(columns==null || rowcount==-1) return null; 120 121 Struct sct = Caster.toStruct(obj,null,false); 122 if(sct!=null && sct.size()==columns.length) { 123 Array[] datas=new Array[columns.length]; 124 Array col; 125 int colLen=-1; 126 for(int i=0;i<columns.length;i++) { 127 col=Caster.toArray(sct.get(columns[i],null),null); 128 if(col==null || colLen!=-1 && colLen!=col.size()) return null; 129 datas[i]=(Array) toQuery(col,col.keys()); 130 colLen=col.size(); 131 } 132 return datas; 133 } 134 return null; 135 } 136 137 private static Array[] toData(Object obj,Key[] columns) throws PageException { 138 if(columns==null) return null; 139 140 Array arr = Caster.toArray(obj,null); 141 if(arr!=null) { 142 Array[] datas=new Array[columns.length]; 143 for(int i=0;i<datas.length;i++) { 144 datas[i]=new ArrayImpl(); 145 } 146 147 Array data; 148 Iterator it = arr.iterator(); 149 while(it.hasNext()) { 150 data=Caster.toArray(it.next(),null); 151 if(data==null || data.size()!=datas.length) return null; 152 for(int i=0;i<datas.length;i++) { 153 datas[i].appendEL(toQuery(data.get(i+1,null))); 154 } 155 } 156 return datas; 157 } 158 return null; 159 } 160 161 162 private static Key[] toColumns(Object obj) { 163 Array arr = Caster.toArray(obj,null); 164 if(arr!=null) { 165 Key[] columns=new Key[arr.size()]; 166 String column; 167 int index=0; 168 Iterator it = arr.iterator(); 169 while(it.hasNext()) { 170 column=Caster.toString(it.next(),null); 171 if(StringUtil.isEmpty(column)) return null; 172 columns[index++]=KeyImpl.getInstance(column); 173 } 174 return columns; 175 } 176 return null; 177 } 178 179 private static Key[] toColumnlist(Object obj) throws PageException { 180 String list = Caster.toString(obj,null); 181 if(StringUtil.isEmpty(list)) return null; 182 return toColumns(List.trimItems(List.listToArrayRemoveEmpty(list, ','))); 183 } 184 185 186 /*private static boolean contains(Key[] haystack, Key[] needle) { 187 Key h; 188 outer:for(int i=0;i<haystack.length;i++) { 189 h=haystack[i]; 190 for(int y=0;y<needle.length;y++) { 191 if(h.equalsIgnoreCase(needle[y])) continue outer; 192 } 193 return false; 194 } 195 return true; 196 }*/ 197 198 199 private static boolean contains(Key[] haystack, Key needle) { 200 for(int i=0;i<haystack.length;i++) { 201 if(haystack[i].equalsIgnoreCase(needle)) return true; 202 } 203 return false; 204 } 205 }