1. /* $Id: DigesterRuleParser.java,v 1.29.2.1 2004/07/30 20:11:01 rdonkin Exp $
  2. *
  3. * Copyright 2001-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. package org.apache.commons.digester.xmlrules;
  18. import java.io.FileNotFoundException;
  19. import java.io.IOException;
  20. import java.net.URL;
  21. import java.util.ArrayList;
  22. import java.util.HashSet;
  23. import java.util.List;
  24. import java.util.Set;
  25. import java.util.StringTokenizer;
  26. import org.apache.commons.beanutils.ConvertUtils;
  27. import org.apache.commons.collections.ArrayStack;
  28. import org.apache.commons.digester.AbstractObjectCreationFactory;
  29. import org.apache.commons.digester.BeanPropertySetterRule;
  30. import org.apache.commons.digester.CallMethodRule;
  31. import org.apache.commons.digester.CallParamRule;
  32. import org.apache.commons.digester.Digester;
  33. import org.apache.commons.digester.FactoryCreateRule;
  34. import org.apache.commons.digester.ObjectCreateRule;
  35. import org.apache.commons.digester.Rule;
  36. import org.apache.commons.digester.RuleSetBase;
  37. import org.apache.commons.digester.Rules;
  38. import org.apache.commons.digester.SetNextRule;
  39. import org.apache.commons.digester.SetPropertiesRule;
  40. import org.apache.commons.digester.SetPropertyRule;
  41. import org.apache.commons.digester.SetRootRule;
  42. import org.apache.commons.digester.SetTopRule;
  43. import org.apache.commons.digester.ObjectParamRule;
  44. import org.xml.sax.Attributes;
  45. import org.xml.sax.SAXException;
  46. /**
  47. * This is a RuleSet that parses XML into Digester rules, and then
  48. * adds those rules to a 'target' Digester.
  49. *
  50. * @since 1.2
  51. */
  52. public class DigesterRuleParser extends RuleSetBase {
  53. public static final String DIGESTER_PUBLIC_ID = "-//Jakarta Apache //DTD digester-rules XML V1.0//EN";
  54. /**
  55. * path to the DTD
  56. */
  57. private String digesterDtdUrl;
  58. /**
  59. * This is the digester to which we are adding the rules that we parse
  60. * from the Rules XML document.
  61. */
  62. protected Digester targetDigester;
  63. /** See {@link #setBasePath}. */
  64. protected String basePath = "";
  65. /**
  66. * A stack whose toString method returns a '/'-separated concatenation
  67. * of all the elements in the stack.
  68. */
  69. protected class PatternStack extends ArrayStack {
  70. public String toString() {
  71. StringBuffer str = new StringBuffer();
  72. for (int i = 0; i < size(); i++) {
  73. String elem = get(i).toString();
  74. if (elem.length() > 0) {
  75. if (str.length() > 0) {
  76. str.append('/');
  77. }
  78. str.append(elem);
  79. }
  80. }
  81. return str.toString();
  82. }
  83. }
  84. /**
  85. * A stack used to maintain the current pattern. The Rules XML document
  86. * type allows nesting of patterns. If an element defines a matching
  87. * pattern, the resulting pattern is a concatenation of that pattern with
  88. * all the ancestor elements' patterns. Hence the need for a stack.
  89. */
  90. protected PatternStack patternStack;
  91. /**
  92. * Used to detect circular includes
  93. */
  94. private Set includedFiles = new HashSet();
  95. /**
  96. * Constructs a DigesterRuleParser. This object will be inoperable
  97. * until the target digester is set, via <code>setTarget(Digester)</code>
  98. */
  99. public DigesterRuleParser() {
  100. patternStack = new PatternStack();
  101. }
  102. /**
  103. * Constructs a rule set for converting XML digester rule descriptions
  104. * into Rule objects, and adding them to the given Digester
  105. * @param targetDigester the Digester to add the rules to
  106. */
  107. public DigesterRuleParser(Digester targetDigester) {
  108. this.targetDigester = targetDigester;
  109. patternStack = new PatternStack();
  110. }
  111. /**
  112. * Constructs a rule set for parsing an XML digester rule file that
  113. * has been included within an outer XML digester rule file. In this
  114. * case, we must pass the pattern stack and the target digester
  115. * to the rule set, as well as the list of files that have already
  116. * been included, for cycle detection.
  117. * @param targetDigester the Digester to add the rules to
  118. * @param stack Stack containing the prefix pattern string to be prepended
  119. * to any pattern parsed by this rule set.
  120. */
  121. private DigesterRuleParser(Digester targetDigester,
  122. PatternStack stack, Set includedFiles) {
  123. this.targetDigester = targetDigester;
  124. patternStack = stack;
  125. this.includedFiles = includedFiles;
  126. }
  127. /**
  128. * Sets the digester into which to add the parsed rules
  129. * @param d the Digester to add the rules to
  130. */
  131. public void setTarget(Digester d) {
  132. targetDigester = d;
  133. }
  134. /**
  135. * Set a base pattern beneath which all the rules loaded by this
  136. * object will be registered. If this string is not empty, and does
  137. * not end in a "/", then one will be added.
  138. *
  139. * @since 1.6
  140. */
  141. public void setBasePath(String path) {
  142. if (path == null) {
  143. basePath = "";
  144. }
  145. else if ((path.length() > 0) && !path.endsWith("/")) {
  146. basePath = path + "/";
  147. } else {
  148. basePath = path;
  149. }
  150. }
  151. /**
  152. * Sets the location of the digester rules DTD. This is the DTD used
  153. * to validate the rules XML file.
  154. */
  155. public void setDigesterRulesDTD(String dtdURL) {
  156. digesterDtdUrl = dtdURL;
  157. }
  158. /**
  159. * Returns the location of the DTD used to validate the digester rules
  160. * XML document.
  161. */
  162. protected String getDigesterRulesDTD() {
  163. //ClassLoader classLoader = getClass().getClassLoader();
  164. //URL url = classLoader.getResource(DIGESTER_DTD_PATH);
  165. //return url.toString();
  166. return digesterDtdUrl;
  167. }
  168. /**
  169. * Adds a rule the the target digester. After a rule has been created by
  170. * parsing the XML, it is added to the digester by calling this method.
  171. * Typically, this method is called via reflection, when executing
  172. * a SetNextRule, from the Digester that is parsing the rules XML.
  173. * @param rule a Rule to add to the target digester.
  174. */
  175. public void add(Rule rule) {
  176. targetDigester.addRule(
  177. basePath + patternStack.toString(), rule);
  178. }
  179. /**
  180. * Add to the given digester the set of Rule instances used to parse an XML
  181. * document defining Digester rules. When the digester parses an XML file,
  182. * it will add the resulting rules & patterns to the 'target digester'
  183. * that was passed in this RuleSet's constructor.<P>
  184. * If you extend this class to support additional rules, your implementation
  185. * should of this method should call this implementation first: i.e.
  186. * <code>super.addRuleInstances(digester);</code>
  187. */
  188. public void addRuleInstances(Digester digester) {
  189. final String ruleClassName = Rule.class.getName();
  190. digester.register(DIGESTER_PUBLIC_ID, getDigesterRulesDTD());
  191. digester.addRule("*/pattern", new PatternRule("value"));
  192. digester.addRule("*/include", new IncludeRule());
  193. digester.addFactoryCreate("*/bean-property-setter-rule", new BeanPropertySetterRuleFactory());
  194. digester.addRule("*/bean-property-setter-rule", new PatternRule("pattern"));
  195. digester.addSetNext("*/bean-property-setter-rule", "add", ruleClassName);
  196. digester.addFactoryCreate("*/call-method-rule", new CallMethodRuleFactory());
  197. digester.addRule("*/call-method-rule", new PatternRule("pattern"));
  198. digester.addSetNext("*/call-method-rule", "add", ruleClassName);
  199. digester.addFactoryCreate("*/object-param-rule", new ObjectParamRuleFactory());
  200. digester.addRule("*/object-param-rule", new PatternRule("pattern"));
  201. digester.addSetNext("*/object-param-rule", "add", ruleClassName);
  202. digester.addFactoryCreate("*/call-param-rule", new CallParamRuleFactory());
  203. digester.addRule("*/call-param-rule", new PatternRule("pattern"));
  204. digester.addSetNext("*/call-param-rule", "add", ruleClassName);
  205. digester.addFactoryCreate("*/factory-create-rule", new FactoryCreateRuleFactory());
  206. digester.addRule("*/factory-create-rule", new PatternRule("pattern"));
  207. digester.addSetNext("*/factory-create-rule", "add", ruleClassName);
  208. digester.addFactoryCreate("*/object-create-rule", new ObjectCreateRuleFactory());
  209. digester.addRule("*/object-create-rule", new PatternRule("pattern"));
  210. digester.addSetNext("*/object-create-rule", "add", ruleClassName);
  211. digester.addFactoryCreate("*/set-properties-rule", new SetPropertiesRuleFactory());
  212. digester.addRule("*/set-properties-rule", new PatternRule("pattern"));
  213. digester.addSetNext("*/set-properties-rule", "add", ruleClassName);
  214. digester.addRule("*/set-properties-rule/alias", new SetPropertiesAliasRule());
  215. digester.addFactoryCreate("*/set-property-rule", new SetPropertyRuleFactory());
  216. digester.addRule("*/set-property-rule", new PatternRule("pattern"));
  217. digester.addSetNext("*/set-property-rule", "add", ruleClassName);
  218. digester.addFactoryCreate("*/set-top-rule", new SetTopRuleFactory());
  219. digester.addRule("*/set-top-rule", new PatternRule("pattern"));
  220. digester.addSetNext("*/set-top-rule", "add", ruleClassName);
  221. digester.addFactoryCreate("*/set-next-rule", new SetNextRuleFactory());
  222. digester.addRule("*/set-next-rule", new PatternRule("pattern"));
  223. digester.addSetNext("*/set-next-rule", "add", ruleClassName);
  224. digester.addFactoryCreate("*/set-root-rule", new SetRootRuleFactory());
  225. digester.addRule("*/set-root-rule", new PatternRule("pattern"));
  226. digester.addSetNext("*/set-root-rule", "add", ruleClassName);
  227. }
  228. /**
  229. * A rule for extracting the pattern matching strings from the rules XML.
  230. * In the digester-rules document type, a pattern can either be declared
  231. * in the 'value' attribute of a <pattern> element (in which case the pattern
  232. * applies to all rules elements contained within the <pattern> element),
  233. * or it can be declared in the optional 'pattern' attribute of a rule
  234. * element.
  235. */
  236. private class PatternRule extends Rule {
  237. private String attrName;
  238. private String pattern = null;
  239. /**
  240. * @param attrName The name of the attribute containing the pattern
  241. */
  242. public PatternRule(String attrName) {
  243. super();
  244. this.attrName = attrName;
  245. }
  246. /**
  247. * If a pattern is defined for the attribute, push it onto the
  248. * pattern stack.
  249. */
  250. public void begin(Attributes attributes) {
  251. pattern = attributes.getValue(attrName);
  252. if (pattern != null) {
  253. patternStack.push(pattern);
  254. }
  255. }
  256. /**
  257. * If there was a pattern for this element, pop it off the pattern
  258. * stack.
  259. */
  260. public void end() {
  261. if (pattern != null) {
  262. patternStack.pop();
  263. }
  264. }
  265. }
  266. /**
  267. * A rule for including one rules XML file within another. Included files
  268. * behave as if they are 'macro-expanded' within the includer. This means
  269. * that the values of the pattern stack are prefixed to every pattern
  270. * in the included rules. <p>This rule will detect 'circular' includes,
  271. * which would result in infinite recursion. It throws a
  272. * CircularIncludeException when a cycle is detected, which will terminate
  273. * the parse.
  274. */
  275. private class IncludeRule extends Rule {
  276. public IncludeRule() {
  277. super();
  278. }
  279. /**
  280. * To include a rules xml file, we instantiate another Digester, and
  281. * another DigesterRulesRuleSet. We pass the
  282. * pattern stack and the target Digester to the new rule set, and
  283. * tell the Digester to parse the file.
  284. */
  285. public void begin(Attributes attributes) throws Exception {
  286. // The path attribute gives the URI to another digester rules xml file
  287. String fileName = attributes.getValue("path");
  288. if (fileName != null && fileName.length() > 0) {
  289. includeXMLRules(fileName);
  290. }
  291. // The class attribute gives the name of a class that implements
  292. // the DigesterRulesSource interface
  293. String className = attributes.getValue("class");
  294. if (className != null && className.length() > 0) {
  295. includeProgrammaticRules(className);
  296. }
  297. }
  298. /**
  299. * Creates another DigesterRuleParser, and uses it to extract the rules
  300. * out of the give XML file. The contents of the current pattern stack
  301. * will be prepended to all of the pattern strings parsed from the file.
  302. */
  303. private void includeXMLRules(String fileName)
  304. throws IOException, SAXException, CircularIncludeException {
  305. ClassLoader cl = Thread.currentThread().getContextClassLoader();
  306. if (cl == null) {
  307. cl = DigesterRuleParser.this.getClass().getClassLoader();
  308. }
  309. URL fileURL = cl.getResource(fileName);
  310. if (fileURL == null) {
  311. throw new FileNotFoundException("File \"" + fileName + "\" not found.");
  312. }
  313. fileName = fileURL.toExternalForm();
  314. if (includedFiles.add(fileName) == false) {
  315. // circular include detected
  316. throw new CircularIncludeException(fileName);
  317. }
  318. // parse the included xml file
  319. DigesterRuleParser includedSet =
  320. new DigesterRuleParser(targetDigester, patternStack, includedFiles);
  321. includedSet.setDigesterRulesDTD(getDigesterRulesDTD());
  322. Digester digester = new Digester();
  323. digester.addRuleSet(includedSet);
  324. digester.push(DigesterRuleParser.this);
  325. digester.parse(fileName);
  326. includedFiles.remove(fileName);
  327. }
  328. /**
  329. * Creates an instance of the indicated class. The class must implement
  330. * the DigesterRulesSource interface. Passes the target digester to
  331. * that instance. The DigesterRulesSource instance is supposed to add
  332. * rules into the digester. The contents of the current pattern stack
  333. * will be automatically prepended to all of the pattern strings added
  334. * by the DigesterRulesSource instance.
  335. */
  336. private void includeProgrammaticRules(String className)
  337. throws ClassNotFoundException, ClassCastException,
  338. InstantiationException, IllegalAccessException {
  339. Class cls = Class.forName(className);
  340. DigesterRulesSource rulesSource = (DigesterRulesSource) cls.newInstance();
  341. // wrap the digester's Rules object, to prepend pattern
  342. Rules digesterRules = targetDigester.getRules();
  343. Rules prefixWrapper =
  344. new RulesPrefixAdapter(patternStack.toString(), digesterRules);
  345. targetDigester.setRules(prefixWrapper);
  346. try {
  347. rulesSource.getRules(targetDigester);
  348. } finally {
  349. // Put the unwrapped rules back
  350. targetDigester.setRules(digesterRules);
  351. }
  352. }
  353. }
  354. /**
  355. * Wraps a Rules object. Delegates all the Rules interface methods
  356. * to the underlying Rules object. Overrides the add method to prepend
  357. * a prefix to the pattern string.
  358. */
  359. private class RulesPrefixAdapter implements Rules {
  360. private Rules delegate;
  361. private String prefix;
  362. /**
  363. * @param patternPrefix the pattern string to prepend to the pattern
  364. * passed to the add method.
  365. * @param rules The wrapped Rules object. All of this class's methods
  366. * pass through to this object.
  367. */
  368. public RulesPrefixAdapter(String patternPrefix, Rules rules) {
  369. prefix = patternPrefix;
  370. delegate = rules;
  371. }
  372. /**
  373. * Register a new Rule instance matching a pattern which is constructed
  374. * by concatenating the pattern prefix with the given pattern.
  375. */
  376. public void add(String pattern, Rule rule) {
  377. StringBuffer buffer = new StringBuffer();
  378. buffer.append(prefix);
  379. if (!pattern.startsWith("/")) {
  380. buffer.append('/');
  381. }
  382. buffer.append(pattern);
  383. delegate.add(buffer.toString(), rule);
  384. }
  385. /**
  386. * This method passes through to the underlying Rules object.
  387. */
  388. public void clear() {
  389. delegate.clear();
  390. }
  391. /**
  392. * This method passes through to the underlying Rules object.
  393. */
  394. public Digester getDigester() {
  395. return delegate.getDigester();
  396. }
  397. /**
  398. * This method passes through to the underlying Rules object.
  399. */
  400. public String getNamespaceURI() {
  401. return delegate.getNamespaceURI();
  402. }
  403. /**
  404. * @deprecated Call match(namespaceURI,pattern) instead.
  405. */
  406. public List match(String pattern) {
  407. return delegate.match(pattern);
  408. }
  409. /**
  410. * This method passes through to the underlying Rules object.
  411. */
  412. public List match(String namespaceURI, String pattern) {
  413. return delegate.match(namespaceURI, pattern);
  414. }
  415. /**
  416. * This method passes through to the underlying Rules object.
  417. */
  418. public List rules() {
  419. return delegate.rules();
  420. }
  421. /**
  422. * This method passes through to the underlying Rules object.
  423. */
  424. public void setDigester(Digester digester) {
  425. delegate.setDigester(digester);
  426. }
  427. /**
  428. * This method passes through to the underlying Rules object.
  429. */
  430. public void setNamespaceURI(String namespaceURI) {
  431. delegate.setNamespaceURI(namespaceURI);
  432. }
  433. }
  434. ///////////////////////////////////////////////////////////////////////
  435. // Classes beyond this point are ObjectCreationFactory implementations,
  436. // used to create Rule objects and initialize them from SAX attributes.
  437. ///////////////////////////////////////////////////////////////////////
  438. /**
  439. * Factory for creating a BeanPropertySetterRule.
  440. */
  441. private class BeanPropertySetterRuleFactory extends AbstractObjectCreationFactory {
  442. public Object createObject(Attributes attributes) throws Exception {
  443. Rule beanPropertySetterRule = null;
  444. String propertyname = attributes.getValue("propertyname");
  445. if (propertyname == null) {
  446. // call the setter method corresponding to the element name.
  447. beanPropertySetterRule = new BeanPropertySetterRule();
  448. } else {
  449. beanPropertySetterRule = new BeanPropertySetterRule(propertyname);
  450. }
  451. return beanPropertySetterRule;
  452. }
  453. }
  454. /**
  455. * Factory for creating a CallMethodRule.
  456. */
  457. protected class CallMethodRuleFactory extends AbstractObjectCreationFactory {
  458. public Object createObject(Attributes attributes) {
  459. Rule callMethodRule = null;
  460. String methodName = attributes.getValue("methodname");
  461. if (attributes.getValue("paramcount") == null) {
  462. // call against empty method
  463. callMethodRule = new CallMethodRule(methodName);
  464. } else {
  465. int paramCount = Integer.parseInt(attributes.getValue("paramcount"));
  466. String paramTypesAttr = attributes.getValue("paramtypes");
  467. if (paramTypesAttr == null || paramTypesAttr.length() == 0) {
  468. callMethodRule = new CallMethodRule(methodName, paramCount);
  469. } else {
  470. // Process the comma separated list or paramTypes
  471. // into an array of String class names
  472. ArrayList paramTypes = new ArrayList();
  473. StringTokenizer tokens = new StringTokenizer(paramTypesAttr, " \t\n\r,");
  474. while (tokens.hasMoreTokens()) {
  475. paramTypes.add(tokens.nextToken());
  476. }
  477. callMethodRule = new CallMethodRule( methodName,
  478. paramCount,
  479. (String[])paramTypes.toArray(new String[0]));
  480. }
  481. }
  482. return callMethodRule;
  483. }
  484. }
  485. /**
  486. * Factory for creating a CallParamRule.
  487. */
  488. protected class CallParamRuleFactory extends AbstractObjectCreationFactory {
  489. public Object createObject(Attributes attributes) {
  490. // create callparamrule
  491. int paramIndex = Integer.parseInt(attributes.getValue("paramnumber"));
  492. String attributeName = attributes.getValue("attrname");
  493. String fromStack = attributes.getValue("from-stack");
  494. Rule callParamRule = null;
  495. if (attributeName == null) {
  496. if (fromStack == null) {
  497. callParamRule = new CallParamRule( paramIndex );
  498. } else {
  499. callParamRule = new CallParamRule( paramIndex, Boolean.valueOf(fromStack).booleanValue());
  500. }
  501. } else {
  502. if (fromStack == null) {
  503. callParamRule = new CallParamRule( paramIndex, attributeName );
  504. } else {
  505. // specifying both from-stack and attribute name is not allowed
  506. throw new RuntimeException("Attributes from-stack and attrname cannot both be present.");
  507. }
  508. }
  509. return callParamRule;
  510. }
  511. }
  512. /**
  513. * Factory for creating a ObjectParamRule
  514. */
  515. protected class ObjectParamRuleFactory extends AbstractObjectCreationFactory {
  516. public Object createObject(Attributes attributes) throws Exception {
  517. // create callparamrule
  518. int paramIndex = Integer.parseInt(attributes.getValue("paramnumber"));
  519. String attributeName = attributes.getValue("attrname");
  520. String type = attributes.getValue("type");
  521. String value = attributes.getValue("value");
  522. Rule objectParamRule = null;
  523. // type name is requried
  524. if (type == null) {
  525. throw new RuntimeException("Attribute 'type' is required.");
  526. }
  527. // create object instance
  528. Object param = null;
  529. Class clazz = Class.forName(type);
  530. if (value == null) {
  531. param = clazz.newInstance();
  532. } else {
  533. param = ConvertUtils.convert(value, clazz);
  534. }
  535. if (attributeName == null) {
  536. objectParamRule = new ObjectParamRule(paramIndex, param);
  537. } else {
  538. objectParamRule = new ObjectParamRule(paramIndex, attributeName, param);
  539. }
  540. return objectParamRule;
  541. }
  542. }
  543. /**
  544. * Factory for creating a FactoryCreateRule
  545. */
  546. protected class FactoryCreateRuleFactory extends AbstractObjectCreationFactory {
  547. public Object createObject(Attributes attributes) {
  548. String className = attributes.getValue("classname");
  549. String attrName = attributes.getValue("attrname");
  550. boolean ignoreExceptions =
  551. "true".equalsIgnoreCase(attributes.getValue("ignore-exceptions"));
  552. return (attrName == null || attrName.length() == 0) ?
  553. new FactoryCreateRule( className, ignoreExceptions) :
  554. new FactoryCreateRule( className, attrName, ignoreExceptions);
  555. }
  556. }
  557. /**
  558. * Factory for creating a ObjectCreateRule
  559. */
  560. protected class ObjectCreateRuleFactory extends AbstractObjectCreationFactory {
  561. public Object createObject(Attributes attributes) {
  562. String className = attributes.getValue("classname");
  563. String attrName = attributes.getValue("attrname");
  564. return (attrName == null || attrName.length() == 0) ?
  565. new ObjectCreateRule( className) :
  566. new ObjectCreateRule( className, attrName);
  567. }
  568. }
  569. /**
  570. * Factory for creating a SetPropertiesRule
  571. */
  572. protected class SetPropertiesRuleFactory extends AbstractObjectCreationFactory {
  573. public Object createObject(Attributes attributes) {
  574. return new SetPropertiesRule();
  575. }
  576. }
  577. /**
  578. * Factory for creating a SetPropertyRule
  579. */
  580. protected class SetPropertyRuleFactory extends AbstractObjectCreationFactory {
  581. public Object createObject(Attributes attributes) {
  582. String name = attributes.getValue("name");
  583. String value = attributes.getValue("value");
  584. return new SetPropertyRule( name, value);
  585. }
  586. }
  587. /**
  588. * Factory for creating a SetTopRuleFactory
  589. */
  590. protected class SetTopRuleFactory extends AbstractObjectCreationFactory {
  591. public Object createObject(Attributes attributes) {
  592. String methodName = attributes.getValue("methodname");
  593. String paramType = attributes.getValue("paramtype");
  594. return (paramType == null || paramType.length() == 0) ?
  595. new SetTopRule( methodName) :
  596. new SetTopRule( methodName, paramType);
  597. }
  598. }
  599. /**
  600. * Factory for creating a SetNextRuleFactory
  601. */
  602. protected class SetNextRuleFactory extends AbstractObjectCreationFactory {
  603. public Object createObject(Attributes attributes) {
  604. String methodName = attributes.getValue("methodname");
  605. String paramType = attributes.getValue("paramtype");
  606. return (paramType == null || paramType.length() == 0) ?
  607. new SetNextRule( methodName) :
  608. new SetNextRule( methodName, paramType);
  609. }
  610. }
  611. /**
  612. * Factory for creating a SetRootRuleFactory
  613. */
  614. protected class SetRootRuleFactory extends AbstractObjectCreationFactory {
  615. public Object createObject(Attributes attributes) {
  616. String methodName = attributes.getValue("methodname");
  617. String paramType = attributes.getValue("paramtype");
  618. return (paramType == null || paramType.length() == 0) ?
  619. new SetRootRule( methodName) :
  620. new SetRootRule( methodName, paramType);
  621. }
  622. }
  623. /**
  624. * A rule for adding a attribute-property alias to the custom alias mappings of
  625. * the containing SetPropertiesRule rule.
  626. */
  627. protected class SetPropertiesAliasRule extends Rule {
  628. /**
  629. * <p>Base constructor.</p>
  630. */
  631. public SetPropertiesAliasRule() {
  632. super();
  633. }
  634. /**
  635. * Add the alias to the SetPropertiesRule object created by the
  636. * enclosing <set-properties-rule> tag.
  637. */
  638. public void begin(Attributes attributes) {
  639. String attrName = attributes.getValue("attr-name");
  640. String propName = attributes.getValue("prop-name");
  641. SetPropertiesRule rule = (SetPropertiesRule) digester.peek();
  642. rule.addAlias(attrName, propName);
  643. }
  644. }
  645. }