1/*
2 * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/message/BasicLineFormatter.java $
3 * $Revision: 574185 $
4 * $Date: 2007-09-10 02:19:47 -0700 (Mon, 10 Sep 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 org.apache.http.ProtocolVersion;
36import org.apache.http.RequestLine;
37import org.apache.http.StatusLine;
38import org.apache.http.Header;
39import org.apache.http.FormattedHeader;
40import org.apache.http.util.CharArrayBuffer;
41
42
43/**
44 * Interface for formatting elements of the HEAD section of an HTTP message.
45 * This is the complement to {@link LineParser}.
46 * There are individual methods for formatting a request line, a
47 * status line, or a header line. The formatting does <i>not</i> include the
48 * trailing line break sequence CR-LF.
49 * The formatted lines are returned in memory, the formatter does not depend
50 * on any specific IO mechanism.
51 * Instances of this interface are expected to be stateless and thread-safe.
52 *
53 * @author <a href="mailto:remm@apache.org">Remy Maucherat</a>
54 * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
55 * @author <a href="mailto:jsdever@apache.org">Jeff Dever</a>
56 * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
57 * @author and others
58 *
59 *
60 * <!-- empty lines above to avoid 'svn diff' context problems -->
61 * @version $Revision: 574185 $
62 *
63 * @since 4.0
64 */
65public class BasicLineFormatter implements LineFormatter {
66
67    /**
68     * A default instance of this class, for use as default or fallback.
69     * Note that {@link BasicLineFormatter} is not a singleton, there can
70     * be many instances of the class itself and of derived classes.
71     * The instance here provides non-customized, default behavior.
72     */
73    public final static BasicLineFormatter DEFAULT = new BasicLineFormatter();
74
75
76
77    // public default constructor
78
79
80    /**
81     * Obtains a buffer for formatting.
82     *
83     * @param buffer    a buffer already available, or <code>null</code>
84     *
85     * @return  the cleared argument buffer if there is one, or
86     *          a new empty buffer that can be used for formatting
87     */
88    protected CharArrayBuffer initBuffer(CharArrayBuffer buffer) {
89        if (buffer != null) {
90            buffer.clear();
91        } else {
92            buffer = new CharArrayBuffer(64);
93        }
94        return buffer;
95    }
96
97
98    /**
99     * Formats a protocol version.
100     *
101     * @param version           the protocol version to format
102     * @param formatter         the formatter to use, or
103     *                          <code>null</code> for the
104     *                          {@link #DEFAULT default}
105     *
106     * @return  the formatted protocol version
107     */
108    public final static
109        String formatProtocolVersion(final ProtocolVersion version,
110                                     LineFormatter formatter) {
111        if (formatter == null)
112            formatter = BasicLineFormatter.DEFAULT;
113        return formatter.appendProtocolVersion(null, version).toString();
114    }
115
116
117    // non-javadoc, see interface LineFormatter
118    public CharArrayBuffer appendProtocolVersion(final CharArrayBuffer buffer,
119                                                 final ProtocolVersion version) {
120        if (version == null) {
121            throw new IllegalArgumentException
122                ("Protocol version may not be null");
123        }
124
125        // can't use initBuffer, that would clear the argument!
126        CharArrayBuffer result = buffer;
127        final int len = estimateProtocolVersionLen(version);
128        if (result == null) {
129            result = new CharArrayBuffer(len);
130        } else {
131            result.ensureCapacity(len);
132        }
133
134        result.append(version.getProtocol());
135        result.append('/');
136        result.append(Integer.toString(version.getMajor()));
137        result.append('.');
138        result.append(Integer.toString(version.getMinor()));
139
140        return result;
141    }
142
143
144    /**
145     * Guesses the length of a formatted protocol version.
146     * Needed to guess the length of a formatted request or status line.
147     *
148     * @param version   the protocol version to format, or <code>null</code>
149     *
150     * @return  the estimated length of the formatted protocol version,
151     *          in characters
152     */
153    protected int estimateProtocolVersionLen(final ProtocolVersion version) {
154        return version.getProtocol().length() + 4; // room for "HTTP/1.1"
155    }
156
157
158    /**
159     * Formats a request line.
160     *
161     * @param reqline           the request line to format
162     * @param formatter         the formatter to use, or
163     *                          <code>null</code> for the
164     *                          {@link #DEFAULT default}
165     *
166     * @return  the formatted request line
167     */
168    public final static String formatRequestLine(final RequestLine reqline,
169                                                 LineFormatter formatter) {
170        if (formatter == null)
171            formatter = BasicLineFormatter.DEFAULT;
172        return formatter.formatRequestLine(null, reqline).toString();
173    }
174
175
176    // non-javadoc, see interface LineFormatter
177    public CharArrayBuffer formatRequestLine(CharArrayBuffer buffer,
178                                             RequestLine reqline) {
179        if (reqline == null) {
180            throw new IllegalArgumentException
181                ("Request line may not be null");
182        }
183
184        CharArrayBuffer result = initBuffer(buffer);
185        doFormatRequestLine(result, reqline);
186
187        return result;
188    }
189
190
191    /**
192     * Actually formats a request line.
193     * Called from {@link #formatRequestLine}.
194     *
195     * @param buffer    the empty buffer into which to format,
196     *                  never <code>null</code>
197     * @param reqline   the request line to format, never <code>null</code>
198     */
199    protected void doFormatRequestLine(final CharArrayBuffer buffer,
200                                       final RequestLine reqline) {
201        final String method = reqline.getMethod();
202        final String uri    = reqline.getUri();
203
204        // room for "GET /index.html HTTP/1.1"
205        int len = method.length() + 1 + uri.length() + 1 +
206            estimateProtocolVersionLen(reqline.getProtocolVersion());
207        buffer.ensureCapacity(len);
208
209        buffer.append(method);
210        buffer.append(' ');
211        buffer.append(uri);
212        buffer.append(' ');
213        appendProtocolVersion(buffer, reqline.getProtocolVersion());
214    }
215
216
217
218    /**
219     * Formats a status line.
220     *
221     * @param statline          the status line to format
222     * @param formatter         the formatter to use, or
223     *                          <code>null</code> for the
224     *                          {@link #DEFAULT default}
225     *
226     * @return  the formatted status line
227     */
228    public final static String formatStatusLine(final StatusLine statline,
229                                                LineFormatter formatter) {
230        if (formatter == null)
231            formatter = BasicLineFormatter.DEFAULT;
232        return formatter.formatStatusLine(null, statline).toString();
233    }
234
235
236    // non-javadoc, see interface LineFormatter
237    public CharArrayBuffer formatStatusLine(final CharArrayBuffer buffer,
238                                            final StatusLine statline) {
239        if (statline == null) {
240            throw new IllegalArgumentException
241                ("Status line may not be null");
242        }
243
244        CharArrayBuffer result = initBuffer(buffer);
245        doFormatStatusLine(result, statline);
246
247        return result;
248    }
249
250
251    /**
252     * Actually formats a status line.
253     * Called from {@link #formatStatusLine}.
254     *
255     * @param buffer    the empty buffer into which to format,
256     *                  never <code>null</code>
257     * @param statline  the status line to format, never <code>null</code>
258     */
259    protected void doFormatStatusLine(final CharArrayBuffer buffer,
260                                      final StatusLine statline) {
261
262        int len = estimateProtocolVersionLen(statline.getProtocolVersion())
263            + 1 + 3 + 1; // room for "HTTP/1.1 200 "
264        final String reason = statline.getReasonPhrase();
265        if (reason != null) {
266            len += reason.length();
267        }
268        buffer.ensureCapacity(len);
269
270        appendProtocolVersion(buffer, statline.getProtocolVersion());
271        buffer.append(' ');
272        buffer.append(Integer.toString(statline.getStatusCode()));
273        buffer.append(' '); // keep whitespace even if reason phrase is empty
274        if (reason != null) {
275            buffer.append(reason);
276        }
277    }
278
279
280    /**
281     * Formats a header.
282     *
283     * @param header            the header to format
284     * @param formatter         the formatter to use, or
285     *                          <code>null</code> for the
286     *                          {@link #DEFAULT default}
287     *
288     * @return  the formatted header
289     */
290    public final static String formatHeader(final Header header,
291                                            LineFormatter formatter) {
292        if (formatter == null)
293            formatter = BasicLineFormatter.DEFAULT;
294        return formatter.formatHeader(null, header).toString();
295    }
296
297
298    // non-javadoc, see interface LineFormatter
299    public CharArrayBuffer formatHeader(CharArrayBuffer buffer,
300                                        Header header) {
301        if (header == null) {
302            throw new IllegalArgumentException
303                ("Header may not be null");
304        }
305        CharArrayBuffer result = null;
306
307        if (header instanceof FormattedHeader) {
308            // If the header is backed by a buffer, re-use the buffer
309            result = ((FormattedHeader)header).getBuffer();
310        } else {
311            result = initBuffer(buffer);
312            doFormatHeader(result, header);
313        }
314        return result;
315
316    } // formatHeader
317
318
319    /**
320     * Actually formats a header.
321     * Called from {@link #formatHeader}.
322     *
323     * @param buffer    the empty buffer into which to format,
324     *                  never <code>null</code>
325     * @param header    the header to format, never <code>null</code>
326     */
327    protected void doFormatHeader(final CharArrayBuffer buffer,
328                                  final Header header) {
329        final String name = header.getName();
330        final String value = header.getValue();
331
332        int len = name.length() + 2;
333        if (value != null) {
334            len += value.length();
335        }
336        buffer.ensureCapacity(len);
337
338        buffer.append(name);
339        buffer.append(": ");
340        if (value != null) {
341            buffer.append(value);
342        }
343    }
344
345
346} // class BasicLineFormatter
347