package railo.runtime.dump;
import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.sql.ResultSet;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpSession;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import railo.commons.date.TimeZoneUtil;
import railo.commons.io.res.Resource;
import railo.commons.lang.IDGenerator;
import railo.commons.lang.StringUtil;
import railo.runtime.PageContext;
import railo.runtime.coder.Base64Coder;
import railo.runtime.converter.WDDXConverter;
import railo.runtime.exp.PageException;
import railo.runtime.op.Caster;
import railo.runtime.op.Decision;
import railo.runtime.text.xml.XMLCaster;
import railo.runtime.type.Array;
import railo.runtime.type.Collection;
import railo.runtime.type.ObjectWrap;
import railo.runtime.type.QueryImpl;
import railo.runtime.type.dt.DateTimeImpl;
import railo.runtime.type.scope.CookieImpl;
public class DumpUtil {
public static final DumpData MAX_LEVEL_REACHED;
static {
MAX_LEVEL_REACHED = new DumpTable("Max Level Reached","#e0e0e0","#ffcc99","#888888");
((DumpTable)MAX_LEVEL_REACHED).appendRow( new DumpRow(1, new SimpleDumpData("[Max Dump Level Reached]") ) );
}
public static DumpData toDumpData(Object o, PageContext pageContext, int maxlevel, DumpProperties props) {
if(maxlevel<0)
return MAX_LEVEL_REACHED;
// null
if(o == null) {
DumpTable table=new DumpTable("null","#ff6600","#ffcc99","#000000");
table.appendRow(new DumpRow(0,new SimpleDumpData("Empty:null")));
return table;
}
if(o instanceof DumpData) {
return ((DumpData)o);
}
// Date
if(o instanceof Date) {
return new DateTimeImpl((Date) o).toDumpData(pageContext,maxlevel,props);
}
// Calendar
if(o instanceof Calendar) {
Calendar c=(Calendar)o;
SimpleDateFormat df = new SimpleDateFormat("EE, dd MMM yyyy HH:mm:ss zz",Locale.ENGLISH);
df.setTimeZone(c.getTimeZone());
DumpTable table=new DumpTable("date","#ff9900","#ffcc00","#000000");
table.setTitle("java.util.Calendar");
table.appendRow(1, new SimpleDumpData("Timezone"), new SimpleDumpData(TimeZoneUtil.toString(c.getTimeZone())));
table.appendRow(1, new SimpleDumpData("Time"), new SimpleDumpData(df.format(c.getTime())));
return table;
}
// StringBuffer
if(o instanceof StringBuffer) {
DumpTable dt=(DumpTable)toDumpData(o.toString(), pageContext, maxlevel, props);
if(StringUtil.isEmpty(dt.getTitle()))
dt.setTitle(Caster.toClassName(o));
return dt;
}
// StringBuilder
if(o instanceof StringBuilder) {
DumpTable dt=(DumpTable)toDumpData(o.toString(), pageContext, maxlevel, props);
if(StringUtil.isEmpty(dt.getTitle()))
dt.setTitle(Caster.toClassName(o));
return dt;
}
// String
if(o instanceof String) {
String str=(String) o;
if(str.trim().startsWith("<wddxPacket ")) {
try {
WDDXConverter converter =new WDDXConverter(pageContext.getTimeZone(),false,true);
converter.setTimeZone(pageContext.getTimeZone());
Object rst = converter.deserialize(str,false);
DumpData data = toDumpData(rst, pageContext, maxlevel, props);
DumpTable table = new DumpTable("string","#cc9999","#ffffff","#000000");
table.setTitle("WDDX");
table.appendRow(1,new SimpleDumpData("encoded"),data);
table.appendRow(1,new SimpleDumpData("raw"),new SimpleDumpData(str));
return table;
}
catch(Throwable t) {}
}
DumpTable table = new DumpTable("string","#ff6600","#ffcc99","#000000");
table.appendRow(1,new SimpleDumpData("string"),new SimpleDumpData(str));
return table;
}
// Character
if(o instanceof Character) {
DumpTable table = new DumpTable("character","#ff6600","#ffcc99","#000000");
table.appendRow(1,new SimpleDumpData("character"),new SimpleDumpData(o.toString()));
return table;
}
// Number
if(o instanceof Number) {
DumpTable table = new DumpTable("numeric","#ff6600","#ffcc99","#000000");
table.appendRow(1,new SimpleDumpData("number"),new SimpleDumpData(Caster.toString(((Number)o))));
return table;
}
// Boolean
if(o instanceof Boolean) {
DumpTable table = new DumpTable("boolean","#ff6600","#ffcc99","#000000");
table.appendRow(1,new SimpleDumpData("boolean"),new SimpleDumpData(((Boolean)o).booleanValue()));
return table;
}
// File
if(o instanceof File) {
DumpTable table = new DumpTable("file","#ffcc00","#ffff66","#000000");
table.appendRow(1,new SimpleDumpData("File"),new SimpleDumpData(o.toString()));
return table;
}
// Cookie
if(o instanceof Cookie) {
Cookie c=(Cookie) o;
DumpTable table = new DumpTable("Cookie","#979EAA","#DEE9FB","#000000");
table.setTitle("Cookie ("+c.getClass().getName()+")");
table.appendRow(1,new SimpleDumpData("name"),new SimpleDumpData(c.getName()));
table.appendRow(1,new SimpleDumpData("value"),new SimpleDumpData(c.getValue()));
table.appendRow(1,new SimpleDumpData("path"),new SimpleDumpData(c.getPath()));
table.appendRow(1,new SimpleDumpData("secure"),new SimpleDumpData(c.getSecure()));
table.appendRow(1,new SimpleDumpData("maxAge"),new SimpleDumpData(c.getMaxAge()));
table.appendRow(1,new SimpleDumpData("version"),new SimpleDumpData(c.getVersion()));
table.appendRow(1,new SimpleDumpData("domain"),new SimpleDumpData(c.getDomain()));
table.appendRow(1,new SimpleDumpData("httpOnly"),new SimpleDumpData(CookieImpl.isHTTPOnly(c)));
table.appendRow(1,new SimpleDumpData("comment"),new SimpleDumpData(c.getComment()));
return table;
}
// Resource
if(o instanceof Resource) {
DumpTable table = new DumpTable("resource","#ffcc00","#ffff66","#000000");
table.appendRow(1,new SimpleDumpData("Resource"),new SimpleDumpData(o.toString()));
return table;
}
// byte[]
if(o instanceof byte[]) {
byte[] bytes=(byte[]) o;
int max=5000;
DumpTable table = new DumpTable("array","#ff9900","#ffcc00","#000000");
table.setTitle("Native Array ("+Caster.toClassName(o)+")");
StringBuilder sb=new StringBuilder("[");
for(int i=0;i<bytes.length;i++) {
if(i!=0)sb.append(",");
sb.append(bytes[i]);
if(i==max) {
sb.append(", ...truncated");
break;
}
}
sb.append("]");
table.appendRow(1,new SimpleDumpData("Raw"+(bytes.length<max?"":" (truncated)")),new SimpleDumpData(sb.toString()));
if(bytes.length<max) {
// base64
table.appendRow(1,new SimpleDumpData("Base64 Encoded"),new SimpleDumpData(Base64Coder.encode(bytes)));
/*try {
table.appendRow(1,new SimpleDumpData("CFML expression"),new SimpleDumpData("evaluateJava('"+JavaConverter.serialize(bytes)+"')"));
}
catch (IOException e) {}*/
}
return table;
}
// Collection.Key
if(o instanceof Collection.Key) {
Collection.Key key=(Collection.Key) o;
DumpTable table = new DumpTable("string","#ff6600","#ffcc99","#000000");
table.appendRow(1,new SimpleDumpData("Collection.Key"),new SimpleDumpData(key.getString()));
return table;
}
String id=""+IDGenerator.intId();
String refid=ThreadLocalDump.get(o);
if(refid!=null) {
DumpTable table = new DumpTable("ref","#ffffff","#cccccc","#000000");
table.appendRow(1,new SimpleDumpData("Reference"),new SimpleDumpData(refid));
table.setRef(refid);
return setId(id,table);
}
ThreadLocalDump.set(o,id);
try{
int top = props.getMaxlevel();
// Printable
if(o instanceof Dumpable) {
return setId(id,((Dumpable)o).toDumpData(pageContext,maxlevel,props));
}
// Map
if(o instanceof Map) {
Map map=(Map) o;
Iterator it=map.keySet().iterator();
DumpTable table = new DumpTable("struct","#ff9900","#ffcc00","#000000");
table.setTitle("Map ("+Caster.toClassName(o)+")");
while(it.hasNext()) {
Object next=it.next();
table.appendRow(1,toDumpData(next,pageContext,maxlevel,props),toDumpData(map.get(next),pageContext,maxlevel,props));
}
return setId(id,table);
}
// List
if(o instanceof List) {
List list=(List) o;
ListIterator it=list.listIterator();
DumpTable table = new DumpTable("array","#ff9900","#ffcc00","#000000");
table.setTitle("Array (List)");
if ( list.size() > top )
table.setComment("Rows: " + list.size() + " (showing top " + top + ")");
int i = 0;
while(it.hasNext() && i++ < top) {
table.appendRow(1,new SimpleDumpData(it.nextIndex()+1),toDumpData(it.next(),pageContext,maxlevel,props));
}
return setId(id,table);
}
// Set
if(o instanceof Set) {
Set set=(Set) o;
Iterator it = set.iterator();
DumpTable table = new DumpTable("array","#ff9900","#ffcc00","#000000");
table.setTitle("Set ("+set.getClass().getName()+")");
int i = 0;
while(it.hasNext() && i++ < top) {
table.appendRow(1,toDumpData(it.next(),pageContext,maxlevel,props));
}
return setId(id,table);
}
// Resultset
if(o instanceof ResultSet) {
try {
DumpData dd = new QueryImpl((ResultSet)o,"query",pageContext.getTimeZone()).toDumpData(pageContext,maxlevel,props);
if(dd instanceof DumpTable)
((DumpTable)dd).setTitle(Caster.toClassName(o));
return setId(id,dd);
}
catch (PageException e) {
}
}
// Enumeration
if(o instanceof Enumeration) {
Enumeration e=(Enumeration)o;
DumpTable table = new DumpTable("enumeration","#ff9900","#ffcc00","#000000");
table.setTitle("Enumeration");
int i = 0;
while(e.hasMoreElements() && i++ < top) {
table.appendRow(0,toDumpData(e.nextElement(),pageContext,maxlevel,props));
}
return setId(id,table);
}
// Object[]
if(Decision.isNativeArray(o)) {
Array arr;
try {
arr = Caster.toArray(o);
DumpTable htmlBox = new DumpTable("array","#ff9900","#ffcc00","#000000");
htmlBox.setTitle("Native Array ("+Caster.toClassName(o)+")");
int length=arr.size();
for(int i=1;i<=length;i++) {
Object ox=null;
try {
ox = arr.getE(i);
} catch (Exception e) {}
htmlBox.appendRow(1,new SimpleDumpData(i),toDumpData(ox,pageContext,maxlevel,props));
}
return setId(id,htmlBox);
}
catch (PageException e) {
return setId(id,new SimpleDumpData(""));
}
}
// Node
if(o instanceof Node) {
return setId(id,XMLCaster.toDumpData((Node)o, pageContext,maxlevel,props));
}
// ObjectWrap
if(o instanceof ObjectWrap) {
maxlevel++;
return setId(id,toDumpData(((ObjectWrap)o).getEmbededObject(null), pageContext,maxlevel,props));
}
// NodeList
if(o instanceof NodeList) {
NodeList list=(NodeList)o;
int len=list.getLength();
DumpTable table = new DumpTable("xml","#cc9999","#ffffff","#000000");
for(int i=0;i<len;i++) {
table.appendRow(1,new SimpleDumpData(i),toDumpData(list.item(i),pageContext,maxlevel,props));
}
return setId(id,table);
}
// AttributeMap
if(o instanceof NamedNodeMap) {
NamedNodeMap attr = (NamedNodeMap)o;
int len = attr.getLength();
DumpTable dt = new DumpTable("array","#ff9900","#ffcc00","#000000");
dt.setTitle("NamedNodeMap ("+Caster.toClassName(o)+")");
for(int i=0;i<len;i++) {
dt.appendRow(1,new SimpleDumpData(i),toDumpData(attr.item(i),pageContext,maxlevel,props));
}
return setId(id,dt);
}
// HttpSession
if(o instanceof HttpSession) {
HttpSession hs = (HttpSession)o;
Enumeration e = hs.getAttributeNames();
DumpTable htmlBox = new DumpTable("httpsession","#9999ff","#ccccff","#000000");
htmlBox.setTitle("HttpSession");
while(e.hasMoreElements()) {
String key=e.nextElement().toString();
htmlBox.appendRow(1,new SimpleDumpData(key),toDumpData(hs.getAttribute(key), pageContext,maxlevel,props));
}
return setId(id,htmlBox);
}
// reflect
//else {
DumpTable table = new DumpTable(o.getClass().getName(),"#cc9999","#ffcccc","#000000");
Class clazz=o.getClass();
if(o instanceof Class) clazz=(Class) o;
String fullClassName=clazz.getName();
int pos=fullClassName.lastIndexOf('.');
String className=pos==-1?fullClassName:fullClassName.substring(pos+1);
table.setTitle(className);
table.appendRow(1,new SimpleDumpData("class"),new SimpleDumpData(fullClassName));
// Fields
Field[] fields=clazz.getFields();
DumpTable fieldDump = new DumpTable("#cc9999","#ffcccc","#000000");
fieldDump.appendRow(7,new SimpleDumpData("name"),new SimpleDumpData("pattern"),new SimpleDumpData("value"));
for(int i=0;i<fields.length;i++) {
Field field = fields[i];
DumpData value;
try {//print.out(o+":"+maxlevel);
value=new SimpleDumpData(Caster.toString(field.get(o), ""));
}
catch (Exception e) {
value=new SimpleDumpData("");
}
fieldDump.appendRow(0,new SimpleDumpData(field.getName()),new SimpleDumpData(field.toString()),value);
}
if(fields.length>0)table.appendRow(1,new SimpleDumpData("fields"),fieldDump);
// Methods
StringBuffer objMethods=new StringBuffer();
Method[] methods=clazz.getMethods();
DumpTable methDump = new DumpTable("#cc9999","#ffcccc","#000000");
methDump.appendRow(7,new SimpleDumpData("return"),new SimpleDumpData("interface"),new SimpleDumpData("exceptions"));
for(int i=0;i<methods.length;i++) {
Method method = methods[i];
if(Object.class==method.getDeclaringClass()) {
if(objMethods.length()>0)objMethods.append(", ");
objMethods.append(method.getName());
continue;
}
// exceptions
StringBuffer sbExp=new StringBuffer();
Class[] exceptions = method.getExceptionTypes();
for(int p=0;p<exceptions.length;p++){
if(p>0)sbExp.append("\n");
sbExp.append(Caster.toClassName(exceptions[p]));
}
// parameters
StringBuffer sbParams=new StringBuffer(method.getName());
sbParams.append('(');
Class[] parameters = method.getParameterTypes();
for(int p=0;p<parameters.length;p++){
if(p>0)sbParams.append(", ");
sbParams.append(Caster.toClassName(parameters[p]));
}
sbParams.append(')');
methDump.appendRow(0,
new SimpleDumpData(Caster.toClassName(method.getReturnType())),
new SimpleDumpData(sbParams.toString()),
new SimpleDumpData(sbExp.toString())
);
}
if(methods.length>0)table.appendRow(1,new SimpleDumpData("methods"),methDump);
DumpTable inherited = new DumpTable("#cc9999","#ffcccc","#000000");
inherited.appendRow(7,new SimpleDumpData("Methods inherited from java.lang.Object"));
inherited.appendRow(0,new SimpleDumpData(objMethods.toString()));
table.appendRow(1,new SimpleDumpData(""),inherited);
return setId(id,table);
//}
}
finally{
ThreadLocalDump.remove(o);
}
}
private static DumpData setId(String id, DumpData data) {
if(data instanceof DumpTable) {
((DumpTable)data).setId(id);
}
// TODO Auto-generated method stub
return data;
}
public static boolean keyValid(DumpProperties props,int level, String key) {
if(props.getMaxlevel()-level>1) return true;
// show
Set set = props.getShow();
if(set!=null && !set.contains(StringUtil.toLowerCase(key)))
return false;
// hide
set = props.getHide();
if(set!=null && set.contains(StringUtil.toLowerCase(key)))
return false;
return true;
}
public static boolean keyValid(DumpProperties props,int level, Collection.Key key) {
if(props.getMaxlevel()-level>1) return true;
// show
Set set = props.getShow();
if(set!=null && !set.contains(key.getLowerString()))
return false;
// hide
set = props.getHide();
if(set!=null && set.contains(key.getLowerString()))
return false;
return true;
}
public static DumpProperties toDumpProperties() {
return DumpProperties.DEFAULT;
}
}