View Javadoc

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