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