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    }