View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.configuration.tree.xpath;
18  
19  import java.util.Iterator;
20  import java.util.List;
21  import java.util.Locale;
22  
23  import org.apache.commons.configuration.tree.ConfigurationNode;
24  import org.apache.commons.jxpath.ri.Compiler;
25  import org.apache.commons.jxpath.ri.QName;
26  import org.apache.commons.jxpath.ri.compiler.NodeTest;
27  import org.apache.commons.jxpath.ri.compiler.NodeTypeTest;
28  import org.apache.commons.jxpath.ri.model.NodeIterator;
29  import org.apache.commons.jxpath.ri.model.NodePointer;
30  
31  /***
32   * <p>
33   * A specific <code>NodePointer</code> implementation for configuration nodes.
34   * </p>
35   * <p>
36   * This is needed for queries using JXPath.
37   * </p>
38   *
39   * @since 1.3
40   * @author Oliver Heger
41   * @version $Id: ConfigurationNodePointer.java 439648 2006-09-02 20:42:10Z oheger $
42   */
43  class ConfigurationNodePointer extends NodePointer
44  {
45      /***
46       * The serial version UID.
47       */
48      private static final long serialVersionUID = -1087475639680007713L;
49  
50      /*** Stores the associated configuration node. */
51      private ConfigurationNode node;
52  
53      /***
54       * Creates a new instance of <code>ConfigurationNodePointer</code>.
55       *
56       * @param node the node
57       * @param locale the locale
58       */
59      public ConfigurationNodePointer(ConfigurationNode node, Locale locale)
60      {
61          super(null, locale);
62          this.node = node;
63      }
64  
65      /***
66       * Creates a new instance of <code>ConfigurationNodePointer</code> and
67       * initializes it with its parent pointer.
68       *
69       * @param parent the parent pointer
70       * @param node the associated node
71       */
72      public ConfigurationNodePointer(NodePointer parent, ConfigurationNode node)
73      {
74          super(parent);
75          this.node = node;
76      }
77  
78      /***
79       * Returns a flag whether this node is a leaf. This is the case if there are
80       * no child nodes.
81       *
82       * @return a flag if this node is a leaf
83       */
84      public boolean isLeaf()
85      {
86          return node.getChildrenCount() < 1;
87      }
88  
89      /***
90       * Returns a flag if this node is a collection. This is not the case.
91       *
92       * @return the collection flag
93       */
94      public boolean isCollection()
95      {
96          return false;
97      }
98  
99      /***
100      * Returns this node's length. This is always 1.
101      *
102      * @return the node's length
103      */
104     public int getLength()
105     {
106         return 1;
107     }
108 
109     /***
110      * Checks whether this node pointer refers to an attribute node. This method
111      * checks the attribute flag of the associated configuration node.
112      *
113      * @return the attribute flag
114      */
115     public boolean isAttribute()
116     {
117         return node.isAttribute();
118     }
119 
120     /***
121      * Returns this node's name.
122      *
123      * @return the name
124      */
125     public QName getName()
126     {
127         return new QName(null, node.getName());
128     }
129 
130     /***
131      * Returns this node's base value. This is the associated configuration
132      * node.
133      *
134      * @return the base value
135      */
136     public Object getBaseValue()
137     {
138         return node;
139     }
140 
141     /***
142      * Returns the immediate node. This is the associated configuration node.
143      *
144      * @return the immediate node
145      */
146     public Object getImmediateNode()
147     {
148         return node;
149     }
150 
151     /***
152      * Returns the value of this node.
153      *
154      * @return the represented node's value
155      */
156     public Object getValue()
157     {
158         return node.getValue();
159     }
160 
161     /***
162      * Sets the value of this node.
163      *
164      * @param value the new value
165      */
166     public void setValue(Object value)
167     {
168         node.setValue(value);
169     }
170 
171     /***
172      * Compares two child node pointers.
173      *
174      * @param pointer1 one pointer
175      * @param pointer2 another pointer
176      * @return a flag, which pointer should be sorted first
177      */
178     public int compareChildNodePointers(NodePointer pointer1,
179             NodePointer pointer2)
180     {
181         ConfigurationNode node1 = (ConfigurationNode) pointer1.getBaseValue();
182         ConfigurationNode node2 = (ConfigurationNode) pointer2.getBaseValue();
183 
184         // attributes will be sorted before child nodes
185         if (node1.isAttribute() && !node2.isAttribute())
186         {
187             return -1;
188         }
189         else if (node2.isAttribute() && !node1.isAttribute())
190         {
191             return 1;
192         }
193 
194         else
195         {
196             // sort based on the occurrence in the sub node list
197             List subNodes = node1.isAttribute() ? node.getAttributes() : node
198                     .getChildren();
199             for (Iterator it = subNodes.iterator(); it.hasNext();)
200             {
201                 ConfigurationNode child = (ConfigurationNode) it.next();
202                 if (child == node1)
203                 {
204                     return -1;
205                 }
206                 else if (child == node2)
207                 {
208                     return 1;
209                 }
210             }
211             return 0; // should not happen
212         }
213     }
214 
215     /***
216      * Returns an iterator for the attributes that match the given name.
217      *
218      * @param name the attribute name
219      * @return the iterator for the attributes
220      */
221     public NodeIterator attributeIterator(QName name)
222     {
223         return new ConfigurationNodeIteratorAttribute(this, name);
224     }
225 
226     /***
227      * Returns an iterator for the children of this pointer that match the given
228      * test object.
229      *
230      * @param test the test object
231      * @param reverse the reverse flag
232      * @param startWith the start value of the iteration
233      */
234     public NodeIterator childIterator(NodeTest test, boolean reverse,
235             NodePointer startWith)
236     {
237         return new ConfigurationNodeIteratorChildren(this, test, reverse,
238                 startWith);
239     }
240 
241     /***
242      * Tests if this node matches the given test. Configuration nodes are text
243      * nodes, too because they can contain a value.
244      *
245      * @param test the test object
246      * @return a flag if this node corresponds to the test
247      */
248     public boolean testNode(NodeTest test)
249     {
250         if (test instanceof NodeTypeTest
251                 && ((NodeTypeTest) test).getNodeType() == Compiler.NODE_TYPE_TEXT)
252         {
253             return true;
254         }
255         return super.testNode(test);
256     }
257 }