001 002 package railo.runtime.converter; 003 004 import java.util.Calendar; 005 import java.util.HashSet; 006 import java.util.Iterator; 007 import java.util.List; 008 import java.util.ListIterator; 009 import java.util.Map; 010 import java.util.Set; 011 012 import railo.commons.date.JREDateTimeUtil; 013 import railo.commons.lang.StringUtil; 014 import railo.runtime.engine.ThreadLocalPageContext; 015 import railo.runtime.exp.PageException; 016 import railo.runtime.op.Caster; 017 import railo.runtime.op.Decision; 018 import railo.runtime.type.Array; 019 import railo.runtime.type.Collection.Key; 020 import railo.runtime.type.Query; 021 import railo.runtime.type.Struct; 022 import railo.runtime.type.dt.DateTime; 023 024 025 /** 026 * class to serialize to Convert Cold Fusion Objects (query,array,struct usw) to a JavaScript representation 027 */ 028 public final class JSConverter { 029 030 private static final String NULL = "null"; 031 private boolean useShortcuts=false; 032 private boolean useWDDX=true; 033 034 /** 035 * serialize a Cold Fusion object to a JavaScript Object 036 * @param object object to serialize 037 * @param clientVariableName name of the variable to create 038 * @return vonverte Javascript Code as String 039 * @throws ConverterException 040 */ 041 public String serialize(Object object, String clientVariableName) throws ConverterException { 042 StringBuffer sb=new StringBuffer(); 043 _serialize(clientVariableName,object,sb,new HashSet<Object>()); 044 String str = sb.toString().trim(); 045 return clientVariableName+"="+str+(StringUtil.endsWith(str, ';')?"":";"); 046 //return sb.toString(); 047 } 048 049 private void _serialize(String name,Object object,StringBuffer sb,Set<Object> done) throws ConverterException { 050 // NULL 051 if(object==null) { 052 sb.append(goIn()); 053 sb.append(NULL+";"); 054 return; 055 } 056 // String 057 if(object instanceof String || object instanceof StringBuffer) { 058 sb.append(goIn()); 059 sb.append("\""); 060 sb.append(StringUtil.escapeJS(object.toString())); 061 sb.append("\";"); 062 return; 063 } 064 // Number 065 if(object instanceof Number) { 066 sb.append(goIn()); 067 sb.append("\""); 068 sb.append(Caster.toString(((Number)object).doubleValue())); 069 sb.append("\";"); 070 return; 071 } 072 // Date 073 if(Decision.isDateSimple(object,false)) { 074 _serializeDateTime(Caster.toDate(object,false,null,null),sb); 075 return; 076 } 077 // Boolean 078 if(object instanceof Boolean) { 079 sb.append(goIn()); 080 sb.append("\""); 081 sb.append((((Boolean)object).booleanValue()?"true":"false")); 082 sb.append("\";"); 083 return; 084 } 085 086 Object raw = LazyConverter.toRaw(object); 087 if(done.contains(raw)){ 088 sb.append(NULL+";"); 089 return; 090 } 091 done.add(raw); 092 try { 093 // Struct 094 if(object instanceof Struct) { 095 _serializeStruct(name,(Struct)object,sb,done); 096 return; 097 } 098 // Map 099 if(object instanceof Map) { 100 _serializeMap(name,(Map)object,sb,done); 101 return; 102 } 103 // List 104 if(object instanceof List) { 105 _serializeList(name,(List)object,sb,done); 106 return; 107 } 108 // Array 109 if(Decision.isArray(object)) { 110 _serializeArray(name,Caster.toArray(object,null),sb,done); 111 return; 112 } 113 // Query 114 if(object instanceof Query) { 115 _serializeQuery(name,(Query)object,sb,done); 116 return; 117 } 118 } 119 finally { 120 done.remove(raw); 121 } 122 123 throw new ConverterException("can't serialize Object of type ["+Caster.toClassName(object)+"] to a js representation"); 124 //deep--; 125 //return rtn; 126 } 127 128 129 130 /** 131 * serialize a Array 132 * @param name 133 * @param array Array to serialize 134 * @param sb 135 * @param done 136 * @return serialized array 137 * @throws ConverterException 138 */ 139 private void _serializeArray(String name, Array array, StringBuffer sb, Set<Object> done) throws ConverterException { 140 _serializeList(name,array.toList(),sb,done); 141 } 142 143 /** 144 * serialize a List (as Array) 145 * @param name 146 * @param list List to serialize 147 * @param sb 148 * @param done 149 * @return serialized list 150 * @throws ConverterException 151 */ 152 private void _serializeList(String name, List list, StringBuffer sb, Set<Object> done) throws ConverterException { 153 154 155 if(useShortcuts)sb.append("[];"); 156 else sb.append("new Array();"); 157 158 ListIterator it=list.listIterator(); 159 int index=-1; 160 while(it.hasNext()) { 161 //if(index!=-1)sb.append(","); 162 index = it.nextIndex(); 163 sb.append(name+"["+index+"]="); 164 _serialize(name+"["+index+"]",it.next(),sb,done); 165 //sb.append(";"); 166 } 167 } 168 169 /** 170 * serialize a Struct 171 * @param name 172 * @param struct Struct to serialize 173 * @param done 174 * @param sb2 175 * @return serialized struct 176 * @throws ConverterException 177 */ 178 private String _serializeStruct(String name, Struct struct, StringBuffer sb, Set<Object> done) throws ConverterException { 179 if(useShortcuts)sb.append("{};"); 180 else sb.append("new Object();"); 181 182 Key[] keys = struct.keys(); 183 for(int i=0;i<keys.length;i++) { 184 // lower case ist ok! 185 String key=StringUtil.escapeJS(Caster.toString(keys[i].getLowerString(),"")); 186 sb.append(name+"[\""+key+"\"]="); 187 try { 188 _serialize(name+"[\""+key+"\"]",struct.get(keys[i]),sb,done); 189 } 190 catch (PageException e) { 191 _serialize(name+"[\""+key+"\"]",e.getMessage(),sb,done); 192 } 193 } 194 return sb.toString(); 195 } 196 197 /** 198 * serialize a Map (as Struct) 199 * @param name 200 * @param map Map to serialize 201 * @param done 202 * @param sb2 203 * @return serialized map 204 * @throws ConverterException 205 */ 206 private String _serializeMap(String name, Map map, StringBuffer sb, Set<Object> done) throws ConverterException { 207 208 if(useShortcuts)sb.append("{}"); 209 else sb.append("new Object();"); 210 Iterator it=map.keySet().iterator(); 211 while(it.hasNext()) { 212 Object key=it.next(); 213 String skey=StringUtil.toLowerCase(StringUtil.escapeJS(key.toString())); 214 sb.append(name+"[\""+skey+"\"]="); 215 _serialize(name+"[\""+skey+"\"]",map.get(key),sb,done); 216 //sb.append(";"); 217 } 218 return sb.toString(); 219 } 220 221 /** 222 * serialize a Query 223 * @param query Query to serialize 224 * @param done 225 * @return serialized query 226 * @throws ConverterException 227 */ 228 private void _serializeQuery(String name,Query query,StringBuffer sb, Set<Object> done) throws ConverterException { 229 if(useWDDX)_serializeWDDXQuery(name,query,sb,done); 230 else _serializeASQuery(name,query,sb,done); 231 } 232 233 private void _serializeWDDXQuery(String name,Query query,StringBuffer sb, Set<Object> done) throws ConverterException { 234 235 Key[] keys = query.keys(); 236 sb.append("new WddxRecordset();"); 237 238 int recordcount=query.getRecordcount(); 239 for(int i=0;i<keys.length;i++) { 240 if(useShortcuts)sb.append("col"+i+"=[];"); 241 else sb.append("col"+i+"=new Array();"); 242 // lower case ist ok! 243 String skey = StringUtil.escapeJS(keys[i].getLowerString()); 244 for(int y=0;y<recordcount;y++) { 245 246 sb.append("col"+i+"["+y+"]="); 247 248 _serialize("col"+i+"["+y+"]",query.getAt(keys[i],y+1,null),sb,done); 249 250 } 251 sb.append(name+"[\""+skey+"\"]=col"+i+";col"+i+"=null;"); 252 } 253 } 254 255 private void _serializeASQuery(String name,Query query,StringBuffer sb, Set<Object> done) throws ConverterException { 256 257 String[] keys = query.keysAsString(); 258 for(int i=0;i<keys.length;i++) { 259 keys[i] = StringUtil.escapeJS(keys[i]); 260 } 261 if(useShortcuts)sb.append("[];"); 262 else sb.append("new Array();"); 263 264 int recordcount=query.getRecordcount(); 265 for(int i=0;i<recordcount;i++) { 266 if(useShortcuts)sb.append(name+"["+i+"]={};"); 267 else sb.append(name+"["+i+"]=new Object();"); 268 269 for(int y=0;y<keys.length;y++) { 270 sb.append(name+"["+i+"]['"+keys[y]+"']="); 271 _serialize(name+"["+i+"]['"+keys[y]+"']",query.getAt(keys[y],i+1,null),sb,done); 272 } 273 } 274 } 275 276 277 278 /** 279 * serialize a DateTime 280 * @param dateTime DateTime to serialize 281 * @param sb 282 * @param sb 283 * @throws ConverterException 284 */ 285 private synchronized void _serializeDateTime(DateTime dateTime, StringBuffer sb) { 286 287 Calendar c = JREDateTimeUtil.newInstance(ThreadLocalPageContext.getTimeZone()); 288 c.setTime(dateTime); 289 sb.append(goIn()); 290 sb.append("new Date("); 291 sb.append(c.get(Calendar.YEAR)); 292 sb.append(","); 293 sb.append(c.get(Calendar.MONTH)); 294 sb.append(","); 295 sb.append(c.get(Calendar.DAY_OF_MONTH)); 296 sb.append(","); 297 sb.append(c.get(Calendar.HOUR_OF_DAY)); 298 sb.append(","); 299 sb.append(c.get(Calendar.MINUTE)); 300 sb.append(","); 301 sb.append(c.get(Calendar.SECOND)); 302 sb.append(");"); 303 } 304 305 private String goIn() { 306 //StringBuffer rtn=new StringBuffer(deep); 307 //for(int i=0;i<deep;i++) rtn.append('\t'); 308 return "";//rtn.toString(); 309 } 310 311 public void useShortcuts(boolean useShortcuts) { 312 this.useShortcuts=useShortcuts; 313 314 } 315 316 public void useWDDX(boolean useWDDX) { 317 this.useWDDX=useWDDX; 318 } 319 320 /* 321 * @param args 322 * @throws Exception 323 324 public static void main(String[] args) throws Exception { 325 JSConverter js=new JSConverter(); 326 Query query=QueryNew.call(null,"aaa,bbb,ccc"); 327 QueryAddRow.call(null,query); 328 QuerySetCell.call(null,query,"aaa","1.1"); 329 QuerySetCell.call(null,query,"bbb","1.2"); 330 QuerySetCell.call(null,query,"ccc","1.3"); 331 QueryAddRow.call(null,query); 332 QuerySetCell.call(null,query,"aaa","2.1"); 333 QuerySetCell.call(null,query,"bbb","2.2"); 334 QuerySetCell.call(null,query,"ccc","2.3"); 335 QueryAddRow.call(null,query); 336 QuerySetCell.call(null,query,"aaa","3.1"); 337 QuerySetCell.call(null,query,"bbb","3.2"); 338 QuerySetCell.call(null,query,"ccc","3.3<hello>"); 339 Array arr2=List ToArray.call(null,"111,222"); 340 Array arr=List ToArray.call(null,"aaaa,bbb,ccc,dddd,eee"); 341 342 arr.set(10,arr2); 343 344 Struct sct= new Struct(); 345 sct.set("aaa","val1"); 346 sct.set("bbb","val2"); 347 sct.set("ccc","val3"); 348 sct.set("ddd",arr2); 349 350 /* 351 }*/ 352 }