alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

What this is

This file is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Other links

The source code

// $Header: /home/cvs/jakarta-jmeter/src/components/org/apache/jmeter/extractor/RegexExtractor.java,v 1.15.2.1 2004/05/19 23:17:01 sebb Exp $
/*
 * Copyright 2003-2004 The Apache Software Foundation.
 *
 * Licensed 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 junit.framework.TestCase;

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.JMeterContextService;
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.PatternCacheLRU;
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;

/**
 * @version $Revision: 1.15.2.1 $
 */
public class RegexExtractor
    extends AbstractTestElement
    implements PostProcessor, Serializable
{
    transient private static Logger log = LoggingManager.getLoggerForClass();
    public static final String USEHEADERS = "RegexExtractor.useHeaders";
    public static final String REGEX = "RegexExtractor.regex";
    public static final String REFNAME = "RegexExtractor.refname";
    public static final String MATCH_NUMBER = "RegexExtractor.match_number";
    public static final String DEFAULT = "RegexExtractor.default";
    public static final String TEMPLATE = "RegexExtractor.template";
    private Object[] template = null;

    private static PatternCacheLRU patternCache =
        new PatternCacheLRU(1000, new Perl5Compiler());
    private static ThreadLocal localMatcher = new ThreadLocal()
    {
        protected Object initialValue()
        {
            return new Perl5Matcher();
        }
    };

    /**
     * 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();
        if (context.getPreviousResult() == null
            || context.getPreviousResult().getResponseData() == null)
        {
            return;
        }
        log.debug("RegexExtractor processing result");

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

        vars.put(refName, getDefaultValue());
        
        Perl5Matcher matcher = (Perl5Matcher) localMatcher.get();
        PatternMatcherInput input =
            new PatternMatcherInput(
            		useHeaders() ? context.getPreviousResult().getResponseHeaders()
                                 : new String(context.getPreviousResult().getResponseData())
				);
        log.debug("Regex = " + getRegex());
		try {
			Pattern pattern =
			    patternCache.getPattern(getRegex(), 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);

			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 // < 0 means we save all the matches
				{
					int prevCount = 0;
					String prevString=(String)vars.get(refName+"_matchNr");
					if (prevString != null)
                    {
                    try
                    {
                        prevCount = Integer.parseInt(prevString);
                    }
                    catch (NumberFormatException e1)
                    {
                        // TODO Auto-generated catch block
                        e1.printStackTrace();
                    }
					}
					vars.put(refName+"_matchNr", ""+matches.size());// Save the count
					for (int i=1;i<=matches.size();i++) {
						match = getCorrectMatch(matches, i);
						if (match != null)
						{
							vars.put(refName+"_"+i, generateResult(match));
							saveGroups(vars, refName+"_"+i, match);
						}
					}
					for (int i = matches.size()+1;i<=prevCount;i++)
					{
						vars.remove(refName+"_"+i);
						vars.remove(refName+"_"+i+"_g0");// Remove known groups ...
						vars.remove(refName+"_"+i+"_g1");// ...
						//TODO remove other groups if present?
					}
				}
			}
			catch (RuntimeException e)
			{
			    log.warn("Error while generating result");
			}
		} catch (MalformedCachePatternException e) {
			log.warn("Error in pattern: "+ getRegex());
		}
    }

    private void saveGroups(
        JMeterVariables vars,
        String basename,
        MatchResult match)
    {
        StringBuffer buf = new StringBuffer();
        for (int x = 0; x < match.groups(); x++)
        {
            buf.append(basename);
            buf.append("_g");
            buf.append(x);
            vars.put(buf.toString(), match.group(x));
            buf.setLength(0);
        }
    }

    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 = (Perl5Matcher) localMatcher.get();
        Pattern templatePattern =
            patternCache.getPattern(
                "\\$(\\d+)\\$",
                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);
        Iterator iter = pieces.iterator();
        boolean startsWith = isFirstElementGroup(rawTemplate);
        log.debug(
            "template split into "
                + pieces.size()
                + " pieces, starts with = "
                + startsWith);
        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 =
                patternCache.getPattern(
                    "^\\$\\d+\\$",
                    Perl5Compiler.READ_ONLY_MASK
                        & Perl5Compiler.SINGLELINE_MASK);
            return ((Perl5Matcher) localMatcher.get()).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 int getMatchNumber()
    {
        return getPropertyAsInt(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);
    }

    private boolean useHeaders()
    {
    	return "true".equalsIgnoreCase(getPropertyAsString(USEHEADERS));
    }
    
    public static class Test extends TestCase
    {
        RegexExtractor extractor;
        SampleResult result;
        JMeterVariables vars;

        public Test(String name)
        {
            super(name);
        }

        private JMeterContext jmctx = null;

        public void setUp()
        {
        	jmctx = JMeterContextService.getContext();
            extractor = new RegexExtractor();
            extractor.setThreadContext(jmctx);// This would be done by the run command
            extractor.setRefName("regVal");
            result = new SampleResult();
            String data =
                "" +
                  "" +
                    "LIS_OK" +
                    "" +
                    "" +
                    "" +
                    "0" +
                    "1" +
                    "" +
                    "5" +
                    "" +
                    "6" +
                    "" +
                  "" +
                "";
            result.setResponseData(data.getBytes());
            result.setResponseHeaders("Header1: Value1\nHeader2: Value2");
            vars = new JMeterVariables();
            jmctx.setVariables(vars);
            jmctx.setPreviousResult(result);
        }

        public void testVariableExtraction() throws Exception
        {
            extractor.setRegex(
                "(\\d+)");
            extractor.setTemplate("$2$");
            extractor.setMatchNumber(2);
            extractor.process();
            assertEquals("5", vars.get("regVal"));
			assertEquals("pinposition2", vars.get("regVal_g1"));
			assertEquals("5", vars.get("regVal_g2"));
			assertEquals("5", vars.get("regVal_g0"));
        }

        public void testVariableExtraction2() throws Exception
        {
            extractor.setRegex(
                "(\\d+)");
            extractor.setTemplate("$1$");
            extractor.setMatchNumber(3);
            extractor.process();
            assertEquals("pinposition3", vars.get("regVal"));
        }

        public void testVariableExtraction6() throws Exception
        {
            extractor.setRegex(
                "(\\d+)");
            extractor.setTemplate("$2$");
            extractor.setMatchNumber(4);
            extractor.setDefaultValue("default");
            extractor.process();
            assertEquals("default", vars.get("regVal"));
        }

        public void testVariableExtraction3() throws Exception
        {
            extractor.setRegex(
                "(\\d+)");
            extractor.setTemplate("_$1$");
            extractor.setMatchNumber(2);
            extractor.process();
            assertEquals("_pinposition2", vars.get("regVal"));
        }
		public void testVariableExtraction5() throws Exception
		{
			extractor.setRegex(
				"(\\d+)");
			extractor.setTemplate("$1$");
			extractor.setMatchNumber(-1);
			extractor.process();
			assertEquals("3",vars.get("regVal_matchNr"));
			assertEquals("pinposition1", vars.get("regVal_1"));
			assertEquals("pinposition2", vars.get("regVal_2"));
			assertEquals("pinposition3", vars.get("regVal_3"));
			assertEquals("pinposition1", vars.get("regVal_1_g1"));
			assertEquals("1", vars.get("regVal_1_g2"));
			assertEquals("1", vars.get("regVal_1_g0"));
			assertNull(vars.get("regVal_4"));

            // Check old values don't hang around:
			extractor.setRegex("(\\w+)count"); // fewer matches
			extractor.process();
			assertEquals("2",vars.get("regVal_matchNr"));
			assertEquals("position", vars.get("regVal_1"));
			assertEquals("invalidpin", vars.get("regVal_2"));
			assertNull("Unused variables should be null",vars.get("regVal_3"));
			assertNull("Unused variables should be null",vars.get("regVal_3_g0"));
			assertNull("Unused variables should be null",vars.get("regVal_3_g1"));
		}
        public void testVariableExtraction7() throws Exception
        {
            extractor.setRegex(
                "Header1: (\\S+)");
            extractor.setTemplate("$1$");
            extractor.setMatchNumber(1);
            assertFalse("useHdrs should be false",extractor.useHeaders());
            extractor.setProperty(USEHEADERS,"true");
            assertTrue("useHdrs should be true",extractor.useHeaders());
            extractor.process();
            assertEquals("Value1", vars.get("regVal"));
        }
    }
}
... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.