altosdroid: Add Dumper class for testing
[fw/altos] / altosdroid / src / org / altusmetrum / AltosDroid / Dumper.java
1 package org.altusmetrum.AltosDroid;\r
2 \r
3         import java.lang.reflect.Array;\r
4         import java.lang.reflect.Field;\r
5         import java.util.HashMap;\r
6 \r
7         public class Dumper {\r
8                 private static Dumper instance = new Dumper();\r
9 \r
10                 protected static Dumper getInstance() {\r
11                         return instance;\r
12                 }\r
13 \r
14                 class DumpContext {\r
15                         int maxDepth = 0;\r
16                         int maxArrayElements = 0;\r
17                         int callCount = 0;\r
18                         HashMap<String, String> ignoreList = new HashMap<String, String>();\r
19                         HashMap<Object, Integer> visited = new HashMap<Object, Integer>();\r
20                 }\r
21 \r
22                 public static String dump(Object o) {\r
23                         return dump(o, 0, 0, null);\r
24                 }\r
25 \r
26                 public static String dump(Object o, int maxDepth, int maxArrayElements, String[] ignoreList) {\r
27                         DumpContext ctx = Dumper.getInstance().new DumpContext();\r
28                         ctx.maxDepth = maxDepth;\r
29                         ctx.maxArrayElements = maxArrayElements;\r
30 \r
31                         if (ignoreList != null) {\r
32                                 for (int i = 0; i < Array.getLength(ignoreList); i++) {\r
33                                         int colonIdx = ignoreList[i].indexOf(':');\r
34                                         if (colonIdx == -1)\r
35                                                 ignoreList[i] = ignoreList[i] + ":";\r
36                                         ctx.ignoreList.put(ignoreList[i], ignoreList[i]);\r
37                                 }\r
38                         }\r
39 \r
40                         return dump(o, ctx);\r
41                 }\r
42 \r
43                 protected static String dump(Object o, DumpContext ctx) {\r
44                         if (o == null) {\r
45                                 return "<null>";\r
46                         }\r
47 \r
48                         ctx.callCount++;\r
49                         StringBuffer tabs = new StringBuffer();\r
50                         for (int k = 0; k < ctx.callCount; k++) {\r
51                                 tabs.append("\t");\r
52                         }\r
53                         StringBuffer buffer = new StringBuffer();\r
54                         @SuppressWarnings("rawtypes")\r
55                         Class oClass = o.getClass();\r
56 \r
57                         String oSimpleName = getSimpleNameWithoutArrayQualifier(oClass);\r
58 \r
59                         if (ctx.ignoreList.get(oSimpleName + ":") != null)\r
60                                 return "<Ignored>";\r
61 \r
62                         if (oClass.isArray()) {\r
63                                 buffer.append("\n");\r
64                                 buffer.append(tabs.toString().substring(1));\r
65                                 buffer.append("[\n");\r
66                                 int rowCount = ctx.maxArrayElements == 0 ? Array.getLength(o) : Math.min(ctx.maxArrayElements, Array.getLength(o));\r
67                                 for (int i = 0; i < rowCount; i++) {\r
68                                         buffer.append(tabs.toString());\r
69                                         try {\r
70                                                 Object value = Array.get(o, i);\r
71                                                 buffer.append(dumpValue(value, ctx));\r
72                                         } catch (Exception e) {\r
73                                                 buffer.append(e.getMessage());\r
74                                         }\r
75                                         if (i < Array.getLength(o) - 1)\r
76                                                 buffer.append(",");\r
77                                         buffer.append("\n");\r
78                                 }\r
79                                 if (rowCount < Array.getLength(o)) {\r
80                                         buffer.append(tabs.toString());\r
81                                         buffer.append(Array.getLength(o) - rowCount + " more array elements...");\r
82                                         buffer.append("\n");\r
83                                 }\r
84                                 buffer.append(tabs.toString().substring(1));\r
85                                 buffer.append("]");\r
86                         } else {\r
87                                 buffer.append("\n");\r
88                                 buffer.append(tabs.toString().substring(1));\r
89                                 buffer.append("{\n");\r
90                                 buffer.append(tabs.toString());\r
91                                 buffer.append("hashCode: " + o.hashCode());\r
92                                 buffer.append("\n");\r
93                                 while (oClass != null && oClass != Object.class) {\r
94                                         Field[] fields = oClass.getDeclaredFields();\r
95 \r
96                                         if (ctx.ignoreList.get(oClass.getSimpleName()) == null) {\r
97                                                 if (oClass != o.getClass()) {\r
98                                                         buffer.append(tabs.toString().substring(1));\r
99                                                         buffer.append("  Inherited from superclass " + oSimpleName + ":\n");\r
100                                                 }\r
101 \r
102                                                 for (int i = 0; i < fields.length; i++) {\r
103 \r
104                                                         String fSimpleName = getSimpleNameWithoutArrayQualifier(fields[i].getType());\r
105                                                         String fName = fields[i].getName();\r
106 \r
107                                                         fields[i].setAccessible(true);\r
108                                                         buffer.append(tabs.toString());\r
109                                                         buffer.append(fName + "(" + fSimpleName + ")");\r
110                                                         buffer.append("=");\r
111 \r
112                                                         if (ctx.ignoreList.get(":" + fName) == null &&\r
113                                                                 ctx.ignoreList.get(fSimpleName + ":" + fName) == null &&\r
114                                                                 ctx.ignoreList.get(fSimpleName + ":") == null) {\r
115 \r
116                                                                 try {\r
117                                                                         Object value = fields[i].get(o);\r
118                                                                         buffer.append(dumpValue(value, ctx));\r
119                                                                 } catch (Exception e) {\r
120                                                                         buffer.append(e.getMessage());\r
121                                                                 }\r
122                                                                 buffer.append("\n");\r
123                                                         } else {\r
124                                                                 buffer.append("<Ignored>");\r
125                                                                 buffer.append("\n");\r
126                                                         }\r
127                                                 }\r
128                                                 oClass = oClass.getSuperclass();\r
129                                                 oSimpleName = oClass.getSimpleName();\r
130                                         } else {\r
131                                                 oClass = null;\r
132                                                 oSimpleName = "";\r
133                                         }\r
134                                 }\r
135                                 buffer.append(tabs.toString().substring(1));\r
136                                 buffer.append("}");\r
137                         }\r
138                         ctx.callCount--;\r
139                         return buffer.toString();\r
140                 }\r
141 \r
142                 protected static String dumpValue(Object value, DumpContext ctx) {\r
143                         if (value == null) {\r
144                                 return "<null>";\r
145                         }\r
146                         if (value.getClass().isPrimitive() ||\r
147                                 value.getClass() == java.lang.Short.class ||\r
148                                 value.getClass() == java.lang.Long.class ||\r
149                                 value.getClass() == java.lang.String.class ||\r
150                                 value.getClass() == java.lang.Integer.class ||\r
151                                 value.getClass() == java.lang.Float.class ||\r
152                                 value.getClass() == java.lang.Byte.class ||\r
153                                 value.getClass() == java.lang.Character.class ||\r
154                                 value.getClass() == java.lang.Double.class ||\r
155                                 value.getClass() == java.lang.Boolean.class) {\r
156 \r
157                                 return value.toString();\r
158 \r
159                         } else {\r
160 \r
161                                 Integer visitedIndex = ctx.visited.get(value);\r
162                                 if (visitedIndex == null) {\r
163                                         ctx.visited.put(value, ctx.callCount);\r
164                                         if (ctx.maxDepth == 0 || ctx.callCount < ctx.maxDepth) {\r
165                                                 return dump(value, ctx);\r
166                                         } else {\r
167                                                 return "<Reached max recursion depth>";\r
168                                         }\r
169                                 } else {\r
170                                         return "<Previously visited - see hashCode " + value.hashCode() + ">";\r
171                                 }\r
172                         }\r
173                 }\r
174 \r
175 \r
176                 private static String getSimpleNameWithoutArrayQualifier(@SuppressWarnings("rawtypes") Class clazz) {\r
177                         String simpleName = clazz.getSimpleName();\r
178                         int indexOfBracket = simpleName.indexOf('['); \r
179                         if (indexOfBracket != -1)\r
180                                 return simpleName.substring(0, indexOfBracket);\r
181                         return simpleName;\r
182                 }\r
183 }\r