package kg.apc.jmeter.timers;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.util.concurrent.ConcurrentHashMap;
import javax.swing.*;
import javax.swing.event.CellEditorListener;
import javax.swing.event.ChangeEvent;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import kg.apc.charting.AbstractGraphRow;
import kg.apc.charting.DateTimeRenderer;
import kg.apc.charting.GraphPanelChart;
import kg.apc.charting.rows.GraphRowExactValues;
import kg.apc.jmeter.JMeterPluginsUtils;
import kg.apc.jmeter.gui.ButtonPanelAddCopyRemove;
import kg.apc.jmeter.gui.GuiBuilderHelper;
import kg.apc.jmeter.threads.UltimateThreadGroupGui;
import org.apache.jmeter.engine.util.CompoundVariable;
import org.apache.jmeter.gui.util.PowerTableModel;
import org.apache.jmeter.gui.util.VerticalPanel;
import org.apache.jmeter.testelement.TestElement;
import org.apache.jmeter.testelement.property.CollectionProperty;
import org.apache.jmeter.testelement.property.JMeterProperty;
import org.apache.jmeter.testelement.property.NullProperty;
import org.apache.jmeter.timers.gui.AbstractTimerGui;
import org.apache.jorphan.logging.LoggingManager;
import org.apache.log.Logger;
/**
*
* @see UltimateThreadGroupGui
*/
public class VariableThroughputTimerGui
extends AbstractTimerGui
implements TableModelListener,
CellEditorListener {
public static final String WIKIPAGE = "ThroughputShapingTimer";
private static final Logger log = LoggingManager.getLoggerForClass();
/**
*
*/
protected ConcurrentHashMap<String, AbstractGraphRow> model;
protected GraphPanelChart chart;
/**
*
*/
private static Integer[] defaultValues = new Integer[]{
1, 1000, 60
};
protected PowerTableModel tableModel;
protected JTable grid;
protected ButtonPanelAddCopyRemove buttons;
/**
*
*/
public VariableThroughputTimerGui() {
super();
init();
}
/**
*
*/
protected final void init() {
setBorder(makeBorder());
setLayout(new BorderLayout());
add(JMeterPluginsUtils.addHelpLinkToPanel(makeTitlePanel(), WIKIPAGE), BorderLayout.NORTH);
JPanel containerPanel = new VerticalPanel();
containerPanel.add(createParamsPanel(), BorderLayout.NORTH);
containerPanel.add(GuiBuilderHelper.getComponentWithMargin(createChart(), 2, 2, 0, 2), BorderLayout.CENTER);
add(containerPanel, BorderLayout.CENTER);
}
private JPanel createParamsPanel() {
JPanel panel = new JPanel(new BorderLayout(5, 5));
panel.setBorder(BorderFactory.createTitledBorder("Requests Per Second (RPS) Schedule"));
panel.setPreferredSize(new Dimension(200, 200));
JScrollPane scroll = new JScrollPane(createGrid());
scroll.setPreferredSize(scroll.getMinimumSize());
panel.add(scroll, BorderLayout.CENTER);
buttons = new ButtonPanelAddCopyRemove(grid, tableModel, defaultValues);
panel.add(buttons, BorderLayout.SOUTH);
return panel;
}
private JTable createGrid() {
grid = new JTable();
grid.getDefaultEditor(String.class).addCellEditorListener(this);
createTableModel();
grid.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
grid.setMinimumSize(new Dimension(200, 100));
return grid;
}
@Override
public String getLabelResource() {
return this.getClass().getSimpleName();
}
@Override
public String getStaticLabel() {
return JMeterPluginsUtils.prefixLabel("Throughput Shaping Timer");
}
@Override
public TestElement createTestElement() {
//log.info("Create test element");
VariableThroughputTimer tg = new VariableThroughputTimer();
modifyTestElement(tg);
tg.setComment(JMeterPluginsUtils.getWikiLinkText(WIKIPAGE));
return tg;
}
@Override
public void modifyTestElement(TestElement tg) {
//log.info("Modify test element");
super.configureTestElement(tg);
if (grid.isEditing()) {
grid.getCellEditor().stopCellEditing();
}
if (tg instanceof VariableThroughputTimer) {
VariableThroughputTimer utg = (VariableThroughputTimer) tg;
CollectionProperty rows = JMeterPluginsUtils.tableModelRowsToCollectionProperty(tableModel, VariableThroughputTimer.DATA_PROPERTY);
utg.setData(rows);
}
}
@Override
public void configure(TestElement tg) {
//log.info("Configure");
super.configure(tg);
VariableThroughputTimer utg = (VariableThroughputTimer) tg;
JMeterProperty threadValues = utg.getData();
if (threadValues instanceof NullProperty) {
log.warn("Received null property instead of collection");
return;
}
CollectionProperty columns = (CollectionProperty) threadValues;
tableModel.removeTableModelListener(this);
JMeterPluginsUtils.collectionPropertyToTableModelRows(columns, tableModel);
tableModel.addTableModelListener(this);
buttons.checkDeleteButtonStatus();
updateUI();
}
@Override
public void updateUI() {
super.updateUI();
if (tableModel != null) {
VariableThroughputTimer utgForPreview = new VariableThroughputTimer();
utgForPreview.setData(JMeterPluginsUtils.tableModelRowsToCollectionPropertyEval(tableModel, VariableThroughputTimer.DATA_PROPERTY));
updateChart(utgForPreview);
}
}
private int getIntFromRow(int row, int col) {
int ret;
try {
ret = Integer.valueOf(new CompoundVariable(tableModel.getValueAt(row, col).toString()).execute());
} catch (NumberFormatException ex) {
ret = -1;
}
return ret;
}
private void updateChart(VariableThroughputTimer tg) {
model.clear();
chart.clearErrorMessage();
AbstractGraphRow row = new GraphRowExactValues();
row.setColor(Color.BLUE);
row.setDrawLine(true);
row.setMarkerSize(AbstractGraphRow.MARKER_SIZE_NONE);
row.setDrawThickLines(true);
long now = System.currentTimeMillis();
int rowsCount = tableModel.getRowCount();
row.add(now, 0);
row.add(now, tg.getRPSForSecond(0));
int duration = 0;
for (int i = 0; i < rowsCount; i++) {
row.add(now + (duration + 1) * 1000, tg.getRPSForSecond(duration + 1));
int rowVal = getIntFromRow(i, 2);
if (rowVal < 0) {
chart.setErrorMessage("The values entered cannot be rendered in preview...");
break;
}
duration = duration + rowVal;
row.add(now + duration * 1000, tg.getRPSForSecond(duration));
}
chart.setxAxisLabelRenderer(new DateTimeRenderer(DateTimeRenderer.HHMMSS, now - 1)); //-1 because row.add(thread.getStartTime() - 1, 0)
chart.setForcedMinX(now);
model.put("Expected RPS", row);
chart.invalidateCache();
chart.repaint();
}
private Component createChart() {
chart = new GraphPanelChart(false, true);
model = new ConcurrentHashMap<String, AbstractGraphRow>();
chart.setRows(model);
chart.getChartSettings().setDrawFinalZeroingLines(true);
chart.setxAxisLabel("Elapsed Time");
chart.setYAxisLabel("Number of requests /sec");
chart.setBorder(javax.swing.BorderFactory.createBevelBorder(javax.swing.border.BevelBorder.LOWERED));
return chart;
}
private void createTableModel() {
tableModel = new PowerTableModel(VariableThroughputTimer.columnIdentifiers, VariableThroughputTimer.columnClasses);
tableModel.addTableModelListener(this);
grid.setModel(tableModel);
}
@Override
public void editingStopped(ChangeEvent e) {
updateUI();
}
@Override
public void editingCanceled(ChangeEvent e) {
// no action needed
}
@Override
public void clearGui() {
super.clearGui();
tableModel.clearData();
tableModel.fireTableDataChanged();
}
@Override
public void tableChanged(TableModelEvent e) {
updateUI();
}
}