KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > jmeter > visualizers > ViewResultsFullVisualizer


1 // $Header: /home/cvs/jakarta-jmeter/src/components/org/apache/jmeter/visualizers/ViewResultsFullVisualizer.java,v 1.42.2.5 2005/01/05 01:05:29 sebb Exp $
2
/*
3  * Copyright 2001-2004 The Apache Software Foundation.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17 */

18
19 package org.apache.jmeter.visualizers;
20
21 import java.awt.BorderLayout JavaDoc;
22 import java.awt.Color JavaDoc;
23 import java.awt.Component JavaDoc;
24 import java.awt.Dimension JavaDoc;
25 import java.awt.event.ActionEvent JavaDoc;
26 import java.awt.event.ActionListener JavaDoc;
27 import java.io.UnsupportedEncodingException JavaDoc;
28
29 import javax.swing.BorderFactory JavaDoc;
30 import javax.swing.ButtonGroup JavaDoc;
31 import javax.swing.Icon JavaDoc;
32 import javax.swing.ImageIcon JavaDoc;
33 import javax.swing.JCheckBox JavaDoc;
34 import javax.swing.JEditorPane JavaDoc;
35 import javax.swing.JLabel JavaDoc;
36 import javax.swing.JPanel JavaDoc;
37 import javax.swing.JRadioButton JavaDoc;
38 import javax.swing.JScrollPane JavaDoc;
39 import javax.swing.JSplitPane JavaDoc;
40 import javax.swing.JTabbedPane JavaDoc;
41 import javax.swing.JTextArea JavaDoc;
42 import javax.swing.JTextPane JavaDoc;
43 import javax.swing.JTree JavaDoc;
44 import javax.swing.event.TreeSelectionEvent JavaDoc;
45 import javax.swing.event.TreeSelectionListener JavaDoc;
46 import javax.swing.text.BadLocationException JavaDoc;
47 import javax.swing.text.ComponentView JavaDoc;
48 import javax.swing.text.Document JavaDoc;
49 import javax.swing.text.EditorKit JavaDoc;
50 import javax.swing.text.Element JavaDoc;
51 import javax.swing.text.Style JavaDoc;
52 import javax.swing.text.StyleConstants JavaDoc;
53 import javax.swing.text.StyledDocument JavaDoc;
54 import javax.swing.text.View JavaDoc;
55 import javax.swing.text.ViewFactory JavaDoc;
56 import javax.swing.text.html.HTML JavaDoc;
57 import javax.swing.text.html.HTMLEditorKit JavaDoc;
58 import javax.swing.tree.DefaultMutableTreeNode JavaDoc;
59 import javax.swing.tree.DefaultTreeCellRenderer JavaDoc;
60 import javax.swing.tree.DefaultTreeModel JavaDoc;
61 import javax.swing.tree.TreeSelectionModel JavaDoc;
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 /**
71  * Allows the tester to view the textual response from sampling an Entry. This
72  * also allows to "single step through" the sampling process via a nice
73  * "Continue" button.
74  *
75  * Created 2001/07/25
76  * @version $Revision: 1.42.2.5 $ $Date: 2005/01/05 01:05:29 $
77  */

78 public class ViewResultsFullVisualizer
79     extends AbstractVisualizer
80     implements ActionListener JavaDoc, TreeSelectionListener JavaDoc, Clearable
81 {
82     transient private static Logger log = LoggingManager.getLoggerForClass();
83
84     public final static Color JavaDoc SERVER_ERROR_COLOR = Color.red;
85     public final static Color JavaDoc CLIENT_ERROR_COLOR = Color.blue;
86     public final static Color JavaDoc REDIRECT_COLOR = Color.green;
87
88     private static final String JavaDoc DOWNLOAD_LABEL = "Download embedded resources";
89     private static final String JavaDoc HTML_BUTTON_LABEL = "Render HTML";
90     private static final String JavaDoc TEXT_BUTTON_LABEL = "Show Text";
91
92     private static final String JavaDoc TEXT_HTML = "text/html"; // $NON-NLS-1$
93
private static final String JavaDoc HTML_COMMAND = "html"; // $NON-NLS-1$
94
private static final String JavaDoc TEXT_COMMAND = "text"; // $NON-NLS-1$
95
private boolean textMode = true;
96     
97     // Keep copies of the two editors needed
98
private static EditorKit JavaDoc customisedEditor = new LocalHTMLEditorKit();
99     private static EditorKit JavaDoc defaultHtmlEditor =
100         JEditorPane.createEditorKitForContentType(TEXT_HTML);
101
102     private DefaultMutableTreeNode JavaDoc root;
103     private DefaultTreeModel JavaDoc treeModel;
104
105     private JTextPane JavaDoc stats;
106     private JEditorPane JavaDoc results;
107     private JScrollPane JavaDoc resultsScrollPane;
108     private JLabel JavaDoc imageLabel;
109     private JTextArea JavaDoc sampleDataField;
110
111     private JRadioButton JavaDoc textButton;
112     private JRadioButton JavaDoc htmlButton;
113     private JCheckBox JavaDoc downloadAll;
114
115     private JTree JavaDoc 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 JavaDoc getLabelResource()
131     {
132         return "view_results_tree_title";
133     }
134
135     /**
136      * Update the visualizer with new data.
137      */

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 JavaDoc currNode = new DefaultMutableTreeNode JavaDoc(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 JavaDoc 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 JavaDoc leafNode =
169                 new DefaultMutableTreeNode JavaDoc(child);
170
171             treeModel.insertNodeInto(leafNode, currNode, leafIndex++);
172             addSubResults(leafNode, child);
173         }
174     }
175
176     /**
177      * Clears the visualizer.
178      */

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             // the child to be removed will always be 0 'cos as the nodes are
191
// removed the nth node will become (n-1)th
192
treeModel.removeNodeFromParent(
193                 (DefaultMutableTreeNode JavaDoc) root.getChildAt(0));
194         }
195
196         results.setText("");//Response Data
197
sampleDataField.setText("");//Request Data
198
log.debug("End : clear1");
199     }
200
201     /**
202      * Returns the description of this visualizer.
203      *
204      * @return description of this visualizer
205      */

206     public String JavaDoc toString()
207     {
208         String JavaDoc 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     /**
218      * Sets the right pane to correspond to the selected node of the left tree.
219      */

220     public void valueChanged(TreeSelectionEvent JavaDoc e)
221     {
222         log.debug("Start : valueChanged1");
223         DefaultMutableTreeNode JavaDoc node =
224             (DefaultMutableTreeNode JavaDoc) jTree.getLastSelectedPathComponent();
225
226         if (log.isDebugEnabled())
227         {
228             log.debug("valueChanged : selected node - " + node);
229         }
230
231         StyledDocument JavaDoc 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                     // load time label
249

250                     log.debug("valueChanged1 : load time - " + res.getTime());
251                     if (res != null && res.getSamplerData() != null)
252                     {
253                         String JavaDoc sd;
254                         String JavaDoc 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 JavaDoc 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 JavaDoc numberFormatException)
283                         {
284                             // no need to change the foreground color
285
}
286                     }
287
288                     Style JavaDoc 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                     // response message label
307
String JavaDoc 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                     // get the text response and image icon
322
// to determine which is NOT null
323
if ((SampleResult.TEXT).equals(res.getDataType())) // equals(null) is OK
324
{
325                         String JavaDoc 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 JavaDoc(responseBytes));
341                         }
342                     }
343                 }
344             }
345         }
346         catch (BadLocationException JavaDoc 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 JavaDoc 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 JavaDoc 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 JavaDoc getResponseAsString(SampleResult res)
374     {
375         
376         byte[] responseBytes = res.getResponseData();
377         String JavaDoc response = null;
378         if ((SampleResult.TEXT).equals(res.getDataType()))
379         {
380             try
381             {
382                 // Showing large strings can be VERY costly, so we will avoid doing so if the response
383
// data is larger than 200K. TODO: instead, we could delay doing the result.setText
384
// call until the user chooses the "Response data" tab. Plus we could warn the user
385
// if this happens and revert the choice if he doesn't confirm he's ready to wait.
386
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 JavaDoc(responseBytes,res.getDataEncoding());
396                 }
397             }
398             catch (UnsupportedEncodingException JavaDoc err)
399             {
400                 log.warn("Could not decode response "+err);
401                 response = new String JavaDoc(responseBytes);// Try the default encoding instead
402
}
403         }
404         return response;
405     }
406
407     /**
408      * Display the response as text or as rendered HTML. Change the
409      * text on the button appropriate to the current display.
410      *
411      * @param e the ActionEvent being processed
412      */

413     public void actionPerformed(ActionEvent JavaDoc e)
414     {
415         String JavaDoc 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 JavaDoc node =
429                 (DefaultMutableTreeNode JavaDoc) jTree.getLastSelectedPathComponent();
430
431             if (node == null)
432             {
433                 results.setText("");
434                 return;
435             }
436
437             SampleResult res = (SampleResult) node.getUserObject();
438             String JavaDoc 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 JavaDoc response, SampleResult res)
451     {
452         if (response == null)
453         {
454             results.setText("");
455             return;
456         }
457
458         int htmlIndex = response.indexOf("<HTML"); // could be <HTML lang="">
459

460         // Look for a case variation
461
if (htmlIndex < 0)
462         {
463             htmlIndex = response.indexOf("<html"); // ditto
464
}
465
466         // If we still can't find it, just try using all of the text
467
if (htmlIndex < 0)
468         {
469             htmlIndex = 0;
470         }
471
472         String JavaDoc html = response.substring(htmlIndex);
473         
474         /*
475          * To disable downloading and rendering of images and frames,
476          * enable the editor-kit. The Stream property can then be
477          */

478         
479         // Must be done before setContentType
480
results.setEditorKitForContentType(TEXT_HTML,
481                 downloadAll.isSelected() ? defaultHtmlEditor : customisedEditor);
482
483         results.setContentType(TEXT_HTML);
484
485         if (downloadAll.isSelected())
486         {
487             // Allow JMeter to render frames (and relative images)
488
// Must be done after setContentType [Why?]
489
results.getDocument().putProperty(Document.StreamDescriptionProperty,res.getURL());
490         }
491
492         /* Get round problems parsing
493          * <META http-equiv='content-type' content='text/html; charset=utf-8'>
494          * See http://issues.apache.org/bugzilla/show_bug.cgi?id=23315
495          *
496          * Is this due to a bug in Java?
497          */

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 JavaDoc createHtmlOrTextPane()
509     {
510         ButtonGroup JavaDoc group = new ButtonGroup JavaDoc();
511
512         textButton = new JRadioButton JavaDoc(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 JavaDoc(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 JavaDoc(DOWNLOAD_LABEL);
525
526         JPanel JavaDoc pane = new JPanel JavaDoc();
527         pane.add(textButton);
528         pane.add(htmlButton);
529         pane.add(downloadAll);
530         return pane;
531     }
532
533     /**
534      * Initialize this visualizer
535      */

536     protected void init()
537     {
538         setLayout(new BorderLayout JavaDoc(0, 5));
539         setBorder(makeBorder());
540
541         add(makeTitlePanel(), BorderLayout.NORTH);
542
543         Component JavaDoc leftSide = createLeftPanel();
544         JTabbedPane JavaDoc rightSide= new JTabbedPane JavaDoc();
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 JavaDoc mainSplit =
551             new JSplitPane JavaDoc(JSplitPane.HORIZONTAL_SPLIT, leftSide, rightSide);
552         add(mainSplit, BorderLayout.CENTER);
553     }
554
555     private Component JavaDoc createLeftPanel()
556     {
557         SampleResult rootSampleResult = new SampleResult();
558         rootSampleResult.setSampleLabel("Root");
559         rootSampleResult.setSuccessful(true);
560         root = new DefaultMutableTreeNode JavaDoc(rootSampleResult);
561
562         treeModel = new DefaultTreeModel JavaDoc(root);
563         jTree = new JTree JavaDoc(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 JavaDoc treePane = new JScrollPane JavaDoc(jTree);
571         treePane.setPreferredSize(new Dimension JavaDoc(200, 300));
572         return treePane;
573     }
574
575     private Component JavaDoc createResponseMetadataPanel()
576     {
577         stats = new JTextPane JavaDoc();
578         stats.setEditable(false);
579         stats.setBackground(getBackground());
580
581         // Add styles to use for different types of status messages
582
StyledDocument JavaDoc doc = (StyledDocument JavaDoc) stats.getDocument();
583
584         Style JavaDoc 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 JavaDoc pane = makeScrollPane(stats);
594         pane.setBorder(BorderFactory.createEmptyBorder(2, 2, 2, 2));
595         return pane;
596     }
597
598     private Component JavaDoc createRequestPanel()
599     {
600         sampleDataField = new JTextArea JavaDoc();
601         sampleDataField.setEditable(false);
602         sampleDataField.setLineWrap(true);
603         sampleDataField.setWrapStyleWord(true);
604
605         JPanel JavaDoc pane = new JPanel JavaDoc(new BorderLayout JavaDoc(0, 5));
606         pane.add(makeScrollPane(sampleDataField));
607         return pane;
608     }
609
610     private Component JavaDoc createResponseDataPanel()
611     {
612         results = new JEditorPane JavaDoc();
613         results.setEditable(false);
614
615         resultsScrollPane = makeScrollPane(results);
616         imageLabel = new JLabel JavaDoc();
617
618         JPanel JavaDoc resultsPane = new JPanel JavaDoc(new BorderLayout JavaDoc());
619         resultsPane.add(resultsScrollPane, BorderLayout.CENTER);
620         resultsPane.add(createHtmlOrTextPane(), BorderLayout.SOUTH);
621
622         return resultsPane;
623     }
624
625     private class ResultsNodeRenderer extends DefaultTreeCellRenderer JavaDoc
626     {
627         public Component JavaDoc getTreeCellRendererComponent(
628             JTree JavaDoc tree,
629             Object JavaDoc 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 JavaDoc) 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 JavaDoc {
655
656         private static final ViewFactory JavaDoc defaultFactory = new LocalHTMLFactory();
657         
658         public ViewFactory JavaDoc getViewFactory() {
659             return defaultFactory;
660         }
661
662         private static class LocalHTMLFactory
663         extends javax.swing.text.html.HTMLEditorKit.HTMLFactory
664         {
665             /*
666              * Provide dummy implementations to suppress download and display
667              * of related resources:
668              * - FRAMEs
669              * - IMAGEs
670              * TODO create better dummy displays
671              */

672             public View JavaDoc create(Element JavaDoc elem)
673             {
674                 Object JavaDoc o = elem.getAttributes().getAttribute(StyleConstants.NameAttribute);
675                 if (o instanceof HTML.Tag JavaDoc)
676                 {
677                     HTML.Tag JavaDoc kind = (HTML.Tag JavaDoc) o;
678                     if (kind == HTML.Tag.FRAME)
679                     {
680                         return new ComponentView JavaDoc(elem);
681                     }
682                     else if (kind==HTML.Tag.IMG)
683                     {
684                         return new ComponentView JavaDoc(elem);
685                     }
686                 }
687                 return super.create(elem);
688             }
689         }
690     }
691 }
692
Popular Tags