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 from      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(int from) {
103         if (from < -1) {
104             return -1;
105         }
106 
107         final int to = this.allHeaders.size()-1;
108         boolean found = false;
109         while (!found && (from < to)) {
110             from++;
111             found = filterHeader(from);
112         }
113         return found ? from : -1;
114     }
115 
116 
117     /**
118      * Checks whether a header is part of the iteration.
119      *
120      * @param index     the index of the header to check
121      *
122      * @return  <code>true</code> if the header should be part of the
123      *          iteration, <code>false</code> to skip
124      */
125     protected boolean filterHeader(final int index) {
126         if (this.headerName == null) {
127             return true;
128         }
129 
130         // non-header elements, including null, will trigger exceptions
131         final String name = (this.allHeaders.get(index)).getName();
132 
133         return this.headerName.equalsIgnoreCase(name);
134     }
135 
136 
137     // non-javadoc, see interface HeaderIterator
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     public Header nextHeader()
151         throws NoSuchElementException {
152 
153         final int current = this.currentIndex;
154         if (current < 0) {
155             throw new NoSuchElementException("Iteration already finished.");
156         }
157 
158         this.lastIndex    = current;
159         this.currentIndex = findNext(current);
160 
161         return this.allHeaders.get(current);
162     }
163 
164 
165     /**
166      * Returns the next header.
167      * Same as {@link #nextHeader nextHeader}, but not type-safe.
168      *
169      * @return  the next header in this iteration
170      *
171      * @throws NoSuchElementException   if there are no more headers
172      */
173     public final Object next()
174         throws NoSuchElementException {
175         return nextHeader();
176     }
177 
178 
179     /**
180      * Removes the header that was returned last.
181      */
182     public void remove()
183         throws UnsupportedOperationException {
184         Asserts.check(this.lastIndex >= 0, "No header to remove");
185         this.allHeaders.remove(this.lastIndex);
186         this.lastIndex = -1;
187         this.currentIndex--; // adjust for the removed element
188     }
189 }