1 17 18 19 package org.apache.commons.digester.xmlrules; 20 21 22 import java.io.FileNotFoundException ; 23 import java.io.IOException ; 24 import java.net.URL ; 25 import java.util.ArrayList ; 26 import java.util.HashSet ; 27 import java.util.List ; 28 import java.util.Set ; 29 import java.util.StringTokenizer ; 30 31 import org.apache.commons.beanutils.ConvertUtils; 32 33 import org.apache.commons.collections.ArrayStack; 34 35 import org.apache.commons.digester.AbstractObjectCreationFactory; 36 import org.apache.commons.digester.BeanPropertySetterRule; 37 import org.apache.commons.digester.CallMethodRule; 38 import org.apache.commons.digester.CallParamRule; 39 import org.apache.commons.digester.Digester; 40 import org.apache.commons.digester.FactoryCreateRule; 41 import org.apache.commons.digester.ObjectCreateRule; 42 import org.apache.commons.digester.Rule; 43 import org.apache.commons.digester.RuleSetBase; 44 import org.apache.commons.digester.Rules; 45 import org.apache.commons.digester.SetNestedPropertiesRule; 46 import org.apache.commons.digester.SetNextRule; 47 import org.apache.commons.digester.SetPropertiesRule; 48 import org.apache.commons.digester.SetPropertyRule; 49 import org.apache.commons.digester.SetRootRule; 50 import org.apache.commons.digester.SetTopRule; 51 import org.apache.commons.digester.ObjectParamRule; 52 53 import org.xml.sax.Attributes ; 54 import org.xml.sax.SAXException ; 55 56 57 63 64 public class DigesterRuleParser extends RuleSetBase { 65 66 public static final String DIGESTER_PUBLIC_ID = "-//Jakarta Apache //DTD digester-rules XML V1.0//EN"; 67 68 71 private String digesterDtdUrl; 72 73 77 protected Digester targetDigester; 78 79 80 protected String basePath = ""; 81 82 86 protected class PatternStack extends ArrayStack { 87 public String toString() { 88 StringBuffer str = new StringBuffer (); 89 for (int i = 0; i < size(); i++) { 90 String elem = get(i).toString(); 91 if (elem.length() > 0) { 92 if (str.length() > 0) { 93 str.append('/'); 94 } 95 str.append(elem); 96 } 97 } 98 return str.toString(); 99 } 100 } 101 102 108 protected PatternStack patternStack; 109 110 113 private Set includedFiles = new HashSet (); 114 115 119 public DigesterRuleParser() { 120 patternStack = new PatternStack(); 121 } 122 123 128 public DigesterRuleParser(Digester targetDigester) { 129 this.targetDigester = targetDigester; 130 patternStack = new PatternStack(); 131 } 132 133 143 private DigesterRuleParser(Digester targetDigester, 144 PatternStack stack, Set includedFiles) { 145 this.targetDigester = targetDigester; 146 patternStack = stack; 147 this.includedFiles = includedFiles; 148 } 149 150 154 public void setTarget(Digester d) { 155 targetDigester = d; 156 } 157 158 165 public void setBasePath(String path) { 166 if (path == null) { 167 basePath = ""; 168 } 169 else if ((path.length() > 0) && !path.endsWith("/")) { 170 basePath = path + "/"; 171 } else { 172 basePath = path; 173 } 174 } 175 176 180 public void setDigesterRulesDTD(String dtdURL) { 181 digesterDtdUrl = dtdURL; 182 } 183 184 188 protected String getDigesterRulesDTD() { 189 return digesterDtdUrl; 193 } 194 195 202 public void add(Rule rule) { 203 targetDigester.addRule( 204 basePath + patternStack.toString(), rule); 205 } 206 207 208 217 public void addRuleInstances(Digester digester) { 218 final String ruleClassName = Rule.class.getName(); 219 digester.register(DIGESTER_PUBLIC_ID, getDigesterRulesDTD()); 220 221 digester.addRule("*/pattern", new PatternRule("value")); 222 223 digester.addRule("*/include", new IncludeRule()); 224 225 digester.addFactoryCreate("*/bean-property-setter-rule", new BeanPropertySetterRuleFactory()); 226 digester.addRule("*/bean-property-setter-rule", new PatternRule("pattern")); 227 digester.addSetNext("*/bean-property-setter-rule", "add", ruleClassName); 228 229 digester.addFactoryCreate("*/call-method-rule", new CallMethodRuleFactory()); 230 digester.addRule("*/call-method-rule", new PatternRule("pattern")); 231 digester.addSetNext("*/call-method-rule", "add", ruleClassName); 232 233 digester.addFactoryCreate("*/object-param-rule", new ObjectParamRuleFactory()); 234 digester.addRule("*/object-param-rule", new PatternRule("pattern")); 235 digester.addSetNext("*/object-param-rule", "add", ruleClassName); 236 237 digester.addFactoryCreate("*/call-param-rule", new CallParamRuleFactory()); 238 digester.addRule("*/call-param-rule", new PatternRule("pattern")); 239 digester.addSetNext("*/call-param-rule", "add", ruleClassName); 240 241 digester.addFactoryCreate("*/factory-create-rule", new FactoryCreateRuleFactory()); 242 digester.addRule("*/factory-create-rule", new PatternRule("pattern")); 243 digester.addSetNext("*/factory-create-rule", "add", ruleClassName); 244 245 digester.addFactoryCreate("*/object-create-rule", new ObjectCreateRuleFactory()); 246 digester.addRule("*/object-create-rule", new PatternRule("pattern")); 247 digester.addSetNext("*/object-create-rule", "add", ruleClassName); 248 249 digester.addFactoryCreate("*/set-properties-rule", new SetPropertiesRuleFactory()); 250 digester.addRule("*/set-properties-rule", new PatternRule("pattern")); 251 digester.addSetNext("*/set-properties-rule", "add", ruleClassName); 252 253 digester.addRule("*/set-properties-rule/alias", new SetPropertiesAliasRule()); 254 255 digester.addFactoryCreate("*/set-property-rule", new SetPropertyRuleFactory()); 256 digester.addRule("*/set-property-rule", new PatternRule("pattern")); 257 digester.addSetNext("*/set-property-rule", "add", ruleClassName); 258 259 digester.addFactoryCreate("*/set-nested-properties-rule", new SetNestedPropertiesRuleFactory()); 260 digester.addRule("*/set-nested-properties-rule", new PatternRule("pattern")); 261 digester.addSetNext("*/set-nested-properties-rule", "add", ruleClassName); 262 263 digester.addRule("*/set-nested-properties-rule/alias", new SetNestedPropertiesAliasRule()); 264 265 digester.addFactoryCreate("*/set-top-rule", new SetTopRuleFactory()); 266 digester.addRule("*/set-top-rule", new PatternRule("pattern")); 267 digester.addSetNext("*/set-top-rule", "add", ruleClassName); 268 269 digester.addFactoryCreate("*/set-next-rule", new SetNextRuleFactory()); 270 digester.addRule("*/set-next-rule", new PatternRule("pattern")); 271 digester.addSetNext("*/set-next-rule", "add", ruleClassName); 272 digester.addFactoryCreate("*/set-root-rule", new SetRootRuleFactory()); 273 digester.addRule("*/set-root-rule", new PatternRule("pattern")); 274 digester.addSetNext("*/set-root-rule", "add", ruleClassName); 275 } 276 277 278 286 private class PatternRule extends Rule { 287 288 private String attrName; 289 private String pattern = null; 290 291 294 public PatternRule(String attrName) { 295 super(); 296 this.attrName = attrName; 297 } 298 299 303 public void begin(Attributes attributes) { 304 pattern = attributes.getValue(attrName); 305 if (pattern != null) { 306 patternStack.push(pattern); 307 } 308 } 309 310 314 public void end() { 315 if (pattern != null) { 316 patternStack.pop(); 317 } 318 } 319 } 320 321 330 private class IncludeRule extends Rule { 331 public IncludeRule() { 332 super(); 333 } 334 335 341 public void begin(Attributes attributes) throws Exception { 342 String fileName = attributes.getValue("path"); 344 if (fileName != null && fileName.length() > 0) { 345 includeXMLRules(fileName); 346 } 347 348 String className = attributes.getValue("class"); 351 if (className != null && className.length() > 0) { 352 includeProgrammaticRules(className); 353 } 354 } 355 356 361 private void includeXMLRules(String fileName) 362 throws IOException , SAXException , CircularIncludeException { 363 ClassLoader cl = Thread.currentThread().getContextClassLoader(); 364 if (cl == null) { 365 cl = DigesterRuleParser.this.getClass().getClassLoader(); 366 } 367 URL fileURL = cl.getResource(fileName); 368 if (fileURL == null) { 369 throw new FileNotFoundException ("File \"" + fileName + "\" not found."); 370 } 371 fileName = fileURL.toExternalForm(); 372 if (includedFiles.add(fileName) == false) { 373 throw new CircularIncludeException(fileName); 375 } 376 DigesterRuleParser includedSet = 378 new DigesterRuleParser(targetDigester, patternStack, includedFiles); 379 includedSet.setDigesterRulesDTD(getDigesterRulesDTD()); 380 Digester digester = new Digester(); 381 digester.addRuleSet(includedSet); 382 digester.push(DigesterRuleParser.this); 383 digester.parse(fileName); 384 includedFiles.remove(fileName); 385 } 386 387 395 private void includeProgrammaticRules(String className) 396 throws ClassNotFoundException , ClassCastException , 397 InstantiationException , IllegalAccessException { 398 399 Class cls = Class.forName(className); 400 DigesterRulesSource rulesSource = (DigesterRulesSource) cls.newInstance(); 401 402 Rules digesterRules = targetDigester.getRules(); 404 Rules prefixWrapper = 405 new RulesPrefixAdapter(patternStack.toString(), digesterRules); 406 407 targetDigester.setRules(prefixWrapper); 408 try { 409 rulesSource.getRules(targetDigester); 410 } finally { 411 targetDigester.setRules(digesterRules); 413 } 414 } 415 } 416 417 418 423 private class RulesPrefixAdapter implements Rules { 424 425 private Rules delegate; 426 private String prefix; 427 428 434 public RulesPrefixAdapter(String patternPrefix, Rules rules) { 435 prefix = patternPrefix; 436 delegate = rules; 437 } 438 439 443 public void add(String pattern, Rule rule) { 444 StringBuffer buffer = new StringBuffer (); 445 buffer.append(prefix); 446 if (!pattern.startsWith("/")) { 447 buffer.append('/'); 448 } 449 buffer.append(pattern); 450 delegate.add(buffer.toString(), rule); 451 } 452 453 456 public void clear() { 457 delegate.clear(); 458 } 459 460 463 public Digester getDigester() { 464 return delegate.getDigester(); 465 } 466 467 470 public String getNamespaceURI() { 471 return delegate.getNamespaceURI(); 472 } 473 474 477 public List match(String pattern) { 478 return delegate.match(pattern); 479 } 480 481 484 public List match(String namespaceURI, String pattern) { 485 return delegate.match(namespaceURI, pattern); 486 } 487 488 491 public List rules() { 492 return delegate.rules(); 493 } 494 495 498 public void setDigester(Digester digester) { 499 delegate.setDigester(digester); 500 } 501 502 505 public void setNamespaceURI(String namespaceURI) { 506 delegate.setNamespaceURI(namespaceURI); 507 } 508 } 509 510 511 516 519 private class BeanPropertySetterRuleFactory extends AbstractObjectCreationFactory { 520 public Object createObject(Attributes attributes) throws Exception { 521 Rule beanPropertySetterRule = null; 522 String propertyname = attributes.getValue("propertyname"); 523 524 if (propertyname == null) { 525 beanPropertySetterRule = new BeanPropertySetterRule(); 527 } else { 528 beanPropertySetterRule = new BeanPropertySetterRule(propertyname); 529 } 530 531 return beanPropertySetterRule; 532 } 533 534 } 535 536 539 protected class CallMethodRuleFactory extends AbstractObjectCreationFactory { 540 public Object createObject(Attributes attributes) { 541 Rule callMethodRule = null; 542 String methodName = attributes.getValue("methodname"); 543 544 int targetOffset = 0; 547 String targetOffsetStr = attributes.getValue("targetoffset"); 548 if (targetOffsetStr != null) { 549 targetOffset = Integer.parseInt(targetOffsetStr); 550 } 551 552 if (attributes.getValue("paramcount") == null) { 553 callMethodRule = new CallMethodRule(targetOffset, methodName); 555 556 } else { 557 int paramCount = Integer.parseInt(attributes.getValue("paramcount")); 558 559 String paramTypesAttr = attributes.getValue("paramtypes"); 560 if (paramTypesAttr == null || paramTypesAttr.length() == 0) { 561 callMethodRule = new CallMethodRule(targetOffset, methodName, paramCount); 562 } else { 563 String [] paramTypes = getParamTypes(paramTypesAttr); 564 callMethodRule = new CallMethodRule( 565 targetOffset, methodName, paramCount, paramTypes); 566 } 567 } 568 return callMethodRule; 569 } 570 571 575 private String [] getParamTypes(String paramTypes) { 576 String [] paramTypesArray; 577 if( paramTypes != null ) { 578 ArrayList paramTypesList = new ArrayList (); 579 StringTokenizer tokens = new StringTokenizer ( 580 paramTypes, " \t\n\r,"); 581 while (tokens.hasMoreTokens()) { 582 paramTypesList.add(tokens.nextToken()); 583 } 584 paramTypesArray = (String [])paramTypesList.toArray(new String [0]); 585 } else { 586 paramTypesArray = new String [0]; 587 } 588 return paramTypesArray; 589 } 590 } 591 592 595 protected class CallParamRuleFactory extends AbstractObjectCreationFactory { 596 597 public Object createObject(Attributes attributes) { 598 int paramIndex = Integer.parseInt(attributes.getValue("paramnumber")); 600 String attributeName = attributes.getValue("attrname"); 601 String fromStack = attributes.getValue("from-stack"); 602 String stackIndex = attributes.getValue("stack-index"); 603 Rule callParamRule = null; 604 605 if (attributeName == null) { 606 if (stackIndex != null) { 607 callParamRule = new CallParamRule( 608 paramIndex, Integer.parseInt(stackIndex)); 609 } else if (fromStack != null) { 610 callParamRule = new CallParamRule( 611 paramIndex, Boolean.valueOf(fromStack).booleanValue()); 612 } else { 613 callParamRule = new CallParamRule(paramIndex); 614 } 615 } else { 616 if (fromStack == null) { 617 callParamRule = new CallParamRule(paramIndex, attributeName); 618 } else { 619 throw new RuntimeException ( 621 "Attributes from-stack and attrname cannot both be present."); 622 } 623 } 624 return callParamRule; 625 } 626 } 627 628 631 protected class ObjectParamRuleFactory extends AbstractObjectCreationFactory { 632 public Object createObject(Attributes attributes) throws Exception { 633 int paramIndex = Integer.parseInt(attributes.getValue("paramnumber")); 635 String attributeName = attributes.getValue("attrname"); 636 String type = attributes.getValue("type"); 637 String value = attributes.getValue("value"); 638 639 Rule objectParamRule = null; 640 641 if (type == null) { 643 throw new RuntimeException ("Attribute 'type' is required."); 644 } 645 646 Object param = null; 648 Class clazz = Class.forName(type); 649 if (value == null) { 650 param = clazz.newInstance(); 651 } else { 652 param = ConvertUtils.convert(value, clazz); 653 } 654 655 if (attributeName == null) { 656 objectParamRule = new ObjectParamRule(paramIndex, param); 657 } else { 658 objectParamRule = new ObjectParamRule(paramIndex, attributeName, param); 659 } 660 return objectParamRule; 661 } 662 } 663 664 665 668 protected class FactoryCreateRuleFactory extends AbstractObjectCreationFactory { 669 public Object createObject(Attributes attributes) { 670 String className = attributes.getValue("classname"); 671 String attrName = attributes.getValue("attrname"); 672 boolean ignoreExceptions = 673 "true".equalsIgnoreCase(attributes.getValue("ignore-exceptions")); 674 return (attrName == null || attrName.length() == 0) ? 675 new FactoryCreateRule( className, ignoreExceptions) : 676 new FactoryCreateRule( className, attrName, ignoreExceptions); 677 } 678 } 679 680 683 protected class ObjectCreateRuleFactory extends AbstractObjectCreationFactory { 684 public Object createObject(Attributes attributes) { 685 String className = attributes.getValue("classname"); 686 String attrName = attributes.getValue("attrname"); 687 return (attrName == null || attrName.length() == 0) ? 688 new ObjectCreateRule( className) : 689 new ObjectCreateRule( className, attrName); 690 } 691 } 692 693 696 protected class SetPropertiesRuleFactory extends AbstractObjectCreationFactory { 697 public Object createObject(Attributes attributes) { 698 return new SetPropertiesRule(); 699 } 700 } 701 702 705 protected class SetPropertyRuleFactory extends AbstractObjectCreationFactory { 706 public Object createObject(Attributes attributes) { 707 String name = attributes.getValue("name"); 708 String value = attributes.getValue("value"); 709 return new SetPropertyRule( name, value); 710 } 711 } 712 713 716 protected class SetNestedPropertiesRuleFactory extends AbstractObjectCreationFactory { 717 public Object createObject(Attributes attributes) { 718 boolean allowUnknownChildElements = 719 "true".equalsIgnoreCase(attributes.getValue("allow-unknown-child-elements")); 720 SetNestedPropertiesRule snpr = new SetNestedPropertiesRule(); 721 snpr.setAllowUnknownChildElements( allowUnknownChildElements ); 722 return snpr; 723 } 724 } 725 726 729 protected class SetTopRuleFactory extends AbstractObjectCreationFactory { 730 public Object createObject(Attributes attributes) { 731 String methodName = attributes.getValue("methodname"); 732 String paramType = attributes.getValue("paramtype"); 733 return (paramType == null || paramType.length() == 0) ? 734 new SetTopRule( methodName) : 735 new SetTopRule( methodName, paramType); 736 } 737 } 738 739 742 protected class SetNextRuleFactory extends AbstractObjectCreationFactory { 743 public Object createObject(Attributes attributes) { 744 String methodName = attributes.getValue("methodname"); 745 String paramType = attributes.getValue("paramtype"); 746 return (paramType == null || paramType.length() == 0) ? 747 new SetNextRule( methodName) : 748 new SetNextRule( methodName, paramType); 749 } 750 } 751 752 755 protected class SetRootRuleFactory extends AbstractObjectCreationFactory { 756 public Object createObject(Attributes attributes) { 757 String methodName = attributes.getValue("methodname"); 758 String paramType = attributes.getValue("paramtype"); 759 return (paramType == null || paramType.length() == 0) ? 760 new SetRootRule( methodName) : 761 new SetRootRule( methodName, paramType); 762 } 763 } 764 765 769 protected class SetPropertiesAliasRule extends Rule { 770 771 774 public SetPropertiesAliasRule() { 775 super(); 776 } 777 778 782 public void begin(Attributes attributes) { 783 String attrName = attributes.getValue("attr-name"); 784 String propName = attributes.getValue("prop-name"); 785 786 SetPropertiesRule rule = (SetPropertiesRule) digester.peek(); 787 rule.addAlias(attrName, propName); 788 } 789 } 790 791 795 protected class SetNestedPropertiesAliasRule extends Rule { 796 797 800 public SetNestedPropertiesAliasRule() { 801 super(); 802 } 803 804 808 public void begin(Attributes attributes) { 809 String attrName = attributes.getValue("attr-name"); 810 String propName = attributes.getValue("prop-name"); 811 812 SetNestedPropertiesRule rule = (SetNestedPropertiesRule) digester.peek(); 813 rule.addAlias(attrName, propName); 814 } 815 } 816 817 } 818 | Popular Tags |