001 package railo.runtime.converter; 002 003 import java.io.IOException; 004 import java.io.Serializable; 005 import java.io.Writer; 006 import java.util.Date; 007 import java.util.HashSet; 008 import java.util.Iterator; 009 import java.util.List; 010 import java.util.ListIterator; 011 import java.util.Map; 012 import java.util.Map.Entry; 013 import java.util.Set; 014 015 import org.w3c.dom.Node; 016 017 import railo.commons.lang.StringUtil; 018 import railo.runtime.Component; 019 import railo.runtime.ComponentScope; 020 import railo.runtime.ComponentWrap; 021 import railo.runtime.PageContext; 022 import railo.runtime.component.Property; 023 import railo.runtime.exp.ExpressionException; 024 import railo.runtime.exp.PageException; 025 import railo.runtime.functions.displayFormatting.DateFormat; 026 import railo.runtime.functions.displayFormatting.TimeFormat; 027 import railo.runtime.op.Caster; 028 import railo.runtime.orm.hibernate.HBMCreator; 029 import railo.runtime.text.xml.XMLCaster; 030 import railo.runtime.type.Array; 031 import railo.runtime.type.Collection; 032 import railo.runtime.type.Collection.Key; 033 import railo.runtime.type.KeyImpl; 034 import railo.runtime.type.ObjectWrap; 035 import railo.runtime.type.Query; 036 import railo.runtime.type.Struct; 037 import railo.runtime.type.UDF; 038 import railo.runtime.type.cfc.ComponentAccess; 039 import railo.runtime.type.dt.DateTime; 040 import railo.runtime.type.dt.DateTimeImpl; 041 import railo.runtime.type.dt.TimeSpan; 042 import railo.runtime.type.util.ComponentUtil; 043 import railo.runtime.type.util.KeyConstants; 044 045 /** 046 * class to serialize and desirilize WDDX Packes 047 */ 048 public final class ScriptConverter extends ConverterSupport { 049 private static final Collection.Key REMOTING_FETCH = KeyImpl.intern("remotingFetch"); 050 051 private int deep=1; 052 private boolean ignoreRemotingFetch=true; 053 054 /** 055 * constructor of the class 056 */ 057 public ScriptConverter() { 058 } 059 public ScriptConverter(boolean ignoreRemotingFetch) { 060 this.ignoreRemotingFetch=ignoreRemotingFetch; 061 } 062 063 064 /** 065 * serialize Serializable class 066 * @param serializable 067 * @param sb 068 * @throws ConverterException 069 */ 070 private void _serializeSerializable(Serializable serializable, StringBuffer sb) throws ConverterException { 071 072 sb.append(goIn()); 073 sb.append("evaluateJava('"); 074 try { 075 sb.append(JavaConverter.serialize(serializable)); 076 } catch (IOException e) { 077 throw toConverterException(e); 078 } 079 sb.append("')"); 080 081 } 082 083 /** 084 * serialize a Date 085 * @param date Date to serialize 086 * @param sb 087 * @throws ConverterException 088 */ 089 private void _serializeDate(Date date, StringBuffer sb) throws ConverterException { 090 _serializeDateTime(new DateTimeImpl(date),sb); 091 } 092 /** 093 * serialize a DateTime 094 * @param dateTime DateTime to serialize 095 * @param sb 096 * @throws ConverterException 097 */ 098 private void _serializeDateTime(DateTime dateTime, StringBuffer sb) throws ConverterException { 099 100 101 try { 102 sb.append(goIn()); 103 sb.append("createDateTime("); 104 sb.append(DateFormat.call(null,dateTime,"yyyy,m,d")); 105 sb.append(','); 106 sb.append(TimeFormat.call(null,dateTime,"H,m,s,l,\"z\"")); 107 sb.append(')'); 108 } 109 catch (PageException e) { 110 throw toConverterException(e); 111 } 112 } 113 114 /** 115 * serialize a Array 116 * @param array Array to serialize 117 * @param sb 118 * @param done 119 * @throws ConverterException 120 */ 121 private void _serializeArray(Array array, StringBuffer sb, Set<Object> done) throws ConverterException { 122 _serializeList(array.toList(),sb,done); 123 } 124 125 /** 126 * serialize a List (as Array) 127 * @param list List to serialize 128 * @param sb 129 * @param done 130 * @throws ConverterException 131 */ 132 private void _serializeList(List list, StringBuffer sb, Set<Object> done) throws ConverterException { 133 134 sb.append(goIn()); 135 sb.append("["); 136 boolean doIt=false; 137 ListIterator it=list.listIterator(); 138 while(it.hasNext()) { 139 if(doIt)sb.append(','); 140 doIt=true; 141 _serialize(it.next(),sb,done); 142 } 143 144 sb.append(']'); 145 } 146 147 /** 148 * serialize a Struct 149 * @param struct Struct to serialize 150 * @param sb 151 * @param done 152 * @throws ConverterException 153 */ 154 public void _serializeStruct(Struct struct, StringBuffer sb, Set<Object> done) throws ConverterException { 155 sb.append(goIn()); 156 sb.append('{'); 157 Iterator it=struct.keyIterator(); 158 boolean doIt=false; 159 deep++; 160 while(it.hasNext()) { 161 String key=Caster.toString(it.next(),""); 162 if(doIt)sb.append(','); 163 doIt=true; 164 sb.append('\''); 165 sb.append(escape(key)); 166 sb.append('\''); 167 sb.append(':'); 168 _serialize(struct.get(key,null),sb,done); 169 } 170 deep--; 171 172 sb.append('}'); 173 } 174 175 public String serializeStruct(Struct struct, Set<Collection.Key> ignoreSet) throws ConverterException { 176 StringBuffer sb =new StringBuffer(); 177 sb.append(goIn()); 178 sb.append("{"); 179 boolean hasIgnores=ignoreSet!=null; 180 Iterator<Key> it = struct.keyIterator(); 181 boolean doIt=false; 182 deep++; 183 Key key; 184 while(it.hasNext()) { 185 key = it.next(); 186 if(hasIgnores && ignoreSet.contains(key)) continue; 187 if(doIt)sb.append(','); 188 doIt=true; 189 sb.append('\''); 190 sb.append(escape(key.getString())); 191 sb.append('\''); 192 sb.append(':'); 193 _serialize(struct.get(key,null),sb,new HashSet<Object>()); 194 } 195 deep--; 196 197 return sb.append('}').toString(); 198 } 199 200 /** 201 * serialize a Map (as Struct) 202 * @param map Map to serialize 203 * @param sb 204 * @param done 205 * @throws ConverterException 206 */ 207 private void _serializeMap(Map map, StringBuffer sb, Set<Object> done) throws ConverterException { 208 sb.append(goIn()); 209 sb.append("{"); 210 211 Iterator it=map.keySet().iterator(); 212 boolean doIt=false; 213 deep++; 214 while(it.hasNext()) { 215 Object key=it.next(); 216 if(doIt)sb.append(','); 217 doIt=true; 218 sb.append('\''); 219 sb.append(escape(key.toString())); 220 sb.append('\''); 221 sb.append(':'); 222 _serialize(map.get(key),sb,done); 223 } 224 deep--; 225 226 sb.append('}'); 227 } 228 /** 229 * serialize a Component 230 * @param component Component to serialize 231 * @param sb 232 * @param done 233 * @throws ConverterException 234 */ 235 private void _serializeComponent(Component c, StringBuffer sb, Set<Object> done) throws ConverterException { 236 237 ComponentAccess ci; 238 try { 239 ci = ComponentUtil.toComponentAccess(c); 240 } catch (ExpressionException ee) { 241 throw new ConverterException(ee.getMessage()); 242 } 243 ComponentWrap cw = new ComponentWrap(Component.ACCESS_PRIVATE,ci); 244 245 246 sb.append(goIn()); 247 try { 248 sb.append("evaluateComponent('"+c.getAbsName()+"','"+ComponentUtil.md5(ci)+"',{"); 249 } catch (Exception e) { 250 throw toConverterException(e); 251 } 252 253 boolean doIt=false; 254 Object member; 255 { 256 257 Iterator<Entry<Key, Object>> it = cw.entryIterator(); 258 deep++; 259 Entry<Key, Object> e; 260 while(it.hasNext()) { 261 e = it.next(); 262 member = e.getValue(); 263 if(member instanceof UDF)continue; 264 if(doIt)sb.append(','); 265 doIt=true; 266 sb.append('\''); 267 sb.append(escape(e.getKey().getString())); 268 sb.append('\''); 269 sb.append(':'); 270 _serialize(member,sb,done); 271 } 272 sb.append("}"); 273 deep--; 274 } 275 { 276 boolean isPeristent=ci.isPersistent(); 277 278 ComponentScope scope = ci.getComponentScope(); 279 Iterator<Entry<Key, Object>> it = scope.entryIterator(); 280 sb.append(",{"); 281 deep++; 282 doIt=false; 283 Property p; 284 Boolean remotingFetch; 285 Struct props = ignoreRemotingFetch?null:ComponentUtil.getPropertiesAsStruct(ci,false); 286 Entry<Key, Object> e; 287 Key k; 288 while(it.hasNext()) { 289 e = it.next(); 290 k = e.getKey(); 291 //String key=Caster.toString(it.next(),""); 292 if(KeyConstants._THIS.equalsIgnoreCase(k))continue; 293 if(!ignoreRemotingFetch) { 294 p=(Property) props.get(k,null); 295 if(p!=null) { 296 remotingFetch=Caster.toBoolean(p.getDynamicAttributes().get(REMOTING_FETCH,null),null); 297 if(remotingFetch==null){ 298 if(isPeristent && HBMCreator.isRelated(p)) continue; 299 } 300 else if(!remotingFetch.booleanValue()) continue; 301 } 302 } 303 304 305 306 member = e.getValue(); 307 if(member instanceof UDF)continue; 308 if(doIt)sb.append(','); 309 doIt=true; 310 sb.append('\''); 311 sb.append(escape(k.getString())); 312 sb.append('\''); 313 sb.append(':'); 314 _serialize(member,sb,done); 315 } 316 sb.append("}"); 317 deep--; 318 } 319 320 sb.append(")"); 321 //sb.append(""); 322 //throw new ConverterException("can't serialize a component "+component.getDisplayName()); 323 } 324 325 /** 326 * serialize a Query 327 * @param query Query to serialize 328 * @param sb 329 * @param done 330 * @throws ConverterException 331 */ 332 private void _serializeQuery(Query query, StringBuffer sb, Set<Object> done) throws ConverterException { 333 334 //Collection.Key[] keys = query.keys(); 335 Iterator<Key> it = query.keyIterator(); 336 Key k; 337 sb.append(goIn()); 338 sb.append("query("); 339 340 341 deep++; 342 boolean oDoIt=false; 343 int len=query.getRecordcount(); 344 while(it.hasNext()) { 345 k = it.next(); 346 if(oDoIt)sb.append(','); 347 oDoIt=true; 348 sb.append(goIn()); 349 sb.append('\''); 350 sb.append(escape(k.getString())); 351 sb.append('\''); 352 sb.append(":["); 353 boolean doIt=false; 354 for(int y=1;y<=len;y++) { 355 if(doIt)sb.append(','); 356 doIt=true; 357 try { 358 _serialize(query.getAt(k,y),sb,done); 359 } catch (PageException e) { 360 _serialize(e.getMessage(),sb,done); 361 } 362 } 363 sb.append(']'); 364 } 365 deep--; 366 367 sb.append(')'); 368 369 } 370 371 /** 372 * serialize a Object to his xml Format represenation 373 * @param object Object to serialize 374 * @param sb StringBuffer to write data 375 * @param done 376 * @throws ConverterException 377 */ 378 private void _serialize(Object object, StringBuffer sb, Set<Object> done) throws ConverterException { 379 //try { 380 deep++; 381 // NULL 382 if(object==null) { 383 sb.append(goIn()); 384 sb.append("nullValue()"); 385 deep--; 386 return; 387 } 388 // String 389 if(object instanceof String) { 390 sb.append(goIn()); 391 sb.append("'"); 392 sb.append(escape(object.toString())); 393 sb.append("'"); 394 deep--; 395 return; 396 } 397 // Number 398 if(object instanceof Number) { 399 sb.append(goIn()); 400 sb.append(Caster.toString(((Number)object).doubleValue())); 401 deep--; 402 return; 403 } 404 // Boolean 405 if(object instanceof Boolean) { 406 sb.append(goIn()); 407 sb.append(Caster.toString(((Boolean)object).booleanValue())); 408 deep--; 409 return; 410 } 411 // DateTime 412 if(object instanceof DateTime) { 413 _serializeDateTime((DateTime)object,sb); 414 deep--; 415 return; 416 } 417 // Date 418 if(object instanceof Date) { 419 _serializeDate((Date)object,sb); 420 deep--; 421 return; 422 } 423 // XML 424 if(object instanceof Node) { 425 _serializeXML((Node)object,sb); 426 deep--; 427 return; 428 } 429 if(object instanceof ObjectWrap) { 430 try { 431 _serialize(((ObjectWrap)object).getEmbededObject(), sb,done); 432 } catch (PageException e) { 433 throw toConverterException(e); 434 } 435 deep--; 436 return; 437 } 438 // Timespan 439 if(object instanceof TimeSpan) { 440 _serializeTimeSpan((TimeSpan) object,sb); 441 deep--; 442 return; 443 } 444 Object raw = LazyConverter.toRaw(object); 445 if(done.contains(raw)) { 446 sb.append(goIn()); 447 sb.append("nullValue()"); 448 deep--; 449 return; 450 } 451 452 done.add(raw); 453 try { 454 // Component 455 if(object instanceof Component) { 456 _serializeComponent((Component)object,sb,done); 457 deep--; 458 return; 459 } 460 461 // Struct 462 if(object instanceof Struct) { 463 _serializeStruct((Struct)object,sb,done); 464 deep--; 465 return; 466 } 467 // Map 468 if(object instanceof Map) { 469 _serializeMap((Map)object,sb,done); 470 deep--; 471 return; 472 } 473 // Array 474 if(object instanceof Array) { 475 _serializeArray((Array)object,sb,done); 476 deep--; 477 return; 478 } 479 // List 480 if(object instanceof List) { 481 _serializeList((List)object,sb,done); 482 deep--; 483 return; 484 } 485 // Query 486 if(object instanceof Query) { 487 _serializeQuery((Query)object,sb,done); 488 deep--; 489 return; 490 } 491 // String Converter 492 if(object instanceof ScriptConvertable) { 493 sb.append(((ScriptConvertable)object).serialize()); 494 deep--; 495 return; 496 } 497 if(object instanceof Serializable) { 498 _serializeSerializable((Serializable)object,sb); 499 deep--; 500 return; 501 } 502 } 503 finally { 504 done.remove(raw); 505 } 506 throw new ConverterException("can't serialize Object of type [ "+Caster.toClassName(object)+" ]"); 507 //deep--; 508 /*} 509 catch(StackOverflowError soe){ 510 throw soe; 511 }*/ 512 } 513 514 515 516 private void _serializeXML(Node node, StringBuffer sb) { 517 node=XMLCaster.toRawNode(node); 518 sb.append(goIn()); 519 sb.append("xmlParse('"); 520 sb.append(escape(XMLCaster.toString(node,""))); 521 sb.append("')"); 522 523 } 524 525 private void _serializeTimeSpan(TimeSpan span, StringBuffer sb) { 526 527 sb.append(goIn()); 528 sb.append("createTimeSpan("); 529 sb.append(span.getDay()); 530 sb.append(','); 531 sb.append(span.getHour()); 532 sb.append(','); 533 sb.append(span.getMinute()); 534 sb.append(','); 535 sb.append(span.getSecond()); 536 sb.append(')'); 537 538 } 539 540 541 private String escape(String str) { 542 return StringUtil.replace(StringUtil.replace(str,"'","''",false),"#","##",false); 543 } 544 545 @Override 546 public void writeOut(PageContext pc, Object source, Writer writer) throws ConverterException, IOException { 547 writer.write(serialize(source)); 548 writer.flush(); 549 } 550 551 /** 552 * serialize a Object to his literal Format 553 * @param object Object to serialize 554 * @return serialized wddx package 555 * @throws ConverterException 556 */ 557 public String serialize(Object object) throws ConverterException { 558 deep=0; 559 StringBuffer sb=new StringBuffer(); 560 _serialize(object,sb,new HashSet<Object>()); 561 return sb.toString(); 562 } 563 564 565 /** 566 * @return return current blockquote 567 */ 568 private String goIn() { 569 /*StringBuffer rtn=new StringBuffer('\n'); 570 for(int i=0;i<deep;i++) rtn.append('\t'); 571 return rtn.toString(); 572 /*/ 573 574 return ""; 575 } 576 577 578 }