View Javadoc

1   /*
2    * $Id: ObjectToHTMLWriter.java 651946 2008-04-27 13:41:38Z apetrelli $
3    *
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *  http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  package org.apache.struts2.interceptor.debugging;
23  
24  import java.beans.IntrospectionException;
25  import java.io.Writer;
26  import java.util.Collection;
27  import java.util.Iterator;
28  import java.util.List;
29  import java.util.Map;
30  import java.util.Set;
31  
32  import com.opensymphony.xwork2.util.reflection.ReflectionException;
33  import com.opensymphony.xwork2.util.reflection.ReflectionProvider;
34  
35  /***
36   * Writes an object as a table, where each field can be expanded if it is an Object/Collection/Array
37   *
38   */
39  class ObjectToHTMLWriter {
40      private PrettyPrintWriter prettyWriter;
41  
42      ObjectToHTMLWriter(Writer writer) {
43          this.prettyWriter = new PrettyPrintWriter(writer);
44          this.prettyWriter.setEscape(false);
45      }
46  
47      @SuppressWarnings("unchecked")
48      public void write(ReflectionProvider reflectionProvider, Object root, String expr) throws IntrospectionException,
49          ReflectionException {
50          prettyWriter.startNode("table");
51          prettyWriter.addAttribute("class", "debugTable");
52  
53          if (root instanceof Map) {
54              for (Iterator iterator = ((Map) root).entrySet().iterator(); iterator
55                  .hasNext();) {
56                  Map.Entry property = (Map.Entry) iterator.next();
57                  String key = property.getKey().toString();
58                  Object value = property.getValue();
59                  writeProperty(key, value, expr);
60              }
61          } else if (root instanceof List) {
62              List list = (List) root;
63              for (int i = 0; i < list.size(); i++) {
64                  Object element = list.get(i);
65                  writeProperty(String.valueOf(i), element, expr);
66              }
67          } else if (root instanceof Set) {
68              Set set = (Set) root;
69              for (Iterator iterator = set.iterator(); iterator.hasNext();) {
70                  writeProperty("", iterator.next(), expr);
71              }
72          } else if (root.getClass().isArray()) {
73              Object[] objects = (Object[]) root;
74              for (int i = 0; i < objects.length; i++) {
75                  writeProperty(String.valueOf(i), objects[i], expr);
76              }
77          } else {
78              //print properties
79              Map<String, Object> properties = reflectionProvider.getBeanMap(root);
80              for (Map.Entry<String, Object> property : properties.entrySet()) {
81                  String name = property.getKey();
82                  Object value = property.getValue();
83  
84                  if ("class".equals(name))
85                      continue;
86  
87                  writeProperty(name, value, expr);
88              }
89          }
90  
91          prettyWriter.endNode();
92      }
93  
94      private void writeProperty(String name, Object value, String expr) {
95          prettyWriter.startNode("tr");
96  
97          //name cell
98          prettyWriter.startNode("td");
99          prettyWriter.addAttribute("class", "nameColumn");
100         prettyWriter.setValue(name);
101         prettyWriter.endNode();
102 
103         //value cell
104         prettyWriter.startNode("td");
105         if (value != null) {
106             //if is is an empty collection or array, don't write a link
107             if (value != null &&
108                 (isEmptyCollection(value) || isEmptyMap(value) || (value.getClass()
109                     .isArray() && ((Object[]) value).length == 0))) {
110                 prettyWriter.addAttribute("class", "emptyCollection");
111                 prettyWriter.setValue("empty");
112             } else {
113                 prettyWriter.addAttribute("class", "valueColumn");
114                 writeValue(name, value, expr);
115             }
116         } else {
117             prettyWriter.addAttribute("class", "nullValue");
118             prettyWriter.setValue("null");
119         }
120         prettyWriter.endNode();
121 
122         //type cell
123         prettyWriter.startNode("td");
124         if (value != null) {
125             prettyWriter.addAttribute("class", "typeColumn");
126             Class clazz = value.getClass();
127             prettyWriter.setValue(clazz.getName());
128         } else {
129             prettyWriter.addAttribute("class", "nullValue");
130             prettyWriter.setValue("unknown");
131         }
132         prettyWriter.endNode();
133 
134         //close tr
135         prettyWriter.endNode();
136     }
137 
138     /***
139      * Some maps, like AttributeMap will throw an exception when isEmpty() is called
140      */
141     private boolean isEmptyMap(Object value) {
142         try {
143             return value instanceof Map && ((Map) value).isEmpty();
144         } catch (Exception e) {
145             return true;
146         }
147     }
148 
149     /***
150      * Some collections might throw an exception when isEmpty() is called
151      */
152     private boolean isEmptyCollection(Object value) {
153         try {
154             return value instanceof Collection && ((Collection) value).isEmpty();
155         } catch (Exception e) {
156             return true;
157         }
158     }
159 
160     private void writeValue(String name, Object value, String expr) {
161         Class clazz = value.getClass();
162         if (clazz.isPrimitive() || Number.class.isAssignableFrom(clazz) ||
163             clazz.equals(String.class) || Boolean.class.equals(clazz)) {
164             prettyWriter.setValue(String.valueOf(value));
165         } else {
166             prettyWriter.startNode("a");
167             String path = expr.replaceAll("#", "%23") + "[\"" +
168                 name.replaceAll("#", "%23") + "\"]";
169             prettyWriter.addAttribute("onclick", "expand(this, '" + path + "')");
170             prettyWriter.addAttribute("href", "javascript://nop/");
171             prettyWriter.setValue("Expand");
172             prettyWriter.endNode();
173         }
174     }
175 }