You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by sk...@apache.org on 2004/02/29 06:52:02 UTC

cvs commit: jakarta-commons/digester/src/java/org/apache/commons/digester/plugins package.html

skitching    2004/02/28 21:52:02

  Modified:    digester/src/java/org/apache/commons/digester/plugins
                        package.html
  Log:
  Significant changes; examples now based on the newly-committed code in
  src/examples/plugins/pipeline. This is a lot simpler to explain than
  the previous "statements" example. Also removed info on limitations
  that no longer exist in current plugins implementation.
  
  Revision  Changes    Path
  1.3       +78 -106   jakarta-commons/digester/src/java/org/apache/commons/digester/plugins/package.html
  
  Index: package.html
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/digester/src/java/org/apache/commons/digester/plugins/package.html,v
  retrieving revision 1.2
  retrieving revision 1.3
  diff -u -r1.2 -r1.3
  --- package.html	5 Oct 2003 19:48:40 -0000	1.2
  +++ package.html	29 Feb 2004 05:52:02 -0000	1.3
  @@ -22,75 +22,62 @@
   <p>
   Given the following digester rules in the main "parsing" application:
   <pre>
  -    Digester digester = new Digester();
  -    PluginRules rules = new PluginRules();
  -    digester.setRules(rules);
  -
  -    digester.addRule("program/plugin", new PluginDeclarationRule());
  -
  -    String pattern="program/statement";
  -    Class baseClass = Statement.class;
  -    Class defaultClass = StmtCompound.class;
  -    PluginCreateRule pluginRule = new PluginCreateRule(baseClass, defaultClass);
  -    digester.addRule(pattern, pluginRule);
  -    digester.addSetNext(pattern, "addStatement", baseClass.getName());
  +        Digester digester = new Digester();
  +        PluginRules rc = new PluginRules();
  +        digester.setRules(rc);
  +        
  +        digester.addObjectCreate("pipeline", Pipeline.class);
  +        
  +        digester.addCallMethod("pipeline/source", "setSource", 1);
  +        digester.addCallParam("pipeline/source", 0, "file");
  +        
  +        PluginCreateRule pcr = new PluginCreateRule(Transform.class);
  +        digester.addRule("pipeline/transform", pcr);
  +        digester.addSetNext("pipeline/transform", "setTransform");
  +        
  +        digester.addCallMethod("pipeline/destination", "setDest", 1);
  +        digester.addCallParam("pipeline/destination", 0, "file");
   
  -    digester.push(this);
  -    digester.parse(filename);
  +        digester.parse(filename);
   </pre>
   <p>
   the following input can be processed:
   <p>
   <pre>
  -    &lt;program&gt;
  -      &lt;plugin id="print" class="StmtPrint"/&gt;
  -      &lt;plugin id="block" class="StmtCompound"/&gt;
  -      &lt;plugin id="if" class="StmtIf"/&gt; 
  -      &lt;plugin id="equal" class="ExprEqual"/&gt; 
  -      &lt;plugin id="notempty" class="ExprNotEmpty"/&gt; 
  -    
  -      &lt;statement plugin-id="print" stmt-label="1"&gt;msg1&lt;/statement&gt;
  -    
  -      &lt;statement plugin-id="block"&gt;
  -        &lt;statement plugin-id="print" stmt-label="2.1"&gt;msg2a&lt;/statement&gt;
  -        &lt;statement plugin-id="print" stmt-label="2.1"&gt;msg2b&lt;/statement&gt;
  -      &lt;/statement&gt;
  -    
  -      &lt;statement plugin-id="if"&gt;
  -        &lt;expr plugin-id="equal"&gt;
  -          &lt;first-param&gt;foo&lt;/first-param&gt;
  -          &lt;second-param&gt;foo&lt;/second-param&gt;
  -        &lt;/expr&gt;
  -        &lt;statement plugin-id="print" stmt-label="foo"&gt;foo equals foo&lt;/statement&gt;
  -      &lt;/statement&gt;
  -    
  -      &lt;statement plugin-id="if"&gt;
  -        &lt;expr plugin-id="notempty"&gt;
  -          &lt;param/&gt;
  -        &lt;/expr&gt;
  -        &lt;statement plugin-id="block"&gt;
  -          &lt;statement plugin-id="print" stmt-label="bar"&gt;never reached part 1&lt;/statement&gt;
  -          &lt;statement plugin-id="print" stmt-label="bar"&gt;never reached part 2&lt;/statement&gt;
  -        &lt;/statement&gt;
  -      &lt;/statement&gt;
  -    
  -    &lt;/program&gt;
  +    &lt;pipeline&gt;
  +      &lt;source file="input.txt"/&gt;
  +      &lt;transform plugin-class="SubstituteTransform"&gt;
  +        &lt;from&gt;changeme&lt;/from&gt;
  +        &lt;to&gt;changed&lt;/to&gt;
  +      &lt;/transform&gt;
  +      &lt;destination file="output.txt"/&gt;
  +    &lt;/pipeline&gt;
   </pre>
   <p>
  -Note that the original application only defined a rule for "program/statement".
  -It is the input file which has defined exactly which class should
  -be instantiated when the statement element is encountered, and furthermore
  -the "plugin" classes have dynamically added rules for parsing elements
  -nested within themselves.
  +Note that the "SubstituteTransform" class is not hard-wired into the
  +application, and also that this class is configuring itself from the
  +same configuration file.
  +<p>
  +The user can specify any class they like here, and (provided that class follows
  +the plugins conventions) it can use any Digester functionality to process
  +the configuration data within the transform tag and its subtags.
  +<p>
  +The original application simply defined a "plugin point" of 
  +"pipeline/transform" at which user classes could be plugged in. However
  +it did not specify what classes were permitted, other than that they
  +must implement the Transform interface. It is the input file which has 
  +defined exactly which class should be instantiated when the transform 
  +element is encountered, and furthermore the "plugin" class itself has
  +dynamically added rules for parsing elements nested within itself.
   <p>
   A class used as a plugin may dynamically add its own rules to the digester,
   in order to process its attributes and any subtags in any manner it wishes.
  -This may be done by either:
  +This may be done by several mechanisms, including:
   <ul>
   <li> declaring a method <code>public static void addRules(Digester d, String
   pattern)</code> on the class being "plugged in", or</li>
  -<li> providing a separate "rule info" class in the plugin declaration, 
  -somewhat in the spirit of "BeanInfo" classes for java beans.</li>
  +<li> providing a separate "rule info" class, somewhat in the spirit of 
  +"BeanInfo" classes for java beans.</li>
   </ul>
   If a plugin class has a no-parameter constructor, does not expect any subtags, 
   and is content to map any attributes on the parent xml tag to 
  @@ -98,9 +85,24 @@
   all; the class can be used as a plugin without any coding.
   <p>
   In the example above, an end user may create their own classes which implement
  -the required Statement interface, then cause these custom classes to be used
  +the required Transform interface, then cause these custom classes to be used
   instead of, or in addition to, classes distributed with the application.
   
  +<h2> Plugin Declarations </h2>
  +
  +As well as the syntax shown above, where plugin classnames were defined
  +as they were used, plugin classes can be pre-defined (provided the application
  +associates a PluginDeclarationRule with a tag for that purpose). Example:
  +<p>
  +The plugin class can be declared once:
  +<pre>
  +  &lt;plugin id="widget" class="com.acme.Widget"/&gt;
  +</pre>
  +and later referenced via the short "id" value:
  +<pre>
  +  &lt;sometag plugin-id="widget" ... &gt;
  +</pre>
  +
   <h2> Possible Applications </h2>
   
   Any application where user-specific operations may need to be performed
  @@ -108,14 +110,9 @@
   benefit from this module. The apache projects listed at the top of this page
   (log4j, cocoon, ant) are examples.
   <p>
  -Note that the example above is an extreme example of configurability; 
  -it is expected that most application would have many rules of which only
  -a few would be "PluginCreateRule" rules, i.e. that the structure of the
  -input data would be <i>mostly</i> fixed, with only a few points at which
  -the end user could control the class being instantiated. Further, the
  -"recursive" nature of the plugin example above (where statements can
  -contain statements) is not expected to be typical; it is however 
  -fully supported.
  +Note also that plugged-in classes can themselves allow user-defined classes
  +to be plugged in within their configuration. This allows a very simple
  +framework to be extended almost without limit by the end user.
   
   <h2> Terminology </h2>
   
  @@ -128,19 +125,14 @@
   
   <h2> Limitations </h2>
   
  -The user cannot replace the <i>name</i> of the tag; 
  +The user cannot replace the <i>name</i> of the tag used as the plugin-point; 
   <code>&lt;statement plugin-id="if"&gt;</code> cannot become &lt;if&gt;.
   <p>
   An instance of "PluginRules" must be used as the Rules implementation
  -for the digester (see example). This class implements only the functionality
  -provided by the RulesBase class, ie no extended rules matching is available.
  -<p>
  -No wildcard patterns are allowed to be associated with PluginCreateRule
  -instances. For example <code>digester.addRule("*/statement", pcr)</code>
  -is not permitted. This is simply because handling "recursive" plugins
  -(ones which allow instances of themselves to be plugged in below themselves,
  -as in the Statement example) becomes extremely complicated when wildcard
  -patterns are involved. 
  +for the digester (see example). However a PluginRules can use any other Rules
  +implementation as its rule-matching engine, so this is not a significant issue.
  +Plugged-in classes may only use the default RulesBase matching for the rules
  +they add dynamically.
   <p>
   For technical reasons, a single instance of PluginCreateRule cannot 
   currently be associated with multiple patterns; multiple instances are 
  @@ -164,13 +156,14 @@
   between xmlrules functionality and plugins functionality are:
   <ul>
   <li> 
  -With xmlrules, the full set of parsing rules is exposed. This is
  -good for developers, but in most cases both too complex and too dangerous
  -to require end users to edit directly.
  +With xmlrules, the full set of parsing rules for the whole configuration file
  +is exposed. This is good for developers, but in most cases both too complex 
  +and too dangerous to require end users to edit directly.
   </li>
   <li>
   Using xmlrules requires a fair level of knowledge of the Apache Digester.
  -How a user can use plugins can be explained in about 3 paragraphs. </li>
  +How an end user (not a plugin developer) can use plugins can be explained in 
  +about 3 paragraphs. </li>
   </ul>
   
   <h2> How to write plugin classes </h2>
  @@ -191,46 +184,25 @@
   the rule info may have any name of your choice, but the original class + 
   "RuleInfo" is recommended.
   <p>
  -Here is the addRules method on class StmtCompound, from the original example:
  +Here is the addRules method on class SubstituteTransform, from the example:
   <pre>
  -    public static void addRules(Digester digester, String patternPrefix)
  -    {
  -        digester.addSetProperties(patternPrefix);
  -
  -        String pattern = patternPrefix + "/statement";
  -        Class baseClass = Statement.class;
  -        PluginCreateRule pluginRule = new PluginCreateRule(baseClass);
  -        digester.addRule(pattern, pluginRule);
  -        digester.addSetNext(pattern, "addStmt", baseClass.getName());
  +    public static void addRules(Digester d, String patternPrefix) {
  +        d.addCallMethod(patternPrefix+"/from", "setFrom", 0);
  +        d.addCallMethod(patternPrefix+"/to", "setTo", 0);
       }
   </pre>
   A "rule info" class consists of nothing but a static method defined as above.
   <p>
  -The plugins module ensures that the addRules method is called exactly once
  -for each "plugin point" in the input document. For example, if a Statement
  -can be present at /program/statement and /program/statement/statement, then
  -the addRules method is called once with each of those patterns as a
  -parameter. Note that these calls are made in a "lazy" manner, ie only 
  -when absolutely necessary, to avoid recursion problems.
  -<p>
   If a plugin class does not define an "addRules" method, and the plugin
   declaration does not associate a rule info class with it, then the 
   plugins module will define a "SetPropertiesRule" by default. However if
   any custom rules are defined for the plugin class, then that implementation
  -is required to define a SetPropertiesRule for itself if it desires one,
  -hence the addSetProperties call above.
  -<p>
  -If the StmtCompound wished to define CallMethodRule rules, or any other
  -Digester functionality, it could do so. The example above shows how the
  -StmtCompound allows a subelement of &lt;statement&gt; at which the user
  - may plug in any class derived from Statement.
  +is required to define a SetPropertiesRule for itself if it desires one.
   <p>
   Note that when adding any rules, the pattern passed to the digester
   <i>must</i> start with the patternPrefix provided. A plugin cannot
  -define rules with absolute paths. And because using plugins requires 
  -using PluginRules, which does not support internal or trailing 
  -wildcards, the pattern should not include any wildcard characters either. 
  -Neither of these are expected to be problems in practice.
  +define rules with absolute paths. And as defined in the limitations, the 
  +pattern should not include any wildcard characters. 
   
   <h2> Other features </h2>
   
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org