| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or |
| * implied. |
| * |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package org.apache.jmeter.visualizers; |
| |
| import java.awt.Component; |
| import java.awt.GridLayout; |
| import java.io.ByteArrayInputStream; |
| import java.io.StringWriter; |
| |
| import javax.swing.JOptionPane; |
| import javax.swing.JPanel; |
| import javax.swing.JScrollPane; |
| import javax.swing.JTree; |
| import javax.swing.ToolTipManager; |
| import javax.swing.tree.DefaultMutableTreeNode; |
| import javax.swing.tree.DefaultTreeCellRenderer; |
| import javax.swing.tree.TreeSelectionModel; |
| |
| import org.apache.jmeter.samplers.SampleResult; |
| import org.apache.jmeter.util.JMeterUtils; |
| import org.apache.jmeter.util.XPathUtil; |
| import org.apache.jorphan.logging.LoggingManager; |
| import org.apache.jorphan.util.JOrphanUtils; |
| import org.apache.log.Logger; |
| import org.w3c.dom.Node; |
| import org.w3c.dom.NodeList; |
| import org.w3c.tidy.Tidy; |
| import org.xml.sax.SAXException; |
| |
| public class RenderAsXML extends SamplerResultTab |
| implements ResultRenderer { |
| |
| private static final Logger log = LoggingManager.getLoggerForClass(); |
| |
| private static final byte[] XML_PFX = {'<','?','x','m','l',' '};//"<?xml " |
| |
| public RenderAsXML(){ |
| activateSearchExtension = false; // TODO work out how to search the XML pane |
| } |
| |
| /** {@inheritDoc} */ |
| @Override |
| public void renderResult(SampleResult sampleResult) { |
| showRenderXMLResponse(sampleResult); |
| } |
| |
| private void showRenderXMLResponse(SampleResult res) { |
| results.setContentType("text/xml"); // $NON-NLS-1$ |
| results.setCaretPosition(0); |
| byte[] source = res.getResponseData(); |
| final ByteArrayInputStream baIS = new ByteArrayInputStream(source); |
| for(int i=0; i<source.length-XML_PFX.length; i++){ |
| if (JOrphanUtils.startsWith(source, XML_PFX, i)){ |
| baIS.skip(i);// Skip the leading bytes (if any) |
| break; |
| } |
| } |
| |
| // there is also a javax.swing.text.Document class. |
| org.w3c.dom.Document document = null; |
| |
| StringWriter sw = new StringWriter(); |
| Tidy tidy = XPathUtil.makeTidyParser(true, true, true, sw); |
| document = tidy.parseDOM(baIS, null); |
| document.normalize(); |
| if (tidy.getParseErrors() > 0) { |
| showErrorMessageDialog(sw.toString(), |
| "Tidy: " + tidy.getParseErrors() + " errors, " + tidy.getParseWarnings() + " warnings", |
| JOptionPane.WARNING_MESSAGE); |
| } |
| |
| JPanel domTreePanel = new DOMTreePanel(document); |
| resultsScrollPane.setViewportView(domTreePanel); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.apache.jmeter.visualizers.SamplerResultTab#clearData() |
| */ |
| @Override |
| public void clearData() { |
| super.clearData(); |
| resultsScrollPane.setViewportView(null); // clear result tab on Ctrl-E |
| } |
| |
| /* |
| * |
| * A Dom tree panel for to display response as tree view author <a |
| * href="mailto:d.maung@mdl.com">Dave Maung</a> |
| * TODO implement to find any nodes in the tree using TreePath. |
| * |
| */ |
| private static class DOMTreePanel extends JPanel { |
| |
| private static final long serialVersionUID = 6871690021183779153L; |
| |
| private JTree domJTree; |
| |
| public DOMTreePanel(org.w3c.dom.Document document) { |
| super(new GridLayout(1, 0)); |
| try { |
| Node firstElement = getFirstElement(document); |
| DefaultMutableTreeNode top = new XMLDefaultMutableTreeNode(firstElement); |
| domJTree = new JTree(top); |
| |
| domJTree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION); |
| domJTree.setShowsRootHandles(true); |
| JScrollPane domJScrollPane = new JScrollPane(domJTree); |
| domJTree.setAutoscrolls(true); |
| this.add(domJScrollPane); |
| ToolTipManager.sharedInstance().registerComponent(domJTree); |
| domJTree.setCellRenderer(new DomTreeRenderer()); |
| } catch (SAXException e) { |
| log.warn("Error trying to parse document", e); |
| } |
| |
| } |
| |
| /** |
| * Skip all DTD nodes, all prolog nodes. They are not supported in tree view |
| * We let user insert them however in DOMTreeView, we don't display them. |
| * |
| * @param parent {@link Node} |
| * @return |
| */ |
| private Node getFirstElement(Node parent) { |
| NodeList childNodes = parent.getChildNodes(); |
| Node toReturn = parent; // Must return a valid node, or may generate an NPE |
| for (int i = 0; i < childNodes.getLength(); i++) { |
| Node childNode = childNodes.item(i); |
| toReturn = childNode; |
| if (childNode.getNodeType() == Node.ELEMENT_NODE){ |
| break; |
| } |
| |
| } |
| return toReturn; |
| } |
| |
| /** |
| * This class is to view as tooltext. This is very useful, when the |
| * contents has long string and does not fit in the view. it will also |
| * automatically wrap line for each 100 characters since tool tip |
| * support html. author <a href="mailto:d.maung@mdl.com">Dave Maung</a> |
| */ |
| private static class DomTreeRenderer extends DefaultTreeCellRenderer { |
| |
| private static final long serialVersionUID = 240210061375790195L; |
| |
| @Override |
| public Component getTreeCellRendererComponent(JTree tree, Object value, boolean sel, boolean expanded, |
| boolean leaf, int row, boolean phasFocus) { |
| super.getTreeCellRendererComponent(tree, value, sel, expanded, leaf, row, phasFocus); |
| |
| DefaultMutableTreeNode valueTreeNode = (DefaultMutableTreeNode) value; |
| setToolTipText(getHTML(valueTreeNode.toString(), "<br>", 100)); // $NON-NLS-1$ |
| return this; |
| } |
| |
| /** |
| * get the html |
| * |
| * @param str |
| * @param separator |
| * @param maxChar |
| * @return |
| */ |
| private String getHTML(String str, String separator, int maxChar) { |
| StringBuilder strBuf = new StringBuilder("<html><body bgcolor=\"yellow\"><b>"); // $NON-NLS-1$ |
| char[] chars = str.toCharArray(); |
| for (int i = 0; i < chars.length; i++) { |
| |
| if (i % maxChar == 0 && i != 0) { |
| strBuf.append(separator); |
| } |
| strBuf.append(encode(chars[i])); |
| |
| } |
| strBuf.append("</b></body></html>"); // $NON-NLS-1$ |
| return strBuf.toString(); |
| |
| } |
| |
| private String encode(char c) { |
| String toReturn = String.valueOf(c); |
| switch (c) { |
| case '<': // $NON-NLS-1$ |
| toReturn = "<"; // $NON-NLS-1$ |
| break; |
| case '>': // $NON-NLS-1$ |
| toReturn = ">"; // $NON-NLS-1$ |
| break; |
| case '\'': // $NON-NLS-1$ |
| toReturn = "'"; // $NON-NLS-1$ |
| break; |
| case '\"': // $NON-NLS-1$ |
| toReturn = """; // $NON-NLS-1$ |
| break; |
| default: |
| // ignored |
| break; |
| |
| } |
| return toReturn; |
| } |
| } |
| } |
| |
| private static void showErrorMessageDialog(String message, String title, int messageType) { |
| JOptionPane.showMessageDialog(null, message, title, messageType); |
| } |
| |
| /** {@inheritDoc} */ |
| @Override |
| public String toString() { |
| return JMeterUtils.getResString("view_results_render_xml"); // $NON-NLS-1$ |
| } |
| |
| } |