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.ArrayList;
21  import java.util.List;
22  
23  import org.apache.commons.jxpath.JXPathException;
24  import org.apache.commons.jxpath.ri.model.NodeIterator;
25  import org.apache.commons.jxpath.ri.model.NodePointer;
26  
27  /**
28   * Combines node iterators of all elements of a collection into one aggregate node iterator.
29   */
30  public abstract class CollectionNodeIterator implements NodeIterator {
31  
32      private final CollectionPointer pointer;
33      private final boolean reverse;
34      private final NodePointer startWith;
35      private int position;
36      private List<NodePointer> collection;
37  
38      /**
39       * Constructs a new CollectionNodeIterator.
40       *
41       * @param pointer   collection pointer
42       * @param reverse   iteration order
43       * @param startWith starting pointer
44       */
45      protected CollectionNodeIterator(final CollectionPointer pointer, final boolean reverse, final NodePointer startWith) {
46          this.pointer = pointer;
47          this.reverse = reverse;
48          this.startWith = startWith;
49      }
50  
51      /**
52       * Implemented by subclasses to produce child/attribute node iterators.
53       *
54       * @param elementPointer owning pointer
55       * @return NodeIterator
56       */
57      protected abstract NodeIterator getElementNodeIterator(NodePointer elementPointer);
58  
59      @Override
60      public NodePointer getNodePointer() {
61          if (position == 0) {
62              return null;
63          }
64          return collection.get(position - 1);
65      }
66  
67      @Override
68      public int getPosition() {
69          return position;
70      }
71  
72      /**
73       * Prepare...
74       */
75      private void prepare() {
76          collection = new ArrayList<>();
77          final NodePointer ptr = (NodePointer) pointer.clone();
78          final int length = ptr.getLength();
79          for (int i = 0; i < length; i++) {
80              ptr.setIndex(i);
81              final NodePointer elementPointer = ptr.getValuePointer();
82              final NodeIterator iter = getElementNodeIterator(elementPointer);
83              for (int j = 1; iter.setPosition(j); j++) {
84                  final NodePointer childPointer = iter.getNodePointer();
85                  if (reverse) {
86                      collection.add(0, childPointer);
87                  } else {
88                      collection.add(childPointer);
89                  }
90              }
91          }
92          if (startWith != null) {
93              final int index = collection.indexOf(startWith);
94              if (index == -1) {
95                  throw new JXPathException("Invalid starting pointer for iterator: " + startWith);
96              }
97              while (collection.size() > index) {
98                  if (!reverse) {
99                      collection.remove(collection.size() - 1);
100                 } else {
101                     collection.remove(0);
102                 }
103             }
104         }
105     }
106 
107     @Override
108     public boolean setPosition(final int position) {
109         if (collection == null) {
110             prepare();
111         }
112         if (position < 1 || position > collection.size()) {
113             return false;
114         }
115         this.position = position;
116         return true;
117     }
118 }