001: /*
002: * Copyright 2006 Dan Shellman
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.iscreen.impl.xml;
017:
018: import java.util.List;
019: import java.util.ArrayList;
020: import java.util.Map;
021: import java.util.HashMap;
022: import java.util.Iterator;
023:
024: /**
025: * Instances of this class track the position within a "stack" (such as an XML
026: * hierarchy) and is used for error messages, giving the user as much information
027: * about where the error occurred as possible.
028: *
029: * @author Shellman, Dan
030: */
031: public class PositionContext {
032: protected String fileLocation;
033: protected List nodes = new ArrayList();
034:
035: /**
036: * Constructor taking the location of the root "file" location.
037: *
038: * @param theFileLocation The root "file" location.
039: */
040: public PositionContext(String theFileLocation) {
041: fileLocation = theFileLocation;
042: } //end PositionContext()
043:
044: /**
045: * Pushes a node onto the top of the context. This is the primary method
046: * of supplying an additional context.
047: *
048: * @param node The name of the node.
049: */
050: public void pushNode(String node) {
051: nodes.add(new Node(node));
052: } //end pushNode()
053:
054: /**
055: * Pushes an attribute and its value onto the current node (the one at
056: * the top of the stack). This should only be called after a call to
057: * pushNode(). However, it can be called multiple times for a particular
058: * node (though the attribute name must be unique, or subsequent calls
059: * will override the value).
060: *
061: * @param attr The name of the attribute.
062: * @param value The value of the attribute.
063: */
064: public void pushAttr(String attr, String value) {
065: Node node;
066:
067: if (nodes.size() > 0) {
068: node = (Node) nodes.get(nodes.size() - 1);
069: node.addAttribute(attr, value);
070: }
071: } //end pushNode()
072:
073: /**
074: * Removes the top-most node from the context (and all associated
075: * attributes of that node).
076: *
077: * @return Returns the top-most node (removing it from the stack).
078: */
079: public String popNode() {
080: if (nodes.size() > 0) {
081: Node node;
082:
083: node = (Node) nodes.remove(nodes.size() - 1);
084:
085: return node.getNodeName();
086: }
087:
088: return null;
089: } //end popNode()
090:
091: /**
092: * Retrieves the root file location.
093: *
094: * @return Returns the root file location.
095: */
096: public String getFileLocation() {
097: return fileLocation;
098: } //end getFileLocation()
099:
100: /**
101: * Builds and returns the context path or full location of
102: * the "position" this instance represents. This method is
103: * called to get the location information so that it can be
104: * logged.
105: *
106: * @return Returns the full context path/location of this context.
107: */
108: public String getLocation() {
109: StringBuffer buf = new StringBuffer();
110:
111: buf.append("/");
112: for (int i = 0; i < nodes.size(); i++) {
113: Node node;
114: Map attrs;
115: Iterator it;
116:
117: node = (Node) nodes.get(i);
118: buf.append(node.getNodeName());
119:
120: attrs = node.getAttributes();
121: it = attrs.keySet().iterator();
122: while (it.hasNext()) {
123: String value;
124: String key;
125:
126: key = (String) it.next();
127: value = (String) attrs.get(key);
128: buf.append("[");
129: buf.append(key);
130: buf.append("=");
131: buf.append(value);
132: buf.append("]");
133: }
134:
135: buf.append("/");
136: }
137:
138: return buf.toString();
139: } //end getLocation()
140:
141: /**
142: * Instance of this inner class represent individual nodes within
143: * the context. A node can have any number of attributes, though
144: * each attribute must be unique.
145: */
146: private class Node {
147: private String node;
148: private Map attributes = new HashMap();
149:
150: public Node(String nodeName) {
151: node = nodeName;
152: } //end Node()
153:
154: public Node(String nodeName, String attrName, String attrValue) {
155: this (nodeName);
156: attributes.put(attrName, attrValue);
157: } //end Node()
158:
159: public void addAttribute(String attr, String value) {
160: attributes.put(attr, value);
161: } //end addAttribute()
162:
163: public String getNodeName() {
164: return node;
165: } //end getNodeName()
166:
167: public Map getAttributes() {
168: return attributes;
169: } //end getAttributes()
170: };
171: } //end PositionContext
|