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  
37  /**
38   * Implementation of a {@link HeaderIterator} based on a {@link List}.
39   * For use by {@link HeaderGroup}.
40   *
41   * @since 4.0
42   */
43  @NotThreadSafe
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</code> 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</code> for any
81       */
82      public BasicListHeaderIterator(List<Header> headers, String name) {
83          if (headers == null) {
84              throw new IllegalArgumentException
85                  ("Header list must not be null.");
86          }
87  
88          this.allHeaders = headers;
89          this.headerName = name;
90          this.currentIndex = findNext(-1);
91          this.lastIndex = -1;
92      }
93  
94  
95      /**
96       * Determines the index of the next header.
97       *
98       * @param from      one less than the index to consider first,
99       *                  -1 to search for the first header
100      *
101      * @return  the index of the next header that matches the filter name,
102      *          or negative if there are no more headers
103      */
104     protected int findNext(int from) {
105         if (from < -1)
106             return -1;
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(int index) {
127         if (this.headerName == null)
128             return true;
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 
185         if (this.lastIndex < 0) {
186             throw new IllegalStateException("No header to remove.");
187         }
188         this.allHeaders.remove(this.lastIndex);
189         this.lastIndex = -1;
190         this.currentIndex--; // adjust for the removed element
191     }
192 }