skitching    2004/03/27 21:51:43

  Modified:    digester/src/java/org/apache/commons/digester/plugins Tag:
                        DIGESTER_PLUGIN_REFACTORING_BRANCH Declaration.java
  Log:
  * store declaration attributes provided by the user as a Properties object
    rather than explicit Object attributes. This allows the set of
    attributes to be open-ended, and removes use of hard-wired English
    attribute names.
  * use new RuleFinder/RuleLoader interfaces to find "pluggable" algorithms
    for finding/loading dynamic plugin rules rather than hard-coding the
    algorithms in this class.
  * move rule finding/loading algorithms to separate classes in the
    strategies subpackage.
  
  Revision  Changes    Path
  No                   revision
  No                   revision
  1.11.2.1  +87 -271   
jakarta-commons/digester/src/java/org/apache/commons/digester/plugins/Declaration.java
  
  Index: Declaration.java
  ===================================================================
  RCS file: 
/home/cvs/jakarta-commons/digester/src/java/org/apache/commons/digester/plugins/Declaration.java,v
  retrieving revision 1.11
  retrieving revision 1.11.2.1
  diff -u -r1.11 -r1.11.2.1
  --- Declaration.java  29 Feb 2004 02:22:15 -0000      1.11
  +++ Declaration.java  28 Mar 2004 05:51:43 -0000      1.11.2.1
  @@ -15,27 +15,19 @@
    */ 
   package org.apache.commons.digester.plugins;
   
  -import java.io.File;
  -import java.io.FileInputStream;
  -import java.io.InputStream;
   import java.io.IOException;
  -import java.lang.reflect.Method;
  +import java.util.Properties;
  +import java.util.List;
   
  -import org.apache.commons.beanutils.MethodUtils;
  -import org.apache.commons.digester.Digester;
   import org.apache.commons.logging.Log;
  +import org.apache.commons.digester.Digester;
   
   /**
  - * Simple structure to store the set of attributes that can be present on 
  - * a plugin declaration.
  + * Represents a Class that can be instantiated by a PluginCreateRule, plus
  + * info on how to load custom digester rules for mapping xml into that
  + * plugged-in class.
    */
   public class Declaration {
  -
  -    /** 
  -     * The name of the method looked for on the plugin class and any
  -     * specific rule class.
  -     */
  -    public final static String DFLT_RULE_METHOD_NAME = "addRules";
      
       /** The class of the object to be instantiated. */
       private Class pluginClass;
  @@ -46,89 +38,66 @@
       /** See [EMAIL PROTECTED] #setId}. */ 
       private String id;
       
  -    /** See [EMAIL PROTECTED] #setRuleMethod}. */
  -    private String ruleMethodName = DFLT_RULE_METHOD_NAME;
  -    
  -    /** See [EMAIL PROTECTED] #setRuleClass}. */ 
  -    private Class ruleClass;
  -    
  -    /** See [EMAIL PROTECTED] #setRuleResource}. */
  -    private String ruleResource;
  -    
  -    /** See [EMAIL PROTECTED] #setRuleFile}. */
  -    private File ruleFile;
  +    /** See [EMAIL PROTECTED] #setProperties}. */
  +    private Properties properties = new Properties();
       
  -    /** See [EMAIL PROTECTED] #setAutoSetProperties}. */
  -    private boolean autoSetProperties = true;
  -
       /** See [EMAIL PROTECTED] #init}. */
       private boolean initialized = false;
  +
  +    /**
  +     * Class which is responsible for dynamically loading this
  +     * plugin's rules on demand.
  +     */
  +    private RuleLoader ruleLoader = null;
       
       //---------------------- constructors ----------------------------------
   
       /**
        * Constructor.
        */
  +    public Declaration(String pluginClassName) {
  +        // We can't load the pluginClass at this time, because we don't
  +        // have a digester instance yet to load it through. So just
  +        // save the name away, and we'll load the Class object in the
  +        // init method.
  +        this.pluginClassName = pluginClassName;
  +    }
  +    
  +    /**
  +     * Constructor.
  +     */
       public Declaration(Class pluginClass) {
           this.pluginClass = pluginClass;
           this.pluginClassName = pluginClass.getName();
       }
       
       /**
  -     * Constructor.
  +     * Create an instance where a fully-initialised ruleLoader instance
  +     * is provided by the caller instead of having the PluginManager
  +     * "discover" an appropriate one.
        */
  -    public Declaration(String pluginClassName) {
  -        this.pluginClassName = pluginClassName;
  +    public Declaration(Class pluginClass, RuleLoader ruleLoader) {
  +        this.pluginClass = pluginClass;
  +        this.pluginClassName = pluginClass.getName();
  +        this.ruleLoader = ruleLoader;
       }
       
       //---------------------- properties -----------------------------------
   
       /** 
  -     * The id of the object defined in a plugin declaration.
  +     * The id that the user associated with a particular plugin declaration
  +     * in the input xml. This id is later used in the input xml to refer
  +     * back to the original declaration.
  +     * <p>
        * For plugins declared "in-line", the id is null.
        */
       public void setId(String id) {
           this.id = id;
       }
       
  -    /** 
  -     * Sets the name of a method which defines custom rules. May be null. 
  -     */
  -    public void setRuleMethod(String ruleMethodName) {
  -        this.ruleMethodName = ruleMethodName;
  -    }
  -    
  -    /** 
  -     * The name of a class containing a method which defines custom rules
  -     * for the plugin class. May be null. 
  -     */
  -    public void setRuleClass(Class ruleClass) {
  -        this.ruleClass = ruleClass;
  -    }
  -    
  -    /**
  -     * The name of a resource file in the classpath containg xmlrules
  -     * specifications of custom rules for the plugin class. May be null.
  -     */
  -    public void setRuleResource(String ruleResource) {
  -        this.ruleResource = ruleResource;
  -    }
  -    
  -    /**
  -     * The name of a file containg xmlrules specifications of custom rules 
  -     * for the plugin class. May be null.
  -     */
  -    public void setRuleFile(File ruleFile) {
  -        this.ruleFile = ruleFile;
  -    }
  -    
  -    /** See [EMAIL PROTECTED] #autoSetProperties}. */
  -    public void setAutoSetProperties(boolean autoSetProperties) {
  -        this.autoSetProperties = autoSetProperties;
  -    }
  -    
       /**
  -     * Return the id associated with this declaration.
  +     * Return the id associated with this declaration. For plugins
  +     * declared "inline", null will be returned.
        * 
        * @return The id value. May be null.
        */
  @@ -136,6 +105,23 @@
           return id;
       }
   
  +    /** 
  +     * Copy all (key,value) pairs in the param into the properties member of
  +     * this object.
  +     * <p>
  +     * The declaration properties cannot be explicit member variables,
  +     * because the set of useful properties a user can provide on a declaration
  +     * depends on what RuleFinder classes are available - and extra RuleFinders
  +     * can be added by the user. So here we keep a map of the settings, and
  +     * let the RuleFinder objects look for whatever properties they consider
  +     * significant.
  +     * <p>
  +     * The "id" and "class" properties are treated differently.
  +     */
  +    public void setProperties(Properties p) {
  +        properties.putAll(p);
  +    }
  +    
       /**
        * Return plugin class associated with this declaration.
        * 
  @@ -145,36 +131,13 @@
           return pluginClass;
       }
   
  -    /**
  -     * return class which specifies custom rules for this plugin.
  -     * 
  -     * @return The ruleClass value. May be null.
  -     */
  -    public Class getRuleClass() {
  -        return ruleClass;
  -    }
  -
  -    /**
  -     * Indicates whether plugins which do <i>not</i> implement custom rules
  -     * should have a SetProperties rule automatically associated with the
  -     * parent tag. In almost all cases this is desirable, so autoSetProperties
  -     * defaults to true. If for some reason you are plugging in a class 
  -     * without custom rules and you do not want xml attributes to be mapped
  -     * to bean properties, you can pass <i>false</i> here to disable this.
  -     * 
  -     * @return true if SetPropertiesRule is automatically applied.
  -     */
  -    public boolean autoSetProperties() {
  -        return autoSetProperties;
  -    }
  -
       //---------------------- methods -----------------------------------
       
       /**
        * Must be called exactly once, and must be called before any call
        * to the configure method.
        */
  -    public void init(Digester digester) throws PluginWrappedException {
  +    public void init(Digester digester, PluginManager pm) throws PluginException {
           Log log = digester.getLogger();
           boolean debug = log.isDebugEnabled();
           if (debug) {
  @@ -191,10 +154,35 @@
                   pluginClass = 
                       digester.getClassLoader().loadClass(pluginClassName);
               } catch(ClassNotFoundException cnfe) {
  -                throw new PluginWrappedException(
  +                throw new PluginException(
                       "Unable to load class " + pluginClassName, cnfe);
               }
           }
  +
  +        if (ruleLoader == null) {
  +            // the caller didn't provide a ruleLoader to the constructor,
  +            // so get the plugin manager to "discover" one.
  +            log.debug("Searching for ruleloader...");
  +            ruleLoader = pm.findLoader(digester, id, pluginClass, properties);
  +        } else {
  +            log.debug("This declaration has an explicit ruleLoader.");
  +        }
  +        
  +        if (debug) {
  +            if (ruleLoader == null) {
  +                log.debug(
  +                    "No ruleLoader found for plugin declaration"
  +                    + " id [" + id + "]"
  +                    + ", class [" + pluginClass.getClass().getName() + "].");
  +            } else {
  +                log.debug(
  +                    "RuleLoader of type [" + ruleLoader.getClass().getName()
  +                    + "] associated with plugin declaration"
  +                    + " id [" + id + "]"
  +                    + ", class [" + pluginClass.getClass().getName() + "].");
  +            }
  +        }
  +        
           initialized = true;        
       }
       
  @@ -202,49 +190,13 @@
        * Attempt to load custom rules for the target class at the specified
        * pattern.
        * <p>
  -     * <ol>
  -     * <li>If there is an explicit File, load from that file.</li>
  -     * <li>If there is an explicit Resource, load from that resource.</li>
  -     * <li>If there is an explicit RuleClass, load from that class.</li>
  -     * <li>If there is an explicit RuleMethod, load from that method.</li>
  -     * <li>If there is a default method, load from that method.</li>
  -     * <li>If there is a default RuleInfo class, load from that class.</li>
  -     * <li>If there is a default resource, load from that resource.</li>
  -     * </ol>
  -     * <p>
  -     * When loading from a File or Resource (a file in the classpath), the
  -     * contents of the file are expected to be xml in xmlrules format.
  -     * <p>
  -     * When loading from a RuleClass, that class is expected to have a
  -     * method with the signature <code>public static void addRules(Digester, 
  -     * String)</code>.
  -     * <p>
  -     * When loading from a specified Method on the plugin class, that method
  -     * is expected to have signature <code> public static void xxx(Digester, 
  -     * String)</code> where xxx is the specified method name.
  -     * <p>
  -     * When loading from the default method on the plugin class, the method
  -     * is expected to have signature <code>public static void addRules(Digester,
  -     * String)</code>.
  -     * <p>
  -     * When looking for a default RuleInfo class, the plugin class name has
  -     * the suffix "RuleInfo" applied to it. If there exists a class of that
  -     * name, then that class is expected to have an addRules method on it.
  -     * <p>
  -     * When looking for a default resource file, the plugin class name has
  -     * the suffix "RuleInfo.xml" applied to it. If there exists a resource
  -     * file of that name, then that file is expected to contain xmlrules
  -     * format rules.
  -     * <p>
  -     * The first source of rules found is used, and searching stops.
  -     * <p>
        * On return, any custom rules associated with the plugin class have
        * been loaded into the Rules object currently associated with the
        * specified digester object.
        */
        
       public void configure(Digester digester, String pattern)
  -                          throws PluginWrappedException {
  +                          throws PluginException {
           Log log = digester.getLogger();
           boolean debug = log.isDebugEnabled();
           if (debug) {
  @@ -254,160 +206,24 @@
           if (!initialized) {
               throw new PluginAssertionFailure("Not initialized.");
           }
  -        
  -        // load from explicit file
  -        if (ruleFile != null) {
  -            InputStream is = null;
  -            try {
  -                is = new FileInputStream(ruleFile);
  -            } catch(IOException ioe) {
  -                throw new PluginWrappedException(
  -                    "Unable to process file [" + ruleFile + "]", ioe);
  -            }
  -            loadRulesFromStream(is, digester, pattern);
  -            return;
  -        }
  -        
  -        // load from explicit resource in classpath
  -        if (ruleResource != null) {
  -            InputStream is = 
  -                pluginClass.getClassLoader().getResourceAsStream(
  -                    ruleResource);
  -            if (is != null) {
  -                loadRulesFromStream(is, digester, pattern);
  -                return;
  -            }
  -        }
  -
  -        // load via method on explicit Rule Class        
  -        if (ruleClass != null) {
  -            loadRulesFromClass(ruleClass, digester, pattern);
  -            return;
  -        }
  -
  -        // load via method on plugin class        
  -        {
  -            Class[] paramSpec = { Digester.class, String.class };
  -            Method ruleMethod = MethodUtils.getAccessibleMethod(
  -                pluginClass, ruleMethodName, paramSpec);
  -            if (ruleMethod != null) 
  -            {
  -                try {
  -                    Object[] params = {digester, pattern};
  -                    Object none = ruleMethod.invoke(null, params);
  -                } catch (Exception e) {
  -                    throw new PluginWrappedException(
  -                        "Unable to configure class [" + pluginClass + "]" +
  -                        " using method [" + ruleMethodName + "]", e);
  -                }
  -                return;
  -            }
  -        }
  -
  -        // look for rule class
  -        {
  -            if (debug) {
  -                log.debug("plugin class type:" + pluginClass.getName());
  -            }
  -            String ruleClassName = pluginClass.getName() + "RuleInfo";
  -
  -            Class ruleClass;
  -            try {
  -                ruleClass = digester.getClassLoader().loadClass(ruleClassName);
  -            } catch(ClassNotFoundException cnfe) {
  -                ruleClass = null;
  -            }
   
  -            if (ruleClass != null) {
  -                loadRulesFromClass(ruleClass, digester, pattern);
  -                return;
  -            }
  -        }
  -        
  -        // look for  resource
  -        {
  -            String resourceName = 
  -                pluginClass.getClass().getName().replace('.', '/') +
  -                "RuleInfo.xml";
  -            InputStream is = 
  -                pluginClass.getClassLoader().getResourceAsStream(
  -                    resourceName);
  -            if (is != null) {
  -                loadRulesFromStream(is, digester, pattern);
  -                return;
  -            }
  -        }
  -        
  -        // try autoSetProperties
  -        if (autoSetProperties) {
  -            if (debug) {
  -                log.debug("adding autoset for pattern [" + pattern + "]");
  -            }
  -            digester.addSetProperties(pattern);
  +        if (ruleLoader != null) {
  +            ruleLoader.addRules(digester, pattern);
           }
       }
   
       /**
  -     * Load custom rules from a specified stream of xml data.
  -     */
  -    private void loadRulesFromStream(InputStream is, Digester digester,
  -                                     String pattern) 
  -                                     throws PluginWrappedException {
  -        try
  -        {
  -            throw new PluginAssertionFailure(
  -                "Load from stream not yet supported.");
  -        }
  -        finally {
  -            try {
  -                is.close();
  -            } catch(IOException ioe) {
  -                Log log = digester.getLogger();
  -                log.warn("Unable to close stream after reading rules", ioe);
  -            }
  -        }
  -    }
  -    
  -    /**
  -     * Load custom rules from a specified class.
  -     */
  -    private void loadRulesFromClass(Class ruleClass, Digester digester,
  -                                    String pattern)
  -                                    throws PluginWrappedException {
  -        Class[] paramSpec = { Digester.class, String.class };
  -        Method ruleMethod = MethodUtils.getAccessibleMethod(
  -            ruleClass, ruleMethodName, paramSpec);
  -        if (ruleMethod == null) {
  -            throw new PluginWrappedException(
  -                "rule class specified, but rules method not found on it.");
  -        }
  -        try {
  -            Object[] params = {digester, pattern};
  -            Object none = ruleMethod.invoke(null, params);
  -        } catch (Exception e) {
  -            throw new PluginWrappedException(
  -                "Unable to configure class [" + pluginClass + "]" +
  -                " using rule class [" + ruleClass + "]" +
  -                " method [" + ruleMethodName + "]", e);
  -        } 
  -    }
  -    
  -    /**
        * Returns true if the declarations are equivalent. Perhaps this would be
        * better as overriding equals, but then I should really override hash as
        * well and I can't be bothered.
  -     * 
  +     *
        * @param d the Declaration object to be compared to this object.
        * @return true if the specified object has the same options as this one.
        */
       public boolean isEquivalent(Declaration d) {
           if (different(id, d.id)) return false;
           if (pluginClass != d.pluginClass) return false;
  -        if (different(ruleMethodName, d.ruleMethodName)) return false;
  -        if (ruleClass != d.ruleClass) return false;
  -        if (different(ruleResource, d.ruleResource)) return false;
  -        if (different(ruleFile, d.ruleFile)) return false;
  -        if (autoSetProperties != d.autoSetProperties) return false;
  +        if (!properties.equals(d.properties)) return false;
   
           // all significant fields match; these declarations are identical.
           return true;
  
  
  

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to