Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.blazemeter.jmeter.http2.visualizers.ViewResultsFullVisualizer Maven / Gradle / Ivy
package com.blazemeter.jmeter.http2.visualizers;
import com.blazemeter.jmeter.http2.sampler.HTTP2SampleResult;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import javax.swing.BorderFactory;
import javax.swing.ComboBoxModel;
import javax.swing.DefaultComboBoxModel;
import javax.swing.ImageIcon;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTabbedPane;
import javax.swing.JTree;
import javax.swing.Timer;
import javax.swing.border.Border;
import javax.swing.event.TreeSelectionEvent;
import javax.swing.event.TreeSelectionListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;
import org.apache.commons.collections.EnumerationUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.jmeter.JMeter;
import org.apache.jmeter.assertions.AssertionResult;
import org.apache.jmeter.gui.util.VerticalPanel;
import org.apache.jmeter.samplers.Clearable;
import org.apache.jmeter.samplers.SampleResult;
import org.apache.jmeter.util.JMeterUtils;
import org.apache.jmeter.visualizers.ResultRenderer;
import org.apache.jmeter.visualizers.SearchTreePanel;
import org.apache.jmeter.visualizers.SearchableTreeNode;
import org.apache.jmeter.visualizers.gui.AbstractVisualizer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Implements a View Result Tree which shows the samplers with pending response different than the
* samplers already responded
*/
public class ViewResultsFullVisualizer extends AbstractVisualizer
implements ActionListener, TreeSelectionListener, Clearable, ItemListener {
private static final Logger LOG = LoggerFactory
.getLogger(org.apache.jmeter.visualizers.ViewResultsFullVisualizer.class);
public static final String VIEW_RESULT_TREE_HTTP2_TITLE = "View Result Tree Http2";
protected static final String COMBO_CHANGE_COMMAND = "change_combo";
private static final Border RED_BORDER = BorderFactory.createLineBorder(Color.red);
private static final Border BLUE_BORDER = BorderFactory.createLineBorder(Color.blue);
private static final String ICON_SIZE = JMeterUtils
.getPropDefault(JMeter.TREE_ICON_SIZE, JMeter.DEFAULT_TREE_ICON_SIZE);
private static final String VIEWERS_ORDER =
JMeterUtils
.getPropDefault("view.results.tree.renderers_order", "");
private static final int REFRESH_PERIOD = JMeterUtils
.getPropDefault("jmeter.gui.refresh_period", 500);
private static final ImageIcon imageSuccess = JMeterUtils.getImage(
JMeterUtils.getPropDefault("viewResultsTree.success",
"vrt/" + ICON_SIZE + "/security-high-2.png"));
private static final ImageIcon imagePending = JMeterUtils
.getImage("toolbar/" + ICON_SIZE + "arrow-right-3.png");
private static final ImageIcon imageFailure = JMeterUtils.getImage(
JMeterUtils.getPropDefault("viewResultsTree.failure",
"vrt/" + ICON_SIZE + "/security-low-2.png"));
private JSplitPane mainSplit;
private DefaultMutableTreeNode root;
private DefaultTreeModel treeModel;
private JTree jTree;
private Component leftSide;
private JTabbedPane rightSide;
private JComboBox selectRenderPanel;
private int selectedTab;
private ResultRenderer resultsRender = null;
private Object resultsObject = null;
private TreeSelectionEvent lastSelectionEvent;
private JCheckBox autoScrollCB;
private HashSet buffer;
private boolean dataChanged;
@Override
public String getLabelResource() {
return VIEW_RESULT_TREE_HTTP2_TITLE;
}
@Override
public String getStaticLabel() {
return VIEW_RESULT_TREE_HTTP2_TITLE;
}
public ViewResultsFullVisualizer() {
collector = new ResultCollector();
buffer = new LinkedHashSet();
init();
new Timer(REFRESH_PERIOD, e -> updateGui()).start();
}
private void updateGui() {
TreePath selectedPath = null;
Object oldSelectedElement;
Set oldExpandedElements;
Set newExpandedPaths = new HashSet<>();
synchronized (buffer) {
if (!dataChanged) {
return;
}
final Enumeration expandedElements = jTree
.getExpandedDescendants(new TreePath(root));
oldExpandedElements = extractExpandedObjects(expandedElements);
oldSelectedElement = getSelectedObject();
root.removeAllChildren();
for (Object sampler : buffer) {
SampleResult res = (SampleResult) sampler;
// Add sample
DefaultMutableTreeNode currNode = new SearchableTreeNode(res, treeModel);
treeModel.insertNodeInto(currNode, root, root.getChildCount());
List path = new ArrayList<>(Arrays.asList(root, currNode));
selectedPath = checkExpandedOrSelected(path,
res, oldSelectedElement,
oldExpandedElements, newExpandedPaths, selectedPath);
TreePath potentialSelection = addSubResults(currNode, res, path, oldSelectedElement,
oldExpandedElements, newExpandedPaths);
if (potentialSelection != null) {
selectedPath = potentialSelection;
}
// Add any assertion that failed as children of the sample node
AssertionResult[] assertionResults = res.getAssertionResults();
int assertionIndex = currNode.getChildCount();
for (AssertionResult assertionResult : assertionResults) {
if (assertionResult.isFailure() || assertionResult.isError()) {
DefaultMutableTreeNode assertionNode = new SearchableTreeNode(assertionResult,
treeModel);
treeModel.insertNodeInto(assertionNode, currNode, assertionIndex++);
selectedPath = checkExpandedOrSelected(path,
assertionResult, oldSelectedElement,
oldExpandedElements, newExpandedPaths, selectedPath,
assertionNode);
}
}
}
treeModel.nodeStructureChanged(root);
dataChanged = false;
}
if (root.getChildCount() == 1) {
jTree.expandPath(new TreePath(root));
}
newExpandedPaths.stream().forEach(jTree::expandPath);
if (selectedPath != null) {
jTree.setSelectionPath(selectedPath);
}
if (autoScrollCB.isSelected() && root.getChildCount() > 1) {
jTree.scrollPathToVisible(new TreePath(new Object[]{root,
treeModel.getChild(root, root.getChildCount() - 1)}));
}
}
@Override
public void actionPerformed(ActionEvent e) {
String command = e.getActionCommand();
if (COMBO_CHANGE_COMMAND.equals(command)) {
JComboBox> jcb = (JComboBox>) e.getSource();
if (jcb != null) {
resultsRender = (ResultRenderer) jcb.getSelectedItem();
if (rightSide != null) {
// to restore last selected tab (better user-friendly)
selectedTab = rightSide.getSelectedIndex();
// Remove old right side
mainSplit.remove(rightSide);
// create and add a new right side
rightSide = new JTabbedPane();
mainSplit.add(rightSide);
resultsRender.setRightSide(rightSide);
resultsRender.setLastSelectedTab(selectedTab);
LOG.debug("selectedTab={}", selectedTab);
resultsRender.init();
// To display current sampler result before change
this.valueChanged(lastSelectionEvent, true);
}
}
}
}
@Override
public void itemStateChanged(ItemEvent e) {
//no action
}
@Override
public void valueChanged(TreeSelectionEvent e) {
valueChanged(e, false);
}
private void valueChanged(TreeSelectionEvent e, boolean forceRendering) {
lastSelectionEvent = e;
DefaultMutableTreeNode node;
synchronized (this) {
node = (DefaultMutableTreeNode) jTree.getLastSelectedPathComponent();
}
if (node != null && (forceRendering || node.getUserObject() != resultsObject)) {
resultsObject = node.getUserObject();
// to restore last tab used
if (rightSide.getTabCount() > selectedTab) {
resultsRender.setLastSelectedTab(rightSide.getSelectedIndex());
}
Object userObject = node.getUserObject();
resultsRender.setSamplerResult(userObject);
resultsRender.setupTabPane(); // Processes Assertions
// display a SampleResult
if (userObject instanceof SampleResult) {
SampleResult sampleResult = (SampleResult) userObject;
if (isTextDataType(sampleResult)) {
resultsRender.renderResult(sampleResult);
} else {
byte[] responseBytes = sampleResult.getResponseData();
if (responseBytes != null) {
resultsRender.renderImage(sampleResult);
}
}
}
}
}
private static boolean isTextDataType(SampleResult sampleResult) {
return (SampleResult.TEXT).equals(sampleResult.getDataType())
|| StringUtils.isEmpty(sampleResult.getDataType());
}
@Override
public void clearData() {
synchronized (buffer) {
buffer.clear();
dataChanged = true;
}
resultsRender.clearData();
resultsObject = null;
}
@Override
public void add(SampleResult sampleResult) {
synchronized (buffer) {
buffer.add(sampleResult);
dataChanged = true;
}
}
/**
* Initialize this visualizer
*/
private void init() { // WARNING: called from ctor so must not be overridden (i.e. must be private or final)
LOG.debug("init() - pass");
setLayout(new BorderLayout(0, 5));
setBorder(makeBorder());
leftSide = createLeftPanel();
// Prepare the common tab
rightSide = new JTabbedPane();
// Create the split pane
mainSplit = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, leftSide, rightSide);
mainSplit.setOneTouchExpandable(true);
JSplitPane searchAndMainSP = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
new SearchTreePanel(root), mainSplit);
searchAndMainSP.setOneTouchExpandable(true);
JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, makeTitlePanel(),
searchAndMainSP);
splitPane.setOneTouchExpandable(true);
add(splitPane);
// init right side with first render
resultsRender.setRightSide(rightSide);
resultsRender.init();
}
private synchronized Component createLeftPanel() {
SampleResult rootSampleResult = new SampleResult();
rootSampleResult.setSampleLabel("Root");
rootSampleResult.setSuccessful(true);
root = new SearchableTreeNode(rootSampleResult, null);
treeModel = new DefaultTreeModel(root);
jTree = new JTree(treeModel);
jTree.setCellRenderer(new ResultsNodeRenderer());
jTree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
jTree.addTreeSelectionListener(this);
jTree.setRootVisible(false);
jTree.setShowsRootHandles(true);
JScrollPane treePane = new JScrollPane(jTree);
treePane.setPreferredSize(new Dimension(200, 300));
VerticalPanel leftPane = new VerticalPanel();
leftPane.add(treePane, BorderLayout.CENTER);
leftPane.add(createComboRender(), BorderLayout.NORTH);
autoScrollCB = new JCheckBox(
JMeterUtils.getResString("view_results_autoscroll"));
autoScrollCB.setSelected(false);
autoScrollCB.addItemListener(this);
leftPane.add(autoScrollCB, BorderLayout.SOUTH);
return leftPane;
}
private static class ResultsNodeRenderer extends DefaultTreeCellRenderer {
private static final long serialVersionUID = 4159626601097711565L;
@Override
public Component getTreeCellRendererComponent(JTree tree, Object value,
boolean sel, boolean expanded, boolean leaf, int row, boolean focus) {
super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, focus);
boolean failure = true;
boolean pending = false;
Object userObject = ((DefaultMutableTreeNode) value).getUserObject();
if (userObject instanceof SampleResult) {
failure = !(((SampleResult) userObject).isSuccessful());
if (userObject instanceof HTTP2SampleResult) {
pending = ((HTTP2SampleResult) userObject).isPendingResponse();
}
} else if (userObject instanceof AssertionResult) {
AssertionResult assertion = (AssertionResult) userObject;
failure = assertion.isError() || assertion.isFailure();
}
// Set the status for the node
if (failure && !pending) {
this.setForeground(Color.red);
this.setIcon(imageFailure);
} else if (pending) {
this.setIcon(imagePending);
this.setForeground(Color.blue);
} else {
this.setIcon(imageSuccess);
}
// Handle search related rendering
SearchableTreeNode node = (SearchableTreeNode) value;
if (node.isNodeHasMatched()) {
setBorder(RED_BORDER);
} else if (node.isChildrenNodesHaveMatched()) {
setBorder(BLUE_BORDER);
} else {
setBorder(null);
}
return this;
}
}
private Component createComboRender() {
ComboBoxModel nodesModel = new DefaultComboBoxModel<>();
// drop-down list for renderer
selectRenderPanel = new JComboBox<>(nodesModel);
selectRenderPanel.setActionCommand(COMBO_CHANGE_COMMAND);
selectRenderPanel.addActionListener(this);
// if no results render in jmeter.properties, load Standard (default)
List classesToAdd = Collections.emptyList();
try {
classesToAdd = JMeterUtils.findClassesThatExtend(ResultRenderer.class);
} catch (IOException e1) {
// ignored
}
String textRenderer = JMeterUtils.getResString("view_results_render_text");
Object textObject = null;
Map map = new HashMap<>(classesToAdd.size());
for (String clazz : classesToAdd) {
try {
// Instantiate render classes
final ResultRenderer renderer = (ResultRenderer) Class.forName(clazz).newInstance();
if (textRenderer.equals(renderer.toString())) {
textObject = renderer;
}
renderer.setBackgroundColor(getBackground());
map.put(renderer.getClass().getName(), renderer);
} catch (Exception | NoClassDefFoundError e) { // NOSONAR See bug 60583
LOG.warn("Error loading result renderer: {}", clazz, e);
}
}
if (VIEWERS_ORDER.length() > 0) {
Arrays.stream(VIEWERS_ORDER.split(","))
.map(key -> key.startsWith(".")
? "org.apache.jmeter.visualizers" + key
: key)
.forEach(key -> {
ResultRenderer renderer = map.remove(key);
if (renderer != null) {
selectRenderPanel.addItem(renderer);
} else {
LOG.warn(
"Missing (check renderer name) or already added (check doublon) result renderer,"
+
" check property 'view.results.tree.renderers_order', renderer name: '{}'",
key);
}
});
}
// Add remaining (plugins or missed in property)
map.values().forEach(renderer -> selectRenderPanel.addItem(renderer));
nodesModel.setSelectedItem(textObject); // preset to "Text" option
return selectRenderPanel;
}
private Set extractExpandedObjects(final Enumeration expandedElements) {
if (expandedElements != null) {
@SuppressWarnings("unchecked") final List list = EnumerationUtils
.toList(expandedElements);
LOG.debug("Expanded: {}", list);
Set result = list.stream()
.map(TreePath::getLastPathComponent)
.map(c -> (DefaultMutableTreeNode) c)
.map(DefaultMutableTreeNode::getUserObject)
.collect(Collectors.toSet());
LOG.debug("Elements: {}", result);
return result;
}
return Collections.emptySet();
}
private TreePath addSubResults(DefaultMutableTreeNode currNode,
SampleResult res, List path, Object selectedObject,
Set oldExpandedObjects, Set newExpandedPaths) {
SampleResult[] subResults = res.getSubResults();
int leafIndex = 0;
TreePath result = null;
for (SampleResult child : subResults) {
LOG.debug("updateGui1 : child sample result - {}", child);
DefaultMutableTreeNode leafNode = new SearchableTreeNode(child, treeModel);
treeModel.insertNodeInto(leafNode, currNode, leafIndex++);
List newPath = new ArrayList<>(path);
newPath.add(leafNode);
result = checkExpandedOrSelected(newPath, child, selectedObject, oldExpandedObjects,
newExpandedPaths, result);
addSubResults(leafNode, child, newPath, selectedObject, oldExpandedObjects, newExpandedPaths);
// Add any assertion that failed as children of the sample node
AssertionResult[] assertionResults = child.getAssertionResults();
int assertionIndex = leafNode.getChildCount();
for (AssertionResult item : assertionResults) {
if (item.isFailure() || item.isError()) {
DefaultMutableTreeNode assertionNode = new SearchableTreeNode(item, treeModel);
treeModel.insertNodeInto(assertionNode, leafNode, assertionIndex++);
result = checkExpandedOrSelected(path, item,
selectedObject, oldExpandedObjects, newExpandedPaths, result,
assertionNode);
}
}
}
return result;
}
private Object getSelectedObject() {
Object oldSelectedElement;
DefaultMutableTreeNode oldSelectedNode = (DefaultMutableTreeNode) jTree
.getLastSelectedPathComponent();
oldSelectedElement = oldSelectedNode == null ? null : oldSelectedNode.getUserObject();
return oldSelectedElement;
}
private TreePath checkExpandedOrSelected(List path,
Object item, Object oldSelectedObject,
Set oldExpandedObjects, Set newExpandedPaths,
TreePath defaultPath) {
TreePath result = defaultPath;
if (oldSelectedObject == item) {
result = toTreePath(path);
}
if (oldExpandedObjects.contains(item)) {
newExpandedPaths.add(toTreePath(path));
}
return result;
}
private TreePath checkExpandedOrSelected(List path,
Object item, Object oldSelectedObject,
Set oldExpandedObjects, Set newExpandedPaths,
TreePath defaultPath, DefaultMutableTreeNode extensionNode) {
TreePath result = defaultPath;
if (oldSelectedObject == item) {
result = toTreePath(path, extensionNode);
}
if (oldExpandedObjects.contains(item)) {
newExpandedPaths.add(toTreePath(path, extensionNode));
}
return result;
}
private TreePath toTreePath(List newPath) {
return new TreePath(newPath.toArray(new TreeNode[newPath.size()]));
}
private TreePath toTreePath(List path,
DefaultMutableTreeNode extensionNode) {
TreeNode[] result = path.toArray(new TreeNode[path.size() + 1]);
result[result.length - 1] = extensionNode;
return new TreePath(result);
}
}