Author: sebb
Date: Sun Jun 10 11:07:10 2007
New Revision: 545917

URL: http://svn.apache.org/viewvc?view=rev&rev=545917
Log:
Bug 42582 - JSON pretty printing in Tree View Listener

Modified:
    
jakarta/jmeter/branches/rel-2-2/src/components/org/apache/jmeter/visualizers/ViewResultsFullVisualizer.java
    jakarta/jmeter/branches/rel-2-2/xdocs/changes.xml
    jakarta/jmeter/branches/rel-2-2/xdocs/usermanual/component_reference.xml

Modified: 
jakarta/jmeter/branches/rel-2-2/src/components/org/apache/jmeter/visualizers/ViewResultsFullVisualizer.java
URL: 
http://svn.apache.org/viewvc/jakarta/jmeter/branches/rel-2-2/src/components/org/apache/jmeter/visualizers/ViewResultsFullVisualizer.java?view=diff&rev=545917&r1=545916&r2=545917
==============================================================================
--- 
jakarta/jmeter/branches/rel-2-2/src/components/org/apache/jmeter/visualizers/ViewResultsFullVisualizer.java
 (original)
+++ 
jakarta/jmeter/branches/rel-2-2/src/components/org/apache/jmeter/visualizers/ViewResultsFullVisualizer.java
 Sun Jun 10 11:07:10 2007
@@ -28,9 +28,12 @@
 import java.io.IOException;
 import java.io.StringReader;
 import java.io.UnsupportedEncodingException;
+import java.lang.Character;
 import java.text.DateFormat;
 import java.text.SimpleDateFormat;
 import java.util.Date;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 import javax.swing.BorderFactory;
 import javax.swing.ButtonGroup;
@@ -116,6 +119,8 @@
 
        private static final String HTML_BUTTON_LABEL = "Render HTML";
 
+       private static final String JSON_BUTTON_LABEL = "Render JSON";
+
        private static final String XML_BUTTON_LABEL = "Render XML";
 
        private static final String TEXT_BUTTON_LABEL = "Show Text";
@@ -124,6 +129,8 @@
 
        private static final String HTML_COMMAND = "html"; // $NON-NLS-1$
 
+       private static final String JSON_COMMAND = "json"; // $NON-NLS-1$
+
        private static final String XML_COMMAND = "xml"; // $NON-NLS-1$
 
        private static final String TEXT_COMMAND = "text"; // $NON-NLS-1$
@@ -136,6 +143,19 @@
 
        private boolean textMode = true;
 
+       private static final String ESC_CHAR_REGEX = 
"\\\\[\"\\\\/bfnrt]|\\\\u[0-9A-Fa-f]{4}"; // $NON-NLS-1$
+
+       private static final String NORMAL_CHARACTER_REGEX = "[^\"\\\\]";  // 
$NON-NLS-1$
+
+       private static final String STRING_REGEX = "\"(" + ESC_CHAR_REGEX + "|" 
+ NORMAL_CHARACTER_REGEX + ")*\""; // $NON-NLS-1$
+
+       // This 'other value' regex is deliberately weak, even accepting an 
empty string, to be useful when reporting malformed data.
+       private static final String OTHER_VALUE_REGEX = "[^\\{\\[\\]\\}\\,]*"; 
// $NON-NLS-1$
+
+       private static final String VALUE_OR_PAIR_REGEX = "((" + STRING_REGEX + 
"\\s*:)?\\s*(" + STRING_REGEX + "|" + OTHER_VALUE_REGEX + ")\\s*,?\\s*)"; // 
$NON-NLS-1$
+
+       private static final Pattern VALUE_OR_PAIR_PATTERN = 
Pattern.compile(VALUE_OR_PAIR_REGEX);
+
        // set default command to Text
        private String command = TEXT_COMMAND;
 
@@ -166,6 +186,8 @@
 
        private JRadioButton htmlButton;
 
+       private JRadioButton jsonButton;
+
        private JRadioButton xmlButton;
 
        private JCheckBox downloadAll;
@@ -393,6 +415,8 @@
                                                                
showTextResponse(response);
                                                        } else if 
(command.equals(HTML_COMMAND)) {
                                                                
showRenderedResponse(response, res);
+                                                       } else if 
(command.equals(JSON_COMMAND)) {
+                                                               
showRenderJSONResponse(response);
                                                        } else if 
(command.equals(XML_COMMAND)) {
                                                                
showRenderXMLResponse(response);
                                                        }
@@ -436,6 +460,7 @@
                resultsScrollPane.setViewportView(imageLabel);
                textButton.setEnabled(false);
                htmlButton.setEnabled(false);
+               jsonButton.setEnabled(false);
                xmlButton.setEnabled(false);
        }
 
@@ -447,6 +472,74 @@
 
                textButton.setEnabled(true);
                htmlButton.setEnabled(true);
+               jsonButton.setEnabled(true);
+               xmlButton.setEnabled(true);
+       }
+
+       // It might be useful also to make this available in the 'Request' tab, 
for
+       // when posting JSON.
+       private static String prettyJSON(String json) {
+               StringBuffer pretty = new StringBuffer(json.length() * 2); // 
Educated guess
+
+               final String tab = ":   "; // $NON-NLS-1$
+               StringBuffer index = new StringBuffer();
+               String nl = ""; // $NON-NLS-1$
+
+               Matcher valueOrPair = VALUE_OR_PAIR_PATTERN.matcher(json);
+
+               boolean misparse = false;
+
+               for (int i = 0; i < json.length(); ) {
+                       final char currentChar = json.charAt(i);
+                       if ((currentChar == '{') || (currentChar == '[')) {
+                               
pretty.append(nl).append(index).append(currentChar);
+                               i++;
+                               index.append(tab);
+                               misparse = false;
+                       }
+                       else if ((currentChar == '}') || (currentChar == ']')) {
+                               if (index.length() > 0) {
+                                       index.delete(0, tab.length());
+                               }
+                               
pretty.append(nl).append(index).append(currentChar);
+                               i++;
+                               int j = i;
+                               while ((j < json.length()) && 
Character.isWhitespace(json.charAt(j))) {
+                                       j++;
+                               }
+                               if ((j < json.length()) && (json.charAt(j) == 
',')) {
+                                       pretty.append(","); // $NON-NLS-1$
+                                       i=j+1;
+                               }
+                               misparse = false;
+                       }
+                       else if (valueOrPair.find(i) && 
valueOrPair.group().length() > 0) {
+                               
pretty.append(nl).append(index).append(valueOrPair.group());
+                               i=valueOrPair.end();
+                               misparse = false;
+                       }
+                       else {
+                               if (!misparse) {
+                                       pretty.append(nl).append("- Parse 
failed from:");
+                               }
+                               pretty.append(currentChar);
+                               i++;
+                               misparse = true;
+                       }
+                       nl = "\n"; // $NON-NLS-1$
+               }
+               return pretty.toString();
+       }
+       
+       private void showRenderJSONResponse(String response) {
+               results.setContentType("text/plain"); // $NON-NLS-1$
+               results.setText(response == null ? "" : prettyJSON(response));
+               results.setCaretPosition(0);
+               resultsScrollPane.setViewportView(results);
+
+               textButton.setEnabled(true);
+               htmlButton.setEnabled(true);
+               jsonButton.setEnabled(true);
                xmlButton.setEnabled(true);
        }
 
@@ -509,6 +602,7 @@
                resultsScrollPane.setViewportView(view);
                textButton.setEnabled(true);
                htmlButton.setEnabled(true);
+               jsonButton.setEnabled(true);
                xmlButton.setEnabled(true);
        }
 
@@ -552,7 +646,8 @@
                command = e.getActionCommand();
 
                if (command != null
-                               && (command.equals(TEXT_COMMAND) || 
command.equals(HTML_COMMAND) || command.equals(XML_COMMAND))) {
+                               && (command.equals(TEXT_COMMAND) || 
command.equals(HTML_COMMAND)
+                               || command.equals(JSON_COMMAND) || 
command.equals(XML_COMMAND))) {
 
                        textMode = command.equals(TEXT_COMMAND);
 
@@ -570,6 +665,8 @@
                                showTextResponse(response);
                        } else if (command.equals(HTML_COMMAND)) {
                                showRenderedResponse(response, res);
+                       } else if (command.equals(JSON_COMMAND)) {
+                               showRenderJSONResponse(response);
                        } else if (command.equals(XML_COMMAND)) {
                                showRenderXMLResponse(response);
                        }
@@ -627,6 +724,7 @@
 
                textButton.setEnabled(true);
                htmlButton.setEnabled(true);
+               jsonButton.setEnabled(true);
                xmlButton.setEnabled(true);
        }
 
@@ -645,6 +743,12 @@
                htmlButton.setSelected(!textMode);
                group.add(htmlButton);
 
+               jsonButton = new JRadioButton(JSON_BUTTON_LABEL);
+               jsonButton.setActionCommand(JSON_COMMAND);
+               jsonButton.addActionListener(this);
+               jsonButton.setSelected(!textMode);
+               group.add(jsonButton);
+
                xmlButton = new JRadioButton(XML_BUTTON_LABEL);
                xmlButton.setActionCommand(XML_COMMAND);
                xmlButton.addActionListener(this);
@@ -657,6 +761,7 @@
                pane.add(textButton);
                pane.add(htmlButton);
                pane.add(xmlButton);
+               pane.add(jsonButton);
                pane.add(downloadAll);
                return pane;
        }

Modified: jakarta/jmeter/branches/rel-2-2/xdocs/changes.xml
URL: 
http://svn.apache.org/viewvc/jakarta/jmeter/branches/rel-2-2/xdocs/changes.xml?view=diff&rev=545917&r1=545916&r2=545917
==============================================================================
--- jakarta/jmeter/branches/rel-2-2/xdocs/changes.xml (original)
+++ jakarta/jmeter/branches/rel-2-2/xdocs/changes.xml Sun Jun 10 11:07:10 2007
@@ -166,6 +166,7 @@
 <li>Bug 41913 - TransactionController now creates samples as sub-samples of 
the transaction</li>
 <li>Bug 42506 - JMeter threads all use the same SSL session</li>
 <li>BeanShell elements now support ThreadListener and TestListener 
interfaces</li>
+<li>Bug 42582 - JSON pretty printing in Tree View Listener</li>
 </ul>
 
 <h4>Non-functional improvements:</h4>

Modified: 
jakarta/jmeter/branches/rel-2-2/xdocs/usermanual/component_reference.xml
URL: 
http://svn.apache.org/viewvc/jakarta/jmeter/branches/rel-2-2/xdocs/usermanual/component_reference.xml?view=diff&rev=545917&r1=545916&r2=545917
==============================================================================
--- jakarta/jmeter/branches/rel-2-2/xdocs/usermanual/component_reference.xml 
(original)
+++ jakarta/jmeter/branches/rel-2-2/xdocs/usermanual/component_reference.xml 
Sun Jun 10 11:07:10 2007
@@ -1663,8 +1663,7 @@
 Note that the Request panel only shows the headers added by JMeter.
 It does not show any headers (such as Host) that may be added by the HTTP 
protocol implementation.
 <p>
-There are three ways to view the response, selectable by a radio
-button.</p>
+There are several ways to view the response, selectable by a radio button.</p>
 <p>The default view shows all of the text contained in the
 response.</p>
 <p>The HTML view attempts to render the response as
@@ -1678,6 +1677,7 @@
 <p>The Render XML view will show response in tree style. 
 Any DTD nodes or Prolog nodes will not show up in tree; however, response may 
contain those nodes.
 </p>
+<p>The Render JSON view will show the response in tree style (also handles 
JSON embedded in JavaScript).</p>
 </description>
 <p>
        The Control Panel (above) shows an example of an HTML display.



---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to