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/03/23 08:11:00 UTC

cvs commit: jakarta-commons/digester/src/java/org/apache/commons/digester/plugins PluginCreateRule.java PluginRules.java

skitching    2004/03/22 23:11:00

  Modified:    digester/src/java/org/apache/commons/digester/plugins
                        PluginCreateRule.java PluginRules.java
  Log:
  Significant changes to simplify design. There is now effectively a
  stack of Rules objects; entering the scope of a plugin pushes a new
  PluginRules instance onto that stack and leaving the scope of the
  plugin pops it from the stack.
  
  Revision  Changes    Path
  1.14      +192 -201  jakarta-commons/digester/src/java/org/apache/commons/digester/plugins/PluginCreateRule.java
  
  Index: PluginCreateRule.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/digester/src/java/org/apache/commons/digester/plugins/PluginCreateRule.java,v
  retrieving revision 1.13
  retrieving revision 1.14
  diff -u -r1.13 -r1.14
  --- PluginCreateRule.java	29 Feb 2004 02:22:15 -0000	1.13
  +++ PluginCreateRule.java	23 Mar 2004 07:11:00 -0000	1.14
  @@ -83,13 +83,6 @@
        */
       private PluginConfigurationException initException;
   
  -    /**
  -     * Our private set of rules associated with the concrete class that
  -     * the user requested to be instantiated. This object is only valid
  -     * between a call to begin() and the corresponding call to end().
  -     */
  -    private PluginRules localRules; 
  -    
       //-------------------- static methods -----------------------------------
       
       /**
  @@ -350,13 +343,6 @@
        * the plugin class are then loaded into that new Rules object.
        * Finally, any custom rules that are associated with the current pattern
        * (such as SetPropertiesRules) have their begin methods executed.
  -     * <p>
  -     * Because a PluginCreateRule is also a Delegate, this method is also
  -     * called on the start of any element occurring below the pattern
  -     * associated with this rule. In this case, this method acts like the
  -     * Digester's startElement method: it fires the begin() method of every
  -     * custom rule associated with the plugin class that matches that pattern.
  -     * See {@link #delegateBegin}.
        * 
        * @param namespace 
        * @param name 
  @@ -382,151 +368,134 @@
               throw initException;
           }
           
  -        String currMatch = digester.getMatch();
  -        if (currMatch.length() == pattern.length()) {
  -            // ok here we are actually instantiating a new plugin object,
  -            // and storing its rules into a new Rules object
  -            if (localRules != null) {
  -                throw new PluginAssertionFailure(
  -                    "Begin called when localRules is not null.");
  -            }
  -                      
  -            PluginRules oldRules = (PluginRules) digester.getRules();
  -            localRules = new PluginRules(this, oldRules);
  -            PluginManager pluginManager = localRules.getPluginManager();
  -            Declaration currDeclaration = null;
  +        String path = digester.getMatch();
  +
  +        // create a new Rules object and effectively push it onto a stack of
  +        // rules objects. The stack is actually a linked list; using the
  +        // PluginRules constructor below causes the new instance to link
  +        // to the previous head-of-stack, then the Digester.setRules() makes
  +        // the new instance the new head-of-stack.
  +        PluginRules oldRules = (PluginRules) digester.getRules();
  +        PluginRules newRules = new PluginRules(path, oldRules);
  +        digester.setRules(newRules);
  +        
  +        // load any custom rules associated with the plugin
  +        PluginManager pluginManager = newRules.getPluginManager();
  +        Declaration currDeclaration = null;
               
  -            if (debug) {
  -                log.debug("PluginCreateRule.begin: installing new plugin: " +
  -                    "oldrules=" + oldRules.toString() +
  -                    ", localrules=" + localRules.toString());
  -            }
  +        if (debug) {
  +            log.debug("PluginCreateRule.begin: installing new plugin: " +
  +                "oldrules=" + oldRules.toString() +
  +                ", newrules=" + newRules.toString());
  +        }
                 
  -            String pluginClassName; 
  -            if (pluginClassAttrNs == null) {
  -                // Yep, this is ugly.
  -                //
  -                // In a namespace-aware parser, the one-param version will 
  -                // return attributes with no namespace.
  -                //
  -                // In a non-namespace-aware parser, the two-param version will 
  -                // never return any attributes, ever.
  -                pluginClassName = attributes.getValue(pluginClassAttr);
  -            } else {
  -                pluginClassName = 
  -                    attributes.getValue(pluginClassAttrNs, pluginClassAttr);
  -            }
  +        String pluginClassName; 
  +        if (pluginClassAttrNs == null) {
  +            // Yep, this is ugly.
  +            //
  +            // In a namespace-aware parser, the one-param version will 
  +            // return attributes with no namespace.
  +            //
  +            // In a non-namespace-aware parser, the two-param version will 
  +            // never return any attributes, ever.
  +            pluginClassName = attributes.getValue(pluginClassAttr);
  +        } else {
  +            pluginClassName = 
  +                attributes.getValue(pluginClassAttrNs, pluginClassAttr);
  +        }
   
  -            String pluginId; 
  -            if (pluginIdAttrNs == null) {
  -                pluginId = attributes.getValue(pluginIdAttr);
  -            }
  -            else {
  -                pluginId = 
  -                    attributes.getValue(pluginIdAttrNs, pluginIdAttr);
  -            }
  -            
  -            if (pluginClassName != null) {
  -                currDeclaration = pluginManager.getDeclarationByClass(
  -                    pluginClassName);
  -    
  -                if (currDeclaration == null) {
  -                    currDeclaration = new Declaration(pluginClassName);
  -                    try {
  -                        currDeclaration.init(digester);
  -                    } catch(PluginWrappedException pwe) {
  -                        throw new PluginInvalidInputException(
  -                            pwe.getMessage(), pwe.getCause());
  -                    }
  -                    pluginManager.addDeclaration(currDeclaration);
  -                }
  -            } else if (pluginId != null) {
  -                currDeclaration = pluginManager.getDeclarationById(pluginId);
  -                
  -                if (currDeclaration == null) {
  +        String pluginId; 
  +        if (pluginIdAttrNs == null) {
  +            pluginId = attributes.getValue(pluginIdAttr);
  +        }
  +        else {
  +            pluginId = 
  +                attributes.getValue(pluginIdAttrNs, pluginIdAttr);
  +        }
  +        
  +        if (pluginClassName != null) {
  +            currDeclaration = pluginManager.getDeclarationByClass(
  +                pluginClassName);
  +
  +            if (currDeclaration == null) {
  +                currDeclaration = new Declaration(pluginClassName);
  +                try {
  +                    currDeclaration.init(digester);
  +                } catch(PluginWrappedException pwe) {
                       throw new PluginInvalidInputException(
  -                        "Plugin id [" + pluginId + "] is not defined.");
  +                        pwe.getMessage(), pwe.getCause());
                   }
  -            } else if (defaultPlugin != null) {
  -                currDeclaration = defaultPlugin;
  +                pluginManager.addDeclaration(currDeclaration);
               }
  -            else {
  +        } else if (pluginId != null) {
  +            currDeclaration = pluginManager.getDeclarationById(pluginId);
  +                
  +            if (currDeclaration == null) {
                   throw new PluginInvalidInputException(
  -                    "No plugin class specified for element " +
  -                    pattern);
  -            }
  -            
  -            // now load up the custom rules into a private Rules instance
  -            digester.setRules(localRules);
  -        
  -            currDeclaration.configure(digester, pattern);
  -    
  -            Class pluginClass = currDeclaration.getPluginClass();
  -            
  -            Object instance = pluginClass.newInstance();
  -            getDigester().push(instance);
  -            if (debug) {
  -                log.debug(
  -                    "PluginCreateRule.begin" + ": pattern=[" + pattern + "]" + 
  -                    " match=[" + digester.getMatch() + "]" + 
  -                    " pushed instance of plugin [" + pluginClass.getName() + "]");
  +                    "Plugin id [" + pluginId + "] is not defined.");
               }
  -        
  -            digester.setRules(oldRules);
  -
  -            ((PluginRules) oldRules).beginPlugin(this);
  +        } else if (defaultPlugin != null) {
  +            currDeclaration = defaultPlugin;
           }
  -        
  -        // fire the begin method of all custom rules
  -        Rules oldRules = digester.getRules();
  -        
  -        if (debug) {
  -            log.debug("PluginCreateRule.begin: firing nested rules: " +
  -                "oldrules=" + oldRules.toString() +
  -                ", localrules=" + localRules.toString());
  +        else {
  +            throw new PluginInvalidInputException(
  +                "No plugin class specified for element " +
  +                pattern);
           }
  +            
  +        // now load up the custom rules
  +        currDeclaration.configure(digester, pattern);
   
  -        // assert oldRules = localRules.oldRules
  -        digester.setRules(localRules);
  -        delegateBegin(namespace, name, attributes);
  -        digester.setRules(oldRules);
  -
  +        // and now create an instance of the plugin class
  +        Class pluginClass = currDeclaration.getPluginClass();
  +        
  +        Object instance = pluginClass.newInstance();
  +        getDigester().push(instance);
           if (debug) {
  -            log.debug("PluginCreateRule.begin: restored old rules to " +
  -                "oldrules=" + oldRules.toString());
  +            log.debug(
  +                "PluginCreateRule.begin" + ": pattern=[" + pattern + "]" + 
  +                " match=[" + digester.getMatch() + "]" + 
  +                " pushed instance of plugin [" + pluginClass.getName() + "]");
           }
  +        
  +        // and now we have to fire any custom rules which would have
  +        // been matched by the same path that matched this rule, had
  +        // they been loaded at that time.
  +        List rules = newRules.getDecoratedRules().match(namespace, path);
  +        fireBeginMethods(rules, namespace, name, attributes); 
       }
   
       /**
  -     * Invoked by the digester when the closing tag matching this Rule's
  -     * pattern is encountered. See {@link #delegateBody}.
  +     * Process the body text of this element.
        *
  -     * @see #begin
  +     * @param text The body text of this element
        */
       public void body(String namespace, String name, String text)
  -                     throws Exception {
  -            
  -        Rules oldRules = digester.getRules();
  -        // assert oldRules == localRules.oldRules
  -        digester.setRules(localRules);
  -        delegateBody(namespace, name, text);
  -        digester.setRules(oldRules);
  +        throws Exception {
  +
  +        // While this class itself has no work to do in the body method,
  +        // we do need to fire the body methods of all dynamically-added
  +        // rules matching the same path as this rule. During begin, we had
  +        // to manually execute the dynamic rules' begin methods because they
  +        // didn't exist in the digester's Rules object when the match begin.
  +        // So in order to ensure consistent ordering of rule execution, the
  +        // PluginRules class deliberately avoids returning any such rules
  +        // in later calls to the match method, instead relying on this
  +        // object to execute them at the appropriate time.
  +        //
  +        // Note that this applies only to rules matching exactly the path
  +        // which is also matched by this PluginCreateRule. 
  +
  +        String path = digester.getMatch();
  +        PluginRules newRules = (PluginRules) digester.getRules();
  +        List rules = newRules.getDecoratedRules().match(namespace, path);
  +        fireBodyMethods(rules, namespace, name, text);
       }
  -    
  +
       /**
        * Invoked by the digester when the closing tag matching this Rule's
        * pattern is encountered.
        * </p>
  -     * As noted on method begin, because PluginCreateRule is a Delegate,
  -     * this method is also called at the end tag of every pattern that
  -     * is "below" the pattern associated with this rule. In this case, we
  -     * fire the end method of every custom rule associated with the 
  -     * current plugin class. See {@link #delegateEnd}.
  -     * <p>
  -     * If we are really encountering the end tag associated with this rule
  -     * (rather than the end of an element "below" that tag), then we
  -     * remove the object we pushed onto the digester stack when the
  -     * opening tag was encountered.
        * 
        * @param namespace Description of the Parameter
        * @param name Description of the Parameter
  @@ -536,21 +505,21 @@
        */
       public void end(String namespace, String name)
                       throws Exception {
  -            
  -        Rules oldRules = digester.getRules();
  -        // assert oldRules == localRules.parentRules
  -        digester.setRules(localRules);
  -        delegateEnd(namespace, name);
  -        digester.setRules(oldRules);
  -
  -        String currMatch = digester.getMatch();
  -        if (currMatch.length() == pattern.length()) {
  -            // the end of the element on which the PluginCreateRule has
  -            // been mounted has been reached.
  -            localRules = null;
  -            ((PluginRules) oldRules).endPlugin(this);
  -            digester.pop();
  -        }
  +
  +
  +        // see body method for more info
  +        String path = digester.getMatch();
  +        PluginRules newRules = (PluginRules) digester.getRules();
  +        List rules = newRules.getDecoratedRules().match(namespace, path);
  +        fireEndMethods(rules, namespace, name);
  +        
  +        // pop the stack of PluginRules instances, which
  +        // discards all custom rules associated with this plugin
  +        digester.setRules(newRules.getParent());
  +        
  +        // and get rid of the instance of the plugin class from the
  +        // digester object stack.
  +        digester.pop();
       }
   
       /**
  @@ -570,70 +539,92 @@
       }
       
       /**
  -     * Here we act like Digester.begin, finding a match for the pattern
  -     * in our private rules object, then executing the begin method of
  -     * each matching rule.
  -     */
  -    public void delegateBegin(String namespace, String name, 
  -                              org.xml.sax.Attributes attributes)
  -                              throws java.lang.Exception {
  +     * Duplicate the processing that the Digester does when firing the
  +     * begin methods of rules. It would be really nice if the Digester
  +     * class provided a way for this functionality to just be invoked
  +     * directly.
  +     */
  +    public void fireBeginMethods(List rules,
  +                      String namespace, String name,
  +                      org.xml.sax.Attributes list)
  +                      throws java.lang.Exception {
           
  -        // Fire "begin" events for all relevant rules
  -        Log log = digester.getLogger();
  -        boolean debug = log.isDebugEnabled();
  -        String match = digester.getMatch();
  -        List rules = digester.getRules().match(namespace, match);
  -        Iterator ri = rules.iterator();
  -        while (ri.hasNext()) {
  -            Rule rule = (Rule) ri.next();
  -            if (debug) {
  -                log.debug("  Fire begin() for " + rule);
  +        if ((rules != null) && (rules.size() > 0)) {
  +            Log log = digester.getLogger();
  +            boolean debug = log.isDebugEnabled();
  +            for (int i = 0; i < rules.size(); i++) {
  +                try {
  +                    Rule rule = (Rule) rules.get(i);
  +                    if (debug) {
  +                        log.debug("  Fire begin() for " + rule);
  +                    }
  +                    rule.begin(namespace, name, list);
  +                } catch (Exception e) {
  +                    throw digester.createSAXException(e);
  +                } catch (Error e) {
  +                    throw e;
  +                }
               }
  -            rule.begin(namespace, name, attributes);
           }
       }
  -    
  +
       /**
  -     * Here we act like Digester.body, except against our private rules.
  -     */
  -    public void delegateBody(String namespace, String name, String text)
  -                             throws Exception {
  -        // Fire "body" events for all relevant rules
  -        Log log = digester.getLogger();
  -        boolean debug = log.isDebugEnabled();
  -        String match = digester.getMatch();
  -        List rules = digester.getRules().match(namespace, match);
  -        Iterator ri = rules.iterator();
  -        while (ri.hasNext()) {
  -            Rule rule = (Rule) ri.next();
  -            if (debug) {
  -                log.debug("  Fire body() for " + rule);
  +     * Duplicate the processing that the Digester does when firing the
  +     * body methods of rules. It would be really nice if the Digester
  +     * class provided a way for this functionality to just be invoked
  +     * directly.
  +     */
  +    private void fireBodyMethods(List rules,
  +                    String namespaceURI, String name,
  +                    String text) throws Exception {
  +
  +        if ((rules != null) && (rules.size() > 0)) {
  +            Log log = digester.getLogger();
  +            boolean debug = log.isDebugEnabled();
  +            for (int i = 0; i < rules.size(); i++) {
  +                try {
  +                    Rule rule = (Rule) rules.get(i);
  +                    if (debug) {
  +                        log.debug("  Fire body() for " + rule);
  +                    }
  +                    rule.body(namespaceURI, name, text);
  +                } catch (Exception e) {
  +                    throw digester.createSAXException(e);
  +                } catch (Error e) {
  +                    throw e;
  +                }
               }
  -            rule.body(namespace, name, text);
           }
       }
       
       /**
  -     * Here we act like Digester.end.
  +     * Duplicate the processing that the Digester does when firing the
  +     * end methods of rules. It would be really nice if the Digester
  +     * class provided a way for this functionality to just be invoked
  +     * directly.
        */
  -    public void delegateEnd(String namespace, String name)
  -                            throws Exception {
  +    public void fireEndMethods(List rules,
  +                    String namespaceURI, String name)
  +                    throws Exception {
  +
           // Fire "end" events for all relevant rules in reverse order
  -        Log log = digester.getLogger();
  -        boolean debug = log.isDebugEnabled();
  -        String match = digester.getMatch();
  -        List rules = digester.getRules().match(namespace, match);
  -        ListIterator ri = rules.listIterator();
  -        while (ri.hasNext()) {
  -            ri.next();
  -        }
  -        
  -        while (ri.hasPrevious()) {
  -            Rule rule = (Rule) ri.previous();
  -            if (debug) {
  -                log.debug("  Fire end() for " + rule);
  +        if (rules != null) {
  +            Log log = digester.getLogger();
  +            boolean debug = log.isDebugEnabled();
  +            for (int i = 0; i < rules.size(); i++) {
  +                int j = (rules.size() - i) - 1;
  +                try {
  +                    Rule rule = (Rule) rules.get(j);
  +                    if (debug) {
  +                        log.debug("  Fire end() for " + rule);
  +                    }
  +                    rule.end(namespaceURI, name);
  +                } catch (Exception e) {
  +                    throw digester.createSAXException(e);
  +                } catch (Error e) {
  +                    throw e;
  +                }
               }
  -            rule.end(namespace, name);
           }
       }
   }
  
  
  
  1.12      +96 -103   jakarta-commons/digester/src/java/org/apache/commons/digester/plugins/PluginRules.java
  
  Index: PluginRules.java
  ===================================================================
  RCS file: /home/cvs/jakarta-commons/digester/src/java/org/apache/commons/digester/plugins/PluginRules.java,v
  retrieving revision 1.11
  retrieving revision 1.12
  diff -u -r1.11 -r1.12
  --- PluginRules.java	29 Feb 2004 02:22:15 -0000	1.11
  +++ PluginRules.java	23 Mar 2004 07:11:00 -0000	1.12
  @@ -34,34 +34,53 @@
   /**
    * A custom digester Rules manager which must be used as the Rules object
    * when using the plugins module functionality.
  + * <p>
  + * During parsing, a linked list of PluginCreateRule instances develop, and
  + * this list also acts like a stack. The original instance that was set before 
  + * the Digester started parsing is always at the tail of the list, and the
  + * Digester always holds a reference to the instance at the head of the list
  + * in the rules member. Initially, this list/stack holds just one instance,
  + * ie head and tail are the same object.
  + * <p>
  + * When the start of an xml element causes a PluginCreateRule to fire, a new 
  + * PluginRules instance is created and inserted at the head of the list (ie
  + * pushed onto the stack of Rules objects). Digester.getRules() therefore
  + * returns this new Rules object, and any custom rules associated with that 
  + * plugin are added to that instance. 
  + * <p>
  + * When the end of the xml element is encountered (and therefore the 
  + * PluginCreateRule end method fires), the stack of Rules objects is popped,
  + * so that Digester.getRules returns the previous Rules object. 
    */
   
   public class PluginRules implements Rules {
                                                  
  -    /** 
  -     * The rules implementation that we are "enhancing" with plugins
  -     * functionality, as per the Decorator pattern.
  -     */
  -    private Rules decoratedRules;
  -
       /**
        * The Digester instance with which this Rules instance is associated.
        */
       protected Digester digester = null;
   
  -    /**
  -     * The currently active PluginCreateRule. When the begin method of a
  -     * PluginCreateRule is encountered, this is set. When the end method is
  -     * encountered, this is cleared. Any attempt to call match() while this
  -     * attribute is set just causes this single rule to be returned.
  +    /** 
  +     * The rules implementation that we are "enhancing" with plugins
  +     * functionality, as per the Decorator pattern.
        */
  -    private PluginCreateRule currPluginCreateRule = null;
  +    private Rules decoratedRules;
       
       /** Object which contains information about all known plugins. */
       private PluginManager pluginManager;
   
  -    /** The parent rules object for this object. */
  -    private Rules parent;
  +    /**
  +     * The path below which this rules object has responsibility.
  +     * For paths shorter than or equal the mountpoint, the parent's 
  +     * match is called.
  +     */
  +    private String mountPoint = null;
  +    
  +    /**
  +     * The Rules object that holds rules applying "above" the mountpoint,
  +     * ie the next Rules object down in the stack.
  +     */
  +    private PluginRules parent = null;
       
       // ------------------------------------------------------------- Constructor
       
  @@ -86,22 +105,22 @@
   
       /**
        * Constructs a Rules instance which has a parent Rules object 
  -     * (not a delegate rules object). One of these is created
  -     * each time a PluginCreateRule's begin method fires, in order to
  -     * manage the custom rules associated with whatever concrete plugin
  -     * class the user has specified.
  +     * (which is different from having a delegate rules object). 
        * <p>
  -     * The first parameter is not actually used; it is required solely
  -     * because a constructor with a single Rules parameter already
  -     * exists.
  -     * <p>
  -     * The parent is recorded so that lookups of Declarations can
  -     * "inherit" declarations from further up the tree.
  -     */
  -     PluginRules(PluginCreateRule pcr, PluginRules parent) {
  +     * One of these is created each time a PluginCreateRule's begin method 
  +     * fires, in order to manage the custom rules associated with whatever 
  +     * concrete plugin class the user has specified.
  +     */
  +     PluginRules(String mountPoint, PluginRules parent) {
  +        // no need to set digester or decoratedRules.digester,
  +        // because when Digester.setRules is called, the setDigester
  +        // method on this object will be called.
  +        
           decoratedRules = new RulesBase();
  -        this.parent = parent;
           pluginManager = new PluginManager(parent.pluginManager);
  +        
  +        this.mountPoint = mountPoint;
  +        this.parent = parent;
       }
       
       // ------------------------------------------------------------- Properties
  @@ -162,6 +181,15 @@
       // --------------------------------------------------------- Public Methods
   
       /**
  +     * This package-scope method is used by the PluginCreateRule class to
  +     * get direct access to the rules that were dynamically added by the
  +     * plugin. No other class should need access to this object.
  +     */
  +    Rules getDecoratedRules() {
  +        return decoratedRules;
  +    }
  +    
  +    /**
        * Return the list of rules registered with this object, in the order
        * they were registered with this object.
        * <p>
  @@ -196,6 +224,27 @@
           {
               pattern = pattern.substring(1);
           }
  +
  +        if (mountPoint != null) {
  +            if (!pattern.equals(mountPoint)
  +              && !pattern.startsWith(mountPoint + "/")) {
  +                // This can only occur if a plugin attempts to add a
  +                // rule with a pattern that doesn't start with the
  +                // prefix passed to the addRules method. Plugins mustn't
  +                // add rules outside the scope of the tag they were specified
  +                // on, so refuse this.
  +                
  +                // alas, can't throw exception
  +                log.warn(
  +                    "An attempt was made to add a rule with a pattern that"
  +                    + "is not at or below the mountpoint of the current"
  +                    + " PluginRules object."
  +                    + " Rule pattern: " + pattern
  +                    + ", mountpoint: " + mountPoint
  +                    + ", rule type: " + rule.getClass().getName());
  +                return;
  +            }
  +        }
           
           decoratedRules.add(pattern, rule);
   
  @@ -236,111 +285,55 @@
        * in the order originally registered through the <code>add()</code>
        * method.
        *
  -     * @param pattern Nesting pattern to be matched
  +     * @param path the path to the xml nodes to be matched.
        *
        * @deprecated Call match(namespaceURI,pattern) instead.
        */
  -    public List match(String pattern) {
  -        return (match(null, pattern));
  +    public List match(String path) {
  +        return (match(null, path));
       }
   
       /**
        * Return a List of all registered Rule instances that match the specified
  -     * nesting pattern, or a zero-length List if there are no matches.  If more
  +     * nodepath, or a zero-length List if there are no matches.  If more
        * than one Rule instance matches, they <strong>must</strong> be returned
        * in the order originally registered through the <code>add()</code>
        * method.
        * <p>
  -     * If we have encountered the start of a PluginCreateRule and have not
  -     * yet encountered the end tag, then the currPluginCreateRule attribute
  -     * will be non-null. In this case, we just return this rule object as the
  -     * sole match. The calling Digester will then invoke the begin/body/end
  -     * methods on this rule, which are responsible for invoking all rules
  -     * matching nodes below itself.
  -     *
        * @param namespaceURI Namespace URI for which to select matching rules,
        *  or <code>null</code> to match regardless of namespace URI
  -     * @param pattern Nesting pattern to be matched
  +     * @param path the path to the xml nodes to be matched.
        */
  -    public List match(String namespaceURI, String pattern) {
  +    public List match(String namespaceURI, String path) {
           Log log = LogUtils.getLogger(digester);
           boolean debug = log.isDebugEnabled();
           
           if (debug) {
               log.debug(
  -                "Matching pattern [" + pattern +
  +                "Matching path [" + path +
                   "] on rules object " + this.toString());
           }
   
           List matches;
  -        if ((currPluginCreateRule != null) && 
  -            (pattern.length() > currPluginCreateRule.getPattern().length())) {
  -            // assert pattern.startsWith(currPluginCreateRule.getPattern())
  +        if ((mountPoint != null) && 
  +            (path.length() <= mountPoint.length())) {
               if (debug) {
                   log.debug(
  -                    "Pattern [" + pattern + "] matching PluginCreateRule " +
  -                    currPluginCreateRule.toString());
  +                    "Path [" + path + "] delegated to parent.");
               }
  -            matches = new ArrayList(1);
  -            matches.add(currPluginCreateRule);
  -        }
  +            
  +            matches = parent.match(namespaceURI, path);
  +            
  +            // Note that in the case where path equals mountPoint, 
  +            // we deliberately return only the rules from the parent,
  +            // even though this object may hold some rules matching
  +            // this same path. See PluginCreateRule's begin, body and end
  +            // methods for the reason.
  +        } 
           else {
  -            matches = decoratedRules.match(namespaceURI, pattern); 
  +            matches = decoratedRules.match(namespaceURI, path); 
           }
   
           return matches;
  -    }
  -    
  -    /**
  -     * Called when a pattern matches a PluginCreateRule, to indicate that
  -     * any attempt to match any following XML elements should simply
  -     * return a single match: this PluginCreateRule.
  -     * <p>
  -     * In other words, once the plugin element starts, all following 
  -     * subelements cause the rule object to be "matched", until the
  -     * endPlugin method is called.
  -     */
  -    public void beginPlugin(PluginCreateRule pcr) {
  -        Log log = LogUtils.getLogger(digester);
  -        boolean debug = log.isDebugEnabled();
  -
  -        if (currPluginCreateRule != null) {
  -            throw new PluginAssertionFailure(
  -                "endPlugin called when currPluginCreateRule is not null.");
  -        }
  -
  -        if (debug) {
  -            log.debug(
  -                "Entering PluginCreateRule " + pcr.toString() +
  -                " on rules object " + this.toString());
  -        }
  -
  -        currPluginCreateRule = pcr;
  -    }
  -    
  -    /**
  -     * Called when a pattern matches the end of a PluginCreateRule.
  -     * See {@link #beginPlugin}.
  -     */
  -    public void endPlugin(PluginCreateRule pcr) {
  -        Log log = LogUtils.getLogger(digester);
  -        boolean debug = log.isDebugEnabled();
  -
  -        if (currPluginCreateRule == null) {
  -            throw new PluginAssertionFailure(
  -                "endPlugin called when currPluginCreateRule is null.");
  -        }
  -        
  -        if (currPluginCreateRule != pcr) {
  -            throw new PluginAssertionFailure(
  -                "endPlugin called with unexpected PluginCreateRule instance.");
  -        }
  -        
  -        currPluginCreateRule = null;
  -        if (debug) {
  -            log.debug(
  -                "Leaving PluginCreateRule " + pcr.toString() +
  -                " on rules object " + this.toString());
  -        }
       }
   }
  
  
  

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