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/10 13:37:57 UTC
svn commit: r153203 -
jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/Context.java
Author: skitching
Date: Thu Feb 10 04:37:52 2005
New Revision: 153203
URL: http://svn.apache.org/viewcvs?view=rev&rev=153203
Log:
* Expanded concept of "named stacks" into "scratch stacks"
* Removed trailing whitespace from all lines
Modified:
jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/Context.java
Modified: jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/Context.java
URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/Context.java?view=diff&r1=153202&r2=153203
==============================================================================
--- jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/Context.java (original)
+++ jakarta/commons/proper/digester/branches/digester2/src/java/org/apache/commons/digester2/Context.java Thu Feb 10 04:37:52 2005
@@ -48,26 +48,90 @@
public class Context {
- // ---------------------------------------------------
+ // ---------------------------------------------------
// Local classes
// ---------------------------------------------------
-
+
/**
- * See method {@link #putInstanceData}.
+ * The context provides "scratch stacks" that any other object with
+ * access to the context can use for storing data; instances of this
+ * class are used to identify which "scratch stack" is to be used when
+ * using those push/pop/peek/isEmpty methods that take a StackId parameter.
+ * <p>
+ * An object of class Foo which wishes to store data on a private scratch
+ * stack for its own use should declare a StackId member variable then
+ * later reference it:
+ * <pre>
+ * private final Context.StackId WIDGET_STACK
+ * = new Context.StackId(Foo.class, "WidgetStack", this);
+ * ....
+ * context.push(WIDGET_STACK, someObject);
+ * ....
+ * Object savedObject = context.pop(WIDGET_STACK);
+ * </pre>
+ * <p>
+ * If an class Bar wishes to share a scratch stack across all instances of
+ * itself, then it should declare a static StackId:
+ * <pre>
+ * private static final Context.StackId GADGET_STACK
+ * = new Context.StackId(Bar.class, "GadgetStack");
+ * </pre>
+ * <p>
+ * If a class wishes to share a scratch stack with objects that are not of
+ * the same class, then it can follow the above example but declare access
+ * to be protected or public. Other classes can then access it via:
+ * <pre>
+ * context.push(Bar.GADGET_STACK, someObject);
+ * </pre>
+ * <p>
+ * The parameters to StackId are actually only used in debugging but
+ * the above conventions should be followed for consistency.
*/
+ public static class StackId {
+ private String desc;
+
+ /**
+ * Create an instance which has no specific owner object.
+ */
+ public StackId(Class sourceClass, String desc) {
+ this.desc = sourceClass.getName() + ":" + desc;
+ }
+
+ /**
+ * Create an instance which has an owner object.
+ */
+ public StackId(Class sourceClass, String desc, Object owner) {
+ this.desc = sourceClass.getName() + ":" + desc
+ + ":" + System.identityHashCode(owner);
+ }
+
+ /**
+ * Provides a nice string which shows what class declares this StackId,
+ * what it is intended to be used for ("desc") and what specific
+ * instance of the class (if any) the stack is associated with.
+ */
+ public String toString() {
+ return desc;
+ }
+ }
+
+ /**
+ * See method {@link #putInstanceData}.
+ */
private static class InstanceItem {
public Object key;
public Map map;
-
+
public InstanceItem(Object key, Map map) {
this.key = key;
this.map = map;
}
}
- // ---------------------------------------------------
+
+ // ---------------------------------------------------
// Instance Variables
- // ---------------------------------------------------
+ // ---------------------------------------------------
/**
* The owner of this object.
@@ -101,10 +165,10 @@
private HashMap namespaces = new HashMap();
/**
- * If not null, then calls to the saxHandler's characters, startElement,
- * endElement and processingInstruction methods are forwarded to the
- * specified object. This is intended to allow rules to temporarily
- * "take control" of the sax events. In particular, this is used by
+ * If not null, then calls to the saxHandler's characters, startElement,
+ * endElement and processingInstruction methods are forwarded to the
+ * specified object. This is intended to allow rules to temporarily
+ * "take control" of the sax events. In particular, this is used by
* NodeCreateAction.
*/
private ContentHandler contentHandler = null;
@@ -112,7 +176,7 @@
/**
* The body text of the current element since the most recent child
* element (or start of the element if no child elements have yet been
- * seen). When a child element is found, this text is reported to
+ * seen). When a child element is found, this text is reported to
* matching actions via the Action.bodySegment method, then the buffer
* can be cleared. There is no need for a stack of these.
*/
@@ -170,27 +234,24 @@
/**
* Stacks used by Action objects to store internal state.
* They can also be used for inter-action communication.
- *
- * By convention, Action instances use their class name as the key
- * (or as a key prefix) to this map.
*/
- private HashMap stacksByName = new HashMap();
+ private HashMap scratchStacks = new HashMap();
/**
* Place where other objects can store any data they like during a parse.
* See method {@link #putInstanceData} for more information.
*/
private List instanceData = new ArrayList();
-
+
/**
* The parameters stack being utilized by CallMethodAction and
* CallParamAction.
*/
private ArrayStack params = new ArrayStack();
- // ---------------------------------------------------------
+ // ---------------------------------------------------------
// Constructors
- // ---------------------------------------------------------
+ // ---------------------------------------------------------
/**
* Construct a new Context.
@@ -203,7 +264,7 @@
// ---------------------------------------------------
// Properties
- // ---------------------------------------------------
+ // ---------------------------------------------------
/**
* Return the current Logger associated with this instance of the Digester
@@ -213,8 +274,8 @@
}
/**
- * Gets the document locator associated with our parser. This object
- * can be consulted to find out which line of the input xml document
+ * Gets the document locator associated with our parser. This object
+ * can be consulted to find out which line of the input xml document
* we are currently on - very useful when generating error messages.
*
* @return the Locator supplied by the document parser
@@ -257,7 +318,7 @@
}
stack.push(namespaceURI);
}
-
+
/**
* Unregister the specified prefix string as being an alias for the
* specified namespace uri.
@@ -284,21 +345,21 @@
}
/**
- * Returns the text seen in the current xml element since the last child
+ * Returns the text seen in the current xml element since the last child
* element was seen (or since the start of the xml element if no child
* elements have yet been encountered).
*/
public StringBuffer getBodyTextSegment() {
return bodyTextSegment;
}
-
+
/**
* Clears the bodyTextSegment buffer. See {@link #getBodyTextSegment}.
*/
public void clearBodyTextSegment() {
bodyTextSegment.setLength(0);
}
-
+
/**
* Save the buffer which is currently being used to accumulate text
* content of the current xml element. This is expected to be called
@@ -308,7 +369,7 @@
bodyTexts.push(bodyText);
bodyText = new StringBuffer();
}
-
+
/**
* Restore a saved buffer. This is expected to be called just after
* completing processing of a child xml element, to continue accumulating
@@ -319,7 +380,7 @@
bodyText = (StringBuffer) bodyTexts.pop();
return tmp;
}
-
+
/**
* Append more text to the buffer representing the text content of the
* current xml element. This is called in multiple stages because:
@@ -333,7 +394,7 @@
bodyTextSegment.append(buffer, start, length);
bodyText.append(buffer, start, length);
}
-
+
/**
* Return the Path object representing the path from the document root
* to the current element.
@@ -341,7 +402,7 @@
public Path getCurrentPath() {
return currentElementPath;
}
-
+
/**
* Return the path to the xml element currently being processed.
* This is exactly equivalent to <code>getCurrentPath().getPath()</code>.
@@ -390,7 +451,7 @@
}
/**
- * Retrieve the list of Actions which matched the current element.
+ * Retrieve the list of Actions which matched the current element.
*
* @return a list of Action objects.
*/
@@ -440,9 +501,9 @@
return contentHandler;
}
- // ---------------------------------------------------
+ // ---------------------------------------------------
// Object Stack Methods
- // ---------------------------------------------------
+ // ---------------------------------------------------
/**
* The root object of the Object stack.
@@ -521,17 +582,17 @@
* is out-of-range. Note that all the Digester.parse methods will turn this
* into a (checked) DigestionException.
*
- * @throws ArrayOutOfBoundsException (a RuntimeException subclass) if
+ * @throws ArrayOutOfBoundsException (a RuntimeException subclass) if
* index < 0. Note that all the Digester.parse methods will turn this
* into a (checked) DigestionException.
*/
- public Object peek(int n)
+ public Object peek(int n)
throws EmptyStackException, IndexOutOfBoundsException {
return stack.peek(n);
}
/**
- * Pop the top object off of the stack, and return it.
+ * Pop the top object off of the stack, and return it.
*
* @throws EmptyStackException (a RuntimeException subclass) if the stack
* is empty. Note that all the Digester.parse methods will turn this into
@@ -553,59 +614,61 @@
stack.push(object);
}
+ // ---------------------------------------------------
+ // Scratch Stack Methods
+ // ---------------------------------------------------
+
/**
- * <p>Is the stack with the given name empty?</p>
- * <p><strong>Note:</strong> a stack is considered empty
- * if no objects have been pushed onto it yet.</p>
+ * Is the stack with the given id empty?
+ * <p>
+ * A stack is considered empty if no objects have been pushed onto it yet.
*
- * @param stackName the name of the stack whose emptiness
+ * @param stackId identifies the stack whose emptiness
* should be evaluated
*
* @return true if the given stack if empty
*/
- public boolean isEmpty(String stackName) {
- boolean result = true;
- ArrayStack namedStack = (ArrayStack) stacksByName.get(stackName);
- if (namedStack != null ) {
- result = namedStack.isEmpty();
- }
- return result;
+ public boolean isEmpty(StackId stackId) {
+ ArrayStack stack = (ArrayStack) scratchStacks.get(stackId);
+ return (stack == null) || stack.isEmpty();
}
/**
- * Return the current depth of the specified stack.
+ * Return the current depth of the specified stack. A stack is
+ * considered to have depth of zero if no objects have been
+ * pushed onto it yet.
*
- * @param stackName the name of the stack to be peeked
+ * @param stackId identifies the stack to be peeked
*/
- public int getStackSize(String stackName) {
+ public int getStackSize(StackId stackId) {
boolean result = true;
- ArrayStack namedStack = (ArrayStack) stacksByName.get(stackName);
- if (namedStack != null ) {
- return namedStack.size();
+ ArrayStack stack = (ArrayStack) scratchStacks.get(stackId);
+ if (stack != null ) {
+ return stack.size();
}
return 0;
}
/**
- * <p>Gets the top object from the stack with the given name.
- * This method does not remove the object from the stack.
- * </p>
+ * <p>Gets the top object from the stack with the given id.
+ * This method does not remove the object from the stack.</p>
+ *
* <p><strong>Note:</strong> a stack is considered empty
* if no objects have been pushed onto it yet.</p>
*
- * @param stackName the name of the stack to be peeked
+ * @param stackId identifies the stack to be peeked
* @return the top <code>Object</code> on the stack.
* @throws EmptyStackException if the named stack is empty
*/
- public Object peek(String stackName) throws EmptyStackException {
- ArrayStack namedStack = (ArrayStack) stacksByName.get(stackName);
- if (namedStack == null ) {
+ public Object peek(StackId stackId) throws EmptyStackException {
+ ArrayStack stack = (ArrayStack) scratchStacks.get(stackId);
+ if (stack == null ) {
if (log.isDebugEnabled()) {
- log.debug("Stack '" + stackName + "' is empty");
+ log.debug("Stack '" + stackId + "' is empty");
}
throw new EmptyStackException();
} else {
- return namedStack.peek();
+ return stack.peek();
}
}
@@ -617,7 +680,7 @@
* <p><strong>Note:</strong> a stack is considered empty
* if no objects have been pushed onto it yet.</p>
*
- * @param stackName the name of the stack to be peeked
+ * @param stackId identifies the stack to be peeked
*
* @param n Index of the desired element, where 0 is the top of the stack,
* 1 is the next element down, and so on.
@@ -626,47 +689,48 @@
* is out-of-range. Note that all the Digester.parse methods will turn this
* into a (checked) DigestionException.
*
- * @throws ArrayOutOfBoundsException (a RuntimeException subclass) if
+ * @throws ArrayOutOfBoundsException (a RuntimeException subclass) if
* index < 0. Note that all the Digester.parse methods will turn this
* into a (checked) DigestionException.
*/
- public Object peek(String stackName, int n)
+ public Object peek(StackId stackId, int n)
throws EmptyStackException, IndexOutOfBoundsException {
- ArrayStack namedStack = (ArrayStack) stacksByName.get(stackName);
- if (namedStack == null ) {
+ ArrayStack stack = (ArrayStack) scratchStacks.get(stackId);
+ if (stack == null ) {
if (log.isDebugEnabled()) {
- log.debug("Stack '" + stackName + "' is empty");
+ log.debug("Stack '" + stackId + "' is empty");
}
throw new EmptyStackException();
} else {
- return namedStack.peek(n);
+ return stack.peek(n);
}
}
/**
- * <p>Pops (gets and removes) the top object from the stack with the
+ * <p>Pops (gets and removes) the top object from the stack with the
* given name.</p>
*
- * <p><strong>Note:</strong> a stack is considered empty
- * if no objects have been pushed onto it yet.</p>
- *
- * @param stackName the name of the stack from which the top value is to
+ * @param stackId identifies the stack from which the top value is to
* be popped
*
* @return the top <code>Object</code> on the stack.
*
- * @throws EmptyStackException if the named stack is empty, or has not
+ * @throws EmptyStackException if the named stack is empty, or has not
* yet been created.
*/
- public Object pop(String stackName) throws EmptyStackException {
- ArrayStack namedStack = (ArrayStack) stacksByName.get(stackName);
- if (namedStack == null) {
+ public Object pop(StackId stackId) throws EmptyStackException {
+ ArrayStack stack = (ArrayStack) scratchStacks.get(stackId);
+ if (stack == null) {
if (log.isDebugEnabled()) {
- log.debug("Stack '" + stackName + "' is empty");
+ log.debug("Stack '" + stackId + "' is empty");
}
throw new EmptyStackException();
} else {
- return namedStack.pop();
+ Object result = stack.pop();
+ if (stack.isEmpty()) {
+ scratchStacks.remove(stackId);
+ }
+ return result;
}
}
@@ -674,18 +738,22 @@
* 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 stackId identifies 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);
+ public void push(StackId stackId, Object value) {
+ ArrayStack stack = (ArrayStack) scratchStacks.get(stackId);
+ if (stack == null) {
+ stack = new ArrayStack();
+ scratchStacks.put(stackId, stack);
}
- namedStack.push(value);
+ stack.push(value);
}
+ // ---------------------------------------------------
+ // Param Stack Methods
+ // ---------------------------------------------------
+
/**
* <p>Return the top object on the parameters stack without removing it.</p>
*
@@ -699,10 +767,10 @@
}
/**
- * <p>Return the n'th object down the parameters stack, where 0 is the
+ * <p>Return the n'th object down the parameters stack, where 0 is the
* top element and [stacksize-1] is the bottom element.
*
- * <p>The parameters stack is used to store <code>CallMethodAction</code>
+ * <p>The parameters stack is used to store <code>CallMethodAction</code>
* parameters. See {@link #params}.</p>
*
* @param n Index of the desired element, where 0 is the top of the stack,
@@ -729,7 +797,7 @@
/**
* <p>Push a new object onto the top of the parameters stack.</p>
*
- * <p>The parameters stack is used to store <code>CallMethodAction</code>
+ * <p>The parameters stack is used to store <code>CallMethodAction</code>
* parameters. See {@link #params}.</p>
*
* @param object The new object
@@ -738,11 +806,11 @@
params.push(object);
}
-
+
// -----------------------------------------------
// Other public methods
// -----------------------------------------------
-
+
/**
* Place where an object (typically an Action) can store any data it likes
* during a parse. Usually the "named stacks" facility is the most
@@ -772,7 +840,7 @@
// Note that if we trusted System.identityHashCode to return a unique
// string for an instance, then we could use a map. However that method
// doesn't promise to return a unique string on all platforms.
-
+
for(Iterator i = instanceData.iterator(); i.hasNext(); ) {
InstanceItem item = (InstanceItem) i.next();
if (item.key == instance) {
@@ -780,7 +848,7 @@
return;
}
}
-
+
// this instance has never stored data before
Map map = new HashMap();
map.put(category, data);
@@ -798,7 +866,7 @@
return item.map.get(category);
}
}
-
+
return null;
}
@@ -819,8 +887,8 @@
}
if (documentLocator != null) {
- String error =
- "Error at line " + documentLocator.getLineNumber()
+ String error =
+ "Error at line " + documentLocator.getLineNumber()
+ ", column " + documentLocator.getColumnNumber()
+ ": " + message;
---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org