BasicListHeaderIterator.java revision 417f3b92ba4549b2f22340e3107d869d2b9c5bb8
1/*
2 * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/message/BasicListHeaderIterator.java $
3 * $Revision: 584542 $
4 * $Date: 2007-10-14 06:29:34 -0700 (Sun, 14 Oct 2007) $
5 *
6 * ====================================================================
7 * Licensed to the Apache Software Foundation (ASF) under one
8 * or more contributor license agreements.  See the NOTICE file
9 * distributed with this work for additional information
10 * regarding copyright ownership.  The ASF licenses this file
11 * to you under the Apache License, Version 2.0 (the
12 * "License"); you may not use this file except in compliance
13 * with the License.  You may obtain a copy of the License at
14 *
15 *   http://www.apache.org/licenses/LICENSE-2.0
16 *
17 * Unless required by applicable law or agreed to in writing,
18 * software distributed under the License is distributed on an
19 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
20 * KIND, either express or implied.  See the License for the
21 * specific language governing permissions and limitations
22 * under the License.
23 * ====================================================================
24 *
25 * This software consists of voluntary contributions made by many
26 * individuals on behalf of the Apache Software Foundation.  For more
27 * information on the Apache Software Foundation, please see
28 * <http://www.apache.org/>.
29 *
30 */
31
32package org.apache.http.message;
33
34
35import java.util.List;
36import java.util.NoSuchElementException;
37
38import org.apache.http.Header;
39import org.apache.http.HeaderIterator;
40
41
42/**
43 * Implementation of a {@link HeaderIterator} based on a {@link List}.
44 * For use by {@link HeaderGroup}.
45 *
46 * @version $Revision: 584542 $
47 */
48public class BasicListHeaderIterator implements HeaderIterator {
49
50    /**
51     * A list of headers to iterate over.
52     * Not all elements of this array are necessarily part of the iteration.
53     */
54    protected final List allHeaders;
55
56
57    /**
58     * The position of the next header in {@link #allHeaders allHeaders}.
59     * Negative if the iteration is over.
60     */
61    protected int currentIndex;
62
63
64    /**
65     * The position of the last returned header.
66     * Negative if none has been returned so far.
67     */
68    protected int lastIndex;
69
70
71    /**
72     * The header name to filter by.
73     * <code>null</code> to iterate over all headers in the array.
74     */
75    protected String headerName;
76
77
78
79    /**
80     * Creates a new header iterator.
81     *
82     * @param headers   a list of headers over which to iterate
83     * @param name      the name of the headers over which to iterate, or
84     *                  <code>null</code> for any
85     */
86    public BasicListHeaderIterator(List headers, String name) {
87        if (headers == null) {
88            throw new IllegalArgumentException
89                ("Header list must not be null.");
90        }
91
92        this.allHeaders = headers;
93        this.headerName = name;
94        this.currentIndex = findNext(-1);
95        this.lastIndex = -1;
96    }
97
98
99    /**
100     * Determines the index of the next header.
101     *
102     * @param from      one less than the index to consider first,
103     *                  -1 to search for the first header
104     *
105     * @return  the index of the next header that matches the filter name,
106     *          or negative if there are no more headers
107     */
108    protected int findNext(int from) {
109        if (from < -1)
110            return -1;
111
112        final int to = this.allHeaders.size()-1;
113        boolean found = false;
114        while (!found && (from < to)) {
115            from++;
116            found = filterHeader(from);
117        }
118        return found ? from : -1;
119    }
120
121
122    /**
123     * Checks whether a header is part of the iteration.
124     *
125     * @param index     the index of the header to check
126     *
127     * @return  <code>true</code> if the header should be part of the
128     *          iteration, <code>false</code> to skip
129     */
130    protected boolean filterHeader(int index) {
131        if (this.headerName == null)
132            return true;
133
134        // non-header elements, including null, will trigger exceptions
135        final String name = ((Header)this.allHeaders.get(index)).getName();
136
137        return this.headerName.equalsIgnoreCase(name);
138    }
139
140
141    // non-javadoc, see interface HeaderIterator
142    public boolean hasNext() {
143        return (this.currentIndex >= 0);
144    }
145
146
147    /**
148     * Obtains the next header from this iteration.
149     *
150     * @return  the next header in this iteration
151     *
152     * @throws NoSuchElementException   if there are no more headers
153     */
154    public Header nextHeader()
155        throws NoSuchElementException {
156
157        final int current = this.currentIndex;
158        if (current < 0) {
159            throw new NoSuchElementException("Iteration already finished.");
160        }
161
162        this.lastIndex    = current;
163        this.currentIndex = findNext(current);
164
165        return (Header) this.allHeaders.get(current);
166    }
167
168
169    /**
170     * Returns the next header.
171     * Same as {@link #nextHeader nextHeader}, but not type-safe.
172     *
173     * @return  the next header in this iteration
174     *
175     * @throws NoSuchElementException   if there are no more headers
176     */
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    public void remove()
187        throws UnsupportedOperationException {
188
189        if (this.lastIndex < 0) {
190            throw new IllegalStateException("No header to remove.");
191        }
192        this.allHeaders.remove(this.lastIndex);
193        this.lastIndex = -1;
194        this.currentIndex--; // adjust for the removed element
195    }
196}
197