--- bin/jmeter.properties (revision 1849621)
+++ bin/jmeter.properties (working copy)
@@ -1320,3 +1320,11 @@
# Switch that allows using Local documentation opened in JMeter GUI
# By default we use Online documentation opened in Browser
#help.local=false
+
+#---------------------------------------------------------------------------
+# Documentation generation
+#---------------------------------------------------------------------------
+
+# Path to XSL file used to generate Schematic View of Test Plan
+# When empty, JMeter will use the embedded one in src/core/org/apache/jmeter/gui/action/schematic.xsl
+#docgeneration.schematic_xsl=
--- build.xml (revision 1851687)
+++ build.xml (working copy)
@@ -1149,6 +1149,7 @@
+
--- src/core/org/apache/jmeter/gui/action/ActionNames.java (revision 1851688)
+++ src/core/org/apache/jmeter/gui/action/ActionNames.java (working copy)
@@ -117,6 +117,7 @@
public static final String ZOOM_IN = "zoom_in"; //$NON-NLS-1$
public static final String ZOOM_OUT = "zoom_out"; //$NON-NLS-1$
public static final String PARSE_CURL = "parse_curl"; ////$NON-NLS-1$
+ public static final String SCHEMATIC_VIEW = "schematic_view";
// Prevent instantiation
private ActionNames() {}
--- src/core/org/apache/jmeter/gui/action/SchematicView.java (revision 0)
+++ src/core/org/apache/jmeter/gui/action/SchematicView.java (revision 0)
@@ -0,0 +1,192 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.jmeter.gui.action;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.KeyEvent;
+import java.io.File;
+import java.text.MessageFormat;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.swing.JFileChooser;
+import javax.swing.JMenu;
+import javax.swing.JMenuItem;
+import javax.swing.JOptionPane;
+import javax.swing.MenuElement;
+import javax.xml.transform.Source;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.stream.StreamResult;
+import javax.xml.transform.stream.StreamSource;
+
+import org.apache.jmeter.gui.GuiPackage;
+import org.apache.jmeter.gui.plugin.MenuCreator;
+import org.apache.jmeter.gui.tree.JMeterTreeNode;
+import org.apache.jmeter.util.JMeterUtils;
+import org.apache.jorphan.collections.HashTree;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Schematic view of Test Plan
+ * @since 5.1
+ */
+public class SchematicView extends AbstractAction implements MenuCreator {
+ private static final Logger log = LoggerFactory.getLogger(SchematicView.class);
+ private static final String DEFAULT_XSL_FILE =
+ JMeterUtils.getProperty("docgeneration.schematic_xsl"); //$NON-NLS-1$
+
+ private static final MessageFormat GENERATION_SUCCESS_MSG = new MessageFormat(JMeterUtils.getResString("schematic_view_generation_ok"));
+
+ @FunctionalInterface
+ public interface SchematicViewGenerator {
+ void generate(HashTree testPlan, File testPlanFile, File outputFile) throws Exception;
+ }
+
+ private static final class XslSchematicViewGenerator implements SchematicViewGenerator {
+ @Override
+ public void generate(HashTree testPlan, File testPlanFile, File outputFile)
+ throws Exception {
+ TransformerFactory factory = TransformerFactory.newInstance(
+ "net.sf.saxon.BasicTransformerFactory", Thread.currentThread().getContextClassLoader());
+ Source xslt = null;
+ if(DEFAULT_XSL_FILE != null) {
+ log.info("Will use file {} for Schematic View generation", DEFAULT_XSL_FILE);
+ xslt = new StreamSource(new File(DEFAULT_XSL_FILE));
+ } else {
+ xslt = new StreamSource(SchematicView.class.getResourceAsStream("/org/apache/jmeter/gui/action/schematic.xsl"));
+ }
+ Transformer transformer = factory.newTransformer(xslt);
+ Source text = new StreamSource(testPlanFile);
+ transformer.transform(text, new StreamResult(outputFile));
+ }
+
+ }
+
+ private static final Set commands = new HashSet<>();
+
+ static {
+ commands.add(ActionNames.SCHEMATIC_VIEW);
+ }
+
+ public SchematicView() {
+ super();
+ }
+
+ /**
+ * @see Command#doAction(ActionEvent)
+ */
+ @Override
+ public void doAction(ActionEvent e) {
+ try {
+ String updateFile = GuiPackage.getInstance().getTestPlanFile();
+ if(updateFile != null) {
+ ActionRouter.getInstance().doActionNow(new ActionEvent(e.getSource(), e.getID(), ActionNames.CHECK_DIRTY));
+ JFileChooser jFileChooser = new JFileChooser();
+ jFileChooser.setDialogTitle(JMeterUtils.getResString("schematic_view_outputfile"));
+ jFileChooser.setCurrentDirectory(new File(updateFile).getParentFile());
+ jFileChooser.setSelectedFile(new File(updateFile+".html"));
+ int retVal = jFileChooser.showSaveDialog(GuiPackage.getInstance().getMainFrame());
+ if (retVal == JFileChooser.APPROVE_OPTION) {
+ File outputFile = jFileChooser.getSelectedFile();
+ if(outputFile.exists()) {
+ int response = JOptionPane.showConfirmDialog(GuiPackage.getInstance().getMainFrame(),
+ JMeterUtils.getResString("save_overwrite_existing_file"), // $NON-NLS-1$
+ JMeterUtils.getResString("save?"), // $NON-NLS-1$
+ JOptionPane.YES_NO_OPTION,
+ JOptionPane.QUESTION_MESSAGE);
+ if (response == JOptionPane.CLOSED_OPTION || response == JOptionPane.NO_OPTION) {
+ return; // Do not save, user does not want to overwrite
+ }
+ }
+ new XslSchematicViewGenerator().generate(GuiPackage.getInstance().getCurrentSubTree(),
+ new File(updateFile), outputFile);
+ JMeterUtils.reportInfoToUser(
+ GENERATION_SUCCESS_MSG.format(new Object[]{outputFile.getAbsolutePath()}),
+ JMeterUtils.getResString("schematic_view_info"));
+ }
+ } else {
+ JMeterUtils.reportInfoToUser(JMeterUtils.getResString("schematic_view_no_plan"), JMeterUtils.getResString("schematic_view_info"));
+ }
+ } catch (Exception ex) {
+ JMeterUtils.reportErrorToUser(JMeterUtils.getResString("schematic_view_errors"), ex);
+ }
+ }
+
+
+ /**
+ * @see Command#getActionNames()
+ */
+ @Override
+ public Set getActionNames() {
+ return commands;
+ }
+
+ @Override
+ public JMenuItem[] getMenuItemsAtLocation(MENU_LOCATION location) {
+ if(location == MENU_LOCATION.TOOLS) {
+
+ JMenuItem menuItemIC = new JMenuItem(
+ JMeterUtils.getResString("schematic_view_menu"), KeyEvent.VK_UNDEFINED);
+ menuItemIC.setName(ActionNames.SCHEMATIC_VIEW);
+ menuItemIC.setActionCommand(ActionNames.SCHEMATIC_VIEW);
+ menuItemIC.setAccelerator(null);
+ menuItemIC.addActionListener(ActionRouter.getInstance());
+
+ return new JMenuItem[]{menuItemIC};
+ }
+ return new JMenuItem[0];
+ }
+
+ @Override
+ public JMenu[] getTopLevelMenus() {
+ return new JMenu[0];
+ }
+
+ @Override
+ public boolean localeChanged(MenuElement menu) {
+ return false;
+ }
+
+ @Override
+ public void localeChanged() {
+ // NOOP
+ }
+}
--- src/core/org/apache/jmeter/gui/action/schematic.xsl (revision 0)
+++ src/core/org/apache/jmeter/gui/action/schematic.xsl (revision 0)
@@ -0,0 +1,689 @@
+
+
+
+
+
+
+
+
+
+ Schematic view of Test Plan
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (globalVars:[
+ ""
+
+ ""
+ ,
+ ],
+ executeTearDownThreadsOnShutdown: )
+
+
+
+
+
+
+
+ ([
+ ""
+
+ ""
+ ,
+ ])
+
+
+
+
+
+
+
+ (
+ threads: "",
+ loops: "",
+ ramp-up: ""
+ )
+
+
+
+
+
+
+
+ (file: "",
+ vars:"",
+ sharing:"",
+ recycleOnEof:,
+ stopThreadOnEof:
+ )
+
+
+
+
+
+
+
+
+ (pct: "%")
+
+
+
+
+
+
+
+
+ (condition: "")
+
+
+
+
+
+
+
+ (method: "",
+ url: "
+
+ ://
+
+ :
+
+ /
+ ",
+
+
+ body: ""
+
+
+ body: [
+
+ ""=
+ ""
+ ,
+
+ ]
+
+ ,
+ upload-files: [
+
+ {param="",
+ path="",
+ mime-type=""}
+ ,
+
+ ]
+ )
+
+
+
+
+
+
+
+ (clearOnEachIteration: ,
+ useCacheControlAndExpires: ,
+ maxSize:
+ )
+
+
+
+
+
+
+
+ (protocol: "",
+ domain: "",
+ port: "",
+ path: "",
+ connectTimeout: ""ms,
+ responseTimeout: ""ms
+ )
+
+
+
+
+
+
+
+
+ (filename: "",
+ xml: ,
+ errorsOnly: ,
+ successOnly: )
+
+
+
+
+
+
+
+
+ that ()
+
+
+
+ matches
+
+
+ contains
+
+
+ does not match
+
+
+ does not contain
+
+
+ is equal to
+
+
+ is not equal to
+
+
+ contains
+
+
+ does not contain as substring
+
+
+ does not matches one of
+
+
+ does not contain one of
+
+
+ is not equal to one of
+
+
+ contains one of
+
+
+ does not contain as substring one of
+
+
+
+ [
+
+ ""
+ ,
+
+ ])
+
+
+
+
+
+
+
+
+
+
+ stop
+
+
+ pause for ms
+
+
+ stop now
+
+
+ go to next iteration of thread loop
+
+
+ go to next iteration of current loop
+
+
+ break current loop
+
+
+
+
+ current thread
+
+
+ test
+
+
+
+
+
+
+
+
+
+
+
+
+
+ continue
+
+
+ stop thread now
+
+
+ shutdown test
+
+
+ stop test now
+
+
+ go to next iteration of thread loop
+
+
+ go to next iteration of current loop
+
+
+ break current loop
+
+
+
+
+
+
+
+
+
+
+ (names=[
+
+ ""
+ ,
+ ],values=[
+
+ ""
+ ,
+ ]
+ )
+
+
+
+
+
+
+
+ (
+
+
+
+
+
+ #
+
+
+ >
+
+
+ )
+
+
+
+
+
+
+
+ (clearOnEachIteration: ,
+ policy: "",
+ cookies: [
+
+ { name:"",
+ value:"",
+ domain:"",
+ path:"",
+ secure:}
+ ,
+ ])
+
+
+
+
+
+
+
+ (headers:[
+
+ {""=
+ ""
+ ,
+ ])
+
+
+
+
+
+
+
+
+ using response headers
+
+
+ using response body
+
+
+ using request headers
+
+
+ using response body unescaped
+
+
+ using URL
+
+
+ using response code
+
+
+ using response message
+
+
+
+
+
+
+
+ using response body
+ (exportedVar: "",
+ xpathQuery: "",
+ fragment: "",
+ default: "",
+ matchNr: "")
+
+
+
+
+
+
+
+ using response body
+ (exportedVar: "",
+ xpathQuery: "",
+ fragment: "",
+ default: "",
+ matchNr: "")
+
+
+
+
+
+
+
+ using response body
+ (exportedVar: "",
+ selector: "",
+ attribute: "",
+ default: "",
+ matchNr: "")
+
+
+
+
+
+
+
+ using response body
+ (exportedVar: "",
+ jsonPaths: "",
+ default: "",
+ matchNr: "")
+
+
+
+
+
+
+
+
+ (exportedVar: "",
+ lboundary: "",
+ rboundary: "",
+ default: "",
+ matchNr: "")
+
+
+
+
+
+
+
+
+ (exportedVar: ""
+ regex: "",
+ template: "",
+ default: "",
+ matchNr: "")
+
+
+
+
+
+
+
+ (const:ms)
+
+
+
+
+
+
+
+ (const:ms,
+ variation:ms)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Comments:
+
+
+
+
+
+
+
+
+
+
+
+
+ container
+
+
+ http request
+
+
+ run before
+
+
+ run
+
+
+ run after
+
+
+ declare reusable Elements
+
+
+ assert as
+
+
+
+
+
+
+ transaction
+
+
+ reuse controller
+
+
+ set variables for thread
+
+
+
+
+
+
+ randomly run children
+
+
+
+
+
+
+ run at percentage
+
+
+
+
+
+
+ if
+
+
+ write samples
+
+
+ think-time Constant
+
+
+ think-time
+
+
+ jsr223 sampler
+
+
+ jsr223 pre-process
+
+
+ jsr223 post-process
+
+
+ read csv into vars
+
+
+ add headers
+
+
+ handle cookies
+
+
+ globalVars
+
+
+ flow control
+
+
+ action after sampler error
+
+
+ http defaults
+
+
+ simulate browser cache
+
+
+ extract-regexp
+
+
+ extract-boundary
+
+
+ extract-css-selector
+
+
+ extract-xpath
+
+
+ extract-xpath2
+
+
+ extract-jsonpath
+
+
+ load test
+
+
+
+
+
+ ""
+
+
+
+
+ (disabled)
+
+
+
--- src/core/org/apache/jmeter/resources/messages.properties (revision 1851856)
+++ src/core/org/apache/jmeter/resources/messages.properties (working copy)
@@ -1039,6 +1039,12 @@
sbind=Single bind/unbind
scheduler=Scheduler
scheduler_configuration=Scheduler Configuration
+schematic_view_errors=Error on generation of schematic view
+schematic_view_generation_ok=Successful generation of schematic view in {0}
+schematic_view_info=Information
+schematic_view_menu=Generate Schematic View (alpha)
+schematic_view_no_plan=No plan opened
+schematic_view_outputfile=Save output file to ?
scope=Scope
search=Search
search_base=Search base
--- src/core/org/apache/jmeter/resources/messages_fr.properties (revision 1851856)
+++ src/core/org/apache/jmeter/resources/messages_fr.properties (working copy)
@@ -1028,6 +1028,12 @@
sbind=Simple connexion/déconnexion
scheduler=Programmateur de démarrage
scheduler_configuration=Configuration du programmateur
+schematic_view_errors=Erreur lors de la génération de la vue schématique
+schematic_view_generation_ok=Génération réussie de la vue schématique dans {0}.
+schematic_view_info=Information
+schematic_view_menu=Générer une vue schématique (alpha)
+schematic_view_no_plan=Pas de plan ouvert
+schematic_view_outputfile=Enregistrer le fichier de sortie dans ?
scope=Portée
search=Rechercher\:
search_base=Base de recherche
--- src/core/org/apache/jmeter/util/JMeterUtils.java (revision 1850550)
+++ src/core/org/apache/jmeter/util/JMeterUtils.java (working copy)
@@ -898,6 +898,29 @@
log.warn("reportErrorToUser(\"{}\") caused", errorMsg, e);
}
}
+
+ /**
+ * Report an information through a dialog box in GUI mode
+ *
+ * @param msg - the information message.
+ * @param titleMsg - title string
+ */
+ public static void reportInfoToUser(String msg, String titleMsg) {
+ GuiPackage instance = GuiPackage.getInstance();
+ if (instance == null) {
+ log.info(msg);
+ System.out.println(msg); // NOSONAR intentional
+ return; // Done
+ }
+ try {
+ JOptionPane.showMessageDialog(instance.getMainFrame(),
+ formatMessage(msg),
+ titleMsg,
+ JOptionPane.INFORMATION_MESSAGE);
+ } catch (HeadlessException e) {
+ log.warn("reportInfoToUser(\"{}\") caused", msg, e);
+ }
+ }
private static JScrollPane formatMessage(String errorMsg) {
JTextArea ta = new JTextArea(10, 50);
--- xdocs/usermanual/properties_reference.xml (revision 1851687)
+++ xdocs/usermanual/properties_reference.xml (working copy)
@@ -1910,6 +1910,16 @@
Defaults to: 100
+
+
+Advanced properties for documentation generation
+
+
+ Path to XSL file used to generate Schematic View of Test Plan.
+ When empty, JMeter will use the embedded one in src/core/org/apache/jmeter/gui/action/schematic.xsl
+ No default value
+
+