001/*
002 * ====================================================================
003 * Licensed to the Apache Software Foundation (ASF) under one
004 * or more contributor license agreements.  See the NOTICE file
005 * distributed with this work for additional information
006 * regarding copyright ownership.  The ASF licenses this file
007 * to you under the Apache License, Version 2.0 (the
008 * "License"); you may not use this file except in compliance
009 * with the License.  You may obtain a copy of the License at
010 *
011 *   http://www.apache.org/licenses/LICENSE-2.0
012 *
013 * Unless required by applicable law or agreed to in writing,
014 * software distributed under the License is distributed on an
015 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
016 * KIND, either express or implied.  See the License for the
017 * specific language governing permissions and limitations
018 * under the License.
019 * ====================================================================
020 *
021 * This software consists of voluntary contributions made by many
022 * individuals on behalf of the Apache Software Foundation.  For more
023 * information on the Apache Software Foundation, please see
024 * <http://www.apache.org/>.
025 *
026 */
027
028package org.apache.http.message;
029
030import java.util.NoSuchElementException;
031
032import org.apache.http.FormattedHeader;
033import org.apache.http.Header;
034import org.apache.http.HeaderElement;
035import org.apache.http.HeaderElementIterator;
036import org.apache.http.HeaderIterator;
037import org.apache.http.util.Args;
038import org.apache.http.util.CharArrayBuffer;
039
040/**
041 * Basic implementation of a {@link HeaderElementIterator}.
042 *
043 * @since 4.0
044 */
045public class BasicHeaderElementIterator implements HeaderElementIterator {
046
047    private final HeaderIterator headerIt;
048    private final HeaderValueParser parser;
049
050    private HeaderElement currentElement = null;
051    private CharArrayBuffer buffer = null;
052    private ParserCursor cursor = null;
053
054    /**
055     * Creates a new instance of BasicHeaderElementIterator
056     */
057    public BasicHeaderElementIterator(
058            final HeaderIterator headerIterator,
059            final HeaderValueParser parser) {
060        this.headerIt = Args.notNull(headerIterator, "Header iterator");
061        this.parser = Args.notNull(parser, "Parser");
062    }
063
064
065    public BasicHeaderElementIterator(final HeaderIterator headerIterator) {
066        this(headerIterator, BasicHeaderValueParser.INSTANCE);
067    }
068
069
070    private void bufferHeaderValue() {
071        this.cursor = null;
072        this.buffer = null;
073        while (this.headerIt.hasNext()) {
074            final Header h = this.headerIt.nextHeader();
075            if (h instanceof FormattedHeader) {
076                this.buffer = ((FormattedHeader) h).getBuffer();
077                this.cursor = new ParserCursor(0, this.buffer.length());
078                this.cursor.updatePos(((FormattedHeader) h).getValuePos());
079                break;
080            } else {
081                final String value = h.getValue();
082                if (value != null) {
083                    this.buffer = new CharArrayBuffer(value.length());
084                    this.buffer.append(value);
085                    this.cursor = new ParserCursor(0, this.buffer.length());
086                    break;
087                }
088            }
089        }
090    }
091
092    private void parseNextElement() {
093        // loop while there are headers left to parse
094        while (this.headerIt.hasNext() || this.cursor != null) {
095            if (this.cursor == null || this.cursor.atEnd()) {
096                // get next header value
097                bufferHeaderValue();
098            }
099            // Anything buffered?
100            if (this.cursor != null) {
101                // loop while there is data in the buffer
102                while (!this.cursor.atEnd()) {
103                    final HeaderElement e = this.parser.parseHeaderElement(this.buffer, this.cursor);
104                    if (!(e.getName().length() == 0 && e.getValue() == null)) {
105                        // Found something
106                        this.currentElement = e;
107                        return;
108                    }
109                }
110                // if at the end of the buffer
111                if (this.cursor.atEnd()) {
112                    // discard it
113                    this.cursor = null;
114                    this.buffer = null;
115                }
116            }
117        }
118    }
119
120    @Override
121    public boolean hasNext() {
122        if (this.currentElement == null) {
123            parseNextElement();
124        }
125        return this.currentElement != null;
126    }
127
128    @Override
129    public HeaderElement nextElement() throws NoSuchElementException {
130        if (this.currentElement == null) {
131            parseNextElement();
132        }
133
134        if (this.currentElement == null) {
135            throw new NoSuchElementException("No more header elements available");
136        }
137
138        final HeaderElement element = this.currentElement;
139        this.currentElement = null;
140        return element;
141    }
142
143    @Override
144    public final Object next() throws NoSuchElementException {
145        return nextElement();
146    }
147
148    @Override
149    public void remove() throws UnsupportedOperationException {
150        throw new UnsupportedOperationException("Remove not supported");
151    }
152
153}