1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package net.sourceforge.servletspy.ctx;
23
24 import java.io.ByteArrayOutputStream;
25 import java.io.PrintWriter;
26 import java.lang.reflect.InvocationTargetException;
27 import java.util.HashMap;
28 import java.util.Map;
29
30 import net.sourceforge.servletspy.IContext;
31 import net.sourceforge.servletspy.IContextHandler;
32 import net.sourceforge.servletspy.Node;
33 import net.sourceforge.servletspy.util.ClassUtil;
34
35 import org.apache.commons.logging.Log;
36 import org.apache.commons.logging.LogFactory;
37
38 /***
39 * @author arno schumacher
40 */
41 public final class Context implements IContext {
42
43 /*** The logger. */
44 private static final Log LOGGER = LogFactory.getLog(Context.class);
45
46 /***
47 * Calculates a default serialization result value.
48 *
49 * @param subject
50 * The subject to serialize
51 * @return The default value.
52 */
53 private static String determineDefaultValue(final Object subject) {
54
55 if (subject == null) {
56 return "";
57 } else {
58 return ClassUtil.getClassName( subject.getClass() );
59 }
60 }
61
62 /*** Map holding already processed subjects, for cycle detection purpose. */
63 private final Map introspected;
64
65 /***
66 * The result node, a container holding the serialization result and a set
67 * of child nodes.
68 */
69 private Node node;
70
71 /*** The object for which a node tree has to be calculated. */
72 private Object subject;
73
74 /*** The transformers responsible for generating the node tree. */
75 private final IContextHandler[] transformers;
76
77 /*** The index of the <i>current</i> transformer. */
78 private int transformerIndex = -1;
79
80 /***
81 * Constructor.
82 *
83 * @param name
84 * The name of the context.
85 * @param pSubject
86 * The object to serialize.
87 * @param parentContext
88 * The parent context.
89 */
90 private Context(final String name, final Object pSubject,
91 final Context parentContext) {
92 this.subject = pSubject;
93 this.transformers = parentContext.transformers;
94 this.introspected = new HashMap(parentContext.introspected);
95 this.node = new Node(parentContext.node, name,
96 determineDefaultValue(pSubject));
97 }
98
99 /***
100 * Constructor.
101 *
102 * @param name
103 * The name of the context.
104 * @param pSubject
105 * The object to serialize
106 * @param pTransformers
107 * The chain of transformers responsible for the serialization
108 * task.
109 */
110 public Context(final String name, final Object pSubject,
111 final IContextHandler[] pTransformers) {
112 this.node = new Node(null, name, determineDefaultValue(pSubject));
113 this.subject = pSubject;
114 this.introspected = new HashMap();
115 this.transformers = pTransformers;
116 }
117
118
119
120
121
122
123
124 public void add(final String name, final Object pSubject) {
125 final Context ctx = new Context(name, pSubject, this);
126 ctx.proceed();
127 if (ctx.getNode() != null) {
128 this.getNode().addChildNode(ctx.getNode());
129 }
130 }
131
132 /***
133 * Returns the map holding the already serialized subjects.
134 *
135 * @return The map of the already serialized subjects.
136 */
137 public Map getIntrospectedMap() {
138 return introspected;
139 }
140
141
142
143
144
145
146 public String getName() {
147 if (getNode() == null) {
148 throw new IllegalStateException();
149 }
150 return getNode().getName();
151 }
152
153 /***
154 * Returns the node associated with this context.
155 *
156 * @return The node.
157 */
158 public Node getNode() {
159 return node;
160 }
161
162
163
164
165
166
167 public Object getSubject() {
168 return subject;
169 }
170
171
172
173
174
175
176 public String getValue() {
177 return getNode() == null ? null : getNode().getValue();
178 }
179
180 private void handleException(final Throwable exception) {
181 LOGGER.info("Caught exception:", exception);
182 if (node != null) {
183 ByteArrayOutputStream bytes = new ByteArrayOutputStream();
184 PrintWriter writer = new PrintWriter(bytes, true);
185 exception.printStackTrace(writer);
186 if (node.getValue() == null || node.getValue().length() == 0) {
187 node.setValue(bytes.toString());
188 } else {
189 node.setValue(node.getValue() + " : " + bytes.toString());
190 }
191 }
192 }
193
194
195
196
197
198
199 public void invalidate() {
200 this.node = null;
201 }
202
203
204
205
206
207
208 public void proceed() {
209 transformerIndex++;
210 try {
211 if (transformerIndex < transformers.length && node != null) {
212 try {
213 node
214 .setDebugHint(ClassUtil.getSimpleClassName(transformers[transformerIndex].getClass())
215 + " -- "
216 + System.identityHashCode(getSubject()));
217 transformers[transformerIndex].handle(this);
218 } catch (InvocationTargetException e) {
219 final Throwable throwable = e.getTargetException();
220 handleException(throwable);
221 } catch (Exception e) {
222 handleException(e);
223 }
224 }
225 } finally {
226 transformerIndex--;
227 }
228 }
229
230
231
232
233
234
235 public void setSubject(final Object pSubject) {
236 getIntrospectedMap().remove(this.subject);
237 if (pSubject != null) {
238 getIntrospectedMap().put(pSubject, this.getNode());
239 }
240 this.subject = pSubject;
241 }
242
243
244
245
246
247
248 public void setValue(final String value) {
249 if (getNode() == null) {
250 throw new IllegalStateException();
251 }
252 getNode().setValue(value);
253 }
254 }