001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.commons.configuration.tree.xpath;
018:
019: import java.util.Iterator;
020: import java.util.List;
021: import java.util.Locale;
022:
023: import org.apache.commons.configuration.tree.ConfigurationNode;
024: import org.apache.commons.jxpath.ri.Compiler;
025: import org.apache.commons.jxpath.ri.QName;
026: import org.apache.commons.jxpath.ri.compiler.NodeTest;
027: import org.apache.commons.jxpath.ri.compiler.NodeTypeTest;
028: import org.apache.commons.jxpath.ri.model.NodeIterator;
029: import org.apache.commons.jxpath.ri.model.NodePointer;
030:
031: /**
032: * <p>
033: * A specific <code>NodePointer</code> implementation for configuration nodes.
034: * </p>
035: * <p>
036: * This is needed for queries using JXPath.
037: * </p>
038: *
039: * @since 1.3
040: * @author Oliver Heger
041: * @version $Id: ConfigurationNodePointer.java 439648 2006-09-02 20:42:10Z oheger $
042: */
043: class ConfigurationNodePointer extends NodePointer {
044: /**
045: * The serial version UID.
046: */
047: private static final long serialVersionUID = -1087475639680007713L;
048:
049: /** Stores the associated configuration node. */
050: private ConfigurationNode node;
051:
052: /**
053: * Creates a new instance of <code>ConfigurationNodePointer</code>.
054: *
055: * @param node the node
056: * @param locale the locale
057: */
058: public ConfigurationNodePointer(ConfigurationNode node,
059: Locale locale) {
060: super (null, locale);
061: this .node = node;
062: }
063:
064: /**
065: * Creates a new instance of <code>ConfigurationNodePointer</code> and
066: * initializes it with its parent pointer.
067: *
068: * @param parent the parent pointer
069: * @param node the associated node
070: */
071: public ConfigurationNodePointer(NodePointer parent,
072: ConfigurationNode node) {
073: super (parent);
074: this .node = node;
075: }
076:
077: /**
078: * Returns a flag whether this node is a leaf. This is the case if there are
079: * no child nodes.
080: *
081: * @return a flag if this node is a leaf
082: */
083: public boolean isLeaf() {
084: return node.getChildrenCount() < 1;
085: }
086:
087: /**
088: * Returns a flag if this node is a collection. This is not the case.
089: *
090: * @return the collection flag
091: */
092: public boolean isCollection() {
093: return false;
094: }
095:
096: /**
097: * Returns this node's length. This is always 1.
098: *
099: * @return the node's length
100: */
101: public int getLength() {
102: return 1;
103: }
104:
105: /**
106: * Checks whether this node pointer refers to an attribute node. This method
107: * checks the attribute flag of the associated configuration node.
108: *
109: * @return the attribute flag
110: */
111: public boolean isAttribute() {
112: return node.isAttribute();
113: }
114:
115: /**
116: * Returns this node's name.
117: *
118: * @return the name
119: */
120: public QName getName() {
121: return new QName(null, node.getName());
122: }
123:
124: /**
125: * Returns this node's base value. This is the associated configuration
126: * node.
127: *
128: * @return the base value
129: */
130: public Object getBaseValue() {
131: return node;
132: }
133:
134: /**
135: * Returns the immediate node. This is the associated configuration node.
136: *
137: * @return the immediate node
138: */
139: public Object getImmediateNode() {
140: return node;
141: }
142:
143: /**
144: * Returns the value of this node.
145: *
146: * @return the represented node's value
147: */
148: public Object getValue() {
149: return node.getValue();
150: }
151:
152: /**
153: * Sets the value of this node.
154: *
155: * @param value the new value
156: */
157: public void setValue(Object value) {
158: node.setValue(value);
159: }
160:
161: /**
162: * Compares two child node pointers.
163: *
164: * @param pointer1 one pointer
165: * @param pointer2 another pointer
166: * @return a flag, which pointer should be sorted first
167: */
168: public int compareChildNodePointers(NodePointer pointer1,
169: NodePointer pointer2) {
170: ConfigurationNode node1 = (ConfigurationNode) pointer1
171: .getBaseValue();
172: ConfigurationNode node2 = (ConfigurationNode) pointer2
173: .getBaseValue();
174:
175: // attributes will be sorted before child nodes
176: if (node1.isAttribute() && !node2.isAttribute()) {
177: return -1;
178: } else if (node2.isAttribute() && !node1.isAttribute()) {
179: return 1;
180: }
181:
182: else {
183: // sort based on the occurrence in the sub node list
184: List subNodes = node1.isAttribute() ? node.getAttributes()
185: : node.getChildren();
186: for (Iterator it = subNodes.iterator(); it.hasNext();) {
187: ConfigurationNode child = (ConfigurationNode) it.next();
188: if (child == node1) {
189: return -1;
190: } else if (child == node2) {
191: return 1;
192: }
193: }
194: return 0; // should not happen
195: }
196: }
197:
198: /**
199: * Returns an iterator for the attributes that match the given name.
200: *
201: * @param name the attribute name
202: * @return the iterator for the attributes
203: */
204: public NodeIterator attributeIterator(QName name) {
205: return new ConfigurationNodeIteratorAttribute(this , name);
206: }
207:
208: /**
209: * Returns an iterator for the children of this pointer that match the given
210: * test object.
211: *
212: * @param test the test object
213: * @param reverse the reverse flag
214: * @param startWith the start value of the iteration
215: */
216: public NodeIterator childIterator(NodeTest test, boolean reverse,
217: NodePointer startWith) {
218: return new ConfigurationNodeIteratorChildren(this , test,
219: reverse, startWith);
220: }
221:
222: /**
223: * Tests if this node matches the given test. Configuration nodes are text
224: * nodes, too because they can contain a value.
225: *
226: * @param test the test object
227: * @return a flag if this node corresponds to the test
228: */
229: public boolean testNode(NodeTest test) {
230: if (test instanceof NodeTypeTest
231: && ((NodeTypeTest) test).getNodeType() == Compiler.NODE_TYPE_TEXT) {
232: return true;
233: }
234: return super.testNode(test);
235: }
236: }
|