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.apache.xerces.dom.AttributeMap;
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.XMLAttributes;
035    import railo.runtime.text.xml.XMLCaster;
036    import railo.runtime.type.Array;
037    import railo.runtime.type.Collection;
038    import railo.runtime.type.ObjectWrap;
039    import railo.runtime.type.QueryImpl;
040    import railo.runtime.type.dt.DateTimeImpl;
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("maximal dump level reached");
048                    }
049                    // null
050                    if(o == null) {
051                            DumpTable table=new DumpTablePro("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 DumpTablePro("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 DumpTablePro("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 DumpTablePro("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 DumpTablePro("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 DumpTablePro("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 DumpTablePro("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 DumpTablePro("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 DumpTablePro("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("comment"),new SimpleDumpData(c.getComment()));
149                            return table;
150                    }
151                    // Resource
152                    if(o instanceof Resource) {
153                            DumpTable table = new DumpTablePro("resource","#ffcc00","#ffff66","#000000");
154                            table.appendRow(1,new SimpleDumpData("Resource"),new SimpleDumpData(o.toString()));
155                            return table;
156                    }
157                    // byte[]
158                    if(o instanceof byte[]) {
159                            byte[] bytes=(byte[]) o;
160                            
161                            DumpTable table = new DumpTablePro("array","#ff9900","#ffcc00","#000000");
162                            table.setTitle("Native Array  ("+Caster.toClassName(o)+")");
163                            
164                            StringBuffer sb=new StringBuffer();
165                            for(int i=0;i<bytes.length;i++) {
166                                    if(i!=0)sb.append("-");
167                                    sb.append(bytes[i]);
168                                    if(i==1000) {
169                                            sb.append("  [truncated]  ");
170                                            break;
171                                    }
172                            }
173                            table.appendRow(0,new SimpleDumpData(sb.toString()));
174                            return table;   
175                    }
176                    // Collection.Key
177                    if(o instanceof Collection.Key) {
178                            Collection.Key key=(Collection.Key) o;
179                            DumpTable table = new DumpTablePro("string","#ff6600","#ffcc99","#000000");
180                            table.appendRow(1,new SimpleDumpData("Collection.Key"),new SimpleDumpData(key.getString()));
181                            return table;
182                    }
183                    
184                    
185                    String id=""+IDGenerator.intId();
186                    String refid=ThreadLocalDump.get(o);
187                    if(refid!=null) {
188                            DumpTablePro table = new DumpTablePro("ref","#ffffff","#cccccc","#000000");
189                            table.appendRow(1,new SimpleDumpData("Reference"),new SimpleDumpData(refid));
190                            table.setRef(refid);
191                            return setId(id,table);
192                    }
193                    
194                    ThreadLocalDump.set(o,id);
195                    try{
196                            // Printable
197                            if(o instanceof Dumpable) {
198                                    return setId(id,((Dumpable)o).toDumpData(pageContext,maxlevel,props));
199                            }
200                            // Map
201                            if(o instanceof Map) {
202                                    Map map=(Map) o;
203                                    Iterator it=map.keySet().iterator();
204            
205                                    DumpTable table = new DumpTablePro("struct","#ff9900","#ffcc00","#000000");
206                                    table.setTitle("Map ("+Caster.toClassName(o)+")");
207                                    
208                                    while(it.hasNext()) {
209                                            Object next=it.next();
210                                            table.appendRow(1,toDumpData(next,pageContext,maxlevel,props),toDumpData(map.get(next),pageContext,maxlevel,props));
211                                    }
212                                    return setId(id,table);
213                            }
214                    
215                            // List
216                            if(o instanceof List) {
217                                    List list=(List) o;
218                                    ListIterator it=list.listIterator();
219                                    
220                                    DumpTable table = new DumpTablePro("array","#ff9900","#ffcc00","#000000");
221                                    table.setTitle("Array (List)");
222                                    
223                                    while(it.hasNext()) {
224                                            table.appendRow(1,new SimpleDumpData(it.nextIndex()+1),toDumpData(it.next(),pageContext,maxlevel,props));
225                                    }
226                                    return setId(id,table);
227                            }
228                            // Resultset
229                            if(o instanceof ResultSet) {
230                                    try {
231                                            DumpData dd = new QueryImpl((ResultSet)o,"query").toDumpData(pageContext,maxlevel,props);
232                                            if(dd instanceof DumpTable)
233                                                    ((DumpTable)dd).setTitle(Caster.toClassName(o));
234                                            return setId(id,dd);
235                                    } 
236                                    catch (PageException e) {
237                                            
238                                    }
239                            }
240                            // Enumeration
241                            if(o instanceof Enumeration) {
242                                    Enumeration e=(Enumeration)o;
243                                    
244                                    DumpTable table = new DumpTablePro("enumeration","#ff9900","#ffcc00","#000000");
245                                    table.setTitle("Enumeration");
246                                    
247                                    while(e.hasMoreElements()) {
248                                            table.appendRow(0,toDumpData(e.nextElement(),pageContext,maxlevel,props));
249                                    }
250                                    return setId(id,table);
251                            }
252                            // Object[]
253                            if(Decision.isNativeArray(o)) {
254                                    Array arr;
255                                    try {
256                                            arr = Caster.toArray(o);
257                                            DumpTable htmlBox = new DumpTablePro("array","#ff9900","#ffcc00","#000000");
258                                            htmlBox.setTitle("Native Array ("+Caster.toClassName(o)+")");
259                                    
260                                            int length=arr.size();
261                                    
262                                            for(int i=1;i<=length;i++) {
263                                                    Object ox=null;
264                                                    try {
265                                                            ox = arr.getE(i);
266                                                    } catch (Exception e) {}
267                                                    htmlBox.appendRow(1,new SimpleDumpData(i),toDumpData(ox,pageContext,maxlevel,props));
268                                            }
269                                            return setId(id,htmlBox);
270                                    } 
271                                    catch (PageException e) {
272                                            return setId(id,new SimpleDumpData(""));
273                                    }
274                            }
275                            // Node
276                            if(o instanceof Node) {
277                                return setId(id,XMLCaster.toDumpData((Node)o, pageContext,maxlevel,props));                 
278                            }
279                            // ObjectWrap
280                            if(o instanceof ObjectWrap) {
281                                    maxlevel++;
282                                return setId(id,toDumpData(((ObjectWrap)o).getEmbededObject(null), pageContext,maxlevel,props));                    
283                            }
284                            // NodeList
285                            if(o instanceof NodeList) {
286                                    NodeList list=(NodeList)o;
287                                    int len=list.getLength();
288                                    DumpTable table = new DumpTablePro("xml","#cc9999","#ffffff","#000000");
289                                    for(int i=0;i<len;i++) {
290                                            table.appendRow(1,new SimpleDumpData(i),toDumpData(list.item(i),pageContext,maxlevel,props));
291                                    }
292                                    return setId(id,table);
293                                    
294                            }
295                    // AttributeMap
296                    if(o instanceof AttributeMap) {
297                            return setId(id,new XMLAttributes((AttributeMap)o,false).toDumpData(pageContext, maxlevel,props));                      
298                    }
299                            // HttpSession
300                            if(o instanceof HttpSession) {
301                                HttpSession hs = (HttpSession)o;
302                                Enumeration e = hs.getAttributeNames();
303                                
304                                DumpTable htmlBox = new DumpTablePro("httpsession","#9999ff","#ccccff","#000000");
305                                    htmlBox.setTitle("HttpSession");
306                                while(e.hasMoreElements()) {
307                                    String key=e.nextElement().toString();
308                                    htmlBox.appendRow(1,new SimpleDumpData(key),toDumpData(hs.getAttribute(key), pageContext,maxlevel,props));
309                                }
310                                return setId(id,htmlBox);
311                            }
312                    
313                    
314                    // reflect
315                    //else {
316                            DumpTable table = new DumpTablePro(o.getClass().getName(),"#cc9999","#ffcccc","#000000");
317                            
318                            Class clazz=o.getClass();
319                            if(o instanceof Class) clazz=(Class) o;
320                            String fullClassName=clazz.getName();
321                            int pos=fullClassName.lastIndexOf('.');
322                            String className=pos==-1?fullClassName:fullClassName.substring(pos+1);
323                            
324                            table.setTitle(className);
325                            table.appendRow(1,new SimpleDumpData("class"),new SimpleDumpData(fullClassName));
326                            
327                            // Fields
328                            Field[] fields=clazz.getFields();
329                            DumpTable fieldDump = new DumpTable("#cc9999","#ffcccc","#000000");
330                            fieldDump.appendRow(7,new SimpleDumpData("name"),new SimpleDumpData("pattern"),new SimpleDumpData("value"));
331                            for(int i=0;i<fields.length;i++) {
332                                    Field field = fields[i];
333                                    DumpData value;
334                                    try {//print.out(o+":"+maxlevel);
335                                            value=new SimpleDumpData(Caster.toString(field.get(o), ""));
336                                    } 
337                                    catch (Exception e) {
338                                            value=new SimpleDumpData("");
339                                    }
340                                    fieldDump.appendRow(0,new SimpleDumpData(field.getName()),new SimpleDumpData(field.toString()),value);
341                            }
342                            if(fields.length>0)table.appendRow(1,new SimpleDumpData("fields"),fieldDump);
343                            
344                            // Methods
345                            StringBuffer objMethods=new StringBuffer();
346                            Method[] methods=clazz.getMethods();
347                            DumpTable methDump = new DumpTable("#cc9999","#ffcccc","#000000");
348                            methDump.appendRow(7,new SimpleDumpData("return"),new SimpleDumpData("interface"),new SimpleDumpData("exceptions"));
349                            for(int i=0;i<methods.length;i++) {
350                                    Method method = methods[i];
351                                    
352                                    if(Object.class==method.getDeclaringClass()) {
353                                            if(objMethods.length()>0)objMethods.append(", ");
354                                            objMethods.append(method.getName());
355                                            continue;
356                                    }
357                                    
358                                    // exceptions
359                                    StringBuffer sbExp=new StringBuffer();
360                                    Class[] exceptions = method.getExceptionTypes();
361                                    for(int p=0;p<exceptions.length;p++){
362                                            if(p>0)sbExp.append("\n");
363                                            sbExp.append(Caster.toClassName(exceptions[p]));
364                                    }
365                                    
366                                    // parameters
367                                    StringBuffer sbParams=new StringBuffer(method.getName());
368                                    sbParams.append('(');
369                                    Class[] parameters = method.getParameterTypes();
370                                    for(int p=0;p<parameters.length;p++){
371                                            if(p>0)sbParams.append(", ");
372                                            sbParams.append(Caster.toClassName(parameters[p]));
373                                    }
374                                    sbParams.append(')');
375                                    
376                                    methDump.appendRow(0,
377                                                    new SimpleDumpData(Caster.toClassName(method.getReturnType())),
378    
379                                                    new SimpleDumpData(sbParams.toString()),
380                                                    new SimpleDumpData(sbExp.toString())
381                                    );
382                            }
383                            if(methods.length>0)table.appendRow(1,new SimpleDumpData("methods"),methDump);
384                            
385                            DumpTable inherited = new DumpTable("#cc9999","#ffcccc","#000000");
386                            inherited.appendRow(7,new SimpleDumpData("Methods inherited from java.lang.Object"));
387                            inherited.appendRow(0,new SimpleDumpData(objMethods.toString()));
388                            table.appendRow(1,new SimpleDumpData(""),inherited);
389                            return setId(id,table);
390                    //}
391                    }
392                    finally{
393                            ThreadLocalDump.remove(o);
394                    }
395            }
396    
397            private static DumpData setId(String id, DumpData data) {
398                    if(data instanceof DumpTablePro) {
399                            ((DumpTablePro)data).setId(id);
400                    }
401                    // TODO Auto-generated method stub
402                    return data;
403            }
404    
405            public static boolean keyValid(DumpProperties props,int level, String key) {
406                    if(props.getMaxlevel()-level>1) return true;
407                    
408                    // show
409                    Set set = props.getShow();
410                    if(set!=null && !set.contains(StringUtil.toLowerCase(key)))
411                            return false;
412                    
413                    // hide
414                    set = props.getHide();
415                    if(set!=null && set.contains(StringUtil.toLowerCase(key)))
416                            return false;
417                    
418                    return true;
419            }
420            
421            public static boolean keyValid(DumpProperties props,int level, Collection.Key key) {
422                    if(props.getMaxlevel()-level>1) return true;
423                    
424                    // show
425                    Set set = props.getShow();
426                    if(set!=null && !set.contains(key.getLowerString()))
427                            return false;
428                    
429                    // hide
430                    set = props.getHide();
431                    if(set!=null && set.contains(key.getLowerString()))
432                            return false;
433                    
434                    return true;
435            }
436            
437            
438            
439    
440            public static DumpProperties toDumpProperties() {
441                    return DumpProperties.DEFAULT;
442            }
443    }