rdonkin 2004/03/07 11:37:08
Modified: digester/src/java/org/apache/commons/digester Digester.java
package.html
digester/src/test/org/apache/commons/digester
DigesterTestCase.java
Log:
Added support for named stacks, a system of interrule communication.
Revision Changes Path
1.95 +53 -1
jakarta-commons/digester/src/java/org/apache/commons/digester/Digester.java
Index: Digester.java
===================================================================
RCS file:
/home/cvs/jakarta-commons/digester/src/java/org/apache/commons/digester/Digester.java,v
retrieving revision 1.94
retrieving revision 1.95
diff -u -r1.94 -r1.95
--- Digester.java 28 Feb 2004 13:32:52 -0000 1.94
+++ Digester.java 7 Mar 2004 19:37:07 -0000 1.95
@@ -314,6 +314,9 @@
*/
protected Substitutor substitutor;
+ /** Stacks used for interrule communication, indexed by name String */
+ private HashMap stacksByName = new HashMap();
+
// ------------------------------------------------------------- Properties
/**
@@ -2454,6 +2457,55 @@
}
stack.push(object);
+ }
+
+ /**
+ * Pushes the given object onto the stack with the given name.
+ * If no stack already exists with the given name then one will be created.
+ *
+ * @param stackName the name of the stack onto which the object should be pushed
+ * @param value the Object to be pushed onto the named stack.
+ */
+ public void push(String stackName, Object value) {
+ ArrayStack namedStack = (ArrayStack) stacksByName.get(stackName);
+ if (namedStack == null) {
+ namedStack = new ArrayStack();
+ stacksByName.put(stackName, namedStack);
+ }
+ namedStack.push(value);
+ }
+
+ /**
+ * Pops (gets and removes) the top object from the stack with the given name.
+ *
+ * @param stackName the name of the stack from which the top value is to be
popped
+ * @return the top <code>Object</code> on the stack or or null if the stack is
either
+ * empty or has not been created yet
+ */
+ public Object pop(String stackName) {
+ Object result = null;
+ ArrayStack namedStack = (ArrayStack) stacksByName.get(stackName);
+ if (namedStack != null && !namedStack.isEmpty()) {
+ result = namedStack.pop();
+ }
+ return result;
+ }
+
+ /**
+ * Gets the top object from the stack with the given name.
+ * This method does not remove the object from the stack.
+ *
+ * @param stackName the name of the stack to be peeked
+ * @return the top <code>Object</code> on the stack or null if the stack is
either
+ * empty or has not been created yet
+ */
+ public Object peek(String stackName) {
+ Object result = null;
+ ArrayStack namedStack = (ArrayStack) stacksByName.get(stackName);
+ if (namedStack != null && !namedStack.isEmpty()) {
+ result = namedStack.peek();
+ }
+ return result;
}
1.28 +42 -0
jakarta-commons/digester/src/java/org/apache/commons/digester/package.html
Index: package.html
===================================================================
RCS file:
/home/cvs/jakarta-commons/digester/src/java/org/apache/commons/digester/package.html,v
retrieving revision 1.27
retrieving revision 1.28
diff -u -r1.27 -r1.28
--- package.html 24 Jan 2004 15:37:30 -0000 1.27
+++ package.html 7 Mar 2004 19:37:07 -0000 1.28
@@ -19,6 +19,7 @@
<a href="#doc.Namespace">[Namespace Aware Parsing]</a>
<a href="#doc.Pluggable">[Pluggable Rules Processing]</a>
<a href="#doc.RuleSets">[Encapsulated Rule Sets]</a>
+<a href="#doc.NamedStacks">[Using Named Stacks For Inter-Rule Communication]</a>
<a href="#doc.RegisteringDTDs">[Registering DTDs]</a>
<a href="#doc.troubleshooting">[Troubleshooting]</a>
<a href="#doc.FAQ">[FAQ]</a>
@@ -1024,6 +1025,47 @@
the same set of nested elements at different nesting levels within an
XML document.</li>
</ul>
+<a name="doc.NamedStacks"></a>
+<h3>Using Named Stacks For Inter-Rule Communication</h3>
+<p>
+<code>Digester</code> is based on <code>Rule</code>'s working together to process
xml.
+For anything other than the most trival processing, communication between
+<code>Rule</code>'s is necessary. Since <code>Rule</code>'s are processed in
sequence,
+this usually means storing an Object somewhere where later instances can retrieve
it.
+</p>
+<p>
+<code>Digester</code> is based on SAX. The most natural data structure to use with
+SAX based xml processing is the stack. This allows more powerful processes to be
+specified more simply since the pushing and popping of objects can mimic the
+nested structure of the xml.
+</p>
+<p>
+<code>Digester</code> uses two basic stacks: one for the main beans and the other
+for parameters for method calls. These are inadequate for complex processing
+where many different <code>Rule</code>'s need to communicate through different
+channels.
+</p>
+<p>
+In this case, it is recommended that named stacks are used. In addition to the
+two basic stacks, <code>Digester</code> allows rules to use an unlimited number
+of other stacks referred two by an identifying string (the name). (That's where
+the term <em>named stack</em> comes from.) These stacks are
+accessed through calls to:
+</p>
+<ul>
+ <li><a href='Digester.html#push(java.lang.String, java.lang.Object)'>
+ void push(String stackName, Object value)</a></li>
+ <li><a href='Digester.html#pop(java.lang.String)'>
+ Object pop(String stackName)</a></li>
+ <li><a href='Digester.html#peek(java.lang.String)'>
+ Object peek(String stackName)</a></li>
+</ul>
+<p>
+<strong>Note:</strong> all stack names beginning with
<code>org.apache.commons.digester</code>
+are reserved for future use by the <code>Digester</code> component. It is also
recommended
+that users choose stack names perfixed by the name of their own domain to avoid
conflicts
+with other <code>Rule</code> implementations.
+</p>
<a name="doc.RegisteringDTDs"></a>
<h3>Registering DTDs</h3>
1.18 +35 -2
jakarta-commons/digester/src/test/org/apache/commons/digester/DigesterTestCase.java
Index: DigesterTestCase.java
===================================================================
RCS file:
/home/cvs/jakarta-commons/digester/src/test/org/apache/commons/digester/DigesterTestCase.java,v
retrieving revision 1.17
retrieving revision 1.18
diff -u -r1.17 -r1.18
--- DigesterTestCase.java 28 Feb 2004 13:32:54 -0000 1.17
+++ DigesterTestCase.java 7 Mar 2004 19:37:08 -0000 1.18
@@ -17,7 +17,7 @@
package org.apache.commons.digester;
-
+import java.math.BigDecimal;
import java.net.URL;
import java.io.StringReader;
import java.util.Iterator;
@@ -380,5 +380,38 @@
assertEquals("Substituted python attribute value", "Cleese",
tsr.attributes.getValue("", "python"));
}
+ /** Tests the push-peek-pop cycle for a named stack */
+ public void testNamedStackPushPeekPop() throws Exception
+ {
+ BigDecimal archimedesAveragePi = new BigDecimal("3.1418");
+ String testStackName =
"org.apache.commons.digester.tests.testNamedStackPushPeekPop";
+ Digester digester = new Digester();
+ assertNull("Stack starts empty:", digester.peek(testStackName));
+ digester.push(testStackName, archimedesAveragePi);
+ assertEquals("Peeked value:", archimedesAveragePi,
digester.peek(testStackName));
+ assertEquals("Popped value:", archimedesAveragePi,
digester.pop(testStackName));
+ assertNull("Stack ends empty:", digester.peek(testStackName));
+ }
+
+ /** Tests that values are stored independently */
+ public void testNamedIndependence()
+ {
+ String testStackOneName =
"org.apache.commons.digester.tests.testNamedIndependenceOne";
+ String testStackTwoName =
"org.apache.commons.digester.tests.testNamedIndependenceTwo";
+ Digester digester = new Digester();
+ digester.push(testStackOneName, "Tweedledum");
+ digester.push(testStackTwoName, "Tweedledee");
+ assertEquals("Popped value one:", "Tweedledum",
digester.pop(testStackOneName));
+ assertEquals("Popped value two:", "Tweedledee",
digester.pop(testStackTwoName));
+ }
+
+ /** Tests popping named stack not yet pushed */
+ public void testPopNamedStackNotPushed()
+ {
+ String testStackName =
"org.apache.commons.digester.tests.testPopNamedStackNotPushed";
+ Digester digester = new Digester();
+ digester.pop(testStackName);
+ digester.peek(testStackName);
+ }
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]