commons-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
Subject svn commit: r1073789 - /commons/sandbox/digester3/trunk/src/site/xdoc/guide/plugins.xml
Date Wed, 23 Feb 2011 15:38:54 GMT
Author: simonetripodi
Date: Wed Feb 23 15:38:54 2011
New Revision: 1073789

added the adapted version of plugin documentation

    commons/sandbox/digester3/trunk/src/site/xdoc/guide/plugins.xml   (with props)

Added: commons/sandbox/digester3/trunk/src/site/xdoc/guide/plugins.xml
--- commons/sandbox/digester3/trunk/src/site/xdoc/guide/plugins.xml (added)
+++ commons/sandbox/digester3/trunk/src/site/xdoc/guide/plugins.xml Wed Feb 23 15:38:54 2011
@@ -0,0 +1,339 @@
+<?xml version="1.0" encoding="UTF-8"?>
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+See the License for the specific language governing permissions and
+limitations under the License.
+<document xmlns=""
+  xmlns:xsi=""
+  xsi:schemaLocation="">
+  <properties>
+    <title>Download Commons Digester</title>
+    <author email="">Commons Documentation Team</author>
+  </properties>
+  <body>
+    <section name="An overview of the Digester Plugins module.">
+      <p>Provides an easy mechanism whereby new digestion rules 
+can be added dynamically during a digestion.</p>
+      <subsection name="Introduction">
+        <p>Many applications have xml configuration files which are "extensible".
+Some examples of this are:</p>
+<li>Apache log4j allows user-provided "Appender" classes to be specified in 
+    its configuration file</li>
+<li>Apache Avalon allows "components" of a user-specified class</li>
+<li>Apache Ant allows custom tasks to be defined</li>
+<p>The Digester "plugins" module can be used to add this kind of functionality
+to your own applications.
+      </subsection>
+      <subsection name="An Example">
+        <p>Let's start off with an example.</p>
+Given the following digester rules in the main "parsing" application:</p>
+    DigesterLoader digesterLoader = newLoader(new AbstractRulesModule() {
+        @Override
+        protected void configure() {
+            forPattern("pipeline")
+                .createObject()
+                    .ofType(Pipeline.class);
+            forPattern("pipeline/source")
+                .callMethod("setSource")
+                    .withParamCount(1)
+                .then()
+                .callParam()
+                    .ofIndex(0)
+                    .fromAttribute("file");
+            forPattern("pipeline/transform")
+                .createPlugin()
+                    .ofType(Transform.class)
+                .then()
+                .setNext("setTransform");
+            forPattern("pipeline/destination")
+                .callMethod("setDest")
+                    .withParamCount(1)
+                .then()
+                .callParam()
+                    .ofIndex(0)
+                    .fromAttribute("file");
+        }
+    });
+    ...
+    digesterLoader.newDigester(new PluginRules()).parse(filename);
+the following input can be processed:
+    &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;
+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 several mechanisms, including:</p>
+<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, somewhat in the spirit of 
+"BeanInfo" classes for java beans, or</li>
+<li> providing an xmlrules file which defines the associated parsing rules.</li>
+<p>If a plugin class has a no-parameter constructor, does not expect any subtags, 
+and is satisfied with mapping any attributes on the parent xml tag to 
+bean-property-setter methods on itself, then no rules need to be defined at 
+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 Transform interface, then cause these custom classes to be used
+instead of, or in addition to, classes distributed with the application.</p>
+      </subsection>
+      <subsection name="Plugin Declarations">
+        <p>As well as the syntax shown above, where plugin classnames were defined
+as they were used, plugin classes can be pre-declared (provided the application
+associates a <code>PluginDeclarationRule</code> with a tag for that purpose).
+<p>The plugin class can be declared once:</p>
+  &lt;plugin id="widget" class="com.acme.Widget"/&gt;
+<p>and later referenced via the short "id" value:</p>
+  &lt;sometag plugin-id="widget" ... &gt;
+      </subsection>
+      <subsection name="Suggested Applications">
+        <p>Any application where user-specific operations may need to be performed
+that cannot be known in advance by the initial application developer may
+benefit from this module. Applications in the style of the Apache projects 
+listed at the top of this page (Log4j, Cocoon, Ant) are examples.</p>
+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.</p>
+      </subsection>
+      <subsection name="Terminology">
+        <p>The term "plugin declaration" refers to an xml element which matches a
+PluginDeclarationRule, where the user specifies an id-to-class mapping.</p>
+The term "plugin point" refers to a pattern associated with a PluginCreateRule.
+An xml element matching that pattern is expected to have a plugin-id attribute
+(but see note on "default plugins" elsewhere in this document).</p>
+      </subsection>
+      <subsection name="Limitations">
+        <p>The user cannot replace the <i>name</i> of the tag used as the
+<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). 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 
+required. This is not expected to be a problem.
+      </subsection>
+      <subsection name="Performance">
+        <p>For patterns which do not involve "plugin points" there is minimal
+performance impact when adding rules to the Digester, and none when
+processing input data.</p>
+Processing elements which match patterns added dynamically by plugin classes 
+does have a performance impact, but not excessively so.</p>
+      </subsection>
+      <subsection name="Alternatives">
+        <p>The "xmlrules" digester module allows modification of parsing rules
+without code changes or recompilation. However this feature is aimed
+at the developer, not the end user of an application. The differences
+between xmlrules functionality and plugins functionality are:</p>
+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.
+Using xmlrules requires a fair level of knowledge of the Apache Digester.
+How an end user (not a plugin developer) can use plugins can be explained in 
+about 3 paragraphs. </li>
+      </subsection>
+      <subsection name="How to write plugin classes">
+        <p>In order to be useful, the problem domain needs to involve a base class
+interface which can have multiple implementations. This section assumes that
+this is the case, that you have already created a concrete implementation
+of that base class or interface, and are wondering what changes need to
+be made to that class to make it suitable for a "plugin".</p>
+Well, if the class has a no-argument constuctor, and only simple configuration
+needs that can be met by a SetPropertiesRule, then no changes need to be
+made at all.</p>
+In other circumstances, you may either define an "addRules" method on the
+class which adds any necessary rules to the digester, a separate class
+containing that information, or write an xmlrules-format file defining the
+necessary rules. In the "separate rule info class" approach, the class containing
+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 SubstituteTransform, from the example:</p>
+    public static void addRules(Digester d, String pathPrefix) {
+        newLoader(new AbstractRulesModule() {
+            @Override
+            protected void configure() {
+                // A Container object can have subtags called "widget" which
+                // define any object of type Widget. Because a Container is
+                // itself a widget, this allows us to build trees of objects.
+                forPattern(pattern + "/from")
+                    .callMethod("setFrom")
+                        .usingElementBodyAsArgument();
+                // allow users to declare plugins under a container as well
+                forPattern(pattern + "/to")
+                    .callMethod("setTo")
+                        .usingElementBodyAsArgument();
+            }
+        }).decorate(digester.getRules());
+    }
+<p>A "rule info" class consists of nothing but a static method defined as above.</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.</p>
+Note that when adding any rules, the pattern passed to the digester
+<i>must</i> start with the pathPrefix provided. A plugin cannot
+define rules with absolute paths. And as defined in the limitations, the 
+pattern should not include any wildcard characters.</p>
+      </subsection>
+      <subsection name="Other features">
+        <p>Multiple plugin declarations are permitted; the latest simply overrides
+earlier ones.</p>
+In situations where a user <i>might</i> want to specify a custom class,
+but will often want "default" behaviour, a PluginCreateRule can specify
+a default class. If the user then omits the "plugin-id" attribute on
+the matching xml element, an instance of the default class will be
+      </subsection>
+    </section>
+    <section name="Plugin strategies">
+      <p>
+The <code>plugins.strategies</code> package contains "rule-finding" strategy
+classes, and their associated "helper" loader classes.</p>
+Note that you do not need to understand or deal with any of the classes in
+this package in order to use the plugins functionality. If you wish to use
+plugins functionality in non-english languages and therefore want to
+change the attribute names used on plugin declaration tags ("id", "file", etc)
+then you will need some familiarity with this package. Otherwise, this package
+is only relevant to people really wishing to tweak plugins in unexpected
+ways. If this is the case, come and talk to us on the digester email lists
+as we would be interested in knowing about your requirements.</p>
+When the plugins module is being used and the input xml indicates that
+a specific plugin class is to be instantiated, that class may then wish
+to configure itself from the xml attributes on that tag or xml attributes
+and elements nested within that tag.</p>
+The question is: how is the digester going to figure out where the plugin
+keeps its custom rules which are to be applied to the xml within that
+plugin tag?</p>
+Well, the answer is that there is a list of "rule finding strategies",
+generally containing an instance of each of the Finder classes in this 
+package in a specific order. The strategies provided here should satisfy 
+just about everyone, but if they don't you can add extra strategies if 
+A RuleFinder is essentially a "strategy" or "algorithm" for finding the dynamic
+rules associated with a plugin class. When a plugin declaration is encountered 
+in the input xml, the PluginContext object is asked for the list of RuleFinder 
+objects, then each RuleFinder instance in turn is passed the declaration 
+parameters, and asked "are you able to locate custom parsing rules for this 
+declaration?". When one can, it returns a RuleLoader instance which is 
+remembered. When the input xml indicates that an instance of the declared 
+plugin class is to be created, that RuleLoader is invoked to temporarily add 
+the relevant custom rules to the Digester in order to map xml 
+attributes/elements/etc into the instantiated plugin object. Once the end of 
+the plugin tag is encountered, those temporary rules are removed. This repeats 
+each time the input xml indicates that an instance of a plugin class is to be 
+If the plugin is declared "inline", using the "plugin-class" attribute
+instead of using "plugin-id" to reference a previous declaration then the
+process is exactly the same, except that the RuleFinder objects don't
+have any user-provided attribute "hints" to tell them where the custom
+rules are.</p>
+The RuleFinder list is carefully ordered; classes which look at the 
+user-provided data in the declaration come first, and classes which look in 
+"well-known places" come later so that users can override default behaviour by 
+providing the appropriate tags on the plugin declaration.</p>
+See the javadoc on the different Finder classes for information on what
+each does, and what attribute (if any) it looks for in the declaration.</p>
+    </section>
+  </body>

Propchange: commons/sandbox/digester3/trunk/src/site/xdoc/guide/plugins.xml
    svn:eol-style = native

Propchange: commons/sandbox/digester3/trunk/src/site/xdoc/guide/plugins.xml
    svn:keywords = Date Revision Author HeadURL Id

Propchange: commons/sandbox/digester3/trunk/src/site/xdoc/guide/plugins.xml
    svn:mime-type = text/xml

View raw message