View Javadoc

1   /*
2    * Copyright (C) 2005 by Arno Schumacher
3    *
4    * This file is part of net.sourceforge.servletspy
5    *
6    * net.sourceforge.servletspy is free software; you can redistribute
7    * it and/or modify it under the terms of the GNU General Public
8    * License as published by the Free Software Foundation; either
9    * version 2, or (at your option) any later version.
10   *
11   * net.sourceforge.servletspy is distributed in the hope that it will
12   * be useful, but WITHOUT ANY WARRANTY; without even the implied
13   * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14   * See the GNU General Public License for more details.
15   *
16   * You should have received a copy of the GNU General Public License
17   * along with this program; if not, write to the Free Software
18   * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA
19   */
20  
21  package net.sourceforge.servletspy.writer;
22  
23  import java.io.BufferedReader;
24  import java.io.IOException;
25  import java.io.InputStream;
26  import java.io.InputStreamReader;
27  import java.io.PrintWriter;
28  import java.util.HashMap;
29  import java.util.Iterator;
30  import java.util.Map;
31  
32  import net.sourceforge.servletspy.INodeWriter;
33  import net.sourceforge.servletspy.Node;
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 HtmlNodeWriter implements INodeWriter {
42      private static class EscapeMap {
43          private static final long serialVersionUID = 3035978367106983288L;
44  
45          private final Map impl = new HashMap();
46  
47          EscapeMap() {
48              super();
49              impl.put(new Long(10), "<br />\n");
50              impl.put(new Long(13), "");
51              impl.put(new Long(34), "&quot;");
52              impl.put(new Long(38), "&amp;");
53              impl.put(new Long(60), "&lt;");
54              impl.put(new Long(62), "&gt;");
55          }
56  
57          public final String map(final char c) {
58              String s = (String) impl.get(new Long(c));
59              return s == null ? String.valueOf(c) : s;
60          }
61      };
62  
63      private static final EscapeMap ESCAPE_MAP = new EscapeMap();
64  
65      private static final Log LOGGER = LogFactory.getLog(HtmlNodeWriter.class);
66  
67      private static void comment(final PrintWriter out, final int id,
68              final Node node, final boolean isBegin) {
69          out.println();
70          out.print("<!-- ");
71          out.print(isBegin ? "  b e g i n :   " : "  e n d :    ");
72          out.print(getPath(node));
73          out.print(" - ");
74          out.print(id);
75          out.println("  -->");
76      }
77  
78      private static String getPath(final Node node) {
79          if (node == null) {
80              throw new NullPointerException();
81          } else {
82              return node.getParent() == null ? node.getName() : (getPath(node
83                      .getParent())
84                      + "/" + node.getName());
85          }
86      }
87  
88      private static String quoteCharacters(final String stringToQuote) {
89          final StringBuffer stringBuffer = new StringBuffer(stringToQuote
90                  .length() * 2);
91          final char[] stringToQuoteAsCharArray = new char[stringToQuote.length()];
92          stringToQuote.getChars(0, stringToQuote.length(),
93                  stringToQuoteAsCharArray, 0);
94          for (int j = 0; j < stringToQuoteAsCharArray.length; j++) {
95              stringBuffer.append(ESCAPE_MAP.map(stringToQuoteAsCharArray[j]));
96          }
97          return stringBuffer.toString();
98      }
99  
100     private final PrintWriter printWriter;
101 
102     private final String resourceName = this.getClass().getName().replace('.',
103             '/')
104             + ".htmlstatic";
105 
106     /***
107      * Constructor.
108      * 
109      * @param pPrintWriter
110      *            The writer.
111      */
112     public HtmlNodeWriter(final PrintWriter pPrintWriter) {
113         printWriter = pPrintWriter;
114     }
115 
116     private String generateDebugHint(final Node node) {
117     	String answer = "";
118         if (LOGGER.isDebugEnabled()) {
119             answer = quoteCharacters(" //  "
120                     + String.valueOf(node.getDebugHint()));
121         } 
122         return answer;
123     }
124 
125     private String generateHeaderString(final Node node, final String id) {
126         final StringBuffer sb = new StringBuffer();
127         sb.append("<div class=\"spyHeader\">");
128         if (node.hasChildNodes()) {
129             sb.append("<a href=\"javascript:changeVisualizationMode('");
130             sb.append(id);
131             sb.append("')\">");
132         }
133         sb.append(quoteCharacters(node.getName()));
134         if (node.hasChildNodes()) {
135             sb.append("</a>");
136         }
137         sb.append("<span class=\"spyHeaderValue\">");
138         sb.append(quoteCharacters(node.getValue()));
139         sb.append(generateDebugHint(node));
140         sb.append("</span>"); // class=spyHeaderValue
141         sb.append("</div>"); // class=spyHeader
142         return sb.toString();
143     }
144 
145     private void writeHtmlStatic(final PrintWriter writer) throws IOException {
146         LOGGER.debug("Writing static part...");
147         boolean succeeded = false;
148         try {
149             final InputStream ios = Thread.currentThread()
150                     .getContextClassLoader().getResourceAsStream(resourceName);
151             if (ios == null) {
152                 throw new IOException("Resource '" + resourceName
153                         + "' could not be found.");
154             }
155             final BufferedReader in = new BufferedReader(new InputStreamReader(
156                     ios));
157             String s = in.readLine();
158             while (s != null) {
159                 writer.println(s);
160                 s = in.readLine();
161             }
162             in.close();
163             succeeded = true;
164         } finally {
165             LOGGER.debug(succeeded ? "..succeeded." : "...failed.");
166         }
167     }
168 
169     /*
170      * (non-Javadoc)
171      * 
172      * @see net.sourceforge.servletspy.html.IHtmlTool#writeState(java.io.PrintWriter,
173      *      net.sourceforge.servletspy.tree.Node)
174      */
175     public void writeNode(final Node rootNode) throws IOException {
176         final long startRandom = System.currentTimeMillis() % 100000;
177         writeHtmlStatic(printWriter);
178         writeNode(printWriter, rootNode, 0, startRandom);
179     }
180 
181     private int writeNode(final PrintWriter out, final Node node, int counter,
182             final long random) {
183         final int fixedCounter = ++counter;
184         final String id = fixedCounter + "R" + String.valueOf(random);
185         final String header = generateHeaderString(node, id);
186 
187         comment(out, fixedCounter, node, true);
188 
189         if (node.hasChildNodes()) {
190             // visible
191             out.print("<div class=\"spyBox\" style=\"display:");
192             out.print("block");
193             out.print("\" id=\"");
194             out.print(id);
195             out.print("C\">");
196             out.print(header);
197             out.println("</div>");
198         }
199 
200         // hidden
201         out.print("<div class=\"spyBox\" ");
202         if (node.hasChildNodes()) {
203             out.print("style=\"display:");
204             out.print("none");
205             out.print("\"  id=\"");
206             out.print(id);
207             out.print("E\"");
208         }
209         out.print(">");
210 
211         out.print(header);
212 
213         // body
214         counter += 1 - (node.getNumberOfChild() % 2);
215         for (Iterator enumNodeChilds = node.childNodes(); enumNodeChilds
216                 .hasNext();) {
217             final Node nodeChild = (Node) enumNodeChilds.next();
218 
219             counter++;
220 
221             if (nodeChild.hasChildNodes()) {
222                 out.print("<div class=\"spyKeyBox");
223                 out.print(counter % 2);
224                 out.print("\">\n    ");
225                 final int counterSave = counter;
226                 counter = writeNode(out, nodeChild, ++counter, random);
227                 if ((counterSave % 2) != (counter % 2)) {
228                     counter++;
229                 }
230                 out.println("</div>"); // class=spyKeyBox
231             } else {
232                 out.print("<div class=\"spyKeyValue");
233                 out.print(counter % 2);
234                 out.print("\">\n    ");
235                 out.print(quoteCharacters(nodeChild.getName()));
236 
237                 if (nodeChild.getValue() != null
238                         && nodeChild.getValue().toString().length() > 0) {
239                     out.print("<span class=\"spyValue\">");
240                     out.print(quoteCharacters(nodeChild.getValue().toString()));
241 
242                     out.print(generateDebugHint(nodeChild));
243                     out.print("</span>");
244                     if (nodeChild.hasReference()) {
245                         out.print("  -  ");
246                         out.print("<span class=\"spyValueReference\">");
247                         out.print(nodeChild.getReference().getName());
248                         out.print("</span>");
249                     }
250                 }
251                 out.print("</div>");
252             }
253         }
254 
255         if (node.hasChildNodes()) {
256             out.print("</div>");
257         }
258 
259         comment(out, fixedCounter, node, false);
260 
261         return counter;
262     }
263 }