When writing any Jmeter component, there are certain contracts you must be aware of – ways a Jmeter component is expected to behave if it will run properly in the Jmeter environment. This section describes the contract that the GUI part of your component must fulfill.
GUI code in Jmeter is strictly separated from Test Element code. Therefore, when you write a component, there will be a class for the Test Element, and another for the GUI presentation. The GUI presentation class is stateless in the sense that it should never hang onto a reference to the Test Element (there are exceptions to this though).
A gui element should extend the appropriate abstract class provided:
These abstract classes provide so much plumbing work for you that not extending them, and instead implementing the interfaces directly is hardly an option. If you have some burning need to not extend these classes, then you can join me in IRC where I can convince you otherwise .
So, you've extended the appropriate gui class, what's left to do? Follow these steps:
private void init() { setLayout(new BorderLayout()); setBorder(makeBorder()); Box box = Box.createVerticalBox(); box.add(makeTitlePanel()); box.add(makeSourcePanel()); add(box,BorderLayout.NORTH); add(makeParameterPanel(),BorderLayout.CENTER); } |
public void configure(TestElement el) { super.configure(el); useHeaders.setSelected(el.getPropertyAsBoolean(RegexExtractor.USEHEADERS)); useBody.setSelected(!el.getPropertyAsBoolean(RegexExtractor.USEHEADERS)); regexField.setText(el.getPropertyAsString(RegexExtractor.REGEX)); templateField.setText(el.getPropertyAsString(RegexExtractor.TEMPLATE)); defaultField.setText(el.getPropertyAsString(RegexExtractor.DEFAULT)); matchNumberField.setText(el.getPropertyAsString(RegexExtractor.MATCH_NUM)); refNameField.setText(el.getPropertyAsString(RegexExtractor.REFNAME)); } |
public void modifyTestElement(TestElement e) { super.configureTestElement(e); e.setProperty(new BooleanProperty(RegexExtractor.USEHEADERS,useHeaders.isSelected())); e.setProperty(RegexExtractor.MATCH_NUMBER,matchNumberField.getText()); if(e instanceof RegexExtractor) { RegexExtractor regex = (RegexExtractor)e; regex.setRefName(refNameField.getText()); regex.setRegex(regexField.getText()); regex.setTemplate(templateField.getText()); regex.setDefaultValue(defaultField.getText()); } } |
public TestElement createTestElement() { RegexExtractor extractor = new RegexExtractor(); modifyTestElement(extractor); return extractor; } |
The reason you cannot hold onto a reference for your Test Element is because Jmeter reuses instance of gui class objects for multiple Test Elements. This saves a lot of memory. It also makes it incredibly easy to write the gui part of your new component. You still have to struggle with the layout in Swing, but you don't have to worry about creating the right events and actions for getting the data from the gui elements into the TestElement where it can do some good. Jmeter knows when to call your configure, and modifyTestElement methods where you can do it in a very straightforward way.