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