Package org.apache.jmeter.protocol.http.proxy

Source Code of org.apache.jmeter.protocol.http.proxy.ProxyControl

/*
* 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.protocol.http.proxy;

import java.util.Collection;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

import org.apache.jmeter.assertions.ResponseAssertion;
import org.apache.jmeter.assertions.gui.AssertionGui;
import org.apache.jmeter.config.Arguments;
import org.apache.jmeter.config.ConfigElement;
import org.apache.jmeter.config.ConfigTestElement;
import org.apache.jmeter.control.GenericController;
import org.apache.jmeter.control.gui.LogicControllerGui;
import org.apache.jmeter.engine.util.ValueReplacer;
import org.apache.jmeter.exceptions.IllegalUserActionException;
import org.apache.jmeter.functions.InvalidVariableException;
import org.apache.jmeter.gui.GuiPackage;
import org.apache.jmeter.gui.tree.JMeterTreeModel;
import org.apache.jmeter.gui.tree.JMeterTreeNode;
import org.apache.jmeter.protocol.http.control.HeaderManager;
import org.apache.jmeter.protocol.http.control.RecordingController;
import org.apache.jmeter.protocol.http.gui.HeaderPanel;
import org.apache.jmeter.protocol.http.sampler.HTTPSamplerBase;
import org.apache.jmeter.samplers.SampleEvent;
import org.apache.jmeter.samplers.SampleListener;
import org.apache.jmeter.samplers.SampleResult;
import org.apache.jmeter.testelement.TestElement;
import org.apache.jmeter.testelement.TestListener;
import org.apache.jmeter.testelement.TestPlan;
import org.apache.jmeter.testelement.WorkBench;
import org.apache.jmeter.testelement.property.BooleanProperty;
import org.apache.jmeter.testelement.property.CollectionProperty;
import org.apache.jmeter.testelement.property.IntegerProperty;
import org.apache.jmeter.testelement.property.JMeterProperty;
import org.apache.jmeter.testelement.property.PropertyIterator;
import org.apache.jmeter.testelement.property.StringProperty;
import org.apache.jmeter.threads.ThreadGroup;
import org.apache.jmeter.timers.Timer;
import org.apache.jmeter.util.JMeterUtils;
import org.apache.jorphan.logging.LoggingManager;
import org.apache.log.Logger;
import org.apache.oro.text.MalformedCachePatternException;
import org.apache.oro.text.regex.Pattern;
import org.apache.oro.text.regex.Perl5Compiler;

//For unit tests, @see TestProxyControl

/**
* Class handles storing of generated samples, etc
*/
public class ProxyControl extends GenericController {
   
    private static final Logger log = LoggingManager.getLoggerForClass();

    private static final String ASSERTION_GUI = AssertionGui.class.getName();

    private static final String LOGIC_CONTROLLER_GUI = LogicControllerGui.class.getName();

    private static final String HEADER_PANEL = HeaderPanel.class.getName();

  private transient Daemon server;

  public static final int DEFAULT_PORT = 8080;

    // and as a string
  public static final String DEFAULT_PORT_S =
        Integer.toString(DEFAULT_PORT);// Used by GUI

  //+ JMX file attributes
  private static final String PORT = "ProxyControlGui.port"; // $NON-NLS-1$

  private static final String EXCLUDE_LIST = "ProxyControlGui.exclude_list"; // $NON-NLS-1$

  private static final String INCLUDE_LIST = "ProxyControlGui.include_list"; // $NON-NLS-1$

  private static final String CAPTURE_HTTP_HEADERS = "ProxyControlGui.capture_http_headers"; // $NON-NLS-1$

  private static final String ADD_ASSERTIONS = "ProxyControlGui.add_assertion"; // $NON-NLS-1$

  private static final String GROUPING_MODE = "ProxyControlGui.grouping_mode"; // $NON-NLS-1$

  private static final String SAMPLER_TYPE_NAME = "ProxyControlGui.sampler_type_name"; // $NON-NLS-1$

  private static final String SAMPLER_REDIRECT_AUTOMATICALLY = "ProxyControlGui.sampler_redirect_automatically"; // $NON-NLS-1$

  private static final String SAMPLER_FOLLOW_REDIRECTS = "ProxyControlGui.sampler_follow_redirects"; // $NON-NLS-1$

  private static final String USE_KEEPALIVE = "ProxyControlGui.use_keepalive"; // $NON-NLS-1$

  private static final String SAMPLER_DOWNLOAD_IMAGES = "ProxyControlGui.sampler_download_images"; // $NON-NLS-1$

  private static final String REGEX_MATCH = "ProxyControlGui.regex_match"; // $NON-NLS-1$

  private static final String HTTPS_SPOOF = "ProxyControlGui.https_spoof"; // $NON-NLS-1$

  private static final String HTTPS_SPOOF_MATCH = "ProxyControlGui.https_spoof_match"; // $NON-NLS-1$

  private static final String CONTENT_TYPE_EXCLUDE = "ProxyControlGui.content_type_exclude"; // $NON-NLS-1$

  private static final String CONTENT_TYPE_INCLUDE = "ProxyControlGui.content_type_include"; // $NON-NLS-1$
  //- JMX file attributes
 
  public static final int GROUPING_NO_GROUPS = 0;

  public static final int GROUPING_ADD_SEPARATORS = 1;

  public static final int GROUPING_IN_CONTROLLERS = 2;

  public static final int GROUPING_STORE_FIRST_ONLY = 3;
 
  // Must agree with the order of entries in the drop-down
  // created in ProxyControlGui.createHTTPSamplerPanel()
  public static final int SAMPLER_TYPE_HTTP_SAMPLER = 0;
  public static final int SAMPLER_TYPE_HTTP_SAMPLER2 = 1;

  private long lastTime = 0;// When was the last sample seen?

  private static final long sampleGap =
        JMeterUtils.getPropDefault("proxy.pause", 1000); // $NON-NLS-1$
    // Detect if user has pressed a new link

  private boolean addAssertions;

  private int groupingMode;
 
  private boolean samplerRedirectAutomatically;

  private boolean samplerFollowRedirects;
 
  private boolean useKeepAlive;

  private boolean samplerDownloadImages;

  private boolean regexMatch = false;// Should we match using regexes?
 
  /**
   * Tree node where the samples should be stored.
   * <p>
   * This property is not persistent.
   */
  private JMeterTreeNode target;

  public ProxyControl() {
    setPort(DEFAULT_PORT);
    setExcludeList(new HashSet());
    setIncludeList(new HashSet());
    setCaptureHttpHeaders(true); // maintain original behaviour
  }

  public void setPort(int port) {
    this.setProperty(new IntegerProperty(PORT, port));
  }

  public void setPort(String port) {
    setProperty(PORT, port);
  }

  public void setCaptureHttpHeaders(boolean capture) {
    setProperty(new BooleanProperty(CAPTURE_HTTP_HEADERS, capture));
  }

  public void setGroupingMode(int grouping) {
    this.groupingMode = grouping;
    setProperty(new IntegerProperty(GROUPING_MODE, grouping));
  }

  public void setAssertions(boolean b) {
    addAssertions = b;
    setProperty(new BooleanProperty(ADD_ASSERTIONS, b));
  }

  public void setSamplerTypeName(int samplerTypeName) {
    setProperty(new IntegerProperty(SAMPLER_TYPE_NAME, samplerTypeName));
  }

  public void setSamplerRedirectAutomatically(boolean b) {
    samplerRedirectAutomatically = b;
    setProperty(new BooleanProperty(SAMPLER_REDIRECT_AUTOMATICALLY, b));
  }

  public void setSamplerFollowRedirects(boolean b) {
    samplerFollowRedirects = b;
    setProperty(new BooleanProperty(SAMPLER_FOLLOW_REDIRECTS, b));
  }

  /**
   * @param b
   */
  public void setUseKeepAlive(boolean b) {
    useKeepAlive = b;
    setProperty(new BooleanProperty(USE_KEEPALIVE, b));
  }

  public void setSamplerDownloadImages(boolean b) {
    samplerDownloadImages = b;
    setProperty(new BooleanProperty(SAMPLER_DOWNLOAD_IMAGES, b));
  }

  public void setIncludeList(Collection list) {
    setProperty(new CollectionProperty(INCLUDE_LIST, new HashSet(list)));
  }

  public void setExcludeList(Collection list) {
    setProperty(new CollectionProperty(EXCLUDE_LIST, new HashSet(list)));
  }

  /**
   * @param b
   */
  public void setRegexMatch(boolean b) {
    regexMatch = b;
    setProperty(new BooleanProperty(REGEX_MATCH, b));
  }
 
  public void setHttpsSpoof(boolean b) {
    setProperty(new BooleanProperty(HTTPS_SPOOF, b));
  }
 
  public void setHttpsSpoofMatch(String s) {
    setProperty(new StringProperty(HTTPS_SPOOF_MATCH, s));
  }
 
  public void setContentTypeExclude(String contentTypeExclude) {
    setProperty(new StringProperty(CONTENT_TYPE_EXCLUDE, contentTypeExclude));
  }

  public void setContentTypeInclude(String contentTypeInclude) {
    setProperty(new StringProperty(CONTENT_TYPE_INCLUDE, contentTypeInclude));
  }

  public String getClassLabel() {
    return JMeterUtils.getResString("proxy_title"); // $NON-NLS-1$
  }

  public boolean getAssertions() {
    return getPropertyAsBoolean(ADD_ASSERTIONS);
  }

  public int getGroupingMode() {
    return getPropertyAsInt(GROUPING_MODE);
  }

  public int getPort() {
    return getPropertyAsInt(PORT);
  }

  public String getPortString() {
    return getPropertyAsString(PORT);
  }

  public int getDefaultPort() {
    return DEFAULT_PORT;
  }

  public boolean getCaptureHttpHeaders() {
    return getPropertyAsBoolean(CAPTURE_HTTP_HEADERS);
  }

  public int getSamplerTypeName() {
    return getPropertyAsInt(SAMPLER_TYPE_NAME);
  }
 
  public boolean getSamplerRedirectAutomatically() {
    return getPropertyAsBoolean(SAMPLER_REDIRECT_AUTOMATICALLY, false);
  }

  public boolean getSamplerFollowRedirects() {
    return getPropertyAsBoolean(SAMPLER_FOLLOW_REDIRECTS, true);
  }
 
  public boolean getUseKeepalive() {
    return getPropertyAsBoolean(USE_KEEPALIVE, true);
  }
 
  public boolean getSamplerDownloadImages() {
    return getPropertyAsBoolean(SAMPLER_DOWNLOAD_IMAGES, false);
  }

  public boolean getRegexMatch() {
    return getPropertyAsBoolean(REGEX_MATCH, false);
  }
 
  public boolean getHttpsSpoof() {
    return getPropertyAsBoolean(HTTPS_SPOOF, false);
  }
 
  public String getHttpsSpoofMatch() {
    return getPropertyAsString(HTTPS_SPOOF_MATCH, "");
  }
 
  public String getContentTypeExclude() {
    return getPropertyAsString(CONTENT_TYPE_EXCLUDE);
  }

  public String getContentTypeInclude() {
    return getPropertyAsString(CONTENT_TYPE_INCLUDE);
  }


  public Class getGuiClass() {
    return org.apache.jmeter.protocol.http.proxy.gui.ProxyControlGui.class;
  }

  public void addConfigElement(ConfigElement config) {
  }

  public void startProxy() {
    notifyTestListenersOfStart();
    server = new Daemon(getPort(), this);
    server.start();
  }

  public void addExcludedPattern(String pattern) {
    getExcludePatterns().addItem(pattern);
  }

  public CollectionProperty getExcludePatterns() {
    return (CollectionProperty) getProperty(EXCLUDE_LIST);
  }

  public void addIncludedPattern(String pattern) {
    getIncludePatterns().addItem(pattern);
  }

  public CollectionProperty getIncludePatterns() {
    return (CollectionProperty) getProperty(INCLUDE_LIST);
  }

  public void clearExcludedPatterns() {
    getExcludePatterns().clear();
  }

  public void clearIncludedPatterns() {
    getIncludePatterns().clear();
  }

  /**
   * @return the target controller node
   */
  public JMeterTreeNode getTarget() {
    return target;
  }

  /**
   * Sets the target node where the samples generated by the proxy have to be
   * stored.
   */
  public void setTarget(JMeterTreeNode target) {
    this.target = target;
  }

  /**
   * Receives the recorded sampler from the proxy server for placing in the
   * test tree. param serverResponse to be added to allow saving of the
   * server's response while recording. A future consideration.
   */
  public synchronized void deliverSampler(HTTPSamplerBase sampler, TestElement[] subConfigs, SampleResult result) {
    if (filterContentType(result) && filterUrl(sampler)) {
      JMeterTreeNode myTarget = findTargetControllerNode();
      Collection defaultConfigurations = findApplicableElements(myTarget, ConfigTestElement.class, false);
      Collection userDefinedVariables = findApplicableElements(myTarget, Arguments.class, true);

      removeValuesFromSampler(sampler, defaultConfigurations);
      replaceValues(sampler, subConfigs, userDefinedVariables);
      sampler.setAutoRedirects(samplerRedirectAutomatically);
      sampler.setFollowRedirects(samplerFollowRedirects);
      sampler.setUseKeepAlive(useKeepAlive);
      sampler.setImageParser(samplerDownloadImages);

      placeSampler(sampler, subConfigs, myTarget);
    }
    else {
      if(log.isDebugEnabled()) {
        log.debug("Sample excluded based on url or content-type: " + result.getUrlAsString() + " - " + result.getContentType());
      }
      result.setSampleLabel("["+result.getSampleLabel()+"]");
    }
    // SampleEvent is not passed JMeterVariables, because they don't make sense for Proxy Recording
    notifySampleListeners(new SampleEvent(result, "WorkBench")); // TODO - is this the correct threadgroup name?
  }

  public void stopProxy() {
    if (server != null) {
      server.stopServer();
      try {
        server.join(1000); // wait for server to stop
      } catch (InterruptedException e) {
      }
      notifyTestListenersOfEnd();
      server = null;
    }
  }

    // Package protected to allow test case access
    boolean filterUrl(HTTPSamplerBase sampler) {
    String domain = sampler.getDomain();
    if (domain == null || domain.length() == 0) {
      return false;
    }

    String url = generateMatchUrl(sampler);
    CollectionProperty includePatterns = getIncludePatterns();
    if (includePatterns.size() > 0) {
      if (!matchesPatterns(url, includePatterns)) {
        return false;
      }
    }

    CollectionProperty excludePatterns = getExcludePatterns();
    if (excludePatterns.size() > 0) {
      if (matchesPatterns(url, excludePatterns)) {
        return false;
      }
    }

    return true;
  }

    // Package protected to allow test case access
    /**
     * Filter the response based on the content type.
     * If no include nor exclude filter is specified, the result will be included
     *
     * @param result the sample result to check
     */
    boolean filterContentType(SampleResult result) {
      String includeExp = getContentTypeInclude();
      String excludeExp = getContentTypeExclude();
      // If no expressions are specified, we let the sample pass
      if((includeExp == null || includeExp.length() == 0) &&
          (excludeExp == null || excludeExp.length() == 0)
          )
      {
        return true;
      }
     
      // Check that we have a content type
      String sampleContentType = result.getContentType();     
      if(sampleContentType == null || sampleContentType.length() == 0) {
          if(log.isDebugEnabled()) {
            log.debug("No Content-type found for : " + result.getUrlAsString());
          }
       
        return true;
      }

      if(log.isDebugEnabled()) {
        log.debug("Content-type to filter : " + sampleContentType);
      }
      // Check if the include pattern is mathed
      if(includeExp != null && includeExp.length() > 0) {
          if(log.isDebugEnabled()) {
            log.debug("Include expression : " + includeExp);
          }       
       
        Pattern pattern = null;
        try {
          pattern = JMeterUtils.getPatternCache().getPattern(includeExp, Perl5Compiler.READ_ONLY_MASK | Perl5Compiler.SINGLELINE_MASK);
          if(!JMeterUtils.getMatcher().contains(sampleContentType, pattern)) {
            return false;
          }
        } catch (MalformedCachePatternException e) {
          log.warn("Skipped invalid content include pattern: " + includeExp, e);
        }
      }

      // Check if the exclude pattern is mathed
      if(excludeExp != null && excludeExp.length() > 0) {
          if(log.isDebugEnabled()) {
            log.debug("Exclude expression : " + excludeExp);
          }

        Pattern pattern = null;
        try {
          pattern = JMeterUtils.getPatternCache().getPattern(excludeExp, Perl5Compiler.READ_ONLY_MASK | Perl5Compiler.SINGLELINE_MASK);
          if(JMeterUtils.getMatcher().contains(sampleContentType, pattern)) {
            return false;
          }
        } catch (MalformedCachePatternException e) {
          log.warn("Skipped invalid content exclude pattern: " + includeExp, e);
        }
      }

      return true;
  }

  /*
   * Helper method to add a Response Assertion
   */
  private void addAssertion(JMeterTreeModel model, JMeterTreeNode node) throws IllegalUserActionException {
    ResponseAssertion ra = new ResponseAssertion();
    ra.setProperty(TestElement.GUI_CLASS, ASSERTION_GUI);
    ra.setName("Check response");
    ra.setTestFieldResponseData();
    model.addComponent(ra, node);
  }

  /*
   * Helper method to add a Divider
   */
  private void addDivider(JMeterTreeModel model, JMeterTreeNode node) throws IllegalUserActionException {
    GenericController sc = new GenericController();
    sc.setProperty(TestElement.GUI_CLASS, LOGIC_CONTROLLER_GUI);
    sc.setName("-------------------"); // $NON-NLS-1$
    model.addComponent(sc, node);
  }

  /**
   * Helper method to add a Simple Controller to contain the samplers.
   *
   * @param model
   *            Test component tree model
   * @param node
   *            Node in the tree where we will add the Controller
   * @param name
   *            A name for the Controller
   */
  private void addSimpleController(JMeterTreeModel model, JMeterTreeNode node, String name)
      throws IllegalUserActionException {
    GenericController sc = new GenericController();
    sc.setProperty(TestElement.GUI_CLASS, LOGIC_CONTROLLER_GUI);
    sc.setName(name);
    model.addComponent(sc, node);
  }

  /**
   * Helpler method to replicate any timers found within the Proxy Controller
   * into the provided sampler, while replacing any occurences of string _T_
   * in the timer's configuration with the provided deltaT.
   *
   * @param model
   *            Test component tree model
   * @param node
   *            Sampler node in where we will add the timers
   * @param deltaT
   *            Time interval from the previous request
   */
  private void addTimers(JMeterTreeModel model, JMeterTreeNode node, long deltaT) {
    TestPlan variables = new TestPlan();
    variables.addParameter("T", Long.toString(deltaT)); // $NON-NLS-1$
    ValueReplacer replacer = new ValueReplacer(variables);
    JMeterTreeNode mySelf = model.getNodeOf(this);
    Enumeration children = mySelf.children();
    while (children.hasMoreElements()) {
      JMeterTreeNode templateNode = (JMeterTreeNode) children.nextElement();
      if (templateNode.isEnabled()) {
        TestElement template = templateNode.getTestElement();
        if (template instanceof Timer) {
          TestElement timer = (TestElement) template.clone();
          try {
            replacer.undoReverseReplace(timer);
            model.addComponent(timer, node);
          } catch (InvalidVariableException e) {
            // Not 100% sure, but I believe this can't happen, so
            // I'll log and throw an error:
            log.error("Program error", e);
            throw new Error(e);
          } catch (IllegalUserActionException e) {
            // Not 100% sure, but I believe this can't happen, so
            // I'll log and throw an error:
            log.error("Program error", e);
            throw new Error(e);
          }
        }
      }
    }
  }

  /**
   * Finds the first enabled node of a given type in the tree.
   *
   * @param type
   *            class of the node to be found
   *
   * @return the first node of the given type in the test component tree, or
   *         <code>null</code> if none was found.
   */
  private JMeterTreeNode findFirstNodeOfType(Class type) {
    JMeterTreeModel treeModel = GuiPackage.getInstance().getTreeModel();
    List nodes = treeModel.getNodesOfType(type);
    Iterator iter = nodes.iterator();
    while (iter.hasNext()) {
      JMeterTreeNode node = (JMeterTreeNode) iter.next();
      if (node.isEnabled()) {
        return node;
      }
    }
    return null;
  }

  /**
   * Finds the controller where samplers have to be stored, that is:
   * <ul>
   * <li>The controller specified by the <code>target</code> property.
   * <li>If none was specified, the first RecordingController in the tree.
   * <li>If none is found, the first ThreadGroup in the tree.
   * <li>If none is found, the Workspace.
   * </ul>
   *
   * @return the tree node for the controller where the proxy must store the
   *         generated samplers.
   */
  private JMeterTreeNode findTargetControllerNode() {
    JMeterTreeNode myTarget = getTarget();
    if (myTarget != null) {
      return myTarget;
    }
    myTarget = findFirstNodeOfType(RecordingController.class);
    if (myTarget != null) {
      return myTarget;
    }
    myTarget = findFirstNodeOfType(ThreadGroup.class);
    if (myTarget != null) {
      return myTarget;
    }
    myTarget = findFirstNodeOfType(WorkBench.class);
    if (myTarget != null) {
      return myTarget;
    }
    log.error("Program error: proxy recording target not found.");
    return null;
  }

  /**
   * Finds all configuration objects of the given class applicable to the
   * recorded samplers, that is:
   * <ul>
   * <li>All such elements directly within the HTTP Proxy Server (these have
   * the highest priority).
   * <li>All such elements directly within the target controller (higher
   * priority) or directly within any containing controller (lower priority),
   * including the Test Plan itself (lowest priority).
   * </ul>
   *
   * @param myTarget
   *            tree node for the recording target controller.
   * @param myClass
   *            Class of the elements to be found.
   * @param ascending
   *            true if returned elements should be ordered in ascending
   *            priority, false if they should be in descending priority.
   *
   * @return a collection of applicable objects of the given class.
   */
  private Collection findApplicableElements(JMeterTreeNode myTarget, Class myClass, boolean ascending) {
    JMeterTreeModel treeModel = GuiPackage.getInstance().getTreeModel();
    LinkedList elements = new LinkedList();

    // Look for elements directly within the HTTP proxy:
    Enumeration kids = treeModel.getNodeOf(this).children();
    while (kids.hasMoreElements()) {
      JMeterTreeNode subNode = (JMeterTreeNode) kids.nextElement();
      if (subNode.isEnabled()) {
        TestElement element = (TestElement) subNode.getUserObject();
        if (myClass.isInstance(element)) {
          if (ascending) {
            elements.addFirst(element);
          } else {
            elements.add(element);
          }
        }
      }
    }

    // Look for arguments elements in the target controller or higher up:
    for (JMeterTreeNode controller = myTarget; controller != null; controller = (JMeterTreeNode) controller
        .getParent()) {
      kids = controller.children();
      while (kids.hasMoreElements()) {
        JMeterTreeNode subNode = (JMeterTreeNode) kids.nextElement();
        if (subNode.isEnabled()) {
          TestElement element = (TestElement) subNode.getUserObject();
          if (myClass.isInstance(element)) {
            log.debug("Applicable: " + element.getName());
            if (ascending) {
              elements.addFirst(element);
            } else {
              elements.add(element);
            }
          }

          // Special case for the TestPlan's Arguments sub-element:
          if (element instanceof TestPlan) {
            TestPlan tp = (TestPlan) element;
            Arguments args = tp.getArguments();
            if (myClass.isInstance(args)) {
              if (ascending) {
                elements.addFirst(args);
              } else {
                elements.add(args);
              }
            }
          }
        }
      }
    }

    return elements;
  }

  private void placeSampler(HTTPSamplerBase sampler, TestElement[] subConfigs, JMeterTreeNode myTarget) {
    try {
      JMeterTreeModel treeModel = GuiPackage.getInstance().getTreeModel();

      boolean firstInBatch = false;
      long now = System.currentTimeMillis();
      long deltaT = now - lastTime;
      if (deltaT > sampleGap) {
        if (!myTarget.isLeaf() && groupingMode == GROUPING_ADD_SEPARATORS) {
          addDivider(treeModel, myTarget);
        }
        if (groupingMode == GROUPING_IN_CONTROLLERS) {
          addSimpleController(treeModel, myTarget, sampler.getName());
        }
        firstInBatch = true;// Remember this was first in its batch
      }
      if (lastTime == 0) {
        deltaT = 0; // Decent value for timers
      }
      lastTime = now;

      if (groupingMode == GROUPING_STORE_FIRST_ONLY) {
        if (!firstInBatch) {
          return; // Huh! don't store this one!
        }

        // If we're not storing subsequent samplers, we'll need the
        // first sampler to do all the work...:
        sampler.setFollowRedirects(true);
        sampler.setImageParser(true);
      }

      if (groupingMode == GROUPING_IN_CONTROLLERS) {
        // Find the last controller in the target to store the
        // sampler there:
        for (int i = myTarget.getChildCount() - 1; i >= 0; i--) {
          JMeterTreeNode c = (JMeterTreeNode) myTarget.getChildAt(i);
          if (c.getTestElement() instanceof GenericController) {
            myTarget = c;
            break;
          }
        }
      }

      JMeterTreeNode newNode = treeModel.addComponent(sampler, myTarget);

      if (firstInBatch) {
        if (addAssertions) {
          addAssertion(treeModel, newNode);
        }
        addTimers(treeModel, newNode, deltaT);
        firstInBatch = false;
      }

      for (int i = 0; subConfigs != null && i < subConfigs.length; i++) {
        if (subConfigs[i] instanceof HeaderManager) {
          subConfigs[i].setProperty(TestElement.GUI_CLASS, HEADER_PANEL);
          treeModel.addComponent(subConfigs[i], newNode);
        }
      }
    } catch (IllegalUserActionException e) {
      JMeterUtils.reportErrorToUser(e.getMessage());
    }
  }

  /**
   * Remove from the sampler all values which match the one provided by the
   * first configuration in the given collection which provides a value for
   * that property.
   *
   * @param sampler
   *            Sampler to remove values from.
   * @param configurations
   *            ConfigTestElements in descending priority.
   */
  private void removeValuesFromSampler(HTTPSamplerBase sampler, Collection configurations) {
    for (PropertyIterator props = sampler.propertyIterator(); props.hasNext();) {
      JMeterProperty prop = props.next();
      String name = prop.getName();
      String value = prop.getStringValue();

      // There's a few properties which are excluded from this processing:
      if (name.equals(TestElement.ENABLED) || name.equals(TestElement.GUI_CLASS) || name.equals(TestElement.NAME)
          || name.equals(TestElement.TEST_CLASS)) {
        continue; // go on with next property.
      }

      for (Iterator configs = configurations.iterator(); configs.hasNext();) {
        ConfigTestElement config = (ConfigTestElement) configs.next();

        String configValue = config.getPropertyAsString(name);

        if (configValue != null && configValue.length() > 0) {
          if (configValue.equals(value)) {
            sampler.setProperty(name, ""); // $NON-NLS-1$
          }
          // Property was found in a config element. Whether or not
          // it matched the value in the sampler, we're done with
          // this property -- don't look at lower-priority configs:
          break;
        }
      }
    }
  }

  private String generateMatchUrl(HTTPSamplerBase sampler) {
    StringBuffer buf = new StringBuffer(sampler.getDomain());
    buf.append(':'); // $NON-NLS-1$
    buf.append(sampler.getPort());
    buf.append(sampler.getPath());
    if (sampler.getQueryString().length() > 0) {
      buf.append('?'); // $NON-NLS-1$
      buf.append(sampler.getQueryString());
    }
    return buf.toString();
  }

  private boolean matchesPatterns(String url, CollectionProperty patterns) {
    PropertyIterator iter = patterns.iterator();
    while (iter.hasNext()) {
      String item = iter.next().getStringValue();
      Pattern pattern = null;
      try {
        pattern = JMeterUtils.getPatternCache().getPattern(item, Perl5Compiler.READ_ONLY_MASK | Perl5Compiler.SINGLELINE_MASK);
        if (JMeterUtils.getMatcher().matches(url, pattern)) {
          return true;
        }
      } catch (MalformedCachePatternException e) {
        log.warn("Skipped invalid pattern: " + item, e);
      }
    }
    return false;
  }

  /**
   * Scan all test elements passed in for values matching the value of any of
   * the variables in any of the variable-holding elements in the collection.
   *
   * @param sampler
   *            A TestElement to replace values on
   * @param configs
   *            More TestElements to replace values on
   * @param variables
   *            Collection of Arguments to use to do the replacement, ordered
   *            by ascending priority.
   */
  private void replaceValues(TestElement sampler, TestElement[] configs, Collection variables) {
    // Build the replacer from all the variables in the collection:
    ValueReplacer replacer = new ValueReplacer();
    for (Iterator vars = variables.iterator(); vars.hasNext();) {
      replacer.addVariables(((Arguments) vars.next()).getArgumentsAsMap());
    }

    try {
      replacer.reverseReplace(sampler, regexMatch);
      for (int i = 0; i < configs.length; i++) {
        if (configs[i] != null) {
          replacer.reverseReplace(configs[i], regexMatch);
        }

      }
    } catch (InvalidVariableException e) {
      log.warn("Invalid variables included for replacement into recorded " + "sample", e);
    }
  }

  /**
   * This will notify sample listeners directly within the Proxy of the
   * sampling that just occured -- so that we have a means to record the
   * server's responses as we go.
   *
   * @param event
   *            sampling event to be delivered
   */
  private void notifySampleListeners(SampleEvent event) {
    JMeterTreeModel treeModel = GuiPackage.getInstance().getTreeModel();
    JMeterTreeNode myNode = treeModel.getNodeOf(this);
    Enumeration kids = myNode.children();
    while (kids.hasMoreElements()) {
      JMeterTreeNode subNode = (JMeterTreeNode) kids.nextElement();
      if (subNode.isEnabled()) {
        TestElement testElement = subNode.getTestElement();
        if (testElement instanceof SampleListener) {
          ((SampleListener) testElement).sampleOccurred(event);
        }
      }
    }
  }

  /**
   * This will notify test listeners directly within the Proxy that the 'test'
   * (here meaning the proxy recording) has started.
   */
  private void notifyTestListenersOfStart() {
    JMeterTreeModel treeModel = GuiPackage.getInstance().getTreeModel();
    JMeterTreeNode myNode = treeModel.getNodeOf(this);
    Enumeration kids = myNode.children();
    while (kids.hasMoreElements()) {
      JMeterTreeNode subNode = (JMeterTreeNode) kids.nextElement();
      if (subNode.isEnabled()) {
        TestElement testElement = subNode.getTestElement();
        if (testElement instanceof TestListener) {
          ((TestListener) testElement).testStarted();
        }
      }
    }
  }

  /**
   * This will notify test listeners directly within the Proxy that the 'test'
   * (here meaning the proxy recording) has ended.
   */
  private void notifyTestListenersOfEnd() {
    JMeterTreeModel treeModel = GuiPackage.getInstance().getTreeModel();
    JMeterTreeNode myNode = treeModel.getNodeOf(this);
    Enumeration kids = myNode.children();
    while (kids.hasMoreElements()) {
      JMeterTreeNode subNode = (JMeterTreeNode) kids.nextElement();
      if (subNode.isEnabled()) {
        TestElement testElement = subNode.getTestElement();
        if (testElement instanceof TestListener) {
          ((TestListener) testElement).testEnded();
        }
      }
    }
  }

  public boolean canRemove() {
    return null == server;
  }
}
TOP

Related Classes of org.apache.jmeter.protocol.http.proxy.ProxyControl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.