001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
013: * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
014: * License for the specific language governing permissions and limitations
015: * under the License.
016: *
017: */
018:
019: package org.apache.jmeter.visualizers;
020:
021: import java.awt.BorderLayout;
022: import java.awt.Dimension; //import java.awt.event.MouseAdapter;
023: //import java.awt.event.MouseEvent;
024: //import java.util.Arrays;
025: import java.util.Collections;
026: import java.util.HashMap;
027: import java.util.Map;
028:
029: import javax.swing.BoxLayout;
030: import javax.swing.JPanel;
031: import javax.swing.JScrollPane;
032: import javax.swing.JTable;
033: import javax.swing.border.Border;
034: import javax.swing.border.EmptyBorder;
035: import javax.swing.table.TableCellRenderer; //import javax.swing.table.AbstractTableModel;
036: //import javax.swing.table.TableModel;
037:
038: import org.apache.jmeter.samplers.Clearable;
039: import org.apache.jmeter.samplers.SampleResult;
040: import org.apache.jmeter.testelement.TestElement;
041: import org.apache.jmeter.util.JMeterUtils;
042: import org.apache.jmeter.visualizers.gui.AbstractVisualizer;
043: import org.apache.jorphan.gui.NumberRenderer;
044: import org.apache.jorphan.gui.ObjectTableModel;
045: import org.apache.jorphan.gui.RateRenderer;
046: import org.apache.jorphan.gui.RendererUtils;
047: import org.apache.jorphan.reflect.Functor;
048:
049: /**
050: * Aggregrate Table-Based Reporting Visualizer for JMeter. Props to the people
051: * who've done the other visualizers ahead of me (Stefano Mazzocchi), who I
052: * borrowed code from to start me off (and much code may still exist). Thank
053: * you!
054: *
055: */
056: public class StatVisualizer extends AbstractVisualizer implements
057: Clearable {
058: private final String[] COLUMNS = {
059: JMeterUtils.getResString("sampler_label"), //$NON-NLS-1$
060: JMeterUtils.getResString("aggregate_report_count"), //$NON-NLS-1$
061: JMeterUtils.getResString("average"), //$NON-NLS-1$
062: JMeterUtils.getResString("aggregate_report_median"), //$NON-NLS-1$
063: JMeterUtils.getResString("aggregate_report_90%_line"), //$NON-NLS-1$
064: JMeterUtils.getResString("aggregate_report_min"), //$NON-NLS-1$
065: JMeterUtils.getResString("aggregate_report_max"), //$NON-NLS-1$
066: JMeterUtils.getResString("aggregate_report_error%"), //$NON-NLS-1$
067: JMeterUtils.getResString("aggregate_report_rate"), //$NON-NLS-1$
068: JMeterUtils.getResString("aggregate_report_bandwidth") }; //$NON-NLS-1$
069:
070: private final String TOTAL_ROW_LABEL = JMeterUtils
071: .getResString("aggregate_report_total_label"); //$NON-NLS-1$
072:
073: protected JTable myJTable;
074:
075: protected JScrollPane myScrollPane;
076:
077: transient private ObjectTableModel model;
078:
079: Map tableRows = Collections.synchronizedMap(new HashMap());
080:
081: public StatVisualizer() {
082: super ();
083: model = new ObjectTableModel(COLUMNS,
084: SamplingStatCalculator.class, new Functor[] {
085: new Functor("getLabel"), //$NON-NLS-1$
086: new Functor("getCount"), //$NON-NLS-1$
087: new Functor("getMeanAsNumber"), //$NON-NLS-1$
088: new Functor("getMedian"), //$NON-NLS-1$
089: new Functor("getPercentPoint", //$NON-NLS-1$
090: new Object[] { new Float(.900) }),
091: new Functor("getMin"), //$NON-NLS-1$
092: new Functor("getMax"), //$NON-NLS-1$
093: new Functor("getErrorPercentage"), //$NON-NLS-1$
094: new Functor("getRate"), //$NON-NLS-1$
095: new Functor("getKBPerSecond") //$NON-NLS-1$
096: }, new Functor[] { null, null, null, null, null, null,
097: null, null, null, null }, new Class[] {
098: String.class, Long.class, Long.class,
099: Long.class, Long.class, Long.class, Long.class,
100: String.class, String.class, String.class });
101: clearData();
102: init();
103: }
104:
105: // Column renderers
106: private static final TableCellRenderer[] RENDERERS = new TableCellRenderer[] {
107: null, // Label
108: null, // count
109: null, // Mean
110: null, // median
111: null, // 90%
112: null, // Min
113: null, // Max
114: new NumberRenderer("#0.00%"), // Error %age //$NON-NLS-1$
115: new RateRenderer("#.0"), // Throughput //$NON-NLS-1$
116: new NumberRenderer("#.0"), // pageSize //$NON-NLS-1$
117: };
118:
119: public static boolean testFunctors() {
120: StatVisualizer instance = new StatVisualizer();
121: return instance.model.checkFunctors(null, instance.getClass());
122: }
123:
124: public String getLabelResource() {
125: return "aggregate_report"; //$NON-NLS-1$
126: }
127:
128: public void add(SampleResult res) {
129: SamplingStatCalculator row = null;
130: synchronized (tableRows) {
131: row = (SamplingStatCalculator) tableRows.get(res
132: .getSampleLabel());
133: if (row == null) {
134: row = new SamplingStatCalculator(res.getSampleLabel());
135: tableRows.put(row.getLabel(), row);
136: model.insertRow(row, model.getRowCount() - 1);
137: }
138: }
139: row.addSample(res);
140: ((SamplingStatCalculator) tableRows.get(TOTAL_ROW_LABEL))
141: .addSample(res);
142: model.fireTableDataChanged();
143: }
144:
145: /**
146: * Clears this visualizer and its model, and forces a repaint of the table.
147: */
148: public void clearData() {
149: model.clearData();
150: tableRows.clear();
151: tableRows.put(TOTAL_ROW_LABEL, new SamplingStatCalculator(
152: TOTAL_ROW_LABEL));
153: model.addRow(tableRows.get(TOTAL_ROW_LABEL));
154: }
155:
156: // overrides AbstractVisualizer
157: // forces GUI update after sample file has been read
158: public TestElement createTestElement() {
159: TestElement t = super .createTestElement();
160:
161: // sleepTill = 0;
162: return t;
163: }
164:
165: /**
166: * Main visualizer setup.
167: */
168: private void init() {
169: this .setLayout(new BorderLayout());
170:
171: // MAIN PANEL
172: JPanel mainPanel = new JPanel();
173: Border margin = new EmptyBorder(10, 10, 5, 10);
174:
175: mainPanel.setBorder(margin);
176: mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
177:
178: mainPanel.add(makeTitlePanel());
179:
180: // SortFilterModel mySortedModel =
181: // new SortFilterModel(myStatTableModel);
182: myJTable = new JTable(model);
183: myJTable.setPreferredScrollableViewportSize(new Dimension(500,
184: 70));
185: RendererUtils.applyRenderers(myJTable, RENDERERS);
186: myScrollPane = new JScrollPane(myJTable);
187: this .add(mainPanel, BorderLayout.NORTH);
188: this .add(myScrollPane, BorderLayout.CENTER);
189: }
190: }
191:
192: /**
193: * Pulled this mainly out of a Core Java book to implement a sorted table -
194: * haven't implemented this yet, it needs some non-trivial work done to it to
195: * support our dynamically-sizing TableModel for this visualizer.
196: *
197: */
198:
199: //class SortFilterModel extends AbstractTableModel {
200: // private TableModel model;
201: //
202: // private int sortColumn;
203: //
204: // private Row[] rows;
205: //
206: // public SortFilterModel(TableModel m) {
207: // model = m;
208: // rows = new Row[model.getRowCount()];
209: // for (int i = 0; i < rows.length; i++) {
210: // rows[i] = new Row();
211: // rows[i].index = i;
212: // }
213: // }
214: //
215: // public SortFilterModel() {
216: // }
217: //
218: // public void setValueAt(Object aValue, int r, int c) {
219: // model.setValueAt(aValue, rows[r].index, c);
220: // }
221: //
222: // public Object getValueAt(int r, int c) {
223: // return model.getValueAt(rows[r].index, c);
224: // }
225: //
226: // public boolean isCellEditable(int r, int c) {
227: // return model.isCellEditable(rows[r].index, c);
228: // }
229: //
230: // public int getRowCount() {
231: // return model.getRowCount();
232: // }
233: //
234: // public int getColumnCount() {
235: // return model.getColumnCount();
236: // }
237: //
238: // public String getColumnName(int c) {
239: // return model.getColumnName(c);
240: // }
241: //
242: // public Class getColumnClass(int c) {
243: // return model.getColumnClass(c);
244: // }
245: //
246: // public void sort(int c) {
247: // sortColumn = c;
248: // Arrays.sort(rows);
249: // fireTableDataChanged();
250: // }
251: //
252: // public void addMouseListener(final JTable table) {
253: // table.getTableHeader().addMouseListener(new MouseAdapter() {
254: // public void mouseClicked(MouseEvent event) {
255: // if (event.getClickCount() < 2) {
256: // return;
257: // }
258: // int tableColumn = table.columnAtPoint(event.getPoint());
259: // int modelColumn = table.convertColumnIndexToModel(tableColumn);
260: //
261: // sort(modelColumn);
262: // }
263: // });
264: // }
265: //
266: // private class Row implements Comparable {
267: // public int index;
268: //
269: // public int compareTo(Object other) {
270: // Row otherRow = (Row) other;
271: // Object a = model.getValueAt(index, sortColumn);
272: // Object b = model.getValueAt(otherRow.index, sortColumn);
273: //
274: // if (a instanceof Comparable) {
275: // return ((Comparable) a).compareTo(b);
276: // } else {
277: // return index - otherRow.index;
278: // }
279: // }
280: // }
281: //} // class SortFilterModel
|