You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jmeter.apache.org by pm...@apache.org on 2016/12/22 20:38:50 UTC

svn commit: r1775729 - in /jmeter/trunk/src: core/org/apache/jmeter/gui/ core/org/apache/jmeter/gui/action/ core/org/apache/jmeter/resources/ protocol/http/org/apache/jmeter/protocol/http/sampler/

Author: pmouawad
Date: Thu Dec 22 20:38:50 2016
New Revision: 1775729

URL: http://svn.apache.org/viewvc?rev=1775729&view=rev
Log:
Bug 54525 - Search Feature : Enhance it with ability to replace
Implement feature for Sampler subclasses
Bugzilla Id: 54525

Added:
    jmeter/trunk/src/core/org/apache/jmeter/gui/Replaceable.java   (with props)
Modified:
    jmeter/trunk/src/core/org/apache/jmeter/gui/GuiPackage.java
    jmeter/trunk/src/core/org/apache/jmeter/gui/action/SearchTreeDialog.java
    jmeter/trunk/src/core/org/apache/jmeter/resources/messages.properties
    jmeter/trunk/src/core/org/apache/jmeter/resources/messages_fr.properties
    jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/sampler/HTTPSamplerBase.java

Modified: jmeter/trunk/src/core/org/apache/jmeter/gui/GuiPackage.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/core/org/apache/jmeter/gui/GuiPackage.java?rev=1775729&r1=1775728&r2=1775729&view=diff
==============================================================================
--- jmeter/trunk/src/core/org/apache/jmeter/gui/GuiPackage.java (original)
+++ jmeter/trunk/src/core/org/apache/jmeter/gui/GuiPackage.java Thu Dec 22 20:38:50 2016
@@ -396,10 +396,18 @@ public final class GuiPackage implements
     /**
      * Update the GUI for the currently selected node. The GUI component is
      * configured to reflect the settings in the current tree node.
-     *
      */
     public void updateCurrentGui() {
         updateCurrentNode();
+        refreshCurrentGui();
+    }
+
+    /**
+     * Refresh GUI from node state. 
+     * This method does not update the current node from GUI at the 
+     * difference of {@link GuiPackage#updateCurrentGui()}
+     */
+    public void refreshCurrentGui() {
         currentNode = treeListener.getCurrentNode();
         TestElement element = currentNode.getTestElement();
         JMeterGUIComponent comp = getGui(element);

Added: jmeter/trunk/src/core/org/apache/jmeter/gui/Replaceable.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/core/org/apache/jmeter/gui/Replaceable.java?rev=1775729&view=auto
==============================================================================
--- jmeter/trunk/src/core/org/apache/jmeter/gui/Replaceable.java (added)
+++ jmeter/trunk/src/core/org/apache/jmeter/gui/Replaceable.java Thu Dec 22 20:38:50 2016
@@ -0,0 +1,42 @@
+/*
+ * 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;
+
+/**
+ * Interface for nodes that have replaceable content.
+ * <p>
+ * A {@link Replaceable} component will get asked for tokens, that should be used
+ * in a search. These tokens will then be matched against a user given search
+ * string.
+ * @since 3.2
+ */
+public interface Replaceable {
+    /**
+     * Replace in object  by replaceBy
+     *
+     * @param regex Regular expression
+     * @param replaceBy Text replacing
+     * @param caseSensitive
+     * @return number of replacements
+     * @throws Exception
+     *             when something fails while replacing
+     */
+    int replace(String regex, String replaceBy, boolean caseSensitive)
+        throws Exception;
+}

Propchange: jmeter/trunk/src/core/org/apache/jmeter/gui/Replaceable.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Modified: jmeter/trunk/src/core/org/apache/jmeter/gui/action/SearchTreeDialog.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/core/org/apache/jmeter/gui/action/SearchTreeDialog.java?rev=1775729&r1=1775728&r2=1775729&view=diff
==============================================================================
--- jmeter/trunk/src/core/org/apache/jmeter/gui/action/SearchTreeDialog.java (original)
+++ jmeter/trunk/src/core/org/apache/jmeter/gui/action/SearchTreeDialog.java Thu Dec 22 20:38:50 2016
@@ -19,13 +19,16 @@
 package org.apache.jmeter.gui.action;
 
 import java.awt.BorderLayout;
+import java.awt.Dimension;
 import java.awt.FlowLayout;
 import java.awt.Font;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
+import java.text.MessageFormat;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
+import java.util.regex.Pattern;
 
 import javax.swing.AbstractAction;
 import javax.swing.Action;
@@ -38,6 +41,7 @@ import javax.swing.JCheckBox;
 import javax.swing.JComponent;
 import javax.swing.JDialog;
 import javax.swing.JFrame;
+import javax.swing.JLabel;
 import javax.swing.JPanel;
 import javax.swing.JRootPane;
 import javax.swing.JTree;
@@ -46,9 +50,11 @@ import javax.swing.tree.TreePath;
 
 import org.apache.commons.lang3.StringUtils;
 import org.apache.jmeter.gui.GuiPackage;
+import org.apache.jmeter.gui.Replaceable;
 import org.apache.jmeter.gui.Searchable;
 import org.apache.jmeter.gui.tree.JMeterTreeModel;
 import org.apache.jmeter.gui.tree.JMeterTreeNode;
+import org.apache.jmeter.testelement.TestElement;
 import org.apache.jmeter.util.JMeterUtils;
 import org.apache.jorphan.gui.ComponentUtil;
 import org.apache.jorphan.gui.JLabeledTextField;
@@ -72,6 +78,10 @@ public class SearchTreeDialog extends JD
 
     private JLabeledTextField searchTF;
 
+    private JLabeledTextField replaceTF;
+
+    private JLabel statusLabel;
+
     private JCheckBox isRegexpCB;
 
     private JCheckBox isCaseSensitiveCB;
@@ -85,6 +95,8 @@ public class SearchTreeDialog extends JD
 
     private JButton searchAndExpandButton;
 
+    private JButton replaceButton;
+
     public SearchTreeDialog() {
         super((JFrame) null, JMeterUtils.getResString("search_tree_title"), true); //$NON-NLS-1$
         init();
@@ -130,8 +142,12 @@ public class SearchTreeDialog extends JD
         if(!StringUtils.isEmpty(lastSearch)) {
             searchTF.setText(lastSearch);
         }
+
+        replaceTF = new JLabeledTextField(JMeterUtils.getResString("search_text_replace"), 20); //$NON-NLS-1$
+        statusLabel = new JLabel();
+        statusLabel.setMinimumSize(new Dimension(100, 30));
         isRegexpCB = new JCheckBox(JMeterUtils.getResString("search_text_chkbox_regexp"), false); //$NON-NLS-1$
-        isCaseSensitiveCB = new JCheckBox(JMeterUtils.getResString("search_text_chkbox_case"), false); //$NON-NLS-1$
+        isCaseSensitiveCB = new JCheckBox(JMeterUtils.getResString("search_text_chkbox_case"), true); //$NON-NLS-1$
         
         isRegexpCB.setFont(FONT_SMALL);
         isCaseSensitiveCB.setFont(FONT_SMALL);
@@ -142,22 +158,31 @@ public class SearchTreeDialog extends JD
 
         JPanel searchPanel = new JPanel();
         searchPanel.setLayout(new BoxLayout(searchPanel, BoxLayout.Y_AXIS));
-        searchPanel.setBorder(BorderFactory.createEmptyBorder(7, 3, 3, 3));
-        searchPanel.add(searchTF, BorderLayout.NORTH);
-        searchPanel.add(searchCriterionPanel, BorderLayout.CENTER);
-        JPanel buttonsPanel = new JPanel(new FlowLayout(FlowLayout.CENTER));
+        searchPanel.setBorder(BorderFactory.createEmptyBorder(7, 3, 3, 3));        
+        searchPanel.add(searchTF);
+        searchPanel.add(replaceTF);
+        searchPanel.add(statusLabel);
 
+        JPanel buttonsPanel = new JPanel(new FlowLayout(FlowLayout.CENTER));
         searchButton = new JButton(JMeterUtils.getResString("search")); //$NON-NLS-1$
         searchButton.addActionListener(this);
         searchAndExpandButton = new JButton(JMeterUtils.getResString("search_expand")); //$NON-NLS-1$
         searchAndExpandButton.addActionListener(this);
+        replaceButton = new JButton(JMeterUtils.getResString("search_replace_all")); //$NON-NLS-1$
+        replaceButton.addActionListener(this);
         cancelButton = new JButton(JMeterUtils.getResString("cancel")); //$NON-NLS-1$
         cancelButton.addActionListener(this);
         buttonsPanel.add(searchButton);
         buttonsPanel.add(searchAndExpandButton);
+        buttonsPanel.add(replaceButton);
         buttonsPanel.add(cancelButton);
-        searchPanel.add(buttonsPanel, BorderLayout.SOUTH);
-        this.getContentPane().add(searchPanel);
+
+        JPanel searchAndReplacePanel = new JPanel();
+        searchAndReplacePanel.setLayout(new BorderLayout());
+        searchAndReplacePanel.add(searchPanel, BorderLayout.NORTH);
+        searchAndReplacePanel.add(searchCriterionPanel, BorderLayout.CENTER);
+        searchAndReplacePanel.add(buttonsPanel, BorderLayout.SOUTH);
+        this.getContentPane().add(searchAndReplacePanel);
         searchTF.requestFocusInWindow();
 
         this.pack();
@@ -170,12 +195,17 @@ public class SearchTreeDialog extends JD
      */
     @Override
     public void actionPerformed(ActionEvent e) {
+        statusLabel.setText("");
         if (e.getSource()==cancelButton) {
             searchTF.requestFocusInWindow();
             this.setVisible(false);
             return;
+        } else if(e.getSource() == searchButton ||
+                e.getSource() == searchAndExpandButton) {
+            doSearch(e);
+        } else {
+            doReplaceAll(e);
         }
-        doSearch(e);
     }
 
     /**
@@ -202,19 +232,19 @@ public class SearchTreeDialog extends JD
         GuiPackage guiPackage = GuiPackage.getInstance();
         JMeterTreeModel jMeterTreeModel = guiPackage.getTreeModel();
         Set<JMeterTreeNode> nodes = new HashSet<>();
+        int numberOfMatches = 0;
         for (JMeterTreeNode jMeterTreeNode : jMeterTreeModel.getNodesOfType(Searchable.class)) {
             try {
-                if (jMeterTreeNode.getUserObject() instanceof Searchable){
-                    Searchable searchable = (Searchable) jMeterTreeNode.getUserObject();
-                    List<JMeterTreeNode> matchingNodes = jMeterTreeNode.getPathToThreadGroup();
-                    List<String> searchableTokens = searchable.getSearchableTokens();
-                    boolean result = searcher.search(searchableTokens);
-                    if (result) {
-                        nodes.addAll(matchingNodes);
-                    }
+                Searchable searchable = (Searchable) jMeterTreeNode.getUserObject();
+                List<JMeterTreeNode> matchingNodes = jMeterTreeNode.getPathToThreadGroup();
+                List<String> searchableTokens = searchable.getSearchableTokens();
+                boolean result = searcher.search(searchableTokens);
+                if (result) {
+                    numberOfMatches++;
+                    nodes.addAll(matchingNodes);
                 }
             } catch (Exception ex) {
-                logger.error("Error occured searching for word:"+ wordToSearch, ex);
+                logger.error("Error occured searching for word:"+ wordToSearch+ " in node:"+jMeterTreeNode.getName(), ex);
             }
         }
         GuiPackage guiInstance = GuiPackage.getInstance();
@@ -228,6 +258,78 @@ public class SearchTreeDialog extends JD
         }
         GuiPackage.getInstance().getMainFrame().repaint();
         searchTF.requestFocusInWindow();
-        this.setVisible(false);
+        if(numberOfMatches > 0) {
+            statusLabel.setText(MessageFormat.format("{0} nodes match the search", new Object[]{numberOfMatches}));
+        }
+    }
+    
+    /**
+     * Replace all occurences in nodes that contain {@link Replaceable} Test Elements
+     * @param e {@link ActionEvent}
+     */
+    private void doReplaceAll(ActionEvent e) {
+        String wordToSearch = searchTF.getText();
+        String wordToReplace = replaceTF.getText();
+        
+        if (StringUtils.isEmpty(wordToReplace)) {
+            return;
+        } 
+        // Save any change to current node
+        GuiPackage.getInstance().updateCurrentNode();
+        // reset previous result
+        ActionRouter.getInstance().doActionNow(new ActionEvent(e.getSource(), e.getID(), ActionNames.SEARCH_RESET));
+        Searcher searcher = null;
+        String regex = null;
+        if (isRegexpCB.isSelected()) {
+            regex = wordToSearch;
+            searcher = new RegexpSearcher(isCaseSensitiveCB.isSelected(), wordToSearch);
+        } else {
+            regex = Pattern.quote(wordToSearch);
+            searcher = new RawTextSearcher(isCaseSensitiveCB.isSelected(), wordToSearch);
+        }
+        GuiPackage guiPackage = GuiPackage.getInstance();
+        JMeterTreeModel jMeterTreeModel = guiPackage.getTreeModel();
+        Set<JMeterTreeNode> nodes = new HashSet<>();
+        boolean caseSensitiveReplacement = isCaseSensitiveCB.isSelected();
+        int totalReplaced = 0;
+        for (JMeterTreeNode jMeterTreeNode : jMeterTreeModel.getNodesOfType(Searchable.class)) {
+            try {
+                Searchable searchable = (Searchable) jMeterTreeNode.getUserObject();
+                List<String> searchableTokens = searchable.getSearchableTokens();
+                boolean result = searcher.search(searchableTokens);
+                if (result) {
+                    if(jMeterTreeNode.getUserObject() instanceof Replaceable) {
+                        Replaceable replaceable = (Replaceable) jMeterTreeNode.getUserObject();
+                        int numberOfReplacements = replaceable.replace(regex, wordToReplace, caseSensitiveReplacement);
+                        if(logger.isInfoEnabled()) {
+                            logger.info("Replaced "+numberOfReplacements+" in element:"
+                                    +((TestElement)jMeterTreeNode.getUserObject()).getName());
+                        }
+                        totalReplaced += numberOfReplacements;
+                        if(numberOfReplacements > 0) {
+                            List<JMeterTreeNode> matchingNodes = jMeterTreeNode.getPathToThreadGroup();
+                            nodes.addAll(matchingNodes);
+                        }
+                    }   
+                }
+            } catch (Exception ex) {
+                logger.error("Error occured replacing data in node:"+jMeterTreeNode.getName(), ex);
+            }
+        }
+        statusLabel.setText(MessageFormat.format("Replaced {0} occurences", new Object[]{totalReplaced}));
+        GuiPackage guiInstance = GuiPackage.getInstance();
+        JTree jTree = guiInstance.getMainFrame().getTree();
+
+        for (JMeterTreeNode jMeterTreeNode : nodes) {
+            jMeterTreeNode.setMarkedBySearch(true);
+            jTree.expandPath(new TreePath(jMeterTreeNode.getPath()));
+        }
+        // Update GUI as current node may be concerned by changes
+        if(totalReplaced>0) {
+            GuiPackage.getInstance().refreshCurrentGui();
+        }
+        GuiPackage.getInstance().getMainFrame().repaint();
+
+        searchTF.requestFocusInWindow();
     }
 }

Modified: jmeter/trunk/src/core/org/apache/jmeter/resources/messages.properties
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/core/org/apache/jmeter/resources/messages.properties?rev=1775729&r1=1775728&r2=1775729&view=diff
==============================================================================
--- jmeter/trunk/src/core/org/apache/jmeter/resources/messages.properties (original)
+++ jmeter/trunk/src/core/org/apache/jmeter/resources/messages.properties Thu Dec 22 20:38:50 2016
@@ -957,6 +957,7 @@ search=Search
 search_base=Search base
 search_expand=Search & Expand
 search_filter=Search Filter
+search_replace_all=Replace All
 search_test=Search Test
 search_text_button_close=Close
 search_text_button_find=Find
@@ -965,6 +966,7 @@ search_text_chkbox_case=Case sensitive
 search_text_chkbox_regexp=Regular exp.
 search_text_field=Search: 
 search_text_msg_not_found=Text not found
+search_text_replace=Replace by
 search_text_title_not_found=Not found
 search_tree_title=Search Tree
 searchbase=Search base

Modified: jmeter/trunk/src/core/org/apache/jmeter/resources/messages_fr.properties
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/core/org/apache/jmeter/resources/messages_fr.properties?rev=1775729&r1=1775728&r2=1775729&view=diff
==============================================================================
--- jmeter/trunk/src/core/org/apache/jmeter/resources/messages_fr.properties (original)
+++ jmeter/trunk/src/core/org/apache/jmeter/resources/messages_fr.properties Thu Dec 22 20:38:50 2016
@@ -947,6 +947,7 @@ search=Rechercher
 search_base=Base de recherche
 search_expand=Rechercher & D\u00E9plier
 search_filter=Filtre de recherche
+search_replace_all=Tout remplacer
 search_test=Recherche
 search_text_button_close=Fermer
 search_text_button_find=Rechercher
@@ -955,6 +956,7 @@ search_text_chkbox_case=Consid\u00E9rer
 search_text_chkbox_regexp=Exp. reguli\u00E8re
 search_text_field=Rechercher \:
 search_text_msg_not_found=Texte non trouv\u00E9
+search_text_replace=Remplacer par
 search_text_title_not_found=Pas trouv\u00E9
 search_tree_title=Rechercher dans l'arbre
 searchbase=Base de recherche

Modified: jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/sampler/HTTPSamplerBase.java
URL: http://svn.apache.org/viewvc/jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/sampler/HTTPSamplerBase.java?rev=1775729&r1=1775728&r2=1775729&view=diff
==============================================================================
--- jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/sampler/HTTPSamplerBase.java (original)
+++ jmeter/trunk/src/protocol/http/org/apache/jmeter/protocol/http/sampler/HTTPSamplerBase.java Thu Dec 22 20:38:50 2016
@@ -46,6 +46,7 @@ import org.apache.jmeter.config.Argument
 import org.apache.jmeter.config.Arguments;
 import org.apache.jmeter.config.ConfigTestElement;
 import org.apache.jmeter.engine.event.LoopIterationEvent;
+import org.apache.jmeter.gui.Replaceable;
 import org.apache.jmeter.protocol.http.control.AuthManager;
 import org.apache.jmeter.protocol.http.control.CacheManager;
 import org.apache.jmeter.protocol.http.control.Cookie;
@@ -93,7 +94,8 @@ import org.apache.oro.text.regex.Perl5Ma
  *
  */
 public abstract class HTTPSamplerBase extends AbstractSampler
-    implements TestStateListener, TestIterationListener, ThreadListener, HTTPConstantsInterface {
+    implements TestStateListener, TestIterationListener, ThreadListener, HTTPConstantsInterface,
+        Replaceable {
 
     private static final long serialVersionUID = 241L;
 
@@ -2036,4 +2038,39 @@ public abstract class HTTPSamplerBase ex
         String guiClass = configElement.getProperty(TestElement.GUI_CLASS).getStringValue();
         return APPLIABLE_CONFIG_CLASSES.contains(guiClass);
     }
+
+    /**
+     * Replace by replaceBy in path and body (arguments) properties
+     */
+    @Override
+    public int replace(String regex, String replaceBy, boolean caseSensitive) throws Exception {
+        int totalReplaced = 0;
+        for (JMeterProperty jMeterProperty : getArguments()) {
+            HTTPArgument arg = (HTTPArgument) jMeterProperty.getObjectValue();
+            String value = arg.getValue();
+            if(!StringUtils.isEmpty(value)) {
+                Object[] result = JOrphanUtils.replaceAllWithRegex(value, regex, replaceBy, caseSensitive);
+                // check if there is anything to replace
+                int nbReplaced = ((Integer)result[1]).intValue();
+                if (nbReplaced>0) {
+                    String replacedText = (String) result[0];
+                    arg.setValue(replacedText);
+                    totalReplaced += nbReplaced;
+                }
+            }
+        }
+        String value = getPath();
+        if(!StringUtils.isEmpty(value)) {
+            Object[] result = JOrphanUtils.replaceAllWithRegex(value, regex, replaceBy, caseSensitive);
+            // check if there is anything to replace
+            int nbReplaced = ((Integer)result[1]).intValue();
+            if (nbReplaced>0) {
+                totalReplaced += nbReplaced;
+                String replacedText = (String) result[0];
+                setPath(replacedText);
+                totalReplaced += nbReplaced;
+            }
+        }
+        return totalReplaced;
+    }
 }