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