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    }