The xmlrules package provides for XML-based definition of rules for Digester. This improves maintainability of Java code, as rules are now defined in XML and read into Digester at run-time.
This is a brief overview of the digester-rules-in-XML feature. Briefly, this feature lets you define Digester rules in XML, instead of creating and initializing the Rules objects programmatically, which can become tedious. In addition, it allows for including of one XML rules file within another, inclusion of programmatically created rule sets within an XML file (via reflection), and recursively nested matching pattern specifications.
A DTD, named digester-rules.dtd has been defined to help in the understanding of how the loader operates.
The DTD is distributed in the commons-digester3-3.0.jar. It can be found at org/apache/commons/digester3/xmlrules/digester-rules.dtd.
Digester input documents wishing to cite this DTD should include the following DOCTYPE declaration:
<!DOCTYPE digester-rules PUBLIC "-//Apache Commons //DTD digester-rules XML V1.0//EN" "http://commons.apache.org/digester/dtds/digester-rules-3.0.dtd">
The DTD defines an element type corresponding to each predefined Digester rule. Each rule element type includes attributes for values needed to initialize the rule, and an optional pattern attribute specifying the pattern to associate with the rule.
The DigesterLoader adds the rules to the digester in the order in which they occur in the XML.
The use of each rule element type should be self-explanatory, if you compare them to the API documentation for the Digester rules classes.
The matching pattern is a simple, xpath-like string which the Digester uses to determine which elements to apply each rule to. See the Digester documentation for more details.
There are two methods for associating patterns to rules in the XML file. One is for each rule element to directly define its pattern in a pattern attribute. An example would like something like:
<digester-rules> <object-create-rule pattern="*/foo" classname="Foo" /> <set-properties-rule pattern="*/foo" /> </digester-rules>
In the above example, an ObjectCreateRule is created and associated with the pattern "*/foo"; then a SetPropertiesRule is created and associated with the pattern "*/foo".
The other method is to nest rules elements inside a <pattern> element. In this way, the same pattern can be defined for a group of rules. The following example has the same effect as the previous example:
<digester-rules> <pattern value="*/foo"> <object-create-rule classname="Foo" /> <set-properties-rule /> </pattern> </digester-rules>
Pattern elements can be recursively nested. If patterns are nested, the pattern string is formed by concatenating all the patterns together. Example:
<digester-rules> <pattern value="*/foo"> <pattern value="bar"> <object-create-rule classname="Foobar" /> <set-properties-rule /> </pattern> </pattern> </digester-rules>
In the above example, an ObjectCreateRule and a SetPropertiesRule are associated with the matching pattern "*/foo/bar".
The use of pattern elements and the use of the pattern attribute inside rules elements can be freely mixed. The next example has the same effect as the previous example:
<digester-rules> <pattern value="*/foo"> <object-create-rule pattern="bar" classname="Foobar" /> <set-properties-rule pattern="bar" /> </pattern> </digester-rules>
The <include> element lets you include one rules file within another. With respect to pattern concatenation, the DigesterLoader behaves as if the include file was 'macro-expanded'. Example:
File rules1.xml: <?xml version="1.0"?> <!DOCTYPE digester-rules PUBLIC "-//Apache Commons //DTD digester-rules XML V1.0//EN" "http://commons.apache.org/digester/dtds/digester-rules-3.0.dtd"> <digester-rules> <pattern value="root/foo"> <object-create-rule classname="Foo" /> <include url="classpath:/rules2.xml" /> </pattern> </digester-rules> File rules2.xml: <?xml version="1.0"?> <!DOCTYPE digester-rules PUBLIC "-//Apache Commons //DTD digester-rules XML V1.0//EN" "http://commons.apache.org/digester/dtds/digester-rules-3.0.dtd"> <digester-rules> <pattern value="bar"> <object-create-rule classname="Bar" /> </pattern> </digester-rules>
Note that the url attribute accepts any valid URL, plus the the meta classpath URL, that points to a any valid resource present in the ClassPath; the ClassLoader used to load the resources is the same users set to resolve classes during the parse-time.
Parsing rule1.xml would result in a Digester initialized with these pattern/rule pairs:
root/foo -> ObjectCreateRule(Foo) root/foo/bar -> ObjectCreateRule(Bar)
Note that the pattern for the bar rule has been prepended with the root/foo pattern. If rule2.xml was parsed by itself, it would yield a Digester initialized with this pattern/rule:
bar -> ObjectCreateRule(Bar)
Sometimes rules cannot be easily defined via XML. Rule sets that are created programmatically can still be included within a digester-rules XML file. This is done by using an <include> element with a class attribute, containing the name of a class that implements org.apache.commons.digester3.binder.RulesModule. The pattern concatenation works exactly as if the rules had been included from an XML file, i.e.:
File rules3.xml: <?xml version="1.0"?> <!DOCTYPE digester-rules PUBLIC "-//Apache Commons //DTD digester-rules XML V1.0//EN" "http://commons.apache.org/digester/dtds/digester-rules-3.0.dtd"> <digester-rules> <pattern value="root/foo"> <object-create-rule classname="Foo" /> <include class="BarRuleModule" /> </pattern> </digester-rules>
BarRuleCreator class definition:
public class BarRuleModule extends AbstractRulesModule { @Override public void configure() { forPattern( "bar" ).objectCreate().ofType( Bar.class ); } }
Parsing rules3.xml yields the same results as rules1.xml above:
root/foo -> ObjectCreateRule(Foo) root/foo/bar -> ObjectCreateRule(Bar)
FromXmlRulesModule is a RulesModule implementation that initializes its Digester from rules defined in one or more XML files. The path to the XML files are passed in the configure() method, i.e.
public class MyRulesModule extends FromXmlRulesModule { @Override protected void loadRules() { loadXMLRules( new URL( "http://www.acme.com/shared/config/digester-rules.xml" ) ); loadXMLRules( new File( "/etc/digester-rules.xml" ) ); } }
The MyRulesModule can be reused now by the DigesterLoader to create Digester instances:
import static org.apache.commons.digester3.binder.DigesterLoader.newLoader; import org.apache.commons.digester3.Digester; import org.apache.commons.digester3.binder.DigesterLoader; ... DigesterLoader loader = newLoader( new MyRulesModule() ); ... Digester digester= loader.newDigester();