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 2005/02/15 04:08:38 UTC

svn commit: r153882 - in jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2: AbstractRuleManager.java DefaultRuleManager.java RuleManager.java

Author: skitching
Date: Mon Feb 14 19:08:36 2005
New Revision: 153882

URL: http://svn.apache.org/viewcvs?view=rev&rev=153882
Log:
Implement fallback and mandatory (aka supplementary) actions.
Also some whitespace tidyups.

Modified:
    jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/AbstractRuleManager.java
    jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/DefaultRuleManager.java
    jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/RuleManager.java

Modified: jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/AbstractRuleManager.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/AbstractRuleManager.java?view=diff&r1=153881&r2=153882
==============================================================================
--- jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/AbstractRuleManager.java (original)
+++ jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/AbstractRuleManager.java Mon Feb 14 19:08:36 2005
@@ -1,19 +1,19 @@
 /* $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.
- */ 
+ */
 
 package org.apache.commons.digester2;
 
@@ -24,9 +24,9 @@
  * match input xml elements to lists of Actions to be executed).
  * <p>
  * Note that extending this abstract class rather than directly implementing
- * the RuleManager interface provides much better "forward compatibility". 
- * Digester minor releases (2.x -> 2.y) guarantee not to break any classes that 
- * subclass this abstract class. However no such guarantee exists for classes 
+ * the RuleManager interface provides much better "forward compatibility".
+ * Digester minor releases (2.x -> 2.y) guarantee not to break any classes that
+ * subclass this abstract class. However no such guarantee exists for classes
  * that directly implement the RuleManager interface.
  */
 
@@ -35,18 +35,18 @@
     /**
      * Returns a new instance with the same type as the concrete object this
      * method is invoked on, complete with contained Actions and patterns. Note
-     * that the new RuleManager instance may contain references to the same 
+     * that the new RuleManager instance may contain references to the same
      * Action instances as the old one, as Action instances are expected to be
-     * stateless and therefore can be safely shared between RuleManagers. 
+     * stateless and therefore can be safely shared between RuleManagers.
      */
     public abstract RuleManager copy();
-    
+
     /**
      * Invoked before parsing each input document, this method gives the
      * RuleManager the opportunity to do per-parse initialisation if required.
      */
     public void startParse(Context context) throws DigestionException {}
-     
+
     /**
      * Invoked after parsing each input document, this method gives the
      * RuleManager and the managed Action objects the opportunity to do
@@ -55,11 +55,52 @@
      public void finishParse(Context context) throws DigestionException {}
 
     /**
+     * Defines an action that should be returned by method getMatchingActions
+     * if no rule pattern matches the specified path.
+     * <p>
+     * The specified action is appended to the existing list of fallback actions.
+     */
+    public abstract void addFallbackAction(Action action);
+
+    /**
+     * Defines actions that should be returned by method getMatchingActions
+     * if no rule pattern matches the specified path.
+     * <p>
+     * The actions contained in the specified list are appended to the
+     * existing list of fallback actions.
+     */
+    public abstract void addFallbackActions(List actions);
+
+    /**
+     * Defines an action that should always be included in the list of actions
+     * returned by method getMatchingActions, no matter what path is provided.
+     * <p>
+     * if no rule pattern matches the specified path. The specified action
+     * is appended to the existing list of fallback actions.
+     * <p>
+     * The mandatory actions (if any) are always returned at the tail of the
+     * list of actions returned by getMatchingActions.
+     */
+    public abstract void addMandatoryAction(Action action);
+
+    /**
+     * Defines actions that should always be included in the list of actions
+     * returned by method getMatchingActions, no matter what path is provided.
+     * <p>
+     * The actions contained in the specified list are appended to the
+     * existing list of mandatory actions.
+     * <p>
+     * The mandatory actions (if any) are always returned at the tail of the
+     * list of actions returned by getMatchingActions.
+     */
+    public abstract void addMandatoryActions(List actions);
+
+    /**
      * Define a mapping between xml element prefix and namespace uri
      * for use when rule patterns contain namespace prefixes.
      */
     public abstract void addNamespace(String prefix, String uri);
-    
+
     /**
      * Cause the specified Action to be invoked whenever an xml element
      * is encountered in the input which matches the specified pattern.
@@ -83,7 +124,7 @@
      * first time it was added.
      */
     public abstract List getActions();
-    
+
     /**
      * Return a List of all registered Action instances that match the specified
      * nesting pattern, or a zero-length List if there are no matches.  If more
@@ -93,7 +134,7 @@
      *
      * @param path is a string of form
      * <pre>/{namespace}elementName/{namespace}elementName"</pre>
-     * identifying the path from the root of the input document to the element 
+     * identifying the path from the root of the input document to the element
      * for which the caller wants the set of matching Action objects. If an
      * element has no namespace, then the {} part is omitted.
      */

Modified: jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/DefaultRuleManager.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/DefaultRuleManager.java?view=diff&r1=153881&r2=153882
==============================================================================
--- jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/DefaultRuleManager.java (original)
+++ jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/DefaultRuleManager.java Mon Feb 14 19:08:36 2005
@@ -1,19 +1,19 @@
 /* $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.
- */ 
+ */
 
 
 package org.apache.commons.digester2;
@@ -46,28 +46,43 @@
  * ActionManager objects cannot be shared between Digester objects; if you have
  * multiple Digester objects then a different RuleManager object must be
  * created for each one. However the copy() method may be used to duplicate
- * an existing RuleManager instance. 
+ * an existing RuleManager instance.
  */
 
 public class DefaultRuleManager extends AbstractRuleManager {
 
-    // ----------------------------------------------------- 
+    // -----------------------------------------------------
     // Instance Variables
-    // ----------------------------------------------------- 
+    // -----------------------------------------------------
+
+    /**
+     * List of actions to be returned by getMatchingActions
+     * if no rule patterns match the provided path. This list
+     * is null unless one or more fallback actions have actually
+     * been defined.
+     */
+    private ArrayList fallbackActions = null;
+
+    /**
+     * List of actions to be returned by getMatchingActions
+     * regardless of path. This list is null unless one or more
+     * mandatory actions have actually been defined.
+     */
+    private ArrayList mandatoryActions = null;
 
     /**
      * Map of namespace-prefix to namespace-uri, used only by the
      * addAction() method.
      */
     private HashMap namespaces = new HashMap();
-    
+
     /**
      * The list of all actions in the cache. This set allows us to
      * iterate over the set of actions to invoke the startParse/finishParse
      * methods.
      */
     private ArrayList actions = new ArrayList(20);
-    
+
     /**
      * Map of expanded-pattern -> list-of-actions, so that we can
      * find the pattern that matches the current xml element, then
@@ -75,10 +90,10 @@
      */
     private MultiHashMap rules = new MultiHashMap();
 
-    
-    // --------------------------------------------------------- 
+
+    // ---------------------------------------------------------
     // Ctor
-    // --------------------------------------------------------- 
+    // ---------------------------------------------------------
 
     /**
      * Default ctor.
@@ -92,15 +107,23 @@
      * re-entrant and thread-safe.
      */
     public DefaultRuleManager(DefaultRuleManager manager) {
+        if (fallbackActions != null) {
+            this.fallbackActions = (ArrayList) fallbackActions.clone();
+        }
+
+        if (mandatoryActions != null) {
+            this.mandatoryActions = (ArrayList) mandatoryActions.clone();
+        }
+
         this.namespaces = (HashMap) manager.namespaces.clone();
         this.actions = (ArrayList) manager.actions.clone();
         this.rules = (MultiHashMap) manager.rules.clone();
     }
-    
-    
-    // --------------------------------------------------------- 
+
+
+    // ---------------------------------------------------------
     // Public Methods
-    // --------------------------------------------------------- 
+    // ---------------------------------------------------------
 
     /**
      * Returns a clone of this object. The Action objects currently
@@ -110,7 +133,7 @@
     public RuleManager copy() {
         return new DefaultRuleManager(this);
     }
-    
+
     /**
      * This method is called at the start of parsing a new input document.
      * <p>
@@ -123,7 +146,7 @@
      */
     public void startParse(Context context) {
     }
-    
+
     /**
      * This method is called after parsing of a new input document has completed.
      * <p>
@@ -132,7 +155,102 @@
      */
     public void finishParse(Context context) {
     }
-    
+
+    /**
+     * Defines an action that should be returned by method getMatchingActions
+     * if no rule pattern matches the specified path.
+     * <p>
+     * The specified action is appended to the existing list of fallback actions.
+     */
+    public void addFallbackAction(Action action) {
+        if (fallbackActions == null) {
+            fallbackActions = new ArrayList(2);
+        }
+        fallbackActions.add(action);
+
+        // if the action isn't already in the unique-action list, add it
+        if (!actions.contains(action)) {
+            actions.add(action);
+        }
+     }
+
+    /**
+     * Defines actions that should be returned by method getMatchingActions
+     * if no rule pattern matches the specified path.
+     * <p>
+     * The actions contained in the specified list are appended to the
+     * existing list of fallback actions.
+     */
+     public void addFallbackActions(List actions) {
+        if (fallbackActions == null) {
+            fallbackActions = new ArrayList(actions);
+        } else {
+            fallbackActions.addAll(actions);
+        }
+
+        // If any action isn't already in the unique-action list, add it.
+        // Yes, this is inefficient - but the list is not expected to be
+        // long...
+        for(Iterator i = actions.iterator(); i.hasNext(); ) {
+            Action action = (Action) i.next();
+
+            if (!actions.contains(action)) {
+                actions.add(action);
+            }
+        }
+     }
+
+    /**
+     * Defines an action that should always be included in the list of actions
+     * returned by method getMatchingActions, no matter what path is provided.
+     * <p>
+     * if no rule pattern matches the specified path. The specified action
+     * is appended to the existing list of fallback actions.
+     * <p>
+     * The mandatory actions (if any) are always returned at the tail of the
+     * list of actions returned by getMatchingActions.
+     */
+    public void addMandatoryAction(Action action) {
+         if (mandatoryActions == null) {
+             mandatoryActions = new ArrayList(2);
+         }
+         mandatoryActions.add(action);
+
+         // if the action isn't already in the unique-action list, add it
+        if (!actions.contains(action)) {
+            actions.add(action);
+        }
+     }
+
+    /**
+     * Defines actions that should always be included in the list of actions
+     * returned by method getMatchingActions, no matter what path is provided.
+     * <p>
+     * The actions contained in the specified list are appended to the
+     * existing list of mandatory actions.
+     * <p>
+     * The mandatory actions (if any) are always returned at the tail of the
+     * list of actions returned by getMatchingActions.
+     */
+    public void addMandatoryActions(List actions) {
+         if (mandatoryActions == null) {
+             mandatoryActions = new ArrayList(actions);
+         } else {
+             mandatoryActions.addAll(actions);
+         }
+
+        // If any action isn't already in the unique-action list, add it.
+        // Yes, this is inefficient - but the list is not expected to be
+        // long...
+        for(Iterator i = actions.iterator(); i.hasNext(); ) {
+            Action action = (Action) i.next();
+
+            if (!actions.contains(action)) {
+                actions.add(action);
+            }
+        }
+     }
+
     /**
      * When rules are added, the pattern is of form
      * <pre>
@@ -151,7 +269,7 @@
      * are expanded to the corresponding namespace URIs using the mapping
      * previously defined in the addNamespace method.
      */
-    public void addRule(String pattern, Action action) 
+    public void addRule(String pattern, Action action)
     throws InvalidRuleException {
         // if pattern has namespaces, then convert them to URIs.
         String path = patternToPath(namespaces, pattern);
@@ -160,47 +278,47 @@
         if (!actions.contains(action)) {
             actions.add(action);
         }
-        
+
         // add the mapping to the multilist
         rules.put(path, action);
     }
-    
+
     /**
      * Given a string of form "prefix:name/prefix:name", return a string of
      * form "{namespace-uri}name/{namespace-uri}/name".
      */
-    private String patternToPath(Map namespaces, String pattern) 
+    private String patternToPath(Map namespaces, String pattern)
     throws InvalidRuleException {
         int nsEndPos = pattern.indexOf(':');
         if (nsEndPos == -1) {
             /* no namespace prefixes present */
             return pattern;
         }
-        
+
         int currPos = 0;
         StringBuffer out = new StringBuffer();
         while (nsEndPos != -1) {
             int nsStartPos = pattern.lastIndexOf('/', nsEndPos);
             String prefix = pattern.substring(nsStartPos+1, nsEndPos);
-            
+
             String uri = (String) namespaces.get(prefix);
             if (uri == null) {
                 throw new InvalidRuleException(
                     "No namespace for prefix [" + prefix + "]");
             }
-            
+
             String prePrefix = pattern.substring(currPos, nsStartPos);
             out.append(prePrefix);
-            
+
             out.append('{');
             out.append(uri);
             out.append('}');
-            
+
             currPos = nsEndPos + 1;
             nsEndPos = pattern.indexOf(':', nsEndPos+1);
         }
         out.append(pattern.substring(currPos));
-        
+
         return out.toString();
     }
 
@@ -216,11 +334,11 @@
     public List getMatchingActions(String path) {
         // assert path.startsWith('/');
         List actionList = (List) rules.get(path);
-        
+
         if ((actionList == null) || (actionList.size() < 1)) {
             /*
              * Ok, there is no absolute path that matches. So what we need to
-             * do now is iterate over all the available paths which are not 
+             * do now is iterate over all the available paths which are not
              * absolute, and see which is the longest match.
              */
 
@@ -233,7 +351,7 @@
                     // yep, this is non-absolute
                     int thisKeyLength = key.length();
                     if ((thisKeyLength > longestMatch) && path.endsWith(key)) {
-                        
+
                         // just check that we aren't trying to match a
                         // pattern of "a/b" against a path of "/gotcha/b"!
                         if (path.charAt(thisPathLength - thisKeyLength - 1) == '/') {
@@ -246,11 +364,23 @@
         }
 
         if (actionList == null) {
-            return java.util.Collections.EMPTY_LIST;
+            actionList = fallbackActions;
         }
-        else {
-            return actionList;
+
+        if (actionList == null) {
+            if (mandatoryActions == null) {
+                actionList = java.util.Collections.EMPTY_LIST;
+            } else {
+                actionList = mandatoryActions;
+            }
+        } else if (mandatoryActions != null) {
+            List oldActions = actionList;
+            actionList = new ArrayList(oldActions.size() + mandatoryActions.size());
+            actionList.addAll(oldActions);
+            actionList.addAll(mandatoryActions);
         }
+
+        return actionList;
     }
 
     /**

Modified: jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/RuleManager.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/RuleManager.java?view=diff&r1=153881&r2=153882
==============================================================================
--- jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/RuleManager.java (original)
+++ jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/RuleManager.java Mon Feb 14 19:08:36 2005
@@ -1,19 +1,19 @@
 /* $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.
- */ 
+ */
 
 package org.apache.commons.digester2;
 
@@ -27,8 +27,13 @@
  *  <p>
  * Terminology:
  * <ul>
- * <li>Pattern: a string with namespace prefixes in it, eg "/foo:bob"</li>
- * <li>Path: a string with namespace uris in it, eg /{urn:foo}bob"</li>
+ * <li>Pattern: a string which may possibly have "wildcard" matching in it,
+ *  for example "a", which matches any "a" element anywhere in the document,
+ *  or "a/b" which matches any "b" element which is a child of an "a" element
+ *  anywhere in the document.
+ *</li>
+ * <li>Path: a string which represents the absolute path from the root element
+ *  of the document to a particular xml element.
  * </ul>
  * <p>
  * <strong>IMPORTANT NOTE</strong>: Anyone implementing a custom RuleManager is
@@ -44,18 +49,18 @@
     /**
      * Returns a new instance with the same type as the concrete object this
      * method is invoked on, complete with contained Actions and patterns. Note
-     * that the new RuleManager instance may contain references to the same 
+     * that the new RuleManager instance may contain references to the same
      * Action instances as the old one, as Action instances are expected to be
-     * stateless and therefore can be safely shared between RuleManagers. 
+     * stateless and therefore can be safely shared between RuleManagers.
      */
     public RuleManager copy();
-    
+
     /**
      * Invoked before parsing each input document, this method gives the
      * RuleManager opportunity to do per-parse initialisation if required.
      */
     public void startParse(Context context) throws DigestionException;
-     
+
     /**
      * Invoked after parsing each input document, this method gives the
      * RuleManager the opportunity to do per-parse cleanup if required.
@@ -63,11 +68,52 @@
      public void finishParse(Context context) throws DigestionException;
 
     /**
+     * Defines an action that should be returned by method getMatchingActions
+     * if no rule pattern matches the specified path.
+     * <p>
+     * The specified action is appended to the existing list of fallback actions.
+     */
+    public void addFallbackAction(Action action);
+
+    /**
+     * Defines actions that should be returned by method getMatchingActions
+     * if no rule pattern matches the specified path.
+     * <p>
+     * The actions contained in the specified list are appended to the
+     * existing list of fallback actions.
+     */
+    public void addFallbackActions(List actions);
+
+    /**
+     * Defines an action that should always be included in the list of actions
+     * returned by method getMatchingActions, no matter what path is provided.
+     * <p>
+     * if no rule pattern matches the specified path. The specified action
+     * is appended to the existing list of fallback actions.
+     * <p>
+     * The mandatory actions (if any) are always returned at the tail of the
+     * list of actions returned by getMatchingActions.
+     */
+    public void addMandatoryAction(Action action);
+
+    /**
+     * Defines actions that should always be included in the list of actions
+     * returned by method getMatchingActions, no matter what path is provided.
+     * <p>
+     * The actions contained in the specified list are appended to the
+     * existing list of mandatory actions.
+     * <p>
+     * The mandatory actions (if any) are always returned at the tail of the
+     * list of actions returned by getMatchingActions.
+     */
+    public void addMandatoryActions(List actions);
+
+    /**
      * Define a mapping between xml element prefix and namespace uri
      * for use when rule patterns contain namespace prefixes.
      */
     public void addNamespace(String prefix, String uri);
-    
+
     /**
      * Cause the specified Action to be invoked whenever an xml element
      * is encountered in the input which matches the specified pattern.
@@ -88,19 +134,34 @@
      * The rules are returned in the order they were added. If an Action
      * instance has been added multiple times, then its order is set by the
      * first time it was added.
+     * <p>
+     * This list includes fallback and mandatory actions (if any).
      */
     public List getActions();
-    
+
     /**
-     * Return a List of all registered Action instances that match the specified
-     * nesting pattern, or a zero-length List if there are no matches.  If more
-     * than one Action instance matches, they <strong>must</strong> be returned
-     * in the order originally registered through the <code>addRule()</code>
-     * method.
+     * Return a List of all registered Action instances whose associated
+     * pattern matches the specified path. If more than one rule matches, then
+     * the associated Action instance are <strong>guaranteed</strong> to be
+     * returned in the order originally registered through the
+     * <code>addRule()</code> method.
+     * <p>
+     * If no rule's pattern matches the path, then the fallback actions
+     * (if any) will be returned.
+     * <p>
+     * If there are any mandatory actions defined, then these will always be
+     * appended to the list of actions that have matched (including any
+     * fallback actions).
+     * <p>
+     * If there are no matching rules, no fallback actions, and no mandatory
+     * actions then an empty list is returned.
+     * <p>
+     * Note that the returned list should be treated as <i>unmodifiable</i>.
+     * Attempting to do so will result in undefined behaviour.
      *
      * @param path is a string of form
      * <pre>/{namespace}elementName/{namespace}elementName"</pre>
-     * identifying the path from the root of the input document to the element 
+     * identifying the path from the root of the input document to the element
      * for which the caller wants the set of matching Action objects. If an
      * element has no namespace, then the {} part is omitted.
      */



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