Coverage Report - kg.apc.jmeter.vizualizers.SynthesisReportGui
 
Classes in this File Line Coverage Branch Coverage Complexity
SynthesisReportGui
85%
129/151
58%
14/24
2.115
SynthesisReportGui$1
100%
20/20
75%
3/4
2.115
SynthesisReportGui$FakeGraphPanelChart
52%
10/19
50%
1/2
2.115
SynthesisReportGui$JMeterHeaderAsPropertyRenderer
19%
4/21
0%
0/10
2.115
 
 1  
 /*
 2  
  * Licensed to the Apache Software Foundation (ASF) under one or more
 3  
  * contributor license agreements.  See the NOTICE file distributed with
 4  
  * this work for additional information regarding copyright ownership.
 5  
  * The ASF licenses this file to You under the Apache License, Version 2.0
 6  
  * (the "License"); you may not use this file except in compliance with
 7  
  * the License.  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 kg.apc.jmeter.vizualizers;
 20  
 
 21  
 import java.awt.BorderLayout;
 22  
 import java.awt.Container;
 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.File;
 28  
 import java.io.FileNotFoundException;
 29  
 import java.io.FileWriter;
 30  
 import java.io.IOException;
 31  
 import java.text.DecimalFormat;
 32  
 import java.text.Format;
 33  
 import java.text.MessageFormat;
 34  
 import java.util.ArrayList;
 35  
 import java.util.List;
 36  
 import java.util.Map;
 37  
 import java.util.concurrent.ConcurrentHashMap;
 38  
 
 39  
 import javax.swing.BoxLayout;
 40  
 import javax.swing.JButton;
 41  
 import javax.swing.JCheckBox;
 42  
 import javax.swing.JFileChooser;
 43  
 import javax.swing.JPanel;
 44  
 import javax.swing.JScrollPane;
 45  
 import javax.swing.JTable;
 46  
 import javax.swing.border.Border;
 47  
 import javax.swing.border.EmptyBorder;
 48  
 import javax.swing.event.ChangeEvent;
 49  
 import javax.swing.table.TableCellRenderer;
 50  
 import javax.swing.SwingConstants;
 51  
 import javax.swing.UIManager;
 52  
 import javax.swing.table.DefaultTableCellRenderer;
 53  
 import javax.swing.table.JTableHeader;
 54  
 
 55  
 import kg.apc.charting.GraphPanelChart;
 56  
 import kg.apc.jmeter.JMeterPluginsUtils;
 57  
 import kg.apc.jmeter.graphs.AbstractGraphPanelVisualizer;
 58  
 
 59  
 import org.apache.commons.lang.math.NumberUtils;
 60  
 import org.apache.jmeter.gui.util.FileDialoger;
 61  
 import org.apache.jmeter.samplers.Clearable;
 62  
 import org.apache.jmeter.samplers.SampleResult;
 63  
 import org.apache.jmeter.save.CSVSaveService;
 64  
 import org.apache.jmeter.testelement.TestElement;
 65  
 import org.apache.jmeter.testelement.property.BooleanProperty;
 66  
 import org.apache.jmeter.testelement.property.StringProperty;
 67  
 import org.apache.jmeter.util.JMeterUtils;
 68  
 import org.apache.jmeter.visualizers.SamplingStatCalculator;
 69  
 import org.apache.jorphan.gui.NumberRenderer;
 70  
 import org.apache.jorphan.gui.ObjectTableModel;
 71  
 import org.apache.jorphan.gui.RateRenderer;
 72  
 import org.apache.jorphan.gui.RendererUtils;
 73  
 import org.apache.jorphan.logging.LoggingManager;
 74  
 import org.apache.jorphan.reflect.Functor;
 75  
 import org.apache.jorphan.util.JOrphanUtils;
 76  
 import org.apache.log.Logger;
 77  
 import org.jmeterplugins.visualizers.gui.FilterPanel;
 78  
 
 79  
 /**
 80  
  * Synthesis Table-Based Reporting Visualizer for JMeter.
 81  
  */
 82  35
 public class SynthesisReportGui extends AbstractGraphPanelVisualizer implements
 83  
         Clearable, ActionListener {
 84  
 
 85  
     private static final long serialVersionUID = 240L;
 86  
 
 87  1
     private static final String pct1Label = JMeterUtils.getPropDefault("aggregate_rpt_pct1", "90");
 88  
 
 89  1
     private static final Float pct1Value = Float.parseFloat(pct1Label) / 100;
 90  
 
 91  
     protected FilterPanel jPanelFilter;
 92  
 
 93  1
     private static final Logger log = LoggingManager.getLoggerForClass();
 94  
 
 95  
     public static final String WIKIPAGE = "SynthesisReport";
 96  
 
 97  
     private static final String USE_GROUP_NAME = "useGroupName";
 98  
 
 99  
     private static final String SAVE_HEADERS = "saveHeaders";
 100  
 
 101  1
     private static final String[] COLUMNS_BEFORE_JM_2_13 = {"sampler_label",
 102  
             "aggregate_report_count",
 103  
             "average",
 104  
             "aggregate_report_min",
 105  
             "aggregate_report_max",
 106  
             "aggregate_report_90%_line",
 107  
             "aggregate_report_stddev",
 108  
             "aggregate_report_error%",
 109  
             "aggregate_report_rate",
 110  
             "aggregate_report_bandwidth",
 111  
             "average_bytes"};
 112  
 
 113  1
     private static final String[] COLUMNS_AFTER_OR_EQUAL_JM_2_13 = {"sampler_label",
 114  
             "aggregate_report_count",
 115  
             "average",
 116  
             "aggregate_report_min",
 117  
             "aggregate_report_max",
 118  
             "aggregate_report_xx_pct1_line",
 119  
             "aggregate_report_stddev",
 120  
             "aggregate_report_error%",
 121  
             "aggregate_report_rate",
 122  
             "aggregate_report_bandwidth",
 123  
             "average_bytes"};
 124  
 
 125  1
     private static boolean bOldVersion = false;
 126  
     
 127  
     static {
 128  
             // jmeterVer could be for example : 2.12 r1636949, 2.13 r1665067, 2.14 r18888888 or r1701891 (no version like <major>.<minor> for nightly builds)
 129  1
             String jmeterVer = JMeterUtils.getJMeterVersion();
 130  
             
 131  
             // older than de 2.13 version like 2.12
 132  1
             if ("2.13".compareTo(jmeterVer) > 0) {
 133  0
                     bOldVersion = true;
 134  
             }
 135  
             //System.out.println("jmeterVer = " + jmeterVer + ", bOldVersion = " + bOldVersion);
 136  
     }
 137  
     
 138  1
     private static final String[] COLUMNS = bOldVersion ? COLUMNS_BEFORE_JM_2_13 : COLUMNS_AFTER_OR_EQUAL_JM_2_13;
 139  
 
 140  1
     static final Object[][] COLUMNS_MSG_PARAMETERS = {null,
 141  
             null,
 142  
             null,
 143  
             null,
 144  
             null,
 145  
             new Object[]{pct1Label},
 146  
             null,
 147  
             null,
 148  
             null,
 149  
             null,
 150  
             null};
 151  
 
 152  13
     private final String TOTAL_ROW_LABEL = JMeterUtils
 153  13
             .getResString("aggregate_report_total_label");
 154  
 
 155  13
     private final JButton saveTable = new JButton(
 156  13
             JMeterUtils.getResString("aggregate_graph_save_table"));
 157  
 
 158  13
     private final JCheckBox saveHeaders = // should header be saved with the
 159  
             // data?
 160  
             new JCheckBox(
 161  13
                     JMeterUtils.getResString("aggregate_graph_save_table_header"), true);
 162  
 
 163  13
     private final JCheckBox useGroupName = new JCheckBox(
 164  13
             JMeterUtils.getResString("aggregate_graph_use_group_name"));
 165  
 
 166  
     private transient ObjectTableModel model;
 167  
 
 168  
     /**
 169  
      * Lock used to protect tableRows update + model update
 170  
      */
 171  13
     private final transient Object lock = new Object();
 172  
 
 173  13
     private final Map<String, SamplingStatCalculator> tableRows = new ConcurrentHashMap<String, SamplingStatCalculator>();
 174  
 
 175  
     public SynthesisReportGui() {
 176  13
         super();
 177  13
         model = createObjectTableModel();
 178  13
         clearData();
 179  13
         init();
 180  13
     }
 181  
 
 182  
     /**
 183  
      * Creates that Table model
 184  
      *
 185  
      * @return ObjectTableModel
 186  
      */
 187  
     static ObjectTableModel createObjectTableModel() {
 188  13
         return new ObjectTableModel(COLUMNS, SamplingStatCalculator.class,
 189  
                 new Functor[]{
 190  
                         new Functor("getLabel"),
 191  
                         new Functor("getCount"),
 192  
                         new Functor("getMeanAsNumber"),
 193  
                         new Functor("getMin"),
 194  
                         new Functor("getMax"),
 195  
                         new Functor("getPercentPoint",
 196  
                                 new Object[]{pct1Value}),
 197  
                         new Functor("getStandardDeviation"),
 198  
                         new Functor("getErrorPercentage"),
 199  
                         new Functor("getRate"),
 200  
                         new Functor("getKBPerSecond"),
 201  
                         new Functor("getAvgPageBytes"),
 202  
                 }, new Functor[]{null, null, null, null, null, null, null,
 203  
                 null, null, null, null}, new Class[]{String.class,
 204  
                 Long.class, Long.class, Long.class, Long.class,
 205  
                 Long.class, String.class, String.class, String.class,
 206  
                 String.class, String.class});
 207  
     }
 208  
 
 209  
     // Column renderers
 210  1
     private static final TableCellRenderer[] RENDERERS = new TableCellRenderer[]{
 211  
             null, // Label
 212  
             null, // count
 213  
             null, // Mean
 214  
             null, // Min
 215  
             null, // Max
 216  
             null, // 90%
 217  
             new NumberRenderer("#0.00"), // Std Dev. 
 218  
             new NumberRenderer("#0.00%"), // Error %age 
 219  
             new RateRenderer("#.0"), // Throughput 
 220  
             new NumberRenderer("#0.00"), // kB/sec 
 221  
             new NumberRenderer("#.0"), // avg. pageSize 
 222  
     };
 223  
 
 224  
     // Column formats
 225  1
     static final Format[] FORMATS = new Format[]{
 226  
             null, // Label
 227  
             null, // count
 228  
             null, // Mean
 229  
             null, // Min
 230  
             null, // Max
 231  
             null, // 90%
 232  
             new DecimalFormat("#0.00"), // Std Dev. 
 233  
             new DecimalFormat("#0.00%"), // Error %age 
 234  
             new DecimalFormat("#.0"),      // Throughput 
 235  
             new DecimalFormat("#0.00"),  // kB/sec 
 236  
             new DecimalFormat("#.0"),    // avg. pageSize 
 237  
     };
 238  
 
 239  
     @Override
 240  
     public String getLabelResource() {
 241  1
         return this.getClass().getSimpleName();
 242  
     }
 243  
 
 244  
     @Override
 245  
     public String getStaticLabel() {
 246  41
         return JMeterPluginsUtils.prefixLabel("Synthesis Report (filtered)");
 247  
     }
 248  
 
 249  
     @Override
 250  
     public void add(final SampleResult res) {
 251  4
         JMeterUtils.runSafe(new Runnable() {
 252  
             @Override
 253  
             public void run() {
 254  4
                 if (isSampleIncluded(res)) {
 255  4
                     SamplingStatCalculator row = null;
 256  4
                     final String sampleLabel = res.getSampleLabel(useGroupName.isSelected());
 257  4
                     synchronized (lock) {
 258  4
                         row = tableRows.get(sampleLabel);
 259  4
                         if (row == null) {
 260  1
                             row = new SamplingStatCalculator(sampleLabel);
 261  1
                             tableRows.put(row.getLabel(), row);
 262  1
                             model.insertRow(row, model.getRowCount() - 1);
 263  
                         }
 264  4
                     }
 265  
                     /*
 266  
                      * Synch is needed because multiple threads can update the
 267  
                      * counts.
 268  
                      */
 269  4
                     synchronized (row) {
 270  4
                         row.addSample(res);
 271  4
                     }
 272  4
                     SamplingStatCalculator tot = tableRows.get(TOTAL_ROW_LABEL);
 273  4
                     synchronized (tot) {
 274  4
                         tot.addSample(res);
 275  4
                     }
 276  4
                     model.fireTableDataChanged();
 277  
                 }
 278  4
             }
 279  
         });
 280  4
     }
 281  
 
 282  
     /**
 283  
      * Clears this visualizer and its model, and forces a repaint of the table.
 284  
      */
 285  
     @Override
 286  
     public void clearData() {
 287  14
         synchronized (lock) {
 288  14
             model.clearData();
 289  14
             tableRows.clear();
 290  14
             tableRows.put(TOTAL_ROW_LABEL, new SamplingStatCalculator(
 291  
                     TOTAL_ROW_LABEL));
 292  14
             model.addRow(tableRows.get(TOTAL_ROW_LABEL));
 293  14
         }
 294  14
     }
 295  
 
 296  
     /**
 297  
      * Main visualizer setup.
 298  
      */
 299  
     private void init() {
 300  13
         this.setLayout(new BorderLayout());
 301  
 
 302  
         // MAIN PANEL
 303  13
         JPanel mainPanel = new JPanel();
 304  13
         Border margin = new EmptyBorder(10, 10, 5, 10);
 305  
 
 306  13
         mainPanel.setBorder(margin);
 307  13
         mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
 308  
 
 309  13
         mainPanel.add(JMeterPluginsUtils.addHelpLinkToPanel(makeTitlePanel(),
 310  
                 WIKIPAGE));
 311  
 
 312  
         // SortFilterModel mySortedModel =
 313  
         // new SortFilterModel(myStatTableModel);
 314  13
         JTable myJTable = new JTable(model);
 315  13
         myJTable.getTableHeader().setDefaultRenderer(new JMeterHeaderAsPropertyRenderer(COLUMNS_MSG_PARAMETERS));
 316  13
         myJTable.setPreferredScrollableViewportSize(new Dimension(500, 70));
 317  13
         RendererUtils.applyRenderers(myJTable, RENDERERS);
 318  13
         JScrollPane myScrollPane = new JScrollPane(myJTable);
 319  13
         this.add(mainPanel, BorderLayout.NORTH);
 320  13
         this.add(myScrollPane, BorderLayout.CENTER);
 321  13
         saveTable.addActionListener(this);
 322  13
         JPanel opts = new JPanel();
 323  13
         opts.add(useGroupName, BorderLayout.WEST);
 324  13
         opts.add(saveTable, BorderLayout.CENTER);
 325  13
         opts.add(saveHeaders, BorderLayout.EAST);
 326  13
         this.add(opts, BorderLayout.SOUTH);
 327  13
     }
 328  
 
 329  
     /**
 330  
      * Invoked when the target of the listener has changed its state. This
 331  
      * implementation assumes that the target is the FilePanel, and will update
 332  
      * the result collector for the new filename.
 333  
      *
 334  
      * @param e the event that has occurred
 335  
      */
 336  
     @Override
 337  
     public void stateChanged(ChangeEvent e) {
 338  0
         log.debug("getting new collector");
 339  0
         collector = (CorrectedResultCollector) createTestElement();
 340  0
         if (collector instanceof CorrectedResultCollector) {
 341  0
             setUpFiltering((CorrectedResultCollector) collector);
 342  
         }
 343  0
         collector.loadExistingFile();
 344  0
     }
 345  
 
 346  
     @Override
 347  
     public void modifyTestElement(TestElement c) {
 348  1
         super.modifyTestElement(c);
 349  1
         c.setProperty(USE_GROUP_NAME, useGroupName.isSelected(), false);
 350  1
         c.setProperty(SAVE_HEADERS, saveHeaders.isSelected(), true);
 351  2
         c.setProperty(new StringProperty(
 352  
                 CorrectedResultCollector.INCLUDE_SAMPLE_LABELS, jPanelFilter
 353  1
                 .getIncludeSampleLabels()));
 354  2
         c.setProperty(new StringProperty(
 355  
                 CorrectedResultCollector.EXCLUDE_SAMPLE_LABELS, jPanelFilter
 356  1
                 .getExcludeSampleLabels()));
 357  
 
 358  2
         c.setProperty(new StringProperty(CorrectedResultCollector.START_OFFSET,
 359  1
                 jPanelFilter.getStartOffset()));
 360  2
         c.setProperty(new StringProperty(CorrectedResultCollector.END_OFFSET,
 361  1
                 jPanelFilter.getEndOffset()));
 362  
 
 363  2
         c.setProperty(new BooleanProperty(
 364  
                 CorrectedResultCollector.INCLUDE_REGEX_CHECKBOX_STATE,
 365  1
                 jPanelFilter.isSelectedRegExpInc()));
 366  2
         c.setProperty(new BooleanProperty(
 367  
                 CorrectedResultCollector.EXCLUDE_REGEX_CHECKBOX_STATE,
 368  1
                 jPanelFilter.isSelectedRegExpExc()));
 369  1
     }
 370  
 
 371  
     @Override
 372  
     public void configure(TestElement el) {
 373  2
         super.configure(el);
 374  2
         useGroupName
 375  2
                 .setSelected(el.getPropertyAsBoolean(USE_GROUP_NAME, false));
 376  2
         saveHeaders.setSelected(el.getPropertyAsBoolean(SAVE_HEADERS, true));
 377  
 
 378  2
         jPanelFilter
 379  2
                 .setIncludeSampleLabels(el
 380  2
                         .getPropertyAsString(CorrectedResultCollector.INCLUDE_SAMPLE_LABELS));
 381  2
         jPanelFilter
 382  2
                 .setExcludeSampleLabels(el
 383  2
                         .getPropertyAsString(CorrectedResultCollector.EXCLUDE_SAMPLE_LABELS));
 384  
 
 385  4
         if (!CorrectedResultCollector.EMPTY_FIELD.equals(el
 386  2
                 .getPropertyAsString(CorrectedResultCollector.START_OFFSET))) {
 387  2
             jPanelFilter.setStartOffset((el
 388  1
                     .getPropertyAsLong(CorrectedResultCollector.START_OFFSET)));
 389  
         }
 390  4
         if (!CorrectedResultCollector.EMPTY_FIELD.equals(el
 391  2
                 .getPropertyAsString(CorrectedResultCollector.END_OFFSET))) {
 392  2
             jPanelFilter.setEndOffset((el
 393  1
                     .getPropertyAsLong(CorrectedResultCollector.END_OFFSET)));
 394  
         }
 395  
 
 396  2
         jPanelFilter
 397  2
                 .setSelectedRegExpInc(el
 398  2
                         .getPropertyAsBoolean(CorrectedResultCollector.INCLUDE_REGEX_CHECKBOX_STATE));
 399  2
         jPanelFilter
 400  2
                 .setSelectedRegExpExc(el
 401  2
                         .getPropertyAsBoolean(CorrectedResultCollector.EXCLUDE_REGEX_CHECKBOX_STATE));
 402  
 
 403  2
         if (el instanceof CorrectedResultCollector) {
 404  2
             setUpFiltering((CorrectedResultCollector) el);
 405  
         }
 406  2
     }
 407  
 
 408  
     @Override
 409  
     protected Container makeTitlePanel() {
 410  26
         jPanelFilter = new FilterPanel();
 411  26
         Container panel = super.makeTitlePanel();
 412  26
         panel.add(jPanelFilter);
 413  26
         return panel;
 414  
     }
 415  
 
 416  
     @Override
 417  
     public void clearGui() {
 418  1
         super.clearGui();
 419  1
         jPanelFilter.clearGui();
 420  1
     }
 421  
 
 422  
     /**
 423  
      * We use this method to get the data, since we are using
 424  
      * ObjectTableModel, so the calling getDataVector doesn't
 425  
      * work as expected.
 426  
      *
 427  
      * @param model   {@link ObjectTableModel}
 428  
      * @param formats Array of {@link Format} array can contain null formatters in this case value is added as is
 429  
      * @return the data from the model
 430  
      */
 431  
     public static List<List<Object>> getAllTableData(ObjectTableModel model, Format[] formats) {
 432  2
         List<List<Object>> data = new ArrayList<List<Object>>();
 433  2
         if (model.getRowCount() > 0) {
 434  6
             for (int rw = 0; rw < model.getRowCount(); rw++) {
 435  4
                 int cols = model.getColumnCount();
 436  4
                 List<Object> column = new ArrayList<Object>();
 437  4
                 data.add(column);
 438  48
                 for (int idx = 0; idx < cols; idx++) {
 439  44
                     Object val = model.getValueAt(rw, idx);
 440  44
                     if (formats[idx] != null) {
 441  18
                         column.add(formats[idx].format(val));
 442  
                     } else {
 443  26
                         column.add(val);
 444  
                     }
 445  
                 }
 446  
             }
 447  
         }
 448  2
         return data;
 449  
     }
 450  
 
 451  
     @Override
 452  
     public void actionPerformed(ActionEvent ev) {
 453  0
         if (ev.getSource() == saveTable) {
 454  0
             JFileChooser chooser = FileDialoger
 455  0
                     .promptToSaveFile("synthesis.csv");
 456  0
             if (chooser == null) {
 457  0
                 return;
 458  
             }
 459  0
             FileWriter writer = null;
 460  
             try {
 461  0
                 writer = new FileWriter(chooser.getSelectedFile()); // TODO
 462  
                 // Charset ?
 463  0
                 CSVSaveService.saveCSVStats(getAllTableData(model, FORMATS), writer, saveHeaders.isSelected() ? getLabels(COLUMNS) : null);
 464  0
             } catch (FileNotFoundException e) {
 465  0
                 log.warn(e.getMessage());
 466  0
             } catch (IOException e) {
 467  0
                 log.warn(e.getMessage());
 468  
             } finally {
 469  0
                 JOrphanUtils.closeQuietly(writer);
 470  0
             }
 471  
         }
 472  0
     }
 473  
 
 474  
     /**
 475  
      * @param keys I18N keys
 476  
      * @return labels
 477  
      */
 478  
     static String[] getLabels(String[] keys) {
 479  1
         String[] labels = new String[keys.length];
 480  12
         for (int i = 0; i < labels.length; i++) {
 481  11
             labels[i] = MessageFormat.format(JMeterUtils.getResString(keys[i]), COLUMNS_MSG_PARAMETERS[i]);
 482  
         }
 483  1
         return labels;
 484  
     }
 485  
 
 486  
     @Override
 487  
     public String getWikiPage() {
 488  14
         return WIKIPAGE;
 489  
     }
 490  
 
 491  
     @Override
 492  
     public GraphPanelChart getGraphPanelChart() {
 493  107
         return new FakeGraphPanelChart();
 494  
     }
 495  
 
 496  
     @Override
 497  
     protected JSettingsPanel createSettingsPanel() {
 498  15
         return new JSettingsPanel(this, 0);
 499  
     }
 500  
 
 501  
     private class FakeGraphPanelChart extends GraphPanelChart {
 502  
 
 503  107
         public FakeGraphPanelChart() {
 504  107
             super(false);
 505  107
         }
 506  
 
 507  
         @Override
 508  
         public void saveGraphToCSV(File file) throws IOException {
 509  1
             log.info("Saving CSV to " + file.getAbsolutePath());
 510  
 
 511  1
             FileWriter writer = null;
 512  
             try {
 513  1
                 writer = new FileWriter(file);
 514  1
                 CSVSaveService.saveCSVStats(getAllTableData(model, FORMATS), writer, saveHeaders.isSelected() ? getLabels(COLUMNS) : null);
 515  0
             } catch (FileNotFoundException e) {
 516  0
                 log.warn(e.getMessage());
 517  0
             } catch (IOException e) {
 518  0
                 log.warn(e.getMessage());
 519  
             } finally {
 520  0
                 try {
 521  1
                     writer.close();
 522  0
                 } catch (IOException ex) {
 523  0
                     log.warn("There was problem closing file stream", ex);
 524  1
                 }
 525  0
             }
 526  1
         }
 527  
 
 528  
         @Override
 529  
         public void saveGraphToPNG(File file, int w, int h) throws IOException {
 530  0
             throw new UnsupportedOperationException(
 531  
                     "This plugin type cannot be saved as image");
 532  
         }
 533  
     }
 534  
 
 535  
     /**
 536  
      * Renders items in a JTable by converting from resource names.
 537  
      */
 538  
     private class JMeterHeaderAsPropertyRenderer extends DefaultTableCellRenderer {
 539  
 
 540  
         private static final long serialVersionUID = 240L;
 541  
         private Object[][] columnsMsgParameters;
 542  
 
 543  
         /**
 544  
          *
 545  
          */
 546  
         public JMeterHeaderAsPropertyRenderer() {
 547  0
             this(null);
 548  0
         }
 549  
 
 550  
         /**
 551  
          * @param columnsMsgParameters Optional parameters of i18n keys
 552  
          */
 553  13
         public JMeterHeaderAsPropertyRenderer(Object[][] columnsMsgParameters) {
 554  13
             super();
 555  13
             this.columnsMsgParameters = columnsMsgParameters;
 556  13
         }
 557  
 
 558  
         @Override
 559  
         public Component getTableCellRendererComponent(JTable table, Object value,
 560  
                                                        boolean isSelected, boolean hasFocus, int row, int column) {
 561  0
             if (table != null) {
 562  0
                 JTableHeader header = table.getTableHeader();
 563  0
                 if (header != null) {
 564  0
                     setForeground(header.getForeground());
 565  0
                     setBackground(header.getBackground());
 566  0
                     setFont(header.getFont());
 567  
                 }
 568  0
                 setText(getText(value, row, column));
 569  0
                 setBorder(UIManager.getBorder("TableHeader.cellBorder"));
 570  0
                 setHorizontalAlignment(SwingConstants.CENTER);
 571  
             }
 572  0
             return this;
 573  
         }
 574  
 
 575  
         /**
 576  
          * Get the text for the value as the translation of the resource name.
 577  
          *
 578  
          * @param value  value for which to get the translation
 579  
          * @param column index which column message parameters should be used
 580  
          * @param row    not used
 581  
          * @return the text
 582  
          */
 583  
         protected String getText(Object value, int row, int column) {
 584  0
             if (value == null) {
 585  0
                 return "";
 586  
             }
 587  0
             if (columnsMsgParameters != null && columnsMsgParameters[column] != null) {
 588  0
                 return MessageFormat.format(JMeterUtils.getResString(value.toString()), columnsMsgParameters[column]);
 589  
             } else {
 590  0
                 return JMeterUtils.getResString(value.toString());
 591  
             }
 592  
         }
 593  
     }
 594  
 }