001    package railo.runtime.dump;
002    
003    import java.io.File;
004    import java.lang.reflect.Field;
005    import java.lang.reflect.Method;
006    import java.sql.ResultSet;
007    import java.text.SimpleDateFormat;
008    import java.util.Calendar;
009    import java.util.Date;
010    import java.util.Enumeration;
011    import java.util.Iterator;
012    import java.util.List;
013    import java.util.ListIterator;
014    import java.util.Locale;
015    import java.util.Map;
016    import java.util.Set;
017    
018    import javax.servlet.http.Cookie;
019    import javax.servlet.http.HttpSession;
020    
021    import org.w3c.dom.NamedNodeMap;
022    import org.w3c.dom.Node;
023    import org.w3c.dom.NodeList;
024    
025    import railo.commons.date.TimeZoneUtil;
026    import railo.commons.io.res.Resource;
027    import railo.commons.lang.IDGenerator;
028    import railo.commons.lang.StringUtil;
029    import railo.runtime.PageContext;
030    import railo.runtime.converter.WDDXConverter;
031    import railo.runtime.exp.PageException;
032    import railo.runtime.op.Caster;
033    import railo.runtime.op.Decision;
034    import railo.runtime.text.xml.XMLCaster;
035    import railo.runtime.type.Array;
036    import railo.runtime.type.Collection;
037    import railo.runtime.type.ObjectWrap;
038    import railo.runtime.type.QueryImpl;
039    import railo.runtime.type.dt.DateTimeImpl;
040    import railo.runtime.type.scope.CookieImpl;
041    
042    public class DumpUtil {
043    
044            
045            public static DumpData toDumpData(Object o,PageContext pageContext, int maxlevel, DumpProperties props) {
046                    if(maxlevel<=0) {
047                            return new SimpleDumpData("maximum dump level reached");
048                    }
049                    // null
050                    if(o == null) {
051                            DumpTable table=new DumpTable("null","#ff6600","#ffcc99","#000000");
052                            table.appendRow(new DumpRow(0,new SimpleDumpData("Empty:null")));
053                            return table;
054                    }
055                    if(o instanceof DumpData) {
056                            return ((DumpData)o);
057                    }
058                    // Date
059                    if(o instanceof Date) {
060                            return new DateTimeImpl((Date) o).toDumpData(pageContext,maxlevel,props);
061                    }
062                    // Calendar
063                    if(o instanceof Calendar) {
064                            Calendar c=(Calendar)o;
065                            
066                            SimpleDateFormat df = new SimpleDateFormat("EE, dd MMM yyyy HH:mm:ss zz",Locale.ENGLISH);
067                            df.setTimeZone(c.getTimeZone());
068                            
069                            DumpTable table=new DumpTable("date","#ff9900","#ffcc00","#000000");
070                            table.setTitle("java.util.Calendar");
071                            table.appendRow(1, new SimpleDumpData("Timezone"), new SimpleDumpData(TimeZoneUtil.toString(c.getTimeZone())));
072                            table.appendRow(1, new SimpleDumpData("Time"), new SimpleDumpData(df.format(c.getTime())));
073                    
074                            return table;
075                    }
076                    // StringBuffer
077                    if(o instanceof StringBuffer) {
078                            DumpTable dt=(DumpTable)toDumpData(o.toString(), pageContext, maxlevel, props);
079                            if(StringUtil.isEmpty(dt.getTitle()))
080                                    dt.setTitle(Caster.toClassName(o));
081                            return dt;
082                    }
083                    // StringBuilder
084                    if(o instanceof StringBuilder) {
085                            DumpTable dt=(DumpTable)toDumpData(o.toString(), pageContext, maxlevel, props);
086                            if(StringUtil.isEmpty(dt.getTitle()))
087                                    dt.setTitle(Caster.toClassName(o));
088                            return dt;
089                    }
090                    // String
091                    if(o instanceof String) {
092                            String str=(String) o;
093                            if(str.trim().startsWith("<wddxPacket ")) {
094                                    try {
095                                            WDDXConverter converter =new WDDXConverter(pageContext.getTimeZone(),false,true);
096                                            converter.setTimeZone(pageContext.getTimeZone());
097                                            Object rst = converter.deserialize(str,false);
098                                            DumpData data = toDumpData(rst, pageContext, maxlevel, props);
099                                            
100                                            DumpTable table = new DumpTable("string","#cc9999","#ffffff","#000000");
101                                            table.setTitle("WDDX");
102                                            table.appendRow(1,new SimpleDumpData("encoded"),data);
103                                            table.appendRow(1,new SimpleDumpData("raw"),new SimpleDumpData(str));
104                                            return table;
105                                    }
106                                    catch(Throwable t) {}
107                            }
108                            DumpTable table = new DumpTable("string","#ff6600","#ffcc99","#000000");
109                            table.appendRow(1,new SimpleDumpData("string"),new SimpleDumpData(str));
110                            return table;
111                    }
112                    // Character
113                    if(o instanceof Character) {
114                            DumpTable table = new DumpTable("character","#ff6600","#ffcc99","#000000");
115                            table.appendRow(1,new SimpleDumpData("character"),new SimpleDumpData(o.toString()));
116                            return table;
117                    }
118                    // Number
119                    if(o instanceof Number) {
120                            DumpTable table = new DumpTable("numeric","#ff6600","#ffcc99","#000000");
121                            table.appendRow(1,new SimpleDumpData("number"),new SimpleDumpData(Caster.toString(((Number)o).doubleValue())));
122                            return table;
123                    }
124                    // Boolean
125                    if(o instanceof Boolean) {
126                            DumpTable table = new DumpTable("boolean","#ff6600","#ffcc99","#000000");
127                            table.appendRow(1,new SimpleDumpData("boolean"),new SimpleDumpData(((Boolean)o).booleanValue()));
128                            return table;
129                    }
130                    // File
131                    if(o instanceof File) {
132                            DumpTable table = new DumpTable("file","#ffcc00","#ffff66","#000000");
133                            table.appendRow(1,new SimpleDumpData("File"),new SimpleDumpData(o.toString()));
134                            return table;
135                    }
136                    // Cookie
137                    if(o instanceof Cookie) {
138                            Cookie c=(Cookie) o;
139                            DumpTable table = new DumpTable("Cookie","#979EAA","#DEE9FB","#000000");
140                            table.setTitle("Cookie ("+c.getClass().getName()+")");
141                            table.appendRow(1,new SimpleDumpData("name"),new SimpleDumpData(c.getName()));
142                            table.appendRow(1,new SimpleDumpData("value"),new SimpleDumpData(c.getValue()));
143                            table.appendRow(1,new SimpleDumpData("path"),new SimpleDumpData(c.getPath()));
144                            table.appendRow(1,new SimpleDumpData("secure"),new SimpleDumpData(c.getSecure()));
145                            table.appendRow(1,new SimpleDumpData("maxAge"),new SimpleDumpData(c.getMaxAge()));
146                            table.appendRow(1,new SimpleDumpData("version"),new SimpleDumpData(c.getVersion()));
147                            table.appendRow(1,new SimpleDumpData("domain"),new SimpleDumpData(c.getDomain()));
148                            table.appendRow(1,new SimpleDumpData("httpOnly"),new SimpleDumpData(CookieImpl.isHTTPOnly(c)));
149                            table.appendRow(1,new SimpleDumpData("comment"),new SimpleDumpData(c.getComment()));
150                            return table;
151                    }
152                    // Resource
153                    if(o instanceof Resource) {
154                            DumpTable table = new DumpTable("resource","#ffcc00","#ffff66","#000000");
155                            table.appendRow(1,new SimpleDumpData("Resource"),new SimpleDumpData(o.toString()));
156                            return table;
157                    }
158                    // byte[]
159                    if(o instanceof byte[]) {
160                            byte[] bytes=(byte[]) o;
161                            
162                            DumpTable table = new DumpTable("array","#ff9900","#ffcc00","#000000");
163                            table.setTitle("Native Array  ("+Caster.toClassName(o)+")");
164                            
165                            StringBuffer sb=new StringBuffer();
166                            for(int i=0;i<bytes.length;i++) {
167                                    if(i!=0)sb.append("-");
168                                    sb.append(bytes[i]);
169                                    if(i==1000) {
170                                            sb.append("  [truncated]  ");
171                                            break;
172                                    }
173                            }
174                            table.appendRow(0,new SimpleDumpData(sb.toString()));
175                            return table;   
176                    }
177                    // Collection.Key
178                    if(o instanceof Collection.Key) {
179                            Collection.Key key=(Collection.Key) o;
180                            DumpTable table = new DumpTable("string","#ff6600","#ffcc99","#000000");
181                            table.appendRow(1,new SimpleDumpData("Collection.Key"),new SimpleDumpData(key.getString()));
182                            return table;
183                    }
184                    
185                    
186                    String id=""+IDGenerator.intId();
187                    String refid=ThreadLocalDump.get(o);
188                    if(refid!=null) {
189                            DumpTable table = new DumpTable("ref","#ffffff","#cccccc","#000000");
190                            table.appendRow(1,new SimpleDumpData("Reference"),new SimpleDumpData(refid));
191                            table.setRef(refid);
192                            return setId(id,table);
193                    }
194                    
195                    ThreadLocalDump.set(o,id);
196                    try{
197                            // Printable
198                            if(o instanceof Dumpable) {
199                                    return setId(id,((Dumpable)o).toDumpData(pageContext,maxlevel,props));
200                            }
201                            // Map
202                            if(o instanceof Map) {
203                                    Map map=(Map) o;
204                                    Iterator it=map.keySet().iterator();
205            
206                                    DumpTable table = new DumpTable("struct","#ff9900","#ffcc00","#000000");
207                                    table.setTitle("Map ("+Caster.toClassName(o)+")");
208                                    
209                                    while(it.hasNext()) {
210                                            Object next=it.next();
211                                            table.appendRow(1,toDumpData(next,pageContext,maxlevel,props),toDumpData(map.get(next),pageContext,maxlevel,props));
212                                    }
213                                    return setId(id,table);
214                            }
215                    
216                            // List
217                            if(o instanceof List) {
218                                    List list=(List) o;
219                                    ListIterator it=list.listIterator();
220                                    
221                                    DumpTable table = new DumpTable("array","#ff9900","#ffcc00","#000000");
222                                    table.setTitle("Array (List)");
223                                    
224                                    while(it.hasNext()) {
225                                            table.appendRow(1,new SimpleDumpData(it.nextIndex()+1),toDumpData(it.next(),pageContext,maxlevel,props));
226                                    }
227                                    return setId(id,table);
228                            }
229                    
230                            // Set
231                            if(o instanceof Set) {
232                                    Set set=(Set) o;
233                                    Iterator it = set.iterator();
234                                    
235                                    DumpTable table = new DumpTable("array","#ff9900","#ffcc00","#000000");
236                                    table.setTitle("Set ("+set.getClass().getName()+")");
237                                    
238                                    while(it.hasNext()) {
239                                            table.appendRow(1,toDumpData(it.next(),pageContext,maxlevel,props));
240                                    }
241                                    return setId(id,table);
242                            }
243                            
244                            // Resultset
245                            if(o instanceof ResultSet) {
246                                    try {
247                                            DumpData dd = new QueryImpl((ResultSet)o,"query",pageContext.getTimeZone()).toDumpData(pageContext,maxlevel,props);
248                                            if(dd instanceof DumpTable)
249                                                    ((DumpTable)dd).setTitle(Caster.toClassName(o));
250                                            return setId(id,dd);
251                                    } 
252                                    catch (PageException e) {
253                                            
254                                    }
255                            }
256                            // Enumeration
257                            if(o instanceof Enumeration) {
258                                    Enumeration e=(Enumeration)o;
259                                    
260                                    DumpTable table = new DumpTable("enumeration","#ff9900","#ffcc00","#000000");
261                                    table.setTitle("Enumeration");
262                                    
263                                    while(e.hasMoreElements()) {
264                                            table.appendRow(0,toDumpData(e.nextElement(),pageContext,maxlevel,props));
265                                    }
266                                    return setId(id,table);
267                            }
268                            // Object[]
269                            if(Decision.isNativeArray(o)) {
270                                    Array arr;
271                                    try {
272                                            arr = Caster.toArray(o);
273                                            DumpTable htmlBox = new DumpTable("array","#ff9900","#ffcc00","#000000");
274                                            htmlBox.setTitle("Native Array ("+Caster.toClassName(o)+")");
275                                    
276                                            int length=arr.size();
277                                    
278                                            for(int i=1;i<=length;i++) {
279                                                    Object ox=null;
280                                                    try {
281                                                            ox = arr.getE(i);
282                                                    } catch (Exception e) {}
283                                                    htmlBox.appendRow(1,new SimpleDumpData(i),toDumpData(ox,pageContext,maxlevel,props));
284                                            }
285                                            return setId(id,htmlBox);
286                                    } 
287                                    catch (PageException e) {
288                                            return setId(id,new SimpleDumpData(""));
289                                    }
290                            }
291                            // Node
292                            if(o instanceof Node) {
293                                return setId(id,XMLCaster.toDumpData((Node)o, pageContext,maxlevel,props));                 
294                            }
295                            // ObjectWrap
296                            if(o instanceof ObjectWrap) {
297                                    maxlevel++;
298                                return setId(id,toDumpData(((ObjectWrap)o).getEmbededObject(null), pageContext,maxlevel,props));                    
299                            }
300                            // NodeList
301                            if(o instanceof NodeList) {
302                                    NodeList list=(NodeList)o;
303                                    int len=list.getLength();
304                                    DumpTable table = new DumpTable("xml","#cc9999","#ffffff","#000000");
305                                    for(int i=0;i<len;i++) {
306                                            table.appendRow(1,new SimpleDumpData(i),toDumpData(list.item(i),pageContext,maxlevel,props));
307                                    }
308                                    return setId(id,table);
309                                    
310                            }
311                            // AttributeMap
312                            if(o instanceof NamedNodeMap) {
313                                    NamedNodeMap attr = (NamedNodeMap)o;
314                                    int len = attr.getLength();
315                                    DumpTable dt = new DumpTable("array","#ff9900","#ffcc00","#000000");
316                                    dt.setTitle("NamedNodeMap ("+Caster.toClassName(o)+")");
317                                    
318                                    for(int i=0;i<len;i++) {
319                                            dt.appendRow(1,new SimpleDumpData(i),toDumpData(attr.item(i),pageContext,maxlevel,props));
320                                    }
321                                    return setId(id,dt);                    
322                            }
323                            // HttpSession
324                            if(o instanceof HttpSession) {
325                                HttpSession hs = (HttpSession)o;
326                                Enumeration e = hs.getAttributeNames();
327                                
328                                DumpTable htmlBox = new DumpTable("httpsession","#9999ff","#ccccff","#000000");
329                                    htmlBox.setTitle("HttpSession");
330                                while(e.hasMoreElements()) {
331                                    String key=e.nextElement().toString();
332                                    htmlBox.appendRow(1,new SimpleDumpData(key),toDumpData(hs.getAttribute(key), pageContext,maxlevel,props));
333                                }
334                                return setId(id,htmlBox);
335                            }
336                    
337                    
338                    // reflect
339                    //else {
340                            DumpTable table = new DumpTable(o.getClass().getName(),"#cc9999","#ffcccc","#000000");
341                            
342                            Class clazz=o.getClass();
343                            if(o instanceof Class) clazz=(Class) o;
344                            String fullClassName=clazz.getName();
345                            int pos=fullClassName.lastIndexOf('.');
346                            String className=pos==-1?fullClassName:fullClassName.substring(pos+1);
347                            
348                            table.setTitle(className);
349                            table.appendRow(1,new SimpleDumpData("class"),new SimpleDumpData(fullClassName));
350                            
351                            // Fields
352                            Field[] fields=clazz.getFields();
353                            DumpTable fieldDump = new DumpTable("#cc9999","#ffcccc","#000000");
354                            fieldDump.appendRow(7,new SimpleDumpData("name"),new SimpleDumpData("pattern"),new SimpleDumpData("value"));
355                            for(int i=0;i<fields.length;i++) {
356                                    Field field = fields[i];
357                                    DumpData value;
358                                    try {//print.out(o+":"+maxlevel);
359                                            value=new SimpleDumpData(Caster.toString(field.get(o), ""));
360                                    } 
361                                    catch (Exception e) {
362                                            value=new SimpleDumpData("");
363                                    }
364                                    fieldDump.appendRow(0,new SimpleDumpData(field.getName()),new SimpleDumpData(field.toString()),value);
365                            }
366                            if(fields.length>0)table.appendRow(1,new SimpleDumpData("fields"),fieldDump);
367                            
368                            // Methods
369                            StringBuffer objMethods=new StringBuffer();
370                            Method[] methods=clazz.getMethods();
371                            DumpTable methDump = new DumpTable("#cc9999","#ffcccc","#000000");
372                            methDump.appendRow(7,new SimpleDumpData("return"),new SimpleDumpData("interface"),new SimpleDumpData("exceptions"));
373                            for(int i=0;i<methods.length;i++) {
374                                    Method method = methods[i];
375                                    
376                                    if(Object.class==method.getDeclaringClass()) {
377                                            if(objMethods.length()>0)objMethods.append(", ");
378                                            objMethods.append(method.getName());
379                                            continue;
380                                    }
381                                    
382                                    // exceptions
383                                    StringBuffer sbExp=new StringBuffer();
384                                    Class[] exceptions = method.getExceptionTypes();
385                                    for(int p=0;p<exceptions.length;p++){
386                                            if(p>0)sbExp.append("\n");
387                                            sbExp.append(Caster.toClassName(exceptions[p]));
388                                    }
389                                    
390                                    // parameters
391                                    StringBuffer sbParams=new StringBuffer(method.getName());
392                                    sbParams.append('(');
393                                    Class[] parameters = method.getParameterTypes();
394                                    for(int p=0;p<parameters.length;p++){
395                                            if(p>0)sbParams.append(", ");
396                                            sbParams.append(Caster.toClassName(parameters[p]));
397                                    }
398                                    sbParams.append(')');
399                                    
400                                    methDump.appendRow(0,
401                                                    new SimpleDumpData(Caster.toClassName(method.getReturnType())),
402    
403                                                    new SimpleDumpData(sbParams.toString()),
404                                                    new SimpleDumpData(sbExp.toString())
405                                    );
406                            }
407                            if(methods.length>0)table.appendRow(1,new SimpleDumpData("methods"),methDump);
408                            
409                            DumpTable inherited = new DumpTable("#cc9999","#ffcccc","#000000");
410                            inherited.appendRow(7,new SimpleDumpData("Methods inherited from java.lang.Object"));
411                            inherited.appendRow(0,new SimpleDumpData(objMethods.toString()));
412                            table.appendRow(1,new SimpleDumpData(""),inherited);
413                            return setId(id,table);
414                    //}
415                    }
416                    finally{
417                            ThreadLocalDump.remove(o);
418                    }
419            }
420    
421            private static DumpData setId(String id, DumpData data) {
422                    if(data instanceof DumpTable) {
423                            ((DumpTable)data).setId(id);
424                    }
425                    // TODO Auto-generated method stub
426                    return data;
427            }
428    
429            public static boolean keyValid(DumpProperties props,int level, String key) {
430                    if(props.getMaxlevel()-level>1) return true;
431                    
432                    // show
433                    Set set = props.getShow();
434                    if(set!=null && !set.contains(StringUtil.toLowerCase(key)))
435                            return false;
436                    
437                    // hide
438                    set = props.getHide();
439                    if(set!=null && set.contains(StringUtil.toLowerCase(key)))
440                            return false;
441                    
442                    return true;
443            }
444            
445            public static boolean keyValid(DumpProperties props,int level, Collection.Key key) {
446                    if(props.getMaxlevel()-level>1) return true;
447                    
448                    // show
449                    Set set = props.getShow();
450                    if(set!=null && !set.contains(key.getLowerString()))
451                            return false;
452                    
453                    // hide
454                    set = props.getHide();
455                    if(set!=null && set.contains(key.getLowerString()))
456                            return false;
457                    
458                    return true;
459            }
460            
461            
462            
463    
464            public static DumpProperties toDumpProperties() {
465                    return DumpProperties.DEFAULT;
466            }
467    }