mirror of https://github.com/apache/jmeter.git
				
				
				
			Bug 42582 - JSON pretty printing in Tree View Listener
git-svn-id: https://svn.apache.org/repos/asf/jakarta/jmeter/branches/rel-2-2@545917 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
		
							parent
							
								
									d32d1f709c
								
							
						
					
					
						commit
						e09e4965b0
					
				| 
						 | 
					@ -28,9 +28,12 @@ import java.awt.event.ActionListener;
 | 
				
			||||||
import java.io.IOException;
 | 
					import java.io.IOException;
 | 
				
			||||||
import java.io.StringReader;
 | 
					import java.io.StringReader;
 | 
				
			||||||
import java.io.UnsupportedEncodingException;
 | 
					import java.io.UnsupportedEncodingException;
 | 
				
			||||||
 | 
					import java.lang.Character;
 | 
				
			||||||
import java.text.DateFormat;
 | 
					import java.text.DateFormat;
 | 
				
			||||||
import java.text.SimpleDateFormat;
 | 
					import java.text.SimpleDateFormat;
 | 
				
			||||||
import java.util.Date;
 | 
					import java.util.Date;
 | 
				
			||||||
 | 
					import java.util.regex.Matcher;
 | 
				
			||||||
 | 
					import java.util.regex.Pattern;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import javax.swing.BorderFactory;
 | 
					import javax.swing.BorderFactory;
 | 
				
			||||||
import javax.swing.ButtonGroup;
 | 
					import javax.swing.ButtonGroup;
 | 
				
			||||||
| 
						 | 
					@ -116,6 +119,8 @@ public class ViewResultsFullVisualizer extends AbstractVisualizer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private static final String HTML_BUTTON_LABEL = "Render HTML";
 | 
						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 XML_BUTTON_LABEL = "Render XML";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private static final String TEXT_BUTTON_LABEL = "Show Text";
 | 
						private static final String TEXT_BUTTON_LABEL = "Show Text";
 | 
				
			||||||
| 
						 | 
					@ -124,6 +129,8 @@ public class ViewResultsFullVisualizer extends AbstractVisualizer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private static final String HTML_COMMAND = "html"; // $NON-NLS-1$
 | 
						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 XML_COMMAND = "xml"; // $NON-NLS-1$
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private static final String TEXT_COMMAND = "text"; // $NON-NLS-1$
 | 
						private static final String TEXT_COMMAND = "text"; // $NON-NLS-1$
 | 
				
			||||||
| 
						 | 
					@ -136,6 +143,19 @@ public class ViewResultsFullVisualizer extends AbstractVisualizer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private boolean textMode = true;
 | 
						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
 | 
						// set default command to Text
 | 
				
			||||||
	private String command = TEXT_COMMAND;
 | 
						private String command = TEXT_COMMAND;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -166,6 +186,8 @@ public class ViewResultsFullVisualizer extends AbstractVisualizer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private JRadioButton htmlButton;
 | 
						private JRadioButton htmlButton;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						private JRadioButton jsonButton;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private JRadioButton xmlButton;
 | 
						private JRadioButton xmlButton;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	private JCheckBox downloadAll;
 | 
						private JCheckBox downloadAll;
 | 
				
			||||||
| 
						 | 
					@ -393,6 +415,8 @@ public class ViewResultsFullVisualizer extends AbstractVisualizer
 | 
				
			||||||
								showTextResponse(response);
 | 
													showTextResponse(response);
 | 
				
			||||||
							} else if (command.equals(HTML_COMMAND)) {
 | 
												} else if (command.equals(HTML_COMMAND)) {
 | 
				
			||||||
								showRenderedResponse(response, res);
 | 
													showRenderedResponse(response, res);
 | 
				
			||||||
 | 
												} else if (command.equals(JSON_COMMAND)) {
 | 
				
			||||||
 | 
													showRenderJSONResponse(response);
 | 
				
			||||||
							} else if (command.equals(XML_COMMAND)) {
 | 
												} else if (command.equals(XML_COMMAND)) {
 | 
				
			||||||
								showRenderXMLResponse(response);
 | 
													showRenderXMLResponse(response);
 | 
				
			||||||
							}
 | 
												}
 | 
				
			||||||
| 
						 | 
					@ -436,6 +460,7 @@ public class ViewResultsFullVisualizer extends AbstractVisualizer
 | 
				
			||||||
		resultsScrollPane.setViewportView(imageLabel);
 | 
							resultsScrollPane.setViewportView(imageLabel);
 | 
				
			||||||
		textButton.setEnabled(false);
 | 
							textButton.setEnabled(false);
 | 
				
			||||||
		htmlButton.setEnabled(false);
 | 
							htmlButton.setEnabled(false);
 | 
				
			||||||
 | 
							jsonButton.setEnabled(false);
 | 
				
			||||||
		xmlButton.setEnabled(false);
 | 
							xmlButton.setEnabled(false);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -447,6 +472,74 @@ public class ViewResultsFullVisualizer extends AbstractVisualizer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		textButton.setEnabled(true);
 | 
							textButton.setEnabled(true);
 | 
				
			||||||
		htmlButton.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);
 | 
							xmlButton.setEnabled(true);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -509,6 +602,7 @@ public class ViewResultsFullVisualizer extends AbstractVisualizer
 | 
				
			||||||
		resultsScrollPane.setViewportView(view);
 | 
							resultsScrollPane.setViewportView(view);
 | 
				
			||||||
		textButton.setEnabled(true);
 | 
							textButton.setEnabled(true);
 | 
				
			||||||
		htmlButton.setEnabled(true);
 | 
							htmlButton.setEnabled(true);
 | 
				
			||||||
 | 
							jsonButton.setEnabled(true);
 | 
				
			||||||
		xmlButton.setEnabled(true);
 | 
							xmlButton.setEnabled(true);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -552,7 +646,8 @@ public class ViewResultsFullVisualizer extends AbstractVisualizer
 | 
				
			||||||
		command = e.getActionCommand();
 | 
							command = e.getActionCommand();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (command != null
 | 
							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);
 | 
								textMode = command.equals(TEXT_COMMAND);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -570,6 +665,8 @@ public class ViewResultsFullVisualizer extends AbstractVisualizer
 | 
				
			||||||
				showTextResponse(response);
 | 
									showTextResponse(response);
 | 
				
			||||||
			} else if (command.equals(HTML_COMMAND)) {
 | 
								} else if (command.equals(HTML_COMMAND)) {
 | 
				
			||||||
				showRenderedResponse(response, res);
 | 
									showRenderedResponse(response, res);
 | 
				
			||||||
 | 
								} else if (command.equals(JSON_COMMAND)) {
 | 
				
			||||||
 | 
									showRenderJSONResponse(response);
 | 
				
			||||||
			} else if (command.equals(XML_COMMAND)) {
 | 
								} else if (command.equals(XML_COMMAND)) {
 | 
				
			||||||
				showRenderXMLResponse(response);
 | 
									showRenderXMLResponse(response);
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
| 
						 | 
					@ -627,6 +724,7 @@ public class ViewResultsFullVisualizer extends AbstractVisualizer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		textButton.setEnabled(true);
 | 
							textButton.setEnabled(true);
 | 
				
			||||||
		htmlButton.setEnabled(true);
 | 
							htmlButton.setEnabled(true);
 | 
				
			||||||
 | 
							jsonButton.setEnabled(true);
 | 
				
			||||||
		xmlButton.setEnabled(true);
 | 
							xmlButton.setEnabled(true);
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -645,6 +743,12 @@ public class ViewResultsFullVisualizer extends AbstractVisualizer
 | 
				
			||||||
		htmlButton.setSelected(!textMode);
 | 
							htmlButton.setSelected(!textMode);
 | 
				
			||||||
		group.add(htmlButton);
 | 
							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 = new JRadioButton(XML_BUTTON_LABEL);
 | 
				
			||||||
		xmlButton.setActionCommand(XML_COMMAND);
 | 
							xmlButton.setActionCommand(XML_COMMAND);
 | 
				
			||||||
		xmlButton.addActionListener(this);
 | 
							xmlButton.addActionListener(this);
 | 
				
			||||||
| 
						 | 
					@ -657,6 +761,7 @@ public class ViewResultsFullVisualizer extends AbstractVisualizer
 | 
				
			||||||
		pane.add(textButton);
 | 
							pane.add(textButton);
 | 
				
			||||||
		pane.add(htmlButton);
 | 
							pane.add(htmlButton);
 | 
				
			||||||
		pane.add(xmlButton);
 | 
							pane.add(xmlButton);
 | 
				
			||||||
 | 
							pane.add(jsonButton);
 | 
				
			||||||
		pane.add(downloadAll);
 | 
							pane.add(downloadAll);
 | 
				
			||||||
		return pane;
 | 
							return pane;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -166,6 +166,7 @@ Removed deprecated method JMeterUtils.split() - use JOrphanUtils version instead
 | 
				
			||||||
<li>Bug 41913 - TransactionController now creates samples as sub-samples of the transaction</li>
 | 
					<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>Bug 42506 - JMeter threads all use the same SSL session</li>
 | 
				
			||||||
<li>BeanShell elements now support ThreadListener and TestListener interfaces</li>
 | 
					<li>BeanShell elements now support ThreadListener and TestListener interfaces</li>
 | 
				
			||||||
 | 
					<li>Bug 42582 - JSON pretty printing in Tree View Listener</li>
 | 
				
			||||||
</ul>
 | 
					</ul>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<h4>Non-functional improvements:</h4>
 | 
					<h4>Non-functional improvements:</h4>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1663,8 +1663,7 @@ this response, and some response codes.
 | 
				
			||||||
Note that the Request panel only shows the headers added by JMeter.
 | 
					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.
 | 
					It does not show any headers (such as Host) that may be added by the HTTP protocol implementation.
 | 
				
			||||||
<p>
 | 
					<p>
 | 
				
			||||||
There are three ways to view the response, selectable by a radio
 | 
					There are several ways to view the response, selectable by a radio button.</p>
 | 
				
			||||||
button.</p>
 | 
					 | 
				
			||||||
<p>The default view shows all of the text contained in the
 | 
					<p>The default view shows all of the text contained in the
 | 
				
			||||||
response.</p>
 | 
					response.</p>
 | 
				
			||||||
<p>The HTML view attempts to render the response as
 | 
					<p>The HTML view attempts to render the response as
 | 
				
			||||||
| 
						 | 
					@ -1678,6 +1677,7 @@ If the checkbox is not selected, the renderer will not download images etc.
 | 
				
			||||||
<p>The Render XML view will show response in tree style. 
 | 
					<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.
 | 
					Any DTD nodes or Prolog nodes will not show up in tree; however, response may contain those nodes.
 | 
				
			||||||
</p>
 | 
					</p>
 | 
				
			||||||
 | 
					<p>The Render JSON view will show the response in tree style (also handles JSON embedded in JavaScript).</p>
 | 
				
			||||||
</description>
 | 
					</description>
 | 
				
			||||||
<p>
 | 
					<p>
 | 
				
			||||||
	The Control Panel (above) shows an example of an HTML display.
 | 
						The Control Panel (above) shows an example of an HTML display.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue