1 18 19 package org.apache.jmeter.visualizers; 20 21 import java.awt.BorderLayout ; 22 import java.awt.Color ; 23 import java.awt.Component ; 24 import java.awt.Dimension ; 25 import java.awt.event.ActionEvent ; 26 import java.awt.event.ActionListener ; 27 import java.io.UnsupportedEncodingException ; 28 29 import javax.swing.BorderFactory ; 30 import javax.swing.ButtonGroup ; 31 import javax.swing.Icon ; 32 import javax.swing.ImageIcon ; 33 import javax.swing.JCheckBox ; 34 import javax.swing.JEditorPane ; 35 import javax.swing.JLabel ; 36 import javax.swing.JPanel ; 37 import javax.swing.JRadioButton ; 38 import javax.swing.JScrollPane ; 39 import javax.swing.JSplitPane ; 40 import javax.swing.JTabbedPane ; 41 import javax.swing.JTextArea ; 42 import javax.swing.JTextPane ; 43 import javax.swing.JTree ; 44 import javax.swing.event.TreeSelectionEvent ; 45 import javax.swing.event.TreeSelectionListener ; 46 import javax.swing.text.BadLocationException ; 47 import javax.swing.text.ComponentView ; 48 import javax.swing.text.Document ; 49 import javax.swing.text.EditorKit ; 50 import javax.swing.text.Element ; 51 import javax.swing.text.Style ; 52 import javax.swing.text.StyleConstants ; 53 import javax.swing.text.StyledDocument ; 54 import javax.swing.text.View ; 55 import javax.swing.text.ViewFactory ; 56 import javax.swing.text.html.HTML ; 57 import javax.swing.text.html.HTMLEditorKit ; 58 import javax.swing.tree.DefaultMutableTreeNode ; 59 import javax.swing.tree.DefaultTreeCellRenderer ; 60 import javax.swing.tree.DefaultTreeModel ; 61 import javax.swing.tree.TreeSelectionModel ; 62 63 import org.apache.jmeter.samplers.Clearable; 64 import org.apache.jmeter.samplers.SampleResult; 65 import org.apache.jmeter.util.JMeterUtils; 66 import org.apache.jmeter.visualizers.gui.AbstractVisualizer; 67 import org.apache.jorphan.logging.LoggingManager; 68 import org.apache.log.Logger; 69 70 78 public class ViewResultsFullVisualizer 79 extends AbstractVisualizer 80 implements ActionListener , TreeSelectionListener , Clearable 81 { 82 transient private static Logger log = LoggingManager.getLoggerForClass(); 83 84 public final static Color SERVER_ERROR_COLOR = Color.red; 85 public final static Color CLIENT_ERROR_COLOR = Color.blue; 86 public final static Color REDIRECT_COLOR = Color.green; 87 88 private static final String DOWNLOAD_LABEL = "Download embedded resources"; 89 private static final String HTML_BUTTON_LABEL = "Render HTML"; 90 private static final String TEXT_BUTTON_LABEL = "Show Text"; 91 92 private static final String TEXT_HTML = "text/html"; private static final String HTML_COMMAND = "html"; private static final String TEXT_COMMAND = "text"; private boolean textMode = true; 96 97 private static EditorKit customisedEditor = new LocalHTMLEditorKit(); 99 private static EditorKit defaultHtmlEditor = 100 JEditorPane.createEditorKitForContentType(TEXT_HTML); 101 102 private DefaultMutableTreeNode root; 103 private DefaultTreeModel treeModel; 104 105 private JTextPane stats; 106 private JEditorPane results; 107 private JScrollPane resultsScrollPane; 108 private JLabel imageLabel; 109 private JTextArea sampleDataField; 110 111 private JRadioButton textButton; 112 private JRadioButton htmlButton; 113 private JCheckBox downloadAll; 114 115 private JTree jTree; 116 117 public ViewResultsFullVisualizer() 118 { 119 super(); 120 log.debug("Start : ViewResultsFullVisualizer1"); 121 init(); 122 log.debug("End : ViewResultsFullVisualizer1"); 123 } 124 125 public void add(SampleResult res) 126 { 127 updateGui(res); 128 } 129 130 public String getLabelResource() 131 { 132 return "view_results_tree_title"; 133 } 134 135 138 public synchronized void updateGui(SampleResult res) 139 { 140 log.debug("Start : updateGui1"); 141 if (log.isDebugEnabled()) 142 { 143 log.debug("updateGui1 : sample result - " + res); 144 } 145 DefaultMutableTreeNode currNode = new DefaultMutableTreeNode (res); 146 147 treeModel.insertNodeInto(currNode, root, root.getChildCount()); 148 addSubResults(currNode, res); 149 log.debug("End : updateGui1"); 150 } 151 152 private void addSubResults( 153 DefaultMutableTreeNode currNode, 154 SampleResult res) 155 { 156 SampleResult[] subResults = res.getSubResults(); 157 158 int leafIndex = 0; 159 160 for (int i = 0; i < subResults.length; i++) 161 { 162 SampleResult child = subResults[i]; 163 164 if (log.isDebugEnabled()) 165 { 166 log.debug("updateGui1 : child sample result - " + child); 167 } 168 DefaultMutableTreeNode leafNode = 169 new DefaultMutableTreeNode (child); 170 171 treeModel.insertNodeInto(leafNode, currNode, leafIndex++); 172 addSubResults(leafNode, child); 173 } 174 } 175 176 179 public void clear() 180 { 181 log.debug("Start : clear1"); 182 int totalChild = root.getChildCount(); 183 184 if (log.isDebugEnabled()) 185 { 186 log.debug("clear1 : total child - " + totalChild); 187 } 188 for (int i = 0; i < totalChild; i++) 189 { 190 treeModel.removeNodeFromParent( 193 (DefaultMutableTreeNode ) root.getChildAt(0)); 194 } 195 196 results.setText(""); sampleDataField.setText(""); log.debug("End : clear1"); 199 } 200 201 206 public String toString() 207 { 208 String desc = "Shows the text results of sampling in tree form"; 209 210 if (log.isDebugEnabled()) 211 { 212 log.debug("toString1 : Returning description - " + desc); 213 } 214 return desc; 215 } 216 217 220 public void valueChanged(TreeSelectionEvent e) 221 { 222 log.debug("Start : valueChanged1"); 223 DefaultMutableTreeNode node = 224 (DefaultMutableTreeNode ) jTree.getLastSelectedPathComponent(); 225 226 if (log.isDebugEnabled()) 227 { 228 log.debug("valueChanged : selected node - " + node); 229 } 230 231 StyledDocument statsDoc = stats.getStyledDocument(); 232 try 233 { 234 statsDoc.remove(0, statsDoc.getLength()); 235 sampleDataField.setText(""); 236 results.setText(""); 237 if (node != null) 238 { 239 SampleResult res = (SampleResult) node.getUserObject(); 240 241 if (log.isDebugEnabled()) 242 { 243 log.debug("valueChanged1 : sample result - " + res); 244 } 245 246 if (res != null) 247 { 248 250 log.debug("valueChanged1 : load time - " + res.getTime()); 251 if (res != null && res.getSamplerData() != null) 252 { 253 String sd; 254 String rh = res.getRequestHeaders(); 255 if (rh==null) 256 { 257 sd=res.getSamplerData().trim(); 258 } else { 259 sd=res.getSamplerData().trim() 260 +"\n"+rh; 261 } 262 sampleDataField.setText(sd); 263 } 264 265 statsDoc.insertString( 266 statsDoc.getLength(), 267 "Load time: " + res.getTime() + "\n", 268 null); 269 270 String responseCode = res.getResponseCode(); 271 log.debug( 272 "valueChanged1 : response code - " + responseCode); 273 274 int responseLevel = 0; 275 if (responseCode != null) 276 { 277 try 278 { 279 responseLevel = 280 Integer.parseInt(responseCode) / 100; 281 } 282 catch (NumberFormatException numberFormatException) 283 { 284 } 286 } 287 288 Style style = null; 289 switch (responseLevel) 290 { 291 case 3 : 292 style = statsDoc.getStyle("Redirect"); 293 break; 294 case 4 : 295 style = statsDoc.getStyle("ClientError"); 296 break; 297 case 5 : 298 style = statsDoc.getStyle("ServerError"); 299 break; 300 } 301 statsDoc.insertString( 302 statsDoc.getLength(), 303 "HTTP response code: " + responseCode + "\n", 304 style); 305 306 String responseMsgStr = res.getResponseMessage(); 308 309 log.debug( 310 "valueChanged1 : response message - " + responseMsgStr); 311 statsDoc.insertString( 312 statsDoc.getLength(), 313 "HTTP response message: " + responseMsgStr + "\n", 314 null); 315 316 statsDoc.insertString( 317 statsDoc.getLength(), 318 "\nHTTP response headers:\n" + res.getResponseHeaders() + "\n", 319 null); 320 321 if ((SampleResult.TEXT).equals(res.getDataType())) { 325 String response = getResponseAsString(res); 326 if (textMode) 327 { 328 showTextResponse(response); 329 } 330 else 331 { 332 showRenderedResponse(response,res); 333 } 334 } 335 else 336 { 337 byte[] responseBytes = res.getResponseData(); 338 if (responseBytes != null) 339 { 340 showImage(new ImageIcon (responseBytes)); 341 } 342 } 343 } 344 } 345 } 346 catch (BadLocationException exc) 347 { 348 log.error("Error setting statistics text", exc); 349 stats.setText(""); 350 } 351 log.debug("End : valueChanged1"); 352 } 353 354 private void showImage(Icon image) 355 { 356 imageLabel.setIcon(image); 357 resultsScrollPane.setViewportView(imageLabel); 358 textButton.setEnabled(false); 359 htmlButton.setEnabled(false); 360 } 361 362 protected void showTextResponse(String response) 363 { 364 results.setContentType("text/plain"); 365 results.setText(response == null ? "" : response); 366 results.setCaretPosition(0); 367 resultsScrollPane.setViewportView(results); 368 369 textButton.setEnabled(true); 370 htmlButton.setEnabled(true); 371 } 372 373 private static String getResponseAsString(SampleResult res) 374 { 375 376 byte[] responseBytes = res.getResponseData(); 377 String response = null; 378 if ((SampleResult.TEXT).equals(res.getDataType())) 379 { 380 try 381 { 382 if (responseBytes.length > 200*1024) 387 { 388 response= 389 ("Response too large to be displayed ("+responseBytes.length+" bytes)."); 390 log.warn("Response too large to display."); 391 } 392 else 393 { 394 response = 395 new String (responseBytes,res.getDataEncoding()); 396 } 397 } 398 catch (UnsupportedEncodingException err) 399 { 400 log.warn("Could not decode response "+err); 401 response = new String (responseBytes); } 403 } 404 return response; 405 } 406 407 413 public void actionPerformed(ActionEvent e) 414 { 415 String command = e.getActionCommand(); 416 417 if (command != null 418 && ( 419 command.equals(TEXT_COMMAND) 420 || 421 command.equals(HTML_COMMAND) 422 ) 423 ) 424 { 425 426 textMode = command.equals(TEXT_COMMAND); 427 428 DefaultMutableTreeNode node = 429 (DefaultMutableTreeNode ) jTree.getLastSelectedPathComponent(); 430 431 if (node == null) 432 { 433 results.setText(""); 434 return; 435 } 436 437 SampleResult res = (SampleResult) node.getUserObject(); 438 String response = getResponseAsString(res); 439 if (textMode) 440 { 441 showTextResponse(response); 442 } 443 else 444 { 445 showRenderedResponse(response,res); 446 } 447 } 448 } 449 450 protected void showRenderedResponse(String response, SampleResult res) 451 { 452 if (response == null) 453 { 454 results.setText(""); 455 return; 456 } 457 458 int htmlIndex = response.indexOf("<HTML"); 460 if (htmlIndex < 0) 462 { 463 htmlIndex = response.indexOf("<html"); } 465 466 if (htmlIndex < 0) 468 { 469 htmlIndex = 0; 470 } 471 472 String html = response.substring(htmlIndex); 473 474 478 479 results.setEditorKitForContentType(TEXT_HTML, 481 downloadAll.isSelected() ? defaultHtmlEditor : customisedEditor); 482 483 results.setContentType(TEXT_HTML); 484 485 if (downloadAll.isSelected()) 486 { 487 results.getDocument().putProperty(Document.StreamDescriptionProperty,res.getURL()); 490 } 491 492 498 results.getDocument().putProperty("IgnoreCharsetDirective", Boolean.TRUE); 499 500 results.setText(html); 501 results.setCaretPosition(0); 502 resultsScrollPane.setViewportView(results); 503 504 textButton.setEnabled(true); 505 htmlButton.setEnabled(true); 506 } 507 508 protected Component createHtmlOrTextPane() 509 { 510 ButtonGroup group = new ButtonGroup (); 511 512 textButton = new JRadioButton (TEXT_BUTTON_LABEL); 513 textButton.setActionCommand(TEXT_COMMAND); 514 textButton.addActionListener(this); 515 textButton.setSelected(textMode); 516 group.add(textButton); 517 518 htmlButton = new JRadioButton (HTML_BUTTON_LABEL); 519 htmlButton.setActionCommand(HTML_COMMAND); 520 htmlButton.addActionListener(this); 521 htmlButton.setSelected(!textMode); 522 group.add(htmlButton); 523 524 downloadAll = new JCheckBox (DOWNLOAD_LABEL); 525 526 JPanel pane = new JPanel (); 527 pane.add(textButton); 528 pane.add(htmlButton); 529 pane.add(downloadAll); 530 return pane; 531 } 532 533 536 protected void init() 537 { 538 setLayout(new BorderLayout (0, 5)); 539 setBorder(makeBorder()); 540 541 add(makeTitlePanel(), BorderLayout.NORTH); 542 543 Component leftSide = createLeftPanel(); 544 JTabbedPane rightSide= new JTabbedPane (); 545 546 rightSide.addTab(JMeterUtils.getResString("view_results_tab_sampler"), createResponseMetadataPanel()); 547 rightSide.addTab(JMeterUtils.getResString("view_results_tab_request"), createRequestPanel()); 548 rightSide.addTab(JMeterUtils.getResString("view_results_tab_response"), createResponseDataPanel()); 549 550 JSplitPane mainSplit = 551 new JSplitPane (JSplitPane.HORIZONTAL_SPLIT, leftSide, rightSide); 552 add(mainSplit, BorderLayout.CENTER); 553 } 554 555 private Component createLeftPanel() 556 { 557 SampleResult rootSampleResult = new SampleResult(); 558 rootSampleResult.setSampleLabel("Root"); 559 rootSampleResult.setSuccessful(true); 560 root = new DefaultMutableTreeNode (rootSampleResult); 561 562 treeModel = new DefaultTreeModel (root); 563 jTree = new JTree (treeModel); 564 jTree.setCellRenderer(new ResultsNodeRenderer()); 565 jTree.getSelectionModel().setSelectionMode( 566 TreeSelectionModel.SINGLE_TREE_SELECTION); 567 jTree.addTreeSelectionListener(this); 568 jTree.setShowsRootHandles(true); 569 570 JScrollPane treePane = new JScrollPane (jTree); 571 treePane.setPreferredSize(new Dimension (200, 300)); 572 return treePane; 573 } 574 575 private Component createResponseMetadataPanel() 576 { 577 stats = new JTextPane (); 578 stats.setEditable(false); 579 stats.setBackground(getBackground()); 580 581 StyledDocument doc = (StyledDocument ) stats.getDocument(); 583 584 Style style = doc.addStyle("Redirect", null); 585 StyleConstants.setForeground(style, REDIRECT_COLOR); 586 587 style = doc.addStyle("ClientError", null); 588 StyleConstants.setForeground(style, CLIENT_ERROR_COLOR); 589 590 style = doc.addStyle("ServerError", null); 591 StyleConstants.setForeground(style, SERVER_ERROR_COLOR); 592 593 JScrollPane pane = makeScrollPane(stats); 594 pane.setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2)); 595 return pane; 596 } 597 598 private Component createRequestPanel() 599 { 600 sampleDataField = new JTextArea (); 601 sampleDataField.setEditable(false); 602 sampleDataField.setLineWrap(true); 603 sampleDataField.setWrapStyleWord(true); 604 605 JPanel pane = new JPanel (new BorderLayout (0, 5)); 606 pane.add(makeScrollPane(sampleDataField)); 607 return pane; 608 } 609 610 private Component createResponseDataPanel() 611 { 612 results = new JEditorPane (); 613 results.setEditable(false); 614 615 resultsScrollPane = makeScrollPane(results); 616 imageLabel = new JLabel (); 617 618 JPanel resultsPane = new JPanel (new BorderLayout ()); 619 resultsPane.add(resultsScrollPane, BorderLayout.CENTER); 620 resultsPane.add(createHtmlOrTextPane(), BorderLayout.SOUTH); 621 622 return resultsPane; 623 } 624 625 private class ResultsNodeRenderer extends DefaultTreeCellRenderer 626 { 627 public Component getTreeCellRendererComponent( 628 JTree tree, 629 Object value, 630 boolean sel, 631 boolean expanded, 632 boolean leaf, 633 int row, 634 boolean hasFocus) 635 { 636 super.getTreeCellRendererComponent( 637 tree, 638 value, 639 sel, 640 expanded, 641 leaf, 642 row, 643 hasFocus); 644 if (!((SampleResult) ((DefaultMutableTreeNode ) value) 645 .getUserObject()) 646 .isSuccessful()) 647 { 648 this.setForeground(Color.red); 649 } 650 return this; 651 } 652 } 653 654 private static class LocalHTMLEditorKit extends HTMLEditorKit { 655 656 private static final ViewFactory defaultFactory = new LocalHTMLFactory(); 657 658 public ViewFactory getViewFactory() { 659 return defaultFactory; 660 } 661 662 private static class LocalHTMLFactory 663 extends javax.swing.text.html.HTMLEditorKit.HTMLFactory 664 { 665 672 public View create(Element elem) 673 { 674 Object o = elem.getAttributes().getAttribute(StyleConstants.NameAttribute); 675 if (o instanceof HTML.Tag ) 676 { 677 HTML.Tag kind = (HTML.Tag ) o; 678 if (kind == HTML.Tag.FRAME) 679 { 680 return new ComponentView (elem); 681 } 682 else if (kind==HTML.Tag.IMG) 683 { 684 return new ComponentView (elem); 685 } 686 } 687 return super.create(elem); 688 } 689 } 690 } 691 } 692 | Popular Tags |