commons-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From skitch...@apache.org
Subject svn commit: r154457 [2/2] - in jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins: ./ strategies/
Date Sun, 20 Feb 2005 00:38:00 GMT
Added: jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/RuleFinder.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/RuleFinder.java?view=auto&rev=154457
==============================================================================
--- jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/RuleFinder.java (added)
+++ jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/RuleFinder.java Sat Feb 19 16:37:55 2005
@@ -0,0 +1,74 @@
+/* $Id$
+ *
+ * Copyright 2004,2005 The Apache Software Foundation.
+ * 
+ * Licensed 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
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+ 
+package org.apache.commons.digester2.plugins;
+
+import java.util.Properties;
+import org.apache.commons.digester2.Context;
+
+/**
+ * Each concrete implementation of RuleFinder is an algorithm for
+ * locating a source of digester rules for a plugin. The algorithm may 
+ * use info explicitly provided by the user as part of the plugin 
+ * declaration, or not (in which case the concrete RuleFinder subclass
+ * typically has Dflt as part of its name).
+ * <p>
+ * Instances of this class can also be regarded as a Factory for RuleLoaders,
+ * except that an instance of a RuleLoader is only created if the particular
+ * finder algorithm can locate a suitable source of rules given the plugin
+ * class and associated properties.
+ * <p>
+ * This is an abstract class rather than an interface in order to make
+ * it possible to enhance this class in future without breaking binary
+ * compatibility; it is possible to add methods to an abstract class, but
+ * not to an interface. 
+ */
+
+public abstract class RuleFinder {
+
+    /**
+     * Apply the finder algorithm to attempt to locate a source of
+     * digester rules for the specified plugin class.
+     * <p>
+     * This method is invoked when a plugin is declared by the user, either
+     * via an explicit use of PluginDeclarationRule, or implicitly via an
+     * "inline declaration" where the declaration and use are simultaneous.
+     * <p>
+     * If dynamic rules for the specified plugin class are located, then
+     * the RuleFinder will return a RuleLoader object encapsulating those
+     * rules, and this object will be invoked each time the user actually
+     * requests an instance of the declared plugin class, to load the
+     * custom rules associated with that plugin instance.
+     * <p>
+     * If no dynamic rules can be found, null is returned. This is not an
+     * error; merely an indication that this particular algorithm found
+     * no matches.
+     * <p>
+     * The properties object holds any xml attributes the user may have
+     * specified on the plugin declaration in order to indicate how to locate
+     * the plugin rules.
+     * <p>
+     * @throws PluginConfigurationException if the algorithm finds a source
+     * of rules, but there is something invalid about that source.
+     */
+
+     public abstract RuleLoader findLoader(
+     Context context, Class pluginClass, 
+     Properties p) 
+     throws PluginException;
+}
+

Propchange: jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/RuleFinder.java
------------------------------------------------------------------------------
    svn:keywords = Id

Added: jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/RuleLoader.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/RuleLoader.java?view=auto&rev=154457
==============================================================================
--- jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/RuleLoader.java (added)
+++ jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/RuleLoader.java Sat Feb 19 16:37:55 2005
@@ -0,0 +1,47 @@
+/* $Id$
+ *
+ * Copyright 2004,2005 The Apache Software Foundation.
+ * 
+ * Licensed 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
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+ 
+package org.apache.commons.digester2.plugins;
+
+import org.apache.commons.digester2.Context;
+
+/**
+ * Interface for classes which can dynamically load custom
+ * plugin rules associated with a user's plugin class.
+ * <p>
+ * Each plugin declaration has an associated RuleLoader instance, and that
+ * instance's addRules method is invoked each time the input xml specifies
+ * that an instance of that plugged-in class is to be created.
+ * <p>
+ * This is an abstract class rather than an interface in order to make
+ * it possible to enhance this class in future without breaking binary
+ * compatibility; it is possible to add methods to an abstract class, but
+ * not to an interface. 
+ */
+
+public abstract class RuleLoader {
+    
+    /**
+     * Configures the digester with custom rules for some plugged-in
+     * class.
+     * <p>
+     * This method is invoked when the start of an xml tag is encountered
+     * which maps to a PluginCreateRule. Any rules added here are removed
+     * from the digester when the end of that xml tag is encountered.
+     */
+    public abstract void addRules(Context context) throws PluginException;
+}

Propchange: jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/RuleLoader.java
------------------------------------------------------------------------------
    svn:keywords = Id

Added: jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/package.html
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/package.html?view=auto&rev=154457
==============================================================================
--- jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/package.html (added)
+++ jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/package.html Sat Feb 19 16:37:55 2005
@@ -0,0 +1,226 @@
+<!-- $Id$
+  
+ Copyright 2001-2005 The Apache Software Foundation.
+ 
+ Licensed 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
+  
+       http://www.apache.org/licenses/LICENSE-2.0
+  
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+--> 
+<html>
+<head>
+<title>An overview of the Digester Plugins module.</title>
+</head>
+<body>
+<p>Provides an easy mechanism whereby new digestion rules 
+can be added dynamically during a digestion.</p>
+<h2> Introduction. </h2>
+Many applications have xml configuration files which are "extensible".
+Some examples of this are:
+<ul>
+<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>
+</ul>
+The Digester "plugins" module can be used to add this kind of functionality
+to your own applications.
+<p>
+<h2> An Example </h2>
+Let's start off with an example.
+<p>
+Given the following digester rules in the main "parsing" application:
+<pre>
+        Digester digester = new Digester();
+        ActionFactory factory = new ActionFactory(digester);
+        
+        factory.addObjectCreate("pipeline", Pipeline.class);
+        factory.addCallMethod("pipeline/source", "setSource", 1);
+        factory.addCallAttributeParam("pipeline/source", 0, "file");
+        
+        PluginCreateAction pca = new PluginCreateAction(Transform.class);
+        factory.addRule("pipeline/transform", pca);
+        factory.addLinkObjects("pipeline/transform", "setTransform");
+        
+        factory.addCallMethod("pipeline/destination", "setDest", 1);
+        factory.addCallAttributeParam("pipeline/destination", 0, "file");
+
+        digester.parse(filename);
+</pre>
+<p>
+the following input can be processed:
+<p>
+<pre>
+    &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 "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:
+<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, somewhat in the spirit of 
+"BeanInfo" classes for java beans, or</li>
+<li> providing an xmlrules file which defines the associated parsing rules.</li>
+</ul>
+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 java
+properties of the same name 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.
+
+<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-declared (provided the application
+associates a <code>PluginDeclarationAction</code> 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> Suggested Applications </h2>
+
+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.
+
+<h2> Terminology </h2>
+
+The term "plugin declaration" refers to an xml element which matches a
+PluginDeclarationAction, where the user specifies an id-to-class mapping.
+<p>
+The term "plugin point" refers to a pattern associated with a PluginCreateAction.
+An xml element matching that pattern is expected to have a plugin-id attribute
+(but see note on "default plugins" elsewhere in this document).
+
+<h2> Limitations </h2>
+
+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;.
+
+<h2> Performance </h2>
+
+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.
+
+<h2> Alternatives </h2>
+
+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:
+<ul>
+<li> 
+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 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>
+
+In order to be useful, the problem domain needs to involve a base class or 
+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 SetPropertiesAction, 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:
+<pre>
+    public static void addRules(RuleManager rm, String pathPrefix) {
+        rm.addRule("/from", new SetPropertyAction());
+        rm.addRule("/to", new SetPropertyAction());
+    }
+</pre>
+Note that if many rules are to be added, it might be more convenient to
+create an ActionFactory instance to assist in adding the rules.
+<p>
+A "rule info" class consists of a class declaration containing 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 "SetPropertiesAction" by default. However if
+any custom rules are defined for the plugin class, then that implementation
+is required to define a SetPropertiesAction for itself if it desires one.
+<p>
+Note that when adding any rules, the path to the xml element which "triggered"
+the plugin is automatically prepended to any absolute patterns.
+
+<h2> Other features </h2>
+
+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 PluginCreateaction 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
+created.
+</body>
+</html>

Added: jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/strategies/FinderFromClass.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/strategies/FinderFromClass.java?view=auto&rev=154457
==============================================================================
--- jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/strategies/FinderFromClass.java (added)
+++ jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/strategies/FinderFromClass.java Sat Feb 19 16:37:55 2005
@@ -0,0 +1,125 @@
+/* $Id$
+ *
+ * Copyright 2004,2005 The Apache Software Foundation.
+ * 
+ * Licensed 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
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+ 
+package org.apache.commons.digester2.plugins.strategies;
+
+import java.util.Properties;
+import org.apache.commons.digester2.Context;
+import org.apache.commons.digester2.plugins.RuleFinder;
+import org.apache.commons.digester2.plugins.RuleLoader;
+import org.apache.commons.digester2.plugins.PluginException;
+
+/**
+ * A rule-finding algorithm which expects the caller to specify a classname and
+ * methodname as plugin properties.
+ */
+
+public class FinderFromClass extends RuleFinder {
+    public static String DFLT_RULECLASS_ATTR = "ruleclass";
+    public static String DFLT_METHOD_ATTR = "method";
+    public static String DFLT_METHOD_NAME = "addRules";
+    
+    private String ruleClassAttr;
+    private String methodAttr;
+    private String dfltMethodName;
+    
+    /**
+     * See {@link #findLoader}.
+     */
+    public FinderFromClass() {
+        this(DFLT_RULECLASS_ATTR, DFLT_METHOD_ATTR, DFLT_METHOD_NAME);
+    }
+
+    /**
+     * Create a rule-finder which invokes a user-specified method on a
+     * user-specified class whenever dynamic rules for a plugin need to be
+     * loaded. See the findRules method for more info.
+     *
+     * @param ruleClassAttr must be non-null.
+     * @param methodAttr may be null.
+     * @param dfltMethodName may be null.
+     */
+    public FinderFromClass(String ruleClassAttr, String methodAttr, 
+                String dfltMethodName) {
+        this.ruleClassAttr = ruleClassAttr;
+        this.methodAttr = methodAttr;
+        this.dfltMethodName = dfltMethodName;
+    }
+    
+    /**
+     * If there exists a property with the name matching constructor param
+     * ruleClassAttr, then load the specified class, locate the appropriate 
+     * rules-adding method on that class, and return an object encapsulating 
+     * that info.
+     * <p>
+     * If there is no matching property provided, then just return null.
+     * <p>
+     * The returned object (when non-null) will invoke the target method
+     * on the selected class whenever its addRules method is invoked. The
+     * target method is expected to have the following prototype:
+     * <code> public static void xxxxx(RuleManager rm, String patternPrefix); </code>
+     * <p>
+     * The target method can be specified in several ways. If this object's
+     * constructor was passed a non-null methodAttr parameter, and the
+     * properties defines a value with that key, then that is taken as the
+     * target method name. If there is no matching property, or the constructor
+     * was passed null for methodAttr, then the dfltMethodName passed to the
+     * constructor is used as the name of the method on the target class. And
+     * if that was null, then DFLT_METHOD_NAME will be used.
+     * <p>
+     * When the user explicitly declares a plugin in the input xml, the
+     * xml attributes on the declaration tag are passed here as properties,
+     * so the user can select any class in the classpath (and any method on
+     * that class provided it has the correct prototype) as the source of
+     * dynamic rules for the plugged-in class.
+     */
+    public RuleLoader findLoader(Context context, Class pluginClass, 
+                        Properties p) throws PluginException {
+
+        String ruleClassName = p.getProperty(ruleClassAttr);
+        if (ruleClassName == null) {
+            // nope, user hasn't requested dynamic rules to be loaded
+            // from a specific class.
+            return null;
+        }
+        
+        // ok, we are in business
+        String methodName = null;
+        if (methodAttr != null) { 
+            methodName = p.getProperty(methodAttr);
+        }
+        if (methodName == null) {
+            methodName = dfltMethodName;
+        }
+        if (methodName == null) {
+            methodName = DFLT_METHOD_NAME;
+        }
+        
+        Class ruleClass;
+        try {
+            // load the plugin class object
+            ruleClass = 
+                context.getClassLoader().loadClass(ruleClassName);
+        } catch(ClassNotFoundException cnfe) {
+            throw new PluginException(
+                "Unable to load class " + ruleClassName, cnfe);
+        }
+
+        return new LoaderFromClass(ruleClass, methodName);
+    }
+}
+

Propchange: jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/strategies/FinderFromClass.java
------------------------------------------------------------------------------
    svn:keywords = Id

Added: jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/strategies/FinderFromDfltClass.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/strategies/FinderFromDfltClass.java?view=auto&rev=154457
==============================================================================
--- jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/strategies/FinderFromDfltClass.java (added)
+++ jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/strategies/FinderFromDfltClass.java Sat Feb 19 16:37:55 2005
@@ -0,0 +1,94 @@
+/* $Id$
+ *
+ * Copyright 2004,2005 The Apache Software Foundation.
+ * 
+ * Licensed 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
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+ 
+package org.apache.commons.digester2.plugins.strategies;
+
+import java.util.Properties;
+import org.apache.commons.digester2.Context;
+import org.apache.commons.digester2.plugins.RuleFinder;
+import org.apache.commons.digester2.plugins.RuleLoader;
+import org.apache.commons.digester2.plugins.PluginException;
+
+/**
+ * A rule-finding algorithm which looks for a method with a specific name
+ * on a class whose name is derived from the plugin class name.
+ */
+
+public class FinderFromDfltClass extends RuleFinder {
+    public static String DFLT_RULECLASS_SUFFIX = "RuleInfo";
+    public static String DFLT_METHOD_NAME = "addRules";
+    
+    private String rulesClassSuffix;
+    private String methodName;
+    
+    /** See {@link #findLoader}. */
+    public FinderFromDfltClass() {
+        this(DFLT_RULECLASS_SUFFIX, DFLT_METHOD_NAME);
+    }
+    
+    /**
+     * Create a rule-finder which invokes a method on a class whenever 
+     * dynamic rules for a plugin need to be loaded. See the findRules 
+     * method for more info.
+     *
+     * @param rulesClassSuffix must be non-null.
+     * @param methodName may be null.
+     */
+     public FinderFromDfltClass(String rulesClassSuffix, String methodName) { 
+        this.rulesClassSuffix = rulesClassSuffix;
+        this.methodName = methodName;
+    }
+    
+    /**
+     * If there exists a class whose name is the plugin class name + the
+     * suffix specified to the constructor, then load that class, locate 
+     * the appropriate rules-adding method on that class, and return an 
+     * object encapsulating that info.
+     * <p>
+     * If there is no such class, then just return null.
+     * <p>
+     * The returned object (when non-null) will invoke the target method
+     * on the selected class whenever its addRules method is invoked. The
+     * target method is expected to have the following prototype:
+     * <code> public static void xxxxx(RuleManager rm, String patternPrefix); </code>
+     */
+    public RuleLoader findLoader(
+    Context context, Class pluginClass, Properties p)
+    throws PluginException {
+
+        String rulesClassName = pluginClass.getName() + rulesClassSuffix;
+
+        Class rulesClass = null;
+        try {
+            rulesClass = context.getClassLoader().loadClass(rulesClassName);
+        } catch(ClassNotFoundException cnfe) {
+            // ok, ignore
+        }
+
+        if (rulesClass == null) {
+            // nope, no rule-info class in the classpath
+            return null;
+        }
+        
+        if (methodName == null) {
+            methodName = DFLT_METHOD_NAME;
+        }
+        
+        return new LoaderFromClass(rulesClass, methodName);
+    }
+}
+

Propchange: jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/strategies/FinderFromDfltClass.java
------------------------------------------------------------------------------
    svn:keywords = Id

Added: jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/strategies/FinderFromDfltMethod.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/strategies/FinderFromDfltMethod.java?view=auto&rev=154457
==============================================================================
--- jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/strategies/FinderFromDfltMethod.java (added)
+++ jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/strategies/FinderFromDfltMethod.java Sat Feb 19 16:37:55 2005
@@ -0,0 +1,79 @@
+/* $Id$
+ *
+ * Copyright 2004,2005 The Apache Software Foundation.
+ * 
+ * Licensed 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
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+ 
+package org.apache.commons.digester2.plugins.strategies;
+
+import java.io.InputStream;
+import java.util.Properties;
+import java.lang.reflect.Method;
+
+import org.apache.commons.digester2.Context;
+import org.apache.commons.digester2.plugins.RuleFinder;
+import org.apache.commons.digester2.plugins.RuleLoader;
+import org.apache.commons.digester2.plugins.PluginException;
+
+/**
+ * A rule-finding algorithm which looks for a method with a specific name
+ * on the plugin class.
+ */
+
+public class FinderFromDfltMethod extends RuleFinder {
+    public static String DFLT_METHOD_NAME = "addRules";
+
+    private String methodName;
+    
+    /** See {@link #findLoader}. */
+    public FinderFromDfltMethod() { 
+        this(DFLT_METHOD_NAME);
+    }
+
+    /**
+     * Create a rule-finder which invokes a specific method on the plugin
+     * class whenever dynamic rules for a plugin need to be loaded. See the 
+     * findRules method for more info.
+     *
+     * @param methodName must be non-null.
+     */
+    public FinderFromDfltMethod(String methodName) { 
+        this.methodName = methodName;
+    }
+    
+    /**
+     * If there exists on the plugin class a method with name matching the 
+     * constructor's methodName value then locate the appropriate Method on 
+     * the plugin class and return an object encapsulating that info.
+     * <p>
+     * If there is no matching method then just return null.
+     * <p>
+     * The returned object (when non-null) will invoke the target method
+     * on the plugin class whenever its addRules method is invoked. The
+     * target method is expected to have the following prototype:
+     * <code> public static void xxxxx(RuleManager rm, String patternPrefix); </code>
+     */
+    public RuleLoader findLoader(
+    Context context, Class pluginClass, Properties p)
+    throws PluginException {
+
+        Method rulesMethod = LoaderFromClass.locateMethod(pluginClass, methodName);
+        if (rulesMethod == null) {
+            return null;
+        }
+        
+        return new LoaderFromClass(pluginClass, rulesMethod);
+    }
+}
+

Propchange: jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/strategies/FinderFromDfltMethod.java
------------------------------------------------------------------------------
    svn:keywords = Id

Added: jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/strategies/FinderFromMethod.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/strategies/FinderFromMethod.java?view=auto&rev=154457
==============================================================================
--- jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/strategies/FinderFromMethod.java (added)
+++ jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/strategies/FinderFromMethod.java Sat Feb 19 16:37:55 2005
@@ -0,0 +1,77 @@
+/* $Id$
+ *
+ * Copyright 2004,2005 The Apache Software Foundation.
+ * 
+ * Licensed 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
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+ 
+package org.apache.commons.digester2.plugins.strategies;
+
+import java.util.Properties;
+import org.apache.commons.digester2.Context;
+import org.apache.commons.digester2.plugins.RuleFinder;
+import org.apache.commons.digester2.plugins.RuleLoader;
+import org.apache.commons.digester2.plugins.PluginException;
+
+/**
+ * A rule-finding algorithm which expects the caller to specify a methodname
+ * as a plugin property, where the method exists on the plugin class.
+ */
+
+public class FinderFromMethod extends RuleFinder {
+    /**
+     * Xml attribute that needs to be present on a plugin declaration
+     * in order to specify the method to load rules from.
+     */
+    public static String DFLT_METHOD_ATTR = "method";
+    
+    /** See {@link #findLoader}. */
+    private String methodAttr;
+    
+    /** Constructor. */
+    public FinderFromMethod() {
+        this(DFLT_METHOD_ATTR);
+    }
+
+    /** See {@link #findLoader}. */
+    public FinderFromMethod(String methodAttr) { 
+        this.methodAttr = methodAttr;
+    }
+    
+    /**
+     * If there exists a property with the name matching constructor param
+     * methodAttr, then locate the appropriate Method on the plugin class 
+     * and return an object encapsulating that info.
+     * <p>
+     * If there is no matching property provided, then just return null.
+     * <p>
+     * The returned object (when non-null) will invoke the target method
+     * on the plugin class whenever its addRules method is invoked. The
+     * target method is expected to have the following prototype:
+     * <code> public static void xxxxx(Digester d, String patternPrefix); </code>
+     */
+    public RuleLoader findLoader(
+    Context context, Class pluginClass, Properties p)
+    throws PluginException {
+
+        String methodName = p.getProperty(methodAttr);
+        if (methodName == null) {
+            // nope, user hasn't requested dynamic rules to be loaded
+            // from a specific class.
+            return null;
+        }
+        
+        return new LoaderFromClass(pluginClass, methodName);
+    }
+}
+

Propchange: jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/strategies/FinderFromMethod.java
------------------------------------------------------------------------------
    svn:keywords = Id

Added: jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/strategies/FinderSetProperties.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/strategies/FinderSetProperties.java?view=auto&rev=154457
==============================================================================
--- jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/strategies/FinderSetProperties.java (added)
+++ jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/strategies/FinderSetProperties.java Sat Feb 19 16:37:55 2005
@@ -0,0 +1,100 @@
+/* $Id$
+ *
+ * Copyright 2004,2005 The Apache Software Foundation.
+ * 
+ * Licensed 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
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+ 
+package org.apache.commons.digester2.plugins.strategies;
+
+import java.util.Properties;
+import java.io.InputStream;
+import java.io.FileInputStream;
+import java.io.IOException;
+
+import org.apache.commons.digester2.Context;
+import org.apache.commons.digester2.plugins.RuleFinder;
+import org.apache.commons.digester2.plugins.RuleLoader;
+import org.apache.commons.digester2.plugins.PluginException;
+
+/**
+ * A rule-finding algorithm which expects the user to specify whether
+ * "automatic property setting" is desired. If this class discovers that
+ * this is in fact the case for a declaration, then a RuleLoader is returned
+ * which, when invoked, adds a single SetPropertiesRule instance to the
+ * digester.
+ * <p>
+ * This allows ordinary JavaBean classes to be used as plugins, and have
+ * xml attributes be mapped to bean properties of the same name, without
+ * any custom plugin rules being created for them.
+ * <p>
+ * This RuleFinder is typically used as the <i>last</i> RuleFinder, so that
+ * automatic property setting only occurs if there is no other source of
+ * custom rules available.
+ */
+
+public class FinderSetProperties extends RuleFinder {
+    public static String DFLT_PROPS_ATTR = "setprops";
+    public static String DFLT_FALSEVAL = "false";
+
+    private String propsAttr;
+    private String falseval;
+    
+    /** See {@link #findLoader}. */
+    public FinderSetProperties() {
+        this(DFLT_PROPS_ATTR, DFLT_FALSEVAL);
+    }
+    
+    /**
+     * Create a rule-finder which will arrange for a SetPropertiesRule to
+     * be defined for each instance of a plugin, so that xml attributes
+     * map to bean properties.
+     * <p>
+     * Param falseval will commonly be the string "false" for config files 
+     * written in English.
+     *
+     * @param propsAttr must be non-null.
+     * @param falseval must be non-null.
+     */
+    public FinderSetProperties(String propsAttr, String falseval) { 
+        this.propsAttr = propsAttr;
+        this.falseval = falseval;
+    }
+    
+    /**
+     * Returns a RuleLoader <i>unless</i> the properties contain an entry
+     * with the name matching constructor param propsAttr, and the value 
+     * matching what is in falseval.
+     * <p>
+     * If no custom source of rules for a plugin is found, then the user
+     * almost always wants xml attributes to map to java bean properties,
+     * so this is the default behaviour unless the user explicitly indicates
+     * that they do <i>not</i> want a SetPropertiesRule to be provided for
+     * the plugged-in class.
+     * <p>
+     * The returned object (when non-null) will add a SetPropertiesRule to
+     * the digester whenever its addRules method is invoked.
+     */
+    public RuleLoader findLoader(
+    Context context, Class pluginClass, Properties p) {
+        String state = p.getProperty(propsAttr);
+        if ((state != null)  && state.equals(falseval)) {
+            // user has explicitly disabled automatic setting of properties.
+            // this is not expected to be common, but allowed.
+            return null;
+        }
+        
+        return new LoaderSetProperties();
+    }
+}
+

Propchange: jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/strategies/FinderSetProperties.java
------------------------------------------------------------------------------
    svn:keywords = Id

Added: jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/strategies/LoaderFromClass.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/strategies/LoaderFromClass.java?view=auto&rev=154457
==============================================================================
--- jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/strategies/LoaderFromClass.java (added)
+++ jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/strategies/LoaderFromClass.java Sat Feb 19 16:37:55 2005
@@ -0,0 +1,104 @@
+/* $Id$
+ *
+ * Copyright 2004,2005 The Apache Software Foundation.
+ *
+ * Licensed 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
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.digester2.plugins.strategies;
+
+import java.lang.reflect.Method;
+
+import org.apache.commons.beanutils.MethodUtils;
+import org.apache.commons.logging.Log;
+
+import org.apache.commons.digester2.Context;
+import org.apache.commons.digester2.RuleManager;
+import org.apache.commons.digester2.plugins.RuleLoader;
+import org.apache.commons.digester2.plugins.PluginException;
+
+/**
+ * A RuleLoader which invokes a static method on a target class, leaving that
+ * method to actually instantiate and add new rules to a Digester instance.
+ */
+
+public class LoaderFromClass extends RuleLoader {
+
+    private Class rulesClass;
+    private Method rulesMethod;
+
+    /** Constructor. */
+    public LoaderFromClass(Class rulesClass, Method rulesMethod) {
+        this.rulesClass = rulesClass;
+        this.rulesMethod = rulesMethod;
+    }
+
+    /** Constructor. */
+    public LoaderFromClass(Class rulesClass, String methodName)
+                throws PluginException {
+
+        Method method = locateMethod(rulesClass, methodName);
+
+        if (method == null) {
+            throw new PluginException(
+                "rule class " + rulesClass.getName()
+                + " does not have method " + methodName
+                + " or that method has an invalid signature.");
+        }
+
+        this.rulesClass = rulesClass;
+        this.rulesMethod = method;
+    }
+
+    /**
+     * Just invoke the target method.
+     */
+    public void addRules(Context context) throws PluginException {
+        String path = context.getMatchPath();
+
+        Log log = context.getLogger();
+        boolean debug = log.isDebugEnabled();
+        if (debug) {
+            log.debug(
+                "LoaderFromClass loading rules for plugin at path ["
+                + path + "]");
+        }
+
+        try {
+            Object[] params = {context.getRuleManager(), path};
+            Object none = rulesMethod.invoke(null, params);
+        } catch (Exception e) {
+            throw new PluginException(
+                "Unable to invoke rules method " + rulesMethod
+                + " on rules class " + rulesClass, e);
+        }
+    }
+
+    /**
+     * Find a method on the specified class whose name matches methodName,
+     * and whose signature is:
+     * <code> public static void foo(RuleManager rm, String patternPrefix);</code>.
+     *
+     * @return null if no such method exists.
+     */
+    public static Method locateMethod(Class rulesClass, String methodName)
+    throws PluginException {
+
+        Class[] paramSpec = { RuleManager.class, String.class };
+        Method rulesMethod = MethodUtils.getAccessibleMethod(
+            rulesClass, methodName, paramSpec);
+
+        return rulesMethod;
+    }
+}
+

Propchange: jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/strategies/LoaderFromClass.java
------------------------------------------------------------------------------
    svn:keywords = Id

Added: jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/strategies/LoaderSetProperties.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/strategies/LoaderSetProperties.java?view=auto&rev=154457
==============================================================================
--- jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/strategies/LoaderSetProperties.java (added)
+++ jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/strategies/LoaderSetProperties.java Sat Feb 19 16:37:55 2005
@@ -0,0 +1,62 @@
+/* $Id$
+ *
+ * Copyright 2004,2005 The Apache Software Foundation.
+ * 
+ * Licensed 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
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */ 
+ 
+package org.apache.commons.digester2.plugins.strategies;
+
+import org.apache.commons.logging.Log;
+
+import org.apache.commons.digester2.Context;
+import org.apache.commons.digester2.InvalidRuleException;
+import org.apache.commons.digester2.actions.SetPropertiesAction;
+import org.apache.commons.digester2.plugins.RuleLoader;
+import org.apache.commons.digester2.plugins.PluginException;
+
+/**
+ * A RuleLoader which creates a single SetPropertiesRule and adds it to the
+ * digester when its addRules() method is invoked.
+ * <p>
+ * This loader ensures that any xml attributes on the plugin tag get
+ * mapped to equivalent properties on a javabean. This allows JavaBean
+ * classes to be used as plugins without any requirement to create custom
+ * plugin rules.
+ */
+
+public class LoaderSetProperties extends RuleLoader {
+    
+    /**
+     * Just add a SetPropertiesRule at the specified path.
+     */
+    public void addRules(Context context) 
+    throws PluginException {
+        String path = context.getMatchPath();
+
+        Log log = context.getLogger();
+        boolean debug = log.isDebugEnabled();
+        if (debug) {
+            log.debug(
+                "LoaderSetProperties loading rules for plugin at path [" 
+                + path + "]");
+        }
+
+        try {
+            context.getRuleManager().addRule(null, new SetPropertiesAction());
+        } catch(InvalidRuleException ex) {
+            throw new PluginException(ex);
+        }
+    }
+}
+

Propchange: jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/strategies/LoaderSetProperties.java
------------------------------------------------------------------------------
    svn:keywords = Id

Added: jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/strategies/package.html
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/strategies/package.html?view=auto&rev=154457
==============================================================================
--- jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/strategies/package.html (added)
+++ jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/plugins/strategies/package.html Sat Feb 19 16:37:55 2005
@@ -0,0 +1,78 @@
+<!-- $Id: package.html 132718 2004-09-09 20:38:21Z rdonkin $
+  
+ Copyright 2001-2004 The Apache Software Foundation.
+ 
+ Licensed 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
+  
+       http://www.apache.org/licenses/LICENSE-2.0
+  
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+--> 
+<html>
+<head>
+<title>The digester.plugins.strategies package.</title>
+</head>
+<body>
+<p>
+This 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 
+desired.
+<p>
+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 
+instantiated.
+<p>
+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.
+</body>
+</html>



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


Mime
View raw message