KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > jmeter > extractor > RegexExtractor


1 // $Header: /home/cvs/jakarta-jmeter/src/components/org/apache/jmeter/extractor/RegexExtractor.java,v 1.15.2.2 2004/12/05 00:34:14 sebb Exp $
2
/*
3  * Copyright 2003-2004 The Apache Software Foundation.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17 */

18
19 package org.apache.jmeter.extractor;
20
21 import java.io.Serializable JavaDoc;
22 import java.util.ArrayList JavaDoc;
23 import java.util.Iterator JavaDoc;
24 import java.util.LinkedList JavaDoc;
25 import java.util.List JavaDoc;
26
27 import junit.framework.TestCase;
28
29 import org.apache.jmeter.processor.PostProcessor;
30 import org.apache.jmeter.samplers.SampleResult;
31 import org.apache.jmeter.testelement.AbstractTestElement;
32 import org.apache.jmeter.testelement.property.IntegerProperty;
33 import org.apache.jmeter.threads.JMeterContext;
34 import org.apache.jmeter.threads.JMeterContextService;
35 import org.apache.jmeter.threads.JMeterVariables;
36 import org.apache.jmeter.util.JMeterUtils;
37 import org.apache.jorphan.logging.LoggingManager;
38 import org.apache.log.Logger;
39 import org.apache.oro.text.MalformedCachePatternException;
40 import org.apache.oro.text.PatternCacheLRU;
41 import org.apache.oro.text.regex.MatchResult;
42 import org.apache.oro.text.regex.Pattern;
43 import org.apache.oro.text.regex.PatternMatcher;
44 import org.apache.oro.text.regex.PatternMatcherInput;
45 import org.apache.oro.text.regex.Perl5Compiler;
46 import org.apache.oro.text.regex.Perl5Matcher;
47 import org.apache.oro.text.regex.Util;
48
49 /**
50  * @version $Revision: 1.15.2.2 $
51  */

52 public class RegexExtractor
53     extends AbstractTestElement
54     implements PostProcessor, Serializable JavaDoc
55 {
56     transient private static Logger log = LoggingManager.getLoggerForClass();
57     public static final String JavaDoc USEHEADERS = "RegexExtractor.useHeaders";
58     public static final String JavaDoc REGEX = "RegexExtractor.regex";
59     public static final String JavaDoc REFNAME = "RegexExtractor.refname";
60     public static final String JavaDoc MATCH_NUMBER = "RegexExtractor.match_number";
61     public static final String JavaDoc DEFAULT = "RegexExtractor.default";
62     public static final String JavaDoc TEMPLATE = "RegexExtractor.template";
63     private Object JavaDoc[] template = null;
64
65     private static PatternCacheLRU patternCache =
66         new PatternCacheLRU(1000, new Perl5Compiler());
67     private static ThreadLocal JavaDoc localMatcher = new ThreadLocal JavaDoc()
68     {
69         protected Object JavaDoc initialValue()
70         {
71             return new Perl5Matcher();
72         }
73     };
74
75     /**
76      * Parses the response data using regular expressions and saving the results
77      * into variables for use later in the test.
78      * @see org.apache.jmeter.processor.PostProcessor#process()
79      */

80     public void process()
81     {
82         initTemplate();
83         JMeterContext context = getThreadContext();
84         if (context.getPreviousResult() == null
85             || context.getPreviousResult().getResponseData() == null)
86         {
87             return;
88         }
89         log.debug("RegexExtractor processing result");
90
91         // Fetch some variables
92
JMeterVariables vars = context.getVariables();
93         String JavaDoc refName = getRefName();
94         int matchNumber = getMatchNumber();
95
96         vars.put(refName, getDefaultValue());
97         
98         Perl5Matcher matcher = (Perl5Matcher) localMatcher.get();
99         PatternMatcherInput input =
100             new PatternMatcherInput(
101                     useHeaders() ? context.getPreviousResult().getResponseHeaders()
102                                  : new String JavaDoc(context.getPreviousResult().getResponseData())
103                 );
104         log.debug("Regex = " + getRegex());
105         try {
106             Pattern pattern =
107                 patternCache.getPattern(getRegex(), Perl5Compiler.READ_ONLY_MASK);
108             List JavaDoc matches = new ArrayList JavaDoc();
109             int x = 0;
110             boolean done = false;
111             do
112             {
113                 if (matcher.contains(input, pattern))
114                 {
115                     log.debug("RegexExtractor: Match found!");
116                     matches.add(matcher.getMatch());
117                 }
118                 else
119                 {
120                     done = true;
121                 }
122                 x++;
123             }
124             while (x != matchNumber && !done);
125
126             try
127             {
128                 MatchResult match;
129                 if (matchNumber >= 0){// Original match behaviour
130
match = getCorrectMatch(matches, matchNumber);
131                     if (match != null)
132                     {
133                         vars.put(refName, generateResult(match));
134                         saveGroups(vars, refName, match);
135                     }
136                 }
137                 else // < 0 means we save all the matches
138
{
139                     int prevCount = 0;
140                     String JavaDoc prevString=vars.get(refName+"_matchNr");
141                     if (prevString != null)
142                     {
143                     try
144                     {
145                         prevCount = Integer.parseInt(prevString);
146                     }
147                     catch (NumberFormatException JavaDoc e1)
148                     {
149                         // TODO Auto-generated catch block
150
e1.printStackTrace();
151                     }
152                     }
153                     vars.put(refName+"_matchNr", ""+matches.size());// Save the count
154
for (int i=1;i<=matches.size();i++) {
155                         match = getCorrectMatch(matches, i);
156                         if (match != null)
157                         {
158                             vars.put(refName+"_"+i, generateResult(match));
159                             saveGroups(vars, refName+"_"+i, match);
160                         }
161                     }
162                     for (int i = matches.size()+1;i<=prevCount;i++)
163                     {
164                         vars.remove(refName+"_"+i);
165                         vars.remove(refName+"_"+i+"_g0");// Remove known groups ...
166
vars.remove(refName+"_"+i+"_g1");// ...
167
//TODO remove other groups if present?
168
}
169                 }
170             }
171             catch (RuntimeException JavaDoc e)
172             {
173                 log.warn("Error while generating result");
174             }
175         } catch (MalformedCachePatternException e) {
176             log.warn("Error in pattern: "+ getRegex());
177         }
178     }
179
180     private void saveGroups(
181         JMeterVariables vars,
182         String JavaDoc basename,
183         MatchResult match)
184     {
185         StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
186         for (int x = 0; x < match.groups(); x++)
187         {
188             buf.append(basename);
189             buf.append("_g");
190             buf.append(x);
191             vars.put(buf.toString(), match.group(x));
192             buf.setLength(0);
193         }
194     }
195
196     public Object JavaDoc clone()
197     {
198         RegexExtractor cloned = (RegexExtractor) super.clone();
199         cloned.template = this.template;
200         return cloned;
201     }
202
203     private String JavaDoc generateResult(MatchResult match)
204     {
205         StringBuffer JavaDoc result = new StringBuffer JavaDoc();
206         for (int a = 0; a < template.length; a++)
207         {
208             log.debug(
209                 "RegexExtractor: Template piece #" + a + " = " + template[a]);
210             if (template[a] instanceof String JavaDoc)
211             {
212                 result.append(template[a]);
213             }
214             else
215             {
216                 result.append(match.group(((Integer JavaDoc) template[a]).intValue()));
217             }
218         }
219         log.debug("Regex Extractor result = " + result.toString());
220         return result.toString();
221     }
222
223     private void initTemplate()
224     {
225         if (template != null)
226         {
227             return;
228         }
229         List JavaDoc pieces = new ArrayList JavaDoc();
230         List JavaDoc combined = new LinkedList JavaDoc();
231         String JavaDoc rawTemplate = getTemplate();
232         PatternMatcher matcher = (Perl5Matcher) localMatcher.get();
233         Pattern templatePattern =
234             patternCache.getPattern(
235                 "\\$(\\d+)\\$",
236                 Perl5Compiler.READ_ONLY_MASK & Perl5Compiler.SINGLELINE_MASK);
237         log.debug("Pattern = " + templatePattern);
238         log.debug("template = " + rawTemplate);
239         Util.split(pieces, matcher, templatePattern, rawTemplate);
240         PatternMatcherInput input = new PatternMatcherInput(rawTemplate);
241         boolean startsWith = isFirstElementGroup(rawTemplate);
242         log.debug(
243             "template split into "
244                 + pieces.size()
245                 + " pieces, starts with = "
246                 + startsWith);
247         if (startsWith){
248             pieces.remove(0);// Remove initial empty entry
249
}
250         Iterator JavaDoc iter = pieces.iterator();
251         while (iter.hasNext())
252         {
253             boolean matchExists = matcher.contains(input, templatePattern);
254             if (startsWith)
255             {
256                 if (matchExists)
257                 {
258                     combined.add(new Integer JavaDoc(matcher.getMatch().group(1)));
259                 }
260                 combined.add(iter.next());
261             }
262             else
263             {
264                 combined.add(iter.next());
265                 if (matchExists)
266                 {
267                     combined.add(new Integer JavaDoc(matcher.getMatch().group(1)));
268                 }
269             }
270         }
271         if (matcher.contains(input, templatePattern))
272         {
273             log.debug("Template does end with template pattern");
274             combined.add(new Integer JavaDoc(matcher.getMatch().group(1)));
275         }
276         template = combined.toArray();
277     }
278
279     private boolean isFirstElementGroup(String JavaDoc rawData)
280     {
281         try
282         {
283             Pattern pattern =
284                 patternCache.getPattern(
285                     "^\\$\\d+\\$",
286                     Perl5Compiler.READ_ONLY_MASK
287                         & Perl5Compiler.SINGLELINE_MASK);
288             return ((Perl5Matcher) localMatcher.get()).contains(
289                 rawData,
290                 pattern);
291         }
292         catch (RuntimeException JavaDoc e)
293         {
294             log.error("", e);
295             return false;
296         }
297     }
298
299     /**
300      * Grab the appropriate result from the list.
301      * @param matches list of matches
302      * @param entry the entry number in the list
303      * @return MatchResult
304      */

305     private MatchResult getCorrectMatch(List JavaDoc matches, int entry)
306     {
307         int matchSize = matches.size();
308
309         if (matchSize <= 0 || entry > matchSize) return null;
310         
311         if (entry == 0) // Random match
312
{
313             return (MatchResult) matches.get(
314                 JMeterUtils.getRandomInt(matchSize));
315         }
316         
317         return (MatchResult) matches.get(entry - 1);
318     }
319
320     public void setRegex(String JavaDoc regex)
321     {
322         setProperty(REGEX, regex);
323     }
324     public String JavaDoc getRegex()
325     {
326         return getPropertyAsString(REGEX);
327     }
328     public void setRefName(String JavaDoc refName)
329     {
330         setProperty(REFNAME, refName);
331     }
332     public String JavaDoc getRefName()
333     {
334         return getPropertyAsString(REFNAME);
335     }
336     /**
337      * Set which Match to use. This can be any positive number, indicating the
338      * exact match to use, or 0, which is interpreted as meaning random.
339      * @param matchNumber
340      */

341     public void setMatchNumber(int matchNumber)
342     {
343         setProperty(new IntegerProperty(MATCH_NUMBER, matchNumber));
344     }
345
346     public int getMatchNumber()
347     {
348         return getPropertyAsInt(MATCH_NUMBER);
349     }
350
351     /**
352      * Sets the value of the variable if no matches are found
353      * @param defaultValue
354      */

355     public void setDefaultValue(String JavaDoc defaultValue)
356     {
357         setProperty(DEFAULT, defaultValue);
358     }
359
360     public String JavaDoc getDefaultValue()
361     {
362         return getPropertyAsString(DEFAULT);
363     }
364
365     public void setTemplate(String JavaDoc template)
366     {
367         setProperty(TEMPLATE, template);
368     }
369
370     public String JavaDoc getTemplate()
371     {
372         return getPropertyAsString(TEMPLATE);
373     }
374
375     private boolean useHeaders()
376     {
377         return "true".equalsIgnoreCase(getPropertyAsString(USEHEADERS));
378     }
379     
380     public static class Test extends TestCase
381     {
382         RegexExtractor extractor;
383         SampleResult result;
384         JMeterVariables vars;
385
386         public Test(String JavaDoc name)
387         {
388             super(name);
389         }
390
391         private JMeterContext jmctx = null;
392
393         public void setUp()
394         {
395             jmctx = JMeterContextService.getContext();
396             extractor = new RegexExtractor();
397             extractor.setThreadContext(jmctx);// This would be done by the run command
398
extractor.setRefName("regVal");
399             result = new SampleResult();
400             String JavaDoc data =
401                 "<company-xmlext-query-ret>" +
402                   "<row>" +
403                     "<value field=\"RetCode\">LIS_OK</value>" +
404                     "<value field=\"RetCodeExtension\"></value>" +
405                     "<value field=\"alias\"></value>" +
406                     "<value field=\"positioncount\"></value>" +
407                     "<value field=\"invalidpincount\">0</value>" +
408                     "<value field=\"pinposition1\">1</value>" +
409                     "<value field=\"pinpositionvalue1\"></value>" +
410                     "<value field=\"pinposition2\">5</value>" +
411                     "<value field=\"pinpositionvalue2\"></value>" +
412                     "<value field=\"pinposition3\">6</value>" +
413                     "<value field=\"pinpositionvalue3\"></value>" +
414                   "</row>" +
415                 "</company-xmlext-query-ret>";
416             result.setResponseData(data.getBytes());
417             result.setResponseHeaders("Header1: Value1\nHeader2: Value2");
418             vars = new JMeterVariables();
419             jmctx.setVariables(vars);
420             jmctx.setPreviousResult(result);
421         }
422
423         public void testVariableExtraction() throws Exception JavaDoc
424         {
425             extractor.setRegex(
426                 "<value field=\"(pinposition\\d+)\">(\\d+)</value>");
427             extractor.setTemplate("$2$");
428             extractor.setMatchNumber(2);
429             extractor.process();
430             assertEquals("5", vars.get("regVal"));
431             assertEquals("pinposition2", vars.get("regVal_g1"));
432             assertEquals("5", vars.get("regVal_g2"));
433             assertEquals("<value field=\"pinposition2\">5</value>", vars.get("regVal_g0"));
434         }
435
436         static void templateSetup(RegexExtractor rex,String JavaDoc tmp){
437             rex.setRegex("<company-(\\w+?)-(\\w+?)-(\\w+?)>");
438             rex.setMatchNumber(1);
439             rex.setTemplate(tmp);
440             rex.process();
441         }
442         public void testTemplate1() throws Exception JavaDoc
443         {
444             templateSetup(extractor,"");
445             assertEquals("<company-xmlext-query-ret>", vars.get("regVal_g0"));
446             assertEquals("xmlext", vars.get("regVal_g1"));
447             assertEquals("query", vars.get("regVal_g2"));
448             assertEquals("ret", vars.get("regVal_g3"));
449             assertEquals("", vars.get("regVal"));
450         }
451
452         public void testTemplate2() throws Exception JavaDoc
453         {
454             templateSetup(extractor,"ABC");
455             assertEquals("ABC", vars.get("regVal"));
456         }
457
458         public void testTemplate3() throws Exception JavaDoc
459         {
460             templateSetup(extractor,"$2$");
461             assertEquals("query", vars.get("regVal"));
462         }
463
464         public void testTemplate4() throws Exception JavaDoc
465         {
466             templateSetup(extractor,"PRE$2$");
467             assertEquals("PREquery", vars.get("regVal"));
468         }
469
470         public void testTemplate5() throws Exception JavaDoc
471         {
472             templateSetup(extractor,"$2$POST");
473             assertEquals("queryPOST", vars.get("regVal"));
474         }
475
476         public void testTemplate6() throws Exception JavaDoc
477         {
478             templateSetup(extractor,"$2$$1$");
479             assertEquals("queryxmlext", vars.get("regVal"));
480         }
481
482         public void testTemplate7() throws Exception JavaDoc
483         {
484             templateSetup(extractor,"$2$MID$1$");
485             assertEquals("queryMIDxmlext", vars.get("regVal"));
486         }
487
488         public void testVariableExtraction2() throws Exception JavaDoc
489         {
490             extractor.setRegex(
491                 "<value field=\"(pinposition\\d+)\">(\\d+)</value>");
492             extractor.setTemplate("$1$");
493             extractor.setMatchNumber(3);
494             extractor.process();
495             assertEquals("pinposition3", vars.get("regVal"));
496         }
497
498         public void testVariableExtraction6() throws Exception JavaDoc
499         {
500             extractor.setRegex(
501                 "<value field=\"(pinposition\\d+)\">(\\d+)</value>");
502             extractor.setTemplate("$2$");
503             extractor.setMatchNumber(4);
504             extractor.setDefaultValue("default");
505             extractor.process();
506             assertEquals("default", vars.get("regVal"));
507         }
508
509         public void testVariableExtraction3() throws Exception JavaDoc
510         {
511             extractor.setRegex(
512                 "<value field=\"(pinposition\\d+)\">(\\d+)</value>");
513             extractor.setTemplate("_$1$");
514             extractor.setMatchNumber(2);
515             extractor.process();
516             assertEquals("_pinposition2", vars.get("regVal"));
517         }
518         public void testVariableExtraction5() throws Exception JavaDoc
519         {
520             extractor.setRegex(
521                 "<value field=\"(pinposition\\d+)\">(\\d+)</value>");
522             extractor.setTemplate("$1$");
523             extractor.setMatchNumber(-1);
524             extractor.process();
525             assertEquals("3",vars.get("regVal_matchNr"));
526             assertEquals("pinposition1", vars.get("regVal_1"));
527             assertEquals("pinposition2", vars.get("regVal_2"));
528             assertEquals("pinposition3", vars.get("regVal_3"));
529             assertEquals("pinposition1", vars.get("regVal_1_g1"));
530             assertEquals("1", vars.get("regVal_1_g2"));
531             assertEquals("<value field=\"pinposition1\">1</value>", vars.get("regVal_1_g0"));
532             assertNull(vars.get("regVal_4"));
533
534             // Check old values don't hang around:
535
extractor.setRegex("(\\w+)count"); // fewer matches
536
extractor.process();
537             assertEquals("2",vars.get("regVal_matchNr"));
538             assertEquals("position", vars.get("regVal_1"));
539             assertEquals("invalidpin", vars.get("regVal_2"));
540             assertNull("Unused variables should be null",vars.get("regVal_3"));
541             assertNull("Unused variables should be null",vars.get("regVal_3_g0"));
542             assertNull("Unused variables should be null",vars.get("regVal_3_g1"));
543         }
544         public void testVariableExtraction7() throws Exception JavaDoc
545         {
546             extractor.setRegex(
547                 "Header1: (\\S+)");
548             extractor.setTemplate("$1$");
549             extractor.setMatchNumber(1);
550             assertFalse("useHdrs should be false",extractor.useHeaders());
551             extractor.setProperty(USEHEADERS,"true");
552             assertTrue("useHdrs should be true",extractor.useHeaders());
553             extractor.process();
554             assertEquals("Value1", vars.get("regVal"));
555         }
556     }
557 }
558
Popular Tags