Package org.apache.jmeter.extractor

Source Code of org.apache.jmeter.extractor.RegexExtractor

/*
* 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.extractor;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

import org.apache.jmeter.processor.PostProcessor;
import org.apache.jmeter.samplers.SampleResult;
import org.apache.jmeter.testelement.AbstractTestElement;
import org.apache.jmeter.testelement.property.IntegerProperty;
import org.apache.jmeter.threads.JMeterContext;
import org.apache.jmeter.threads.JMeterVariables;
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.MatchResult;
import org.apache.oro.text.regex.Pattern;
import org.apache.oro.text.regex.PatternMatcher;
import org.apache.oro.text.regex.PatternMatcherInput;
import org.apache.oro.text.regex.Perl5Compiler;
import org.apache.oro.text.regex.Perl5Matcher;
import org.apache.oro.text.regex.Util;

// @see org.apache.jmeter.extractor.TestRegexExtractor for unit tests

public class RegexExtractor extends AbstractTestElement implements PostProcessor, Serializable {


  private static final Logger log = LoggingManager.getLoggerForClass();

  // What to match against. N.B. do not change the string value or test plans will break!
  private static final String MATCH_AGAINST = "RegexExtractor.useHeaders"; // $NON-NLS-1$
  /*
   * Permissible values:
   *  true - match against headers
   *  false or absent - match against body (this was the original default)
   *  URL - match against URL
   *  These are passed to the setUseField() method
   * 
   *  Do not change these values!
  */
  public static final String USE_HDRS = "true"; // $NON-NLS-1$
  public static final String USE_BODY = "false"; // $NON-NLS-1$
    public static final String USE_URL = "URL"; // $NON-NLS-1$
  public static final String USE_CODE = "code"; // $NON-NLS-1$
  public static final String USE_MESSAGE = "message"; // $NON-NLS-1$


  private static final String REGEX = "RegexExtractor.regex"; // $NON-NLS-1$

  private static final String REFNAME = "RegexExtractor.refname"; // $NON-NLS-1$

  private static final String MATCH_NUMBER = "RegexExtractor.match_number"; // $NON-NLS-1$

  private static final String DEFAULT = "RegexExtractor.default"; // $NON-NLS-1$

  private static final String TEMPLATE = "RegexExtractor.template"; // $NON-NLS-1$

    private static final String REF_MATCH_NR = "_matchNr"; // $NON-NLS-1$

    private static final String UNDERSCORE = "_"// $NON-NLS-1$


    private Object[] template = null;

  /**
   * Parses the response data using regular expressions and saving the results
   * into variables for use later in the test.
   *
   * @see org.apache.jmeter.processor.PostProcessor#process()
   */
  public void process() {
    initTemplate();
    JMeterContext context = getThreadContext();
    SampleResult previousResult = context.getPreviousResult();
    if (previousResult == null) {
      return;
    }
    log.debug("RegexExtractor processing result");

    // Fetch some variables
    JMeterVariables vars = context.getVariables();
    String refName = getRefName();
    int matchNumber = getMatchNumber();

    final String defaultValue = getDefaultValue();
        if (defaultValue.length() > 0){// Only replace default if it is provided
            vars.put(refName, defaultValue);
        }

    Perl5Matcher matcher = JMeterUtils.getMatcher();
    String inputString =
        useUrl() ? previousResult.getUrlAsString() // Bug 39707
      : useHeaders() ? previousResult.getResponseHeaders()
      : useCode() ? previousResult.getResponseCode() //Bug 43451
      : useMessage() ? previousResult.getResponseMessage() //Bug 43451
        : previousResult.getResponseDataAsString() // Bug 36898
        ;
       if (log.isDebugEnabled()) {
         log.debug("Input = " + inputString);
       }
    PatternMatcherInput input = new PatternMatcherInput(inputString);
       String regex = getRegex();
    if (log.isDebugEnabled()) {
      log.debug("Regex = " + regex);
       }
    try {
      Pattern pattern = JMeterUtils.getPatternCache().getPattern(regex, Perl5Compiler.READ_ONLY_MASK);
      List matches = new ArrayList();
      int x = 0;
      boolean done = false;
      do {
        if (matcher.contains(input, pattern)) {
          log.debug("RegexExtractor: Match found!");
          matches.add(matcher.getMatch());
        } else {
          done = true;
        }
        x++;
      } while (x != matchNumber && !done);

            int prevCount = 0;
            String prevString = vars.get(refName + REF_MATCH_NR);
            if (prevString != null) {
                vars.remove(refName + REF_MATCH_NR);// ensure old value is not left defined
                try {
                    prevCount = Integer.parseInt(prevString);
                } catch (NumberFormatException e1) {
                    log.warn("Could not parse "+prevString+" "+e1);
                }
            }
            int matchCount=0;// Number of refName_n variable sets to keep
      try {
        MatchResult match;
        if (matchNumber >= 0) {// Original match behaviour
          match = getCorrectMatch(matches, matchNumber);
          if (match != null) {
            vars.put(refName, generateResult(match));
            saveGroups(vars, refName, match);
          } else {
              // refname has already been set to the default (if present)
              removeGroups(vars, refName);
                    }
        } else // < 0 means we save all the matches
        {
                    removeGroups(vars, refName); // remove any single matches
            matchCount = matches.size();
          vars.put(refName + REF_MATCH_NR, Integer.toString(matchCount));// Save the count
          for (int i = 1; i <= matchCount; i++) {
            match = getCorrectMatch(matches, i);
            if (match != null) {
                        final String refName_n = new StringBuffer(refName).append(UNDERSCORE).append(i).toString();
                            vars.put(refName_n, generateResult(match));
              saveGroups(vars, refName_n, match);
            }
          }
        }
        // Remove any left-over variables
                for (int i = matchCount + 1; i <= prevCount; i++) {
                    final String refName_n = new StringBuffer(refName).append(UNDERSCORE).append(i).toString();
                    vars.remove(refName_n);
                    removeGroups(vars, refName_n);
                }
      } catch (RuntimeException e) {
        log.warn("Error while generating result");
      }
    } catch (MalformedCachePatternException e) {
      log.warn("Error in pattern: " + regex);
    }
  }

  /**
   * Creates the variables:<br/>
   * basename_gn, where n=0...# of groups<br/>
   * basename_g = number of groups (apart from g0)
   */
  private void saveGroups(JMeterVariables vars, String basename, MatchResult match) {
    StringBuffer buf = new StringBuffer();
        buf.append(basename);
        buf.append("_g"); // $NON-NLS-1$
        int pfxlen=buf.length();
        String prevString=vars.get(buf.toString());
        int previous=0;
        if (prevString!=null){
            try {
                previous=Integer.parseInt(prevString);
            } catch (NumberFormatException e) {
                log.warn("Could not parse "+prevString+" "+e);               
            }
        }
        //Note: match.groups() includes group 0
    final int groups = match.groups();
        for (int x = 0; x < groups; x++) {
      buf.append(x);
      vars.put(buf.toString(), match.group(x));
      buf.setLength(pfxlen);
    }
        vars.put(buf.toString(), Integer.toString(groups-1));
        for (int i = groups; i <= previous; i++){
            buf.append(i);
            vars.remove(buf.toString());// remove the remaining _gn vars
            buf.setLength(pfxlen);           
        }
  }

    /**
     * Removes the variables:<br/>
     * basename_gn, where n=0...# of groups<br/>
     * basename_g = number of groups (apart from g0)
     */
    private void removeGroups(JMeterVariables vars, String basename) {
        StringBuffer buf = new StringBuffer();
        buf.append(basename);
        buf.append("_g"); // $NON-NLS-1$
        int pfxlen=buf.length();
        // How many groups are there?
        int groups;
        try {
            groups=Integer.parseInt(vars.get(buf.toString()));
        } catch (NumberFormatException e) {
            groups=0;
        }
        vars.remove(buf.toString());// Remove the group count
        for (int i = 0; i <= groups; i++) {
            buf.append(i);
            vars.remove(buf.toString());// remove the g0,g1...gn vars
            buf.setLength(pfxlen);
        }
    }

  public Object clone() {
    RegexExtractor cloned = (RegexExtractor) super.clone();
    cloned.template = this.template;
    return cloned;
  }

  private String generateResult(MatchResult match) {
    StringBuffer result = new StringBuffer();
    for (int a = 0; a < template.length; a++) {
      log.debug("RegexExtractor: Template piece #" + a + " = " + template[a]);
      if (template[a] instanceof String) {
        result.append(template[a]);
      } else {
        result.append(match.group(((Integer) template[a]).intValue()));
      }
    }
    log.debug("Regex Extractor result = " + result.toString());
    return result.toString();
  }

  private void initTemplate() {
    if (template != null) {
      return;
    }
    List pieces = new ArrayList();
    List combined = new LinkedList();
    String rawTemplate = getTemplate();
    PatternMatcher matcher = JMeterUtils.getMatcher();
    Pattern templatePattern = JMeterUtils.getPatternCache().getPattern("\\$(\\d+)\\$"  // $NON-NLS-1$
                , Perl5Compiler.READ_ONLY_MASK
        & Perl5Compiler.SINGLELINE_MASK);
    log.debug("Pattern = " + templatePattern);
    log.debug("template = " + rawTemplate);
    Util.split(pieces, matcher, templatePattern, rawTemplate);
    PatternMatcherInput input = new PatternMatcherInput(rawTemplate);
    boolean startsWith = isFirstElementGroup(rawTemplate);
    log.debug("template split into " + pieces.size() + " pieces, starts with = " + startsWith);
    if (startsWith) {
      pieces.remove(0);// Remove initial empty entry
    }
    Iterator iter = pieces.iterator();
    while (iter.hasNext()) {
      boolean matchExists = matcher.contains(input, templatePattern);
      if (startsWith) {
        if (matchExists) {
          combined.add(new Integer(matcher.getMatch().group(1)));
        }
        combined.add(iter.next());
      } else {
        combined.add(iter.next());
        if (matchExists) {
          combined.add(new Integer(matcher.getMatch().group(1)));
        }
      }
    }
    if (matcher.contains(input, templatePattern)) {
      log.debug("Template does end with template pattern");
      combined.add(new Integer(matcher.getMatch().group(1)));
    }
    template = combined.toArray();
  }

  private boolean isFirstElementGroup(String rawData) {
    try {
      Pattern pattern = JMeterUtils.getPatternCache().getPattern("^\\$\\d+\\$" // $NON-NLS-1$
                    , Perl5Compiler.READ_ONLY_MASK
          & Perl5Compiler.SINGLELINE_MASK);
      return (JMeterUtils.getMatcher()).contains(rawData, pattern);
    } catch (RuntimeException e) {
      log.error("", e);
      return false;
    }
  }

  /**
   * Grab the appropriate result from the list.
   *
   * @param matches
   *            list of matches
   * @param entry
   *            the entry number in the list
   * @return MatchResult
   */
  private MatchResult getCorrectMatch(List matches, int entry) {
    int matchSize = matches.size();

    if (matchSize <= 0 || entry > matchSize){
        return null;
    }

    if (entry == 0) // Random match
    {
      return (MatchResult) matches.get(JMeterUtils.getRandomInt(matchSize));
    }

    return (MatchResult) matches.get(entry - 1);
  }

  public void setRegex(String regex) {
    setProperty(REGEX, regex);
  }

  public String getRegex() {
    return getPropertyAsString(REGEX);
  }

  public void setRefName(String refName) {
    setProperty(REFNAME, refName);
  }

  public String getRefName() {
    return getPropertyAsString(REFNAME);
  }

  /**
   * Set which Match to use. This can be any positive number, indicating the
   * exact match to use, or 0, which is interpreted as meaning random.
   *
   * @param matchNumber
   */
  public void setMatchNumber(int matchNumber) {
    setProperty(new IntegerProperty(MATCH_NUMBER, matchNumber));
  }

  public void setMatchNumber(String matchNumber) {
    setProperty(MATCH_NUMBER, matchNumber);
  }

  public int getMatchNumber() {
    return getPropertyAsInt(MATCH_NUMBER);
  }

  public String getMatchNumberAsString() {
    return getPropertyAsString(MATCH_NUMBER);
  }

  /**
   * Sets the value of the variable if no matches are found
   *
   * @param defaultValue
   */
  public void setDefaultValue(String defaultValue) {
    setProperty(DEFAULT, defaultValue);
  }

  public String getDefaultValue() {
    return getPropertyAsString(DEFAULT);
  }

  public void setTemplate(String template) {
    setProperty(TEMPLATE, template);
  }

  public String getTemplate() {
    return getPropertyAsString(TEMPLATE);
  }

  public boolean useHeaders() {
    return USE_HDRS.equalsIgnoreCase( getPropertyAsString(MATCH_AGAINST));
  }

  // Allow for property not yet being set (probably only applies to Test cases)
  public boolean useBody() {
      String prop = getPropertyAsString(MATCH_AGAINST);
        return prop.length()==0 || USE_BODY.equalsIgnoreCase(prop);// $NON-NLS-1$
    }

  public boolean useUrl() {
      String prop = getPropertyAsString(MATCH_AGAINST);
        return USE_URL.equalsIgnoreCase(prop);
    }

  public boolean useCode() {
      String prop = getPropertyAsString(MATCH_AGAINST);
        return USE_CODE.equalsIgnoreCase(prop);
  }

  public boolean useMessage() {
      String prop = getPropertyAsString(MATCH_AGAINST);
        return USE_MESSAGE.equalsIgnoreCase(prop);
  }

  public void setUseField(String actionCommand) {
    setProperty(MATCH_AGAINST,actionCommand);
  }
}
TOP

Related Classes of org.apache.jmeter.extractor.RegexExtractor

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.