1 /* 2 * ==================================================================== 3 * Licensed to the Apache Software Foundation (ASF) under one 4 * or more contributor license agreements. See the NOTICE file 5 * distributed with this work for additional information 6 * regarding copyright ownership. The ASF licenses this file 7 * to you under the Apache License, Version 2.0 (the 8 * "License"); you may not use this file except in compliance 9 * with the License. You may obtain a copy of the License at 10 * 11 * http://www.apache.org/licenses/LICENSE-2.0 12 * 13 * Unless required by applicable law or agreed to in writing, 14 * software distributed under the License is distributed on an 15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 * KIND, either express or implied. See the License for the 17 * specific language governing permissions and limitations 18 * under the License. 19 * ==================================================================== 20 * 21 * This software consists of voluntary contributions made by many 22 * individuals on behalf of the Apache Software Foundation. For more 23 * information on the Apache Software Foundation, please see 24 * <http://www.apache.org/>. 25 * 26 */ 27 28 package org.apache.http.message; 29 30 import java.util.List; 31 import java.util.NoSuchElementException; 32 33 import org.apache.http.Header; 34 import org.apache.http.HeaderIterator; 35 import org.apache.http.util.Args; 36 import org.apache.http.util.Asserts; 37 38 /** 39 * Implementation of a {@link HeaderIterator} based on a {@link List}. 40 * For use by {@link HeaderGroup}. 41 * 42 * @since 4.0 43 */ 44 public class BasicListHeaderIterator implements HeaderIterator { 45 46 /** 47 * A list of headers to iterate over. 48 * Not all elements of this array are necessarily part of the iteration. 49 */ 50 protected final List<Header> allHeaders; 51 52 53 /** 54 * The position of the next header in {@link #allHeaders allHeaders}. 55 * Negative if the iteration is over. 56 */ 57 protected int currentIndex; 58 59 60 /** 61 * The position of the last returned header. 62 * Negative if none has been returned so far. 63 */ 64 protected int lastIndex; 65 66 67 /** 68 * The header name to filter by. 69 * {@code null} to iterate over all headers in the array. 70 */ 71 protected String headerName; 72 73 74 75 /** 76 * Creates a new header iterator. 77 * 78 * @param headers a list of headers over which to iterate 79 * @param name the name of the headers over which to iterate, or 80 * {@code null} for any 81 */ 82 public BasicListHeaderIterator(final List<Header> headers, final String name) { 83 super(); 84 this.allHeaders = Args.notNull(headers, "Header list"); 85 this.headerName = name; 86 this.currentIndex = findNext(-1); 87 this.lastIndex = -1; 88 } 89 90 91 /** 92 * Determines the index of the next header. 93 * 94 * @param pos one less than the index to consider first, 95 * -1 to search for the first header 96 * 97 * @return the index of the next header that matches the filter name, 98 * or negative if there are no more headers 99 */ 100 protected int findNext(final int pos) { 101 int from = pos; 102 if (from < -1) { 103 return -1; 104 } 105 106 final int to = this.allHeaders.size()-1; 107 boolean found = false; 108 while (!found && (from < to)) { 109 from++; 110 found = filterHeader(from); 111 } 112 return found ? from : -1; 113 } 114 115 116 /** 117 * Checks whether a header is part of the iteration. 118 * 119 * @param index the index of the header to check 120 * 121 * @return {@code true} if the header should be part of the 122 * iteration, {@code false} to skip 123 */ 124 protected boolean filterHeader(final int index) { 125 if (this.headerName == null) { 126 return true; 127 } 128 129 // non-header elements, including null, will trigger exceptions 130 final String name = (this.allHeaders.get(index)).getName(); 131 132 return this.headerName.equalsIgnoreCase(name); 133 } 134 135 136 // non-javadoc, see interface HeaderIterator 137 @Override 138 public boolean hasNext() { 139 return (this.currentIndex >= 0); 140 } 141 142 143 /** 144 * Obtains the next header from this iteration. 145 * 146 * @return the next header in this iteration 147 * 148 * @throws NoSuchElementException if there are no more headers 149 */ 150 @Override 151 public Header nextHeader() 152 throws NoSuchElementException { 153 154 final int current = this.currentIndex; 155 if (current < 0) { 156 throw new NoSuchElementException("Iteration already finished."); 157 } 158 159 this.lastIndex = current; 160 this.currentIndex = findNext(current); 161 162 return this.allHeaders.get(current); 163 } 164 165 166 /** 167 * Returns the next header. 168 * Same as {@link #nextHeader nextHeader}, but not type-safe. 169 * 170 * @return the next header in this iteration 171 * 172 * @throws NoSuchElementException if there are no more headers 173 */ 174 @Override 175 public final Object next() 176 throws NoSuchElementException { 177 return nextHeader(); 178 } 179 180 181 /** 182 * Removes the header that was returned last. 183 */ 184 @Override 185 public void remove() 186 throws UnsupportedOperationException { 187 Asserts.check(this.lastIndex >= 0, "No header to remove"); 188 this.allHeaders.remove(this.lastIndex); 189 this.lastIndex = -1; 190 this.currentIndex--; // adjust for the removed element 191 } 192 }