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.jxpath.ri.model.beans;
18  
19  import java.util.Locale;
20  
21  import org.apache.commons.jxpath.JXPathContext;
22  import org.apache.commons.jxpath.JXPathIntrospector;
23  import org.apache.commons.jxpath.ri.Compiler;
24  import org.apache.commons.jxpath.ri.QName;
25  import org.apache.commons.jxpath.ri.compiler.NodeNameTest;
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  import org.apache.commons.jxpath.util.ValueUtils;
31  
32  /**
33   * Transparent pointer to a collection (array or Collection).
34   *
35   * @author Dmitri Plotnikov
36   * @version $Revision: 668329 $ $Date: 2008-06-16 23:59:48 +0200 (Mo, 16 Jun 2008) $
37   */
38  public class CollectionPointer extends NodePointer {
39      private Object collection;
40      private NodePointer valuePointer;
41  
42      private static final long serialVersionUID = 8620254915563256588L;
43  
44      /**
45       * Create a new CollectionPointer.
46       * @param collection value
47       * @param locale Locale
48       */
49      public CollectionPointer(Object collection, Locale locale) {
50          super(null, locale);
51          this.collection = collection;
52      }
53  
54      /**
55       * Create a new CollectionPointer.
56       * @param parent parent NodePointer
57       * @param collection value
58       */
59      public CollectionPointer(NodePointer parent, Object collection) {
60          super(parent);
61          this.collection = collection;
62      }
63  
64      public QName getName() {
65          return null;
66      }
67  
68      public Object getBaseValue() {
69          return collection;
70      }
71  
72      public boolean isCollection() {
73          return true;
74      }
75  
76      public int getLength() {
77          return ValueUtils.getLength(getBaseValue());
78      }
79  
80      public boolean isLeaf() {
81          Object value = getNode();
82          return value == null || JXPathIntrospector.getBeanInfo(value.getClass()).isAtomic();
83      }
84  
85      public boolean isContainer() {
86          return index != WHOLE_COLLECTION;
87      }
88  
89      public Object getImmediateNode() {
90          return index == WHOLE_COLLECTION ? ValueUtils.getValue(collection)
91                  : ValueUtils.getValue(collection, index);
92      }
93  
94      public void setValue(Object value) {
95          if (index == WHOLE_COLLECTION) {
96              parent.setValue(value);
97          }
98          else {
99              ValueUtils.setValue(collection, index, value);
100         }
101     }
102 
103     public void setIndex(int index) {
104         super.setIndex(index);
105         valuePointer = null;
106     }
107 
108     public NodePointer getValuePointer() {
109         if (valuePointer == null) {
110             if (index == WHOLE_COLLECTION) {
111                 valuePointer = this;
112             }
113             else {
114                 Object value = getImmediateNode();
115                 valuePointer =
116                     NodePointer.newChildNodePointer(this, getName(), value);
117             }
118         }
119         return valuePointer;
120     }
121 
122     public NodePointer createPath(JXPathContext context) {
123         if (ValueUtils.getLength(getBaseValue()) <= index) {
124             collection = ValueUtils.expandCollection(getNode(), index + 1);
125         }
126         return this;
127     }
128 
129     public NodePointer createPath(JXPathContext context, Object value) {
130         NodePointer ptr = createPath(context);
131         ptr.setValue(value);
132         return ptr;
133     }
134 
135     public NodePointer createChild(
136         JXPathContext context,
137         QName name,
138         int index,
139         Object value) {
140         NodePointer ptr = (NodePointer) clone();
141         ptr.setIndex(index);
142         return ptr.createPath(context, value);
143     }
144 
145     public NodePointer createChild(
146         JXPathContext context,
147         QName name,
148         int index) {
149         NodePointer ptr = (NodePointer) clone();
150         ptr.setIndex(index);
151         return ptr.createPath(context);
152     }
153 
154     public int hashCode() {
155         return System.identityHashCode(collection) + index;
156     }
157 
158     public boolean equals(Object object) {
159         if (object == this) {
160             return true;
161         }
162 
163         if (!(object instanceof CollectionPointer)) {
164             return false;
165         }
166 
167         CollectionPointer other = (CollectionPointer) object;
168         return collection == other.collection && index == other.index;
169     }
170 
171     public NodeIterator childIterator(NodeTest test,
172                 boolean reverse, NodePointer startWith) {
173         if (index == WHOLE_COLLECTION) {
174             return new CollectionChildNodeIterator(
175                 this,
176                 test,
177                 reverse,
178                 startWith);
179         }
180         return getValuePointer().childIterator(test, reverse, startWith);
181     }
182 
183     public NodeIterator attributeIterator(QName name) {
184         return index == WHOLE_COLLECTION ? new CollectionAttributeNodeIterator(this, name)
185                 : getValuePointer().attributeIterator(name);
186     }
187 
188     public NodeIterator namespaceIterator() {
189         return index == WHOLE_COLLECTION ? null : getValuePointer().namespaceIterator();
190     }
191 
192     public NodePointer namespacePointer(String namespace) {
193         return index == WHOLE_COLLECTION ? null : getValuePointer().namespacePointer(namespace);
194     }
195 
196     public boolean testNode(NodeTest test) {
197         if (index == WHOLE_COLLECTION) {
198             if (test == null) {
199                 return true;
200             }
201             if (test instanceof NodeNameTest) {
202                 return false;
203             }
204             return test instanceof NodeTypeTest && ((NodeTypeTest) test).getNodeType() == Compiler.NODE_TYPE_NODE;
205         }
206         return getValuePointer().testNode(test);
207     }
208 
209     public int compareChildNodePointers(
210                 NodePointer pointer1, NodePointer pointer2) {
211         return pointer1.getIndex() - pointer2.getIndex();
212     }
213 
214     public String asPath() {
215         StringBuffer buffer = new StringBuffer();
216         NodePointer parent = getImmediateParentPointer();
217         if (parent != null) {
218             buffer.append(parent.asPath());
219             if (index != WHOLE_COLLECTION) {
220                 // Address the list[1][2] case
221                 if (parent.getIndex() != WHOLE_COLLECTION) {
222                     buffer.append("/.");
223                 }
224                 buffer.append("[").append(index + 1).append(']');
225             }
226         }
227         else {
228             if (index != WHOLE_COLLECTION) {
229                 buffer.append("/.[").append(index + 1).append(']');
230             }
231             else {
232                 buffer.append("/");
233             }
234         }
235         return buffer.toString();
236     }
237 }