1 64 package com.jcorporate.expresso.core.dataobjects.jdbc; 65 66 import com.jcorporate.expresso.core.dataobjects.DataFieldMetaData; 67 import com.jcorporate.expresso.kernel.util.FastStringBuffer; 68 import org.apache.log4j.Logger; 69 import org.apache.oro.text.regex.MalformedPatternException; 70 import org.apache.oro.text.regex.Pattern; 71 import org.apache.oro.text.regex.PatternCompiler; 72 import org.apache.oro.text.regex.PatternMatcher; 73 import org.apache.oro.text.regex.Perl5Compiler; 74 import org.apache.oro.text.regex.Perl5Matcher; 75 76 import java.util.Collections ; 77 import java.util.HashSet ; 78 import java.util.Set ; 79 import java.util.StringTokenizer ; 80 81 109 public class FieldRangeParser { 110 111 112 115 private static final transient Logger log = Logger.getLogger(FieldRangeParser.class); 116 117 120 private static final String MODIFIERS[] = {"AND", "OR", "and", "or"}; 121 122 125 private static final String RANGES[] = {"<", "<=", ">=", ">", "<>"}; 126 127 130 private static final Set MODIFIER_SET = Collections.synchronizedSet(new HashSet (MODIFIERS.length)); 131 132 135 private static final Set RANGE_SET = Collections.synchronizedSet(new HashSet (RANGES.length)); 136 137 138 142 private static final String LEGAL_NUMBER_RE = "^[^\\\\'%\"]+"; 143 144 150 private static final String LEGAL_STRING_RE = "^'[^']*'$"; 151 152 153 159 private static final String IN_FORMAT_RE = "^IN\\s*\\(.+\\)$"; 160 161 162 165 private Pattern legalCharacters = null; 166 167 168 171 private Pattern legalStrings = null; 172 173 174 177 private Pattern inStatementPattern = null; 178 179 183 private transient static ThreadLocal patternMatcher = new ThreadLocal () { 184 protected synchronized Object initialValue() { 185 return new Perl5Matcher(); 186 } 187 }; 188 189 190 193 private static FieldRangeParser myInstance = new FieldRangeParser(); 194 195 196 202 protected PatternMatcher getMatcher() { 203 return (PatternMatcher) patternMatcher.get(); 204 } 205 206 210 public FieldRangeParser() { 211 try { 212 PatternCompiler compiler = new Perl5Compiler(); 213 legalCharacters = compiler.compile(LEGAL_NUMBER_RE, Perl5Compiler.READ_ONLY_MASK); 214 legalStrings = compiler.compile(LEGAL_STRING_RE, Perl5Compiler.READ_ONLY_MASK); 215 inStatementPattern = compiler.compile(IN_FORMAT_RE, Perl5Compiler.READ_ONLY_MASK); 216 217 for (int i = 0; i < MODIFIERS.length; i++) { 218 MODIFIER_SET.add(MODIFIERS[i]); 219 } 220 221 for (int i = 0; i < RANGES.length; i++) { 222 RANGE_SET.add(RANGES[i]); 223 } 224 225 226 } catch (MalformedPatternException ex) { 227 log.error("Error setting up Illegal Character Regular Expression"); 228 } 229 } 230 231 236 public static synchronized FieldRangeParser getInstance() { 237 return FieldRangeParser.myInstance; 238 239 } 240 241 242 250 public boolean isValidRange(DataFieldMetaData metadata, String fieldValue) { 251 252 if (fieldValue == null) { 254 return false; 255 } 256 257 String examineString = fieldValue.trim(); 259 260 switch (examineString.charAt(0)) { 261 case 'N': 262 case 'n': 263 if (examineString.startsWith("NOT") || examineString.startsWith("not")) { 264 examineString = examineString.substring(3).trim(); 265 } else { 266 return false; 269 } 270 271 case 'I': 273 case 'i': 274 case 'B': 275 case 'b': 276 if (examineString.equalsIgnoreCase("is null") || 277 examineString.equalsIgnoreCase("is not null")) { 278 return true; 279 } 280 if (examineString.startsWith("BETWEEN") || examineString.startsWith("between")) { 281 return validateBetweenStatement(metadata, examineString); 282 } else if (examineString.startsWith("IN") || examineString.startsWith("in")) { 283 return validateInStatement(metadata, examineString); 284 } else { 285 return false; 286 } 287 288 case '>': 289 case '<': 290 return validateComparisonStatement(metadata, examineString); 291 292 default: 293 return false; 294 295 } 296 } 297 298 299 306 private boolean validateFieldValue(DataFieldMetaData metadata, String fieldValue) { 307 if (metadata.isDateType() || metadata.isDateTimeType() || metadata.isTimeType()) { 308 return validateFieldDateValue(fieldValue); 309 } else if (metadata.isNumericType()) { 310 return validateFieldNumberValue(fieldValue); 311 } else { 312 return validateFieldStringValue(fieldValue); 313 } 314 } 315 316 322 private boolean validateFieldStringValue(String fieldValue) { 323 return getMatcher().matches(fieldValue, legalStrings); 324 } 325 326 333 private boolean validateFieldNumberValue(String fieldValue) { 334 return getMatcher().matches(fieldValue, legalCharacters); 335 } 336 337 344 private boolean validateFieldDateValue(String fieldValue) { 345 return getMatcher().matches(fieldValue, legalStrings); 346 } 347 348 349 357 private boolean validateBetweenStatement(DataFieldMetaData metadata, String expressionValue) { 358 StringTokenizer stok = new StringTokenizer (expressionValue); 359 if (!stok.hasMoreTokens()) { 360 return false; 361 } 362 363 String betweenStatement = stok.nextToken(); 367 if (!("BETWEEN".equalsIgnoreCase(betweenStatement)) || !stok.hasMoreTokens()) { 368 return false; 369 } 370 371 boolean foundAnd = false; 372 373 FastStringBuffer fsb = FastStringBuffer.getInstance(); 375 String fieldValue; 376 try { 377 while (!foundAnd && stok.hasMoreTokens()) { 378 String token = stok.nextToken(); 379 if ("AND".equalsIgnoreCase(token)) { 380 foundAnd = true; 381 } else { 382 fsb.append(" "); 383 fsb.append(token); 384 } 385 } 386 fieldValue = fsb.toString().trim(); 387 } finally { 388 fsb.release(); 389 } 390 391 if (!foundAnd) { 392 return false; 393 } else { 394 if (!validateFieldValue(metadata, fieldValue)) { 395 return false; 396 } 397 } 398 399 if (!stok.hasMoreTokens()) { 401 return false; 403 } 404 405 fsb = FastStringBuffer.getInstance(); 406 try { 407 while (stok.hasMoreTokens()) { 408 String token = stok.nextToken(); 409 fsb.append(" "); 410 fsb.append(token); 411 } 412 413 fieldValue = fsb.toString().trim(); 414 } finally { 415 fsb.release(); 416 } 417 418 return (validateFieldValue(metadata, fieldValue)); 420 } 421 422 429 private boolean validateInStatement(DataFieldMetaData metadata, String expressionValue) { 430 431 boolean match; 432 433 match = getMatcher().matches(expressionValue, inStatementPattern); 435 436 if (!match) { 437 return false; 439 } 440 441 int openParen = expressionValue.indexOf("("); 442 int closeParen = expressionValue.lastIndexOf(")"); 443 444 447 String toEvaluate = expressionValue.substring(openParen + 1, 448 closeParen); 449 450 StringTokenizer stok = new StringTokenizer (toEvaluate, ","); 451 while (stok.hasMoreTokens()) { 452 String oneFieldValue = stok.nextToken(); 453 boolean result = validateFieldValue(metadata, oneFieldValue); 454 if (result == false) { 455 return false; 456 } 457 } 458 459 return true; 460 } 461 462 470 private boolean validateComparisonStatement(DataFieldMetaData metadata, String expressionValue) { 471 StringTokenizer stok = new StringTokenizer (expressionValue); 472 473 if (!stok.hasMoreTokens()) { 475 return false; 476 } 477 478 return validateComparisonRecusive(metadata, stok); 479 } 480 481 487 private String [] consumeOperator(String expression) { 488 String returnValue[] = new String [2]; 489 490 int index = 0; 491 boolean done = false; 492 int length = expression.length(); 493 494 StringBuffer buffer = new StringBuffer (); 495 496 497 while (!done && index < length) { 498 char opChar = expression.charAt(index); 499 switch (opChar) { 500 case '>': 501 case '<': 502 case '=': 503 buffer.append(opChar); 504 index++; 505 break; 506 default: 507 returnValue[1] = expression.substring(index); 508 done = true; 509 } 510 511 } 512 513 String operator = buffer.toString(); 514 if (RANGE_SET.contains(operator)) { 515 returnValue[0] = operator; 516 } 517 518 return returnValue; 519 } 520 521 532 private boolean validateComparisonRecusive(DataFieldMetaData metadata, StringTokenizer tokenizer) { 533 String operator = tokenizer.nextToken(); 534 535 FastStringBuffer fsb = FastStringBuffer.getInstance(); 536 537 String [] result = consumeOperator(operator); 538 String fieldValue; 539 boolean moreComparisons = false; 540 541 if (result[0] == null) { 543 return false; 544 } 545 546 if (result[1] == null && !tokenizer.hasMoreTokens()) { 547 return false; 548 } 549 550 if (result[1] != null) { 552 fsb.append(result[1]); 553 } 554 555 try { 556 boolean done = false; 557 while (!done && tokenizer.hasMoreTokens()) { 558 String oneValue = tokenizer.nextToken(); 559 if (MODIFIER_SET.contains(oneValue)) { 562 moreComparisons = true; 563 done = true; 564 } else { 565 fsb.append(" "); 566 fsb.append(oneValue); 567 } 568 } 569 570 fieldValue = fsb.toString(); 571 572 } finally { 573 fsb.release(); 574 } 575 576 if (validateFieldValue(metadata, fieldValue.trim())) { 577 if (moreComparisons) { 578 return validateComparisonRecusive(metadata, tokenizer); 579 } else { 580 return true; 581 } 582 } else { 583 return false; 585 } 586 } 587 588 594 public String denotesRange(String fieldValue) { 595 596 if (fieldValue == null || fieldValue.length() == 0) { 598 return null; 599 } 600 601 602 char firstChar = fieldValue.charAt(0); 603 switch (firstChar) { 604 case 'b': 605 case 'B': 606 if (fieldValue.startsWith("between ")) { 607 return "between "; 608 } else if (fieldValue.startsWith("BETWEEN ")) { 609 return "BETWEEN "; 610 } 611 break; 612 613 case 'i': 614 case 'I': 615 if (fieldValue.startsWith("in ")) { 616 return "in "; 617 } else if (fieldValue.startsWith("IN ")) { 618 return "IN "; 619 } else if (fieldValue.trim().equalsIgnoreCase("is not null") || 620 fieldValue.trim().equalsIgnoreCase("is null")) { 621 return ""; 622 } 623 break; 624 625 case 'n': 626 case 'N': 627 if (fieldValue.startsWith("not in ")) { 628 return "not in "; 629 } else if (fieldValue.startsWith("NOT IN")) { 630 return "NOT IN "; 631 } else if (fieldValue.startsWith("not between ")) { 632 return "not between "; 633 } else if (fieldValue.startsWith("NOT BETWEEN ")) { 634 return "NOT BETWEEN "; 635 } 636 break; 637 638 639 case '<': 640 if (fieldValue.startsWith("<>")) { 641 return "<> "; 642 } else if (fieldValue.startsWith("<=")) { 643 return "<="; 644 } else if (fieldValue.startsWith("< ")) { 645 return "< "; 646 647 648 } else if (fieldValue.startsWith("<")) { 649 return "<"; 650 } 651 break; 652 653 case '>': 654 if (fieldValue.startsWith("> ")) { 655 return "> "; 656 } else if (fieldValue.startsWith(">=")) { 657 return ">="; 658 } else if (fieldValue.startsWith(">")) { 659 return ">"; 660 } 661 break; 662 663 default: 664 return null; 665 } 666 667 return null; 668 } 669 670 } | Popular Tags |