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 }