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.hc.core5.http.message; 29 30 import java.util.Iterator; 31 import java.util.List; 32 import java.util.NoSuchElementException; 33 34 import org.apache.hc.core5.http.Header; 35 import org.apache.hc.core5.util.Args; 36 import org.apache.hc.core5.util.Asserts; 37 38 /** 39 * {@link java.util.Iterator} of {@link org.apache.hc.core5.http.Header}s. For use by {@link HeaderGroup}. 40 * 41 * @since 4.0 42 */ 43 class BasicListHeaderIterator implements Iterator<Header> { 44 45 /** 46 * A list of headers to iterate over. 47 * Not all elements of this array are necessarily part of the iteration. 48 */ 49 private final List<Header> allHeaders; 50 51 /** 52 * The position of the next header in {@link #allHeaders allHeaders}. 53 * Negative if the iteration is over. 54 */ 55 private int currentIndex; 56 57 /** 58 * The position of the last returned header. 59 * Negative if none has been returned so far. 60 */ 61 private int lastIndex; 62 63 /** 64 * The header name to filter by. 65 * {@code null} to iterate over all headers in the array. 66 */ 67 private final String headerName; 68 69 /** 70 * Creates a new header iterator. 71 * 72 * @param headers a list of headers over which to iterate 73 * @param name the name of the headers over which to iterate, or 74 * {@code null} for any 75 */ 76 public BasicListHeaderIterator(final List<Header> headers, final String name) { 77 super(); 78 this.allHeaders = Args.notNull(headers, "Header list"); 79 this.headerName = name; 80 this.currentIndex = findNext(-1); 81 this.lastIndex = -1; 82 } 83 84 /** 85 * Determines the index of the next header. 86 * 87 * @param pos one less than the index to consider first, 88 * -1 to search for the first header 89 * 90 * @return the index of the next header that matches the filter name, 91 * or negative if there are no more headers 92 */ 93 protected int findNext(final int pos) { 94 int from = pos; 95 if (from < -1) { 96 return -1; 97 } 98 99 final int to = this.allHeaders.size()-1; 100 boolean found = false; 101 while (!found && (from < to)) { 102 from++; 103 found = filterHeader(from); 104 } 105 return found ? from : -1; 106 } 107 108 /** 109 * Checks whether a header is part of the iteration. 110 * 111 * @param index the index of the header to check 112 * 113 * @return {@code true} if the header should be part of the 114 * iteration, {@code false} to skip 115 */ 116 private boolean filterHeader(final int index) { 117 if (this.headerName == null) { 118 return true; 119 } 120 121 // non-header elements, including null, will trigger exceptions 122 final String name = (this.allHeaders.get(index)).getName(); 123 124 return this.headerName.equalsIgnoreCase(name); 125 } 126 127 @Override 128 public boolean hasNext() { 129 return this.currentIndex >= 0; 130 } 131 132 /** 133 * Obtains the next header from this iteration. 134 * 135 * @return the next header in this iteration 136 * 137 * @throws NoSuchElementException if there are no more headers 138 */ 139 @Override 140 public Header next() throws NoSuchElementException { 141 final int current = this.currentIndex; 142 if (current < 0) { 143 throw new NoSuchElementException("Iteration already finished."); 144 } 145 146 this.lastIndex = current; 147 this.currentIndex = findNext(current); 148 149 return this.allHeaders.get(current); 150 } 151 152 /** 153 * Removes the header that was returned last. 154 */ 155 @Override 156 public void remove() throws UnsupportedOperationException { 157 Asserts.check(this.lastIndex >= 0, "No header to remove"); 158 this.allHeaders.remove(this.lastIndex); 159 this.lastIndex = -1; 160 this.currentIndex--; // adjust for the removed element 161 } 162 163 }