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.NoSuchElementException; 32 33 import org.apache.hc.core5.http.Header; 34 import org.apache.hc.core5.util.Args; 35 36 /** 37 * {@link java.util.Iterator} of {@link org.apache.hc.core5.http.Header}s. 38 * 39 * @since 4.0 40 */ 41 public class BasicHeaderIterator implements Iterator<Header> { 42 43 /** 44 * An array of headers to iterate over. 45 * Not all elements of this array are necessarily part of the iteration. 46 * This array will never be modified by the iterator. 47 * Derived implementations are expected to adhere to this restriction. 48 */ 49 private final 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 header name to filter by. 59 * {@code null} to iterate over all headers in the array. 60 */ 61 private final String headerName; 62 63 /** 64 * Creates a new header iterator. 65 * 66 * @param headers an array of headers over which to iterate 67 * @param name the name of the headers over which to iterate, or 68 * {@code null} for any 69 */ 70 public BasicHeaderIterator(final Header[] headers, final String name) { 71 super(); 72 this.allHeaders = Args.notNull(headers, "Header array"); 73 this.headerName = name; 74 this.currentIndex = findNext(-1); 75 } 76 77 /** 78 * Determines the index of the next header. 79 * 80 * @param pos one less than the index to consider first, 81 * -1 to search for the first header 82 * 83 * @return the index of the next header that matches the filter name, 84 * or negative if there are no more headers 85 */ 86 private int findNext(final int pos) { 87 int from = pos; 88 if (from < -1) { 89 return -1; 90 } 91 92 final int to = this.allHeaders.length-1; 93 boolean found = false; 94 while (!found && (from < to)) { 95 from++; 96 found = filterHeader(from); 97 } 98 return found ? from : -1; 99 } 100 101 /** 102 * Checks whether a header is part of the iteration. 103 * 104 * @param index the index of the header to check 105 * 106 * @return {@code true} if the header should be part of the 107 * iteration, {@code false} to skip 108 */ 109 private boolean filterHeader(final int index) { 110 return (this.headerName == null) || 111 this.headerName.equalsIgnoreCase(this.allHeaders[index].getName()); 112 } 113 114 @Override 115 public boolean hasNext() { 116 return this.currentIndex >= 0; 117 } 118 119 /** 120 * Obtains the next header from this iteration. 121 * 122 * @return the next header in this iteration 123 * 124 * @throws NoSuchElementException if there are no more headers 125 */ 126 @Override 127 public Header next() throws NoSuchElementException { 128 129 final int current = this.currentIndex; 130 if (current < 0) { 131 throw new NoSuchElementException("Iteration already finished."); 132 } 133 134 this.currentIndex = findNext(current); 135 136 return this.allHeaders[current]; 137 } 138 139 /** 140 * Removing headers is not supported. 141 * 142 * @throws UnsupportedOperationException always 143 */ 144 @Override 145 public void remove() throws UnsupportedOperationException { 146 throw new UnsupportedOperationException("Removing headers is not supported."); 147 } 148 149 }