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