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 018package org.apache.commons.jxpath.ri.model.beans; 019 020import java.util.ArrayList; 021import java.util.List; 022 023import org.apache.commons.jxpath.JXPathException; 024import org.apache.commons.jxpath.ri.model.NodeIterator; 025import org.apache.commons.jxpath.ri.model.NodePointer; 026 027/** 028 * Combines node iterators of all elements of a collection into one aggregate node iterator. 029 */ 030public abstract class CollectionNodeIterator implements NodeIterator { 031 032 private final CollectionPointer pointer; 033 private final boolean reverse; 034 private final NodePointer startWith; 035 private int position; 036 private List<NodePointer> collection; 037 038 /** 039 * Constructs a new CollectionNodeIterator. 040 * 041 * @param pointer collection pointer 042 * @param reverse iteration order 043 * @param startWith starting pointer 044 */ 045 protected CollectionNodeIterator(final CollectionPointer pointer, final boolean reverse, final NodePointer startWith) { 046 this.pointer = pointer; 047 this.reverse = reverse; 048 this.startWith = startWith; 049 } 050 051 /** 052 * Implemented by subclasses to produce child/attribute node iterators. 053 * 054 * @param elementPointer owning pointer 055 * @return NodeIterator 056 */ 057 protected abstract NodeIterator getElementNodeIterator(NodePointer elementPointer); 058 059 @Override 060 public NodePointer getNodePointer() { 061 if (position == 0) { 062 return null; 063 } 064 return collection.get(position - 1); 065 } 066 067 @Override 068 public int getPosition() { 069 return position; 070 } 071 072 /** 073 * Prepare... 074 */ 075 private void prepare() { 076 collection = new ArrayList<>(); 077 final NodePointer ptr = (NodePointer) pointer.clone(); 078 final int length = ptr.getLength(); 079 for (int i = 0; i < length; i++) { 080 ptr.setIndex(i); 081 final NodePointer elementPointer = ptr.getValuePointer(); 082 final NodeIterator iter = getElementNodeIterator(elementPointer); 083 for (int j = 1; iter.setPosition(j); j++) { 084 final NodePointer childPointer = iter.getNodePointer(); 085 if (reverse) { 086 collection.add(0, childPointer); 087 } else { 088 collection.add(childPointer); 089 } 090 } 091 } 092 if (startWith != null) { 093 final int index = collection.indexOf(startWith); 094 if (index == -1) { 095 throw new JXPathException("Invalid starting pointer for iterator: " + startWith); 096 } 097 while (collection.size() > index) { 098 if (!reverse) { 099 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}