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.jxpath.ri.model.beans;
018
019 import java.util.ArrayList;
020 import java.util.List;
021
022 import org.apache.commons.jxpath.JXPathException;
023 import org.apache.commons.jxpath.ri.model.NodeIterator;
024 import org.apache.commons.jxpath.ri.model.NodePointer;
025
026 /**
027 * Combines node iterators of all elements of a collection into one
028 * aggregate node iterator.
029 *
030 * @author Dmitri Plotnikov
031 * @version $Revision: 652845 $ $Date: 2008-05-02 12:46:46 -0500 (Fri, 02 May 2008) $
032 */
033 public abstract class CollectionNodeIterator implements NodeIterator {
034 private CollectionPointer pointer;
035 private boolean reverse;
036 private NodePointer startWith;
037 private int position;
038 private List collection;
039
040 /**
041 * Create a new CollectionNodeIterator.
042 * @param pointer collection pointer
043 * @param reverse iteration order
044 * @param startWith starting pointer
045 */
046 protected CollectionNodeIterator(
047 CollectionPointer pointer,
048 boolean reverse,
049 NodePointer startWith) {
050 this.pointer = pointer;
051 this.reverse = reverse;
052 this.startWith = startWith;
053 }
054
055 /**
056 * Implemented by subclasses to produce child/attribute node iterators.
057 * @param elementPointer owning pointer
058 * @return NodeIterator
059 */
060 protected abstract NodeIterator
061 getElementNodeIterator(NodePointer elementPointer);
062
063 public int getPosition() {
064 return position;
065 }
066
067 public boolean setPosition(int position) {
068 if (collection == null) {
069 prepare();
070 }
071
072 if (position < 1 || position > collection.size()) {
073 return false;
074 }
075 this.position = position;
076 return true;
077 }
078
079 public NodePointer getNodePointer() {
080 if (position == 0) {
081 return null;
082 }
083 return (NodePointer) collection.get(position - 1);
084 }
085
086 /**
087 * Prepare...
088 */
089 private void prepare() {
090 collection = new ArrayList();
091 NodePointer ptr = (NodePointer) pointer.clone();
092 int length = ptr.getLength();
093 for (int i = 0; i < length; i++) {
094 ptr.setIndex(i);
095 NodePointer elementPointer = ptr.getValuePointer();
096 NodeIterator iter = getElementNodeIterator(elementPointer);
097
098 for (int j = 1; iter.setPosition(j); j++) {
099 NodePointer childPointer = iter.getNodePointer();
100 if (reverse) {
101 collection.add(0, childPointer);
102 }
103 else {
104 collection.add(childPointer);
105 }
106 }
107 }
108 if (startWith != null) {
109 int index = collection.indexOf(startWith);
110 if (index == -1) {
111 throw new JXPathException(
112 "Invalid starting pointer for iterator: " + startWith);
113 }
114 while (collection.size() > index) {
115 if (!reverse) {
116 collection.remove(collection.size() - 1);
117 }
118 else {
119 collection.remove(0);
120 }
121 }
122 }
123 }
124 }