package railo.runtime.converter; import java.io.IOException; import java.io.Serializable; import java.io.Writer; import java.util.Date; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.ListIterator; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import org.w3c.dom.Node; import railo.commons.lang.StringUtil; import railo.runtime.Component; import railo.runtime.ComponentScope; import railo.runtime.ComponentWrap; import railo.runtime.PageContext; import railo.runtime.component.Property; import railo.runtime.exp.ExpressionException; import railo.runtime.exp.PageException; import railo.runtime.functions.displayFormatting.DateFormat; import railo.runtime.functions.displayFormatting.TimeFormat; import railo.runtime.op.Caster; import railo.runtime.orm.ORMUtil; import railo.runtime.text.xml.XMLCaster; import railo.runtime.type.Array; import railo.runtime.type.Collection; import railo.runtime.type.Collection.Key; import railo.runtime.type.KeyImpl; import railo.runtime.type.ObjectWrap; import railo.runtime.type.Query; import railo.runtime.type.Struct; import railo.runtime.type.UDF; import railo.runtime.type.cfc.ComponentAccess; import railo.runtime.type.dt.DateTime; import railo.runtime.type.dt.DateTimeImpl; import railo.runtime.type.dt.TimeSpan; import railo.runtime.type.util.ComponentUtil; import railo.runtime.type.util.KeyConstants; /** * class to serialize and desirilize WDDX Packes */ public final class ScriptConverter extends ConverterSupport { private static final Collection.Key REMOTING_FETCH = KeyImpl.intern("remotingFetch"); private int deep=1; private boolean ignoreRemotingFetch=true; /** * constructor of the class */ public ScriptConverter() { } public ScriptConverter(boolean ignoreRemotingFetch) { this.ignoreRemotingFetch=ignoreRemotingFetch; } /** * serialize Serializable class * @param serializable * @param sb * @throws ConverterException */ private void _serializeSerializable(Serializable serializable, StringBuffer sb) throws ConverterException { sb.append(goIn()); sb.append("evaluateJava('"); try { sb.append(JavaConverter.serialize(serializable)); } catch (IOException e) { throw toConverterException(e); } sb.append("')"); } /** * serialize a Date * @param date Date to serialize * @param sb * @throws ConverterException */ private void _serializeDate(Date date, StringBuffer sb) throws ConverterException { _serializeDateTime(new DateTimeImpl(date),sb); } /** * serialize a DateTime * @param dateTime DateTime to serialize * @param sb * @throws ConverterException */ private void _serializeDateTime(DateTime dateTime, StringBuffer sb) throws ConverterException { try { sb.append(goIn()); sb.append("createDateTime("); sb.append(DateFormat.call(null,dateTime,"yyyy,m,d")); sb.append(','); sb.append(TimeFormat.call(null,dateTime,"H,m,s,l,\"z\"")); sb.append(')'); } catch (PageException e) { throw toConverterException(e); } } /** * serialize a Array * @param array Array to serialize * @param sb * @param done * @throws ConverterException */ private void _serializeArray(Array array, StringBuffer sb, Set<Object> done) throws ConverterException { _serializeList(array.toList(),sb,done); } /** * serialize a List (as Array) * @param list List to serialize * @param sb * @param done * @throws ConverterException */ private void _serializeList(List list, StringBuffer sb, Set<Object> done) throws ConverterException { sb.append(goIn()); sb.append("["); boolean doIt=false; ListIterator it=list.listIterator(); while(it.hasNext()) { if(doIt)sb.append(','); doIt=true; _serialize(it.next(),sb,done); } sb.append(']'); } /** * serialize a Struct * @param struct Struct to serialize * @param sb * @param done * @throws ConverterException */ public void _serializeStruct(Struct struct, StringBuffer sb, Set<Object> done) throws ConverterException { sb.append(goIn()); sb.append('{'); Iterator it=struct.keyIterator(); boolean doIt=false; deep++; while(it.hasNext()) { String key=Caster.toString(it.next(),""); if(doIt)sb.append(','); doIt=true; sb.append('\''); sb.append(escape(key)); sb.append('\''); sb.append(':'); _serialize(struct.get(key,null),sb,done); } deep--; sb.append('}'); } public String serializeStruct(Struct struct, Set<Collection.Key> ignoreSet) throws ConverterException { StringBuffer sb =new StringBuffer(); sb.append(goIn()); sb.append("{"); boolean hasIgnores=ignoreSet!=null; Iterator<Key> it = struct.keyIterator(); boolean doIt=false; deep++; Key key; while(it.hasNext()) { key = it.next(); if(hasIgnores && ignoreSet.contains(key)) continue; if(doIt)sb.append(','); doIt=true; sb.append('\''); sb.append(escape(key.getString())); sb.append('\''); sb.append(':'); _serialize(struct.get(key,null),sb,new HashSet<Object>()); } deep--; return sb.append('}').toString(); } /** * serialize a Map (as Struct) * @param map Map to serialize * @param sb * @param done * @throws ConverterException */ private void _serializeMap(Map map, StringBuffer sb, Set<Object> done) throws ConverterException { if(map instanceof Serializable) { _serializeSerializable((Serializable)map,sb); return; } sb.append(goIn()); sb.append("{"); Iterator it=map.keySet().iterator(); boolean doIt=false; deep++; while(it.hasNext()) { Object key=it.next(); if(doIt)sb.append(','); doIt=true; sb.append('\''); sb.append(escape(key.toString())); sb.append('\''); sb.append(':'); _serialize(map.get(key),sb,done); } deep--; sb.append('}'); } /** * serialize a Component * @param component Component to serialize * @param sb * @param done * @throws ConverterException */ private void _serializeComponent(Component c, StringBuffer sb, Set<Object> done) throws ConverterException { ComponentAccess ci; try { ci = ComponentUtil.toComponentAccess(c); } catch (ExpressionException ee) { throw new ConverterException(ee.getMessage()); } ComponentWrap cw = new ComponentWrap(Component.ACCESS_PRIVATE,ci); sb.append(goIn()); try { sb.append("evaluateComponent('"+c.getAbsName()+"','"+ComponentUtil.md5(ci)+"',{"); } catch (Exception e) { throw toConverterException(e); } boolean doIt=false; Object member; { Iterator<Entry<Key, Object>> it = cw.entryIterator(); deep++; Entry<Key, Object> e; while(it.hasNext()) { e = it.next(); member = e.getValue(); if(member instanceof UDF)continue; if(doIt)sb.append(','); doIt=true; sb.append('\''); sb.append(escape(e.getKey().getString())); sb.append('\''); sb.append(':'); _serialize(member,sb,done); } sb.append("}"); deep--; } { boolean isPeristent=ci.isPersistent(); ComponentScope scope = ci.getComponentScope(); Iterator<Entry<Key, Object>> it = scope.entryIterator(); sb.append(",{"); deep++; doIt=false; Property p; Boolean remotingFetch; Struct props = ignoreRemotingFetch?null:ComponentUtil.getPropertiesAsStruct(ci,false); Entry<Key, Object> e; Key k; while(it.hasNext()) { e = it.next(); k = e.getKey(); //String key=Caster.toString(it.next(),""); if(KeyConstants._THIS.equalsIgnoreCase(k))continue; if(!ignoreRemotingFetch) { p=(Property) props.get(k,null); if(p!=null) { remotingFetch=Caster.toBoolean(p.getDynamicAttributes().get(REMOTING_FETCH,null),null); if(remotingFetch==null){ if(isPeristent && ORMUtil.isRelated(p)) continue; } else if(!remotingFetch.booleanValue()) continue; } } member = e.getValue(); if(member instanceof UDF)continue; if(doIt)sb.append(','); doIt=true; sb.append('\''); sb.append(escape(k.getString())); sb.append('\''); sb.append(':'); _serialize(member,sb,done); } sb.append("}"); deep--; } sb.append(")"); //sb.append(""); //throw new ConverterException("can't serialize a component "+component.getDisplayName()); } /** * serialize a Query * @param query Query to serialize * @param sb * @param done * @throws ConverterException */ private void _serializeQuery(Query query, StringBuffer sb, Set<Object> done) throws ConverterException { //Collection.Key[] keys = query.keys(); Iterator<Key> it = query.keyIterator(); Key k; sb.append(goIn()); sb.append("query("); deep++; boolean oDoIt=false; int len=query.getRecordcount(); while(it.hasNext()) { k = it.next(); if(oDoIt)sb.append(','); oDoIt=true; sb.append(goIn()); sb.append('\''); sb.append(escape(k.getString())); sb.append('\''); sb.append(":["); boolean doIt=false; for(int y=1;y<=len;y++) { if(doIt)sb.append(','); doIt=true; try { _serialize(query.getAt(k,y),sb,done); } catch (PageException e) { _serialize(e.getMessage(),sb,done); } } sb.append(']'); } deep--; sb.append(')'); } /** * serialize a Object to his xml Format represenation * @param object Object to serialize * @param sb StringBuffer to write data * @param done * @throws ConverterException */ private void _serialize(Object object, StringBuffer sb, Set<Object> done) throws ConverterException { //try { deep++; // NULL if(object==null) { sb.append(goIn()); sb.append("nullValue()"); deep--; return; } // String if(object instanceof String) { sb.append(goIn()); sb.append("'"); sb.append(escape(object.toString())); sb.append("'"); deep--; return; } // Number if(object instanceof Number) { sb.append(goIn()); sb.append(Caster.toString(((Number)object))); deep--; return; } // Boolean if(object instanceof Boolean) { sb.append(goIn()); sb.append(Caster.toString(((Boolean)object).booleanValue())); deep--; return; } // DateTime if(object instanceof DateTime) { _serializeDateTime((DateTime)object,sb); deep--; return; } // Date if(object instanceof Date) { _serializeDate((Date)object,sb); deep--; return; } // XML if(object instanceof Node) { _serializeXML((Node)object,sb); deep--; return; } if(object instanceof ObjectWrap) { try { _serialize(((ObjectWrap)object).getEmbededObject(), sb,done); } catch (PageException e) { throw toConverterException(e); } deep--; return; } // Timespan if(object instanceof TimeSpan) { _serializeTimeSpan((TimeSpan) object,sb); deep--; return; } Object raw = LazyConverter.toRaw(object); if(done.contains(raw)) { sb.append(goIn()); sb.append("nullValue()"); deep--; return; } done.add(raw); try { // Component if(object instanceof Component) { _serializeComponent((Component)object,sb,done); deep--; return; } // Struct if(object instanceof Struct) { _serializeStruct((Struct)object,sb,done); deep--; return; } // Map if(object instanceof Map) { _serializeMap((Map)object,sb,done); deep--; return; } // Array if(object instanceof Array) { _serializeArray((Array)object,sb,done); deep--; return; } // List if(object instanceof List) { _serializeList((List)object,sb,done); deep--; return; } // Query if(object instanceof Query) { _serializeQuery((Query)object,sb,done); deep--; return; } // String Converter if(object instanceof ScriptConvertable) { sb.append(((ScriptConvertable)object).serialize()); deep--; return; } if(object instanceof Serializable) { _serializeSerializable((Serializable)object,sb); deep--; return; } } finally { done.remove(raw); } throw new ConverterException("can't serialize Object of type [ "+Caster.toClassName(object)+" ]"); //deep--; /*} catch(StackOverflowError soe){ throw soe; }*/ } private void _serializeXML(Node node, StringBuffer sb) { node=XMLCaster.toRawNode(node); sb.append(goIn()); sb.append("xmlParse('"); sb.append(escape(XMLCaster.toString(node,""))); sb.append("')"); } private void _serializeTimeSpan(TimeSpan span, StringBuffer sb) { sb.append(goIn()); sb.append("createTimeSpan("); sb.append(span.getDay()); sb.append(','); sb.append(span.getHour()); sb.append(','); sb.append(span.getMinute()); sb.append(','); sb.append(span.getSecond()); sb.append(')'); } private String escape(String str) { return StringUtil.replace(StringUtil.replace(str,"'","''",false),"#","##",false); } @Override public void writeOut(PageContext pc, Object source, Writer writer) throws ConverterException, IOException { writer.write(serialize(source)); writer.flush(); } /** * serialize a Object to his literal Format * @param object Object to serialize * @return serialized wddx package * @throws ConverterException */ public String serialize(Object object) throws ConverterException { deep=0; StringBuffer sb=new StringBuffer(); _serialize(object,sb,new HashSet<Object>()); return sb.toString(); } /** * @return return current blockquote */ private String goIn() { /*StringBuffer rtn=new StringBuffer('\n'); for(int i=0;i<deep;i++) rtn.append('\t'); return rtn.toString(); /*/ return ""; } }