1 18 19 package org.apache.jmeter.extractor; 20 21 import java.io.Serializable ; 22 import java.util.ArrayList ; 23 import java.util.Iterator ; 24 import java.util.LinkedList ; 25 import java.util.List ; 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 52 public class RegexExtractor 53 extends AbstractTestElement 54 implements PostProcessor, Serializable 55 { 56 transient private static Logger log = LoggingManager.getLoggerForClass(); 57 public static final String USEHEADERS = "RegexExtractor.useHeaders"; 58 public static final String REGEX = "RegexExtractor.regex"; 59 public static final String REFNAME = "RegexExtractor.refname"; 60 public static final String MATCH_NUMBER = "RegexExtractor.match_number"; 61 public static final String DEFAULT = "RegexExtractor.default"; 62 public static final String TEMPLATE = "RegexExtractor.template"; 63 private Object [] template = null; 64 65 private static PatternCacheLRU patternCache = 66 new PatternCacheLRU(1000, new Perl5Compiler()); 67 private static ThreadLocal localMatcher = new ThreadLocal () 68 { 69 protected Object initialValue() 70 { 71 return new Perl5Matcher(); 72 } 73 }; 74 75 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 JMeterVariables vars = context.getVariables(); 93 String 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 (context.getPreviousResult().getResponseData()) 103 ); 104 log.debug("Regex = " + getRegex()); 105 try { 106 Pattern pattern = 107 patternCache.getPattern(getRegex(), Perl5Compiler.READ_ONLY_MASK); 108 List matches = new ArrayList (); 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){ match = getCorrectMatch(matches, matchNumber); 131 if (match != null) 132 { 133 vars.put(refName, generateResult(match)); 134 saveGroups(vars, refName, match); 135 } 136 } 137 else { 139 int prevCount = 0; 140 String prevString=vars.get(refName+"_matchNr"); 141 if (prevString != null) 142 { 143 try 144 { 145 prevCount = Integer.parseInt(prevString); 146 } 147 catch (NumberFormatException e1) 148 { 149 e1.printStackTrace(); 151 } 152 } 153 vars.put(refName+"_matchNr", ""+matches.size()); 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"); vars.remove(refName+"_"+i+"_g1"); } 169 } 170 } 171 catch (RuntimeException 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 basename, 183 MatchResult match) 184 { 185 StringBuffer buf = new StringBuffer (); 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 clone() 197 { 198 RegexExtractor cloned = (RegexExtractor) super.clone(); 199 cloned.template = this.template; 200 return cloned; 201 } 202 203 private String generateResult(MatchResult match) 204 { 205 StringBuffer result = new StringBuffer (); 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 ) 211 { 212 result.append(template[a]); 213 } 214 else 215 { 216 result.append(match.group(((Integer ) 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 pieces = new ArrayList (); 230 List combined = new LinkedList (); 231 String 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); } 250 Iterator 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 (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 (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 (matcher.getMatch().group(1))); 275 } 276 template = combined.toArray(); 277 } 278 279 private boolean isFirstElementGroup(String 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 e) 293 { 294 log.error("", e); 295 return false; 296 } 297 } 298 299 305 private MatchResult getCorrectMatch(List matches, int entry) 306 { 307 int matchSize = matches.size(); 308 309 if (matchSize <= 0 || entry > matchSize) return null; 310 311 if (entry == 0) { 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 regex) 321 { 322 setProperty(REGEX, regex); 323 } 324 public String getRegex() 325 { 326 return getPropertyAsString(REGEX); 327 } 328 public void setRefName(String refName) 329 { 330 setProperty(REFNAME, refName); 331 } 332 public String getRefName() 333 { 334 return getPropertyAsString(REFNAME); 335 } 336 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 355 public void setDefaultValue(String defaultValue) 356 { 357 setProperty(DEFAULT, defaultValue); 358 } 359 360 public String getDefaultValue() 361 { 362 return getPropertyAsString(DEFAULT); 363 } 364 365 public void setTemplate(String template) 366 { 367 setProperty(TEMPLATE, template); 368 } 369 370 public String 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 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); extractor.setRefName("regVal"); 399 result = new SampleResult(); 400 String 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 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 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 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 453 { 454 templateSetup(extractor,"ABC"); 455 assertEquals("ABC", vars.get("regVal")); 456 } 457 458 public void testTemplate3() throws Exception 459 { 460 templateSetup(extractor,"$2$"); 461 assertEquals("query", vars.get("regVal")); 462 } 463 464 public void testTemplate4() throws Exception 465 { 466 templateSetup(extractor,"PRE$2$"); 467 assertEquals("PREquery", vars.get("regVal")); 468 } 469 470 public void testTemplate5() throws Exception 471 { 472 templateSetup(extractor,"$2$POST"); 473 assertEquals("queryPOST", vars.get("regVal")); 474 } 475 476 public void testTemplate6() throws Exception 477 { 478 templateSetup(extractor,"$2$$1$"); 479 assertEquals("queryxmlext", vars.get("regVal")); 480 } 481 482 public void testTemplate7() throws Exception 483 { 484 templateSetup(extractor,"$2$MID$1$"); 485 assertEquals("queryMIDxmlext", vars.get("regVal")); 486 } 487 488 public void testVariableExtraction2() throws Exception 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 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 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 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 extractor.setRegex("(\\w+)count"); 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 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 |