• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/impl/io/AbstractSessionOutputBuffer.java $
3  * $Revision: 652091 $
4  * $Date: 2008-04-29 13:41:07 -0700 (Tue, 29 Apr 2008) $
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 
32 package org.apache.http.impl.io;
33 
34 import java.io.IOException;
35 import java.io.OutputStream;
36 
37 import org.apache.http.io.SessionOutputBuffer;
38 import org.apache.http.io.HttpTransportMetrics;
39 import org.apache.http.params.HttpParams;
40 import org.apache.http.params.HttpProtocolParams;
41 import org.apache.http.protocol.HTTP;
42 import org.apache.http.util.ByteArrayBuffer;
43 import org.apache.http.util.CharArrayBuffer;
44 
45 /**
46  * Abstract base class for session output buffers that stream data
47  * to an {@link OutputStream}.
48  *
49  * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
50  *
51  */
52 public abstract class AbstractSessionOutputBuffer implements SessionOutputBuffer {
53 
54     private static final byte[] CRLF = new byte[] {HTTP.CR, HTTP.LF};
55 
56     private static final int MAX_CHUNK = 256;
57 
58     private OutputStream outstream;
59     private ByteArrayBuffer buffer;
60 
61     private String charset = HTTP.US_ASCII;
62     private boolean ascii = true;
63 
64     private HttpTransportMetricsImpl metrics;
65 
init(final OutputStream outstream, int buffersize, final HttpParams params)66     protected void init(final OutputStream outstream, int buffersize, final HttpParams params) {
67         if (outstream == null) {
68             throw new IllegalArgumentException("Input stream may not be null");
69         }
70         if (buffersize <= 0) {
71             throw new IllegalArgumentException("Buffer size may not be negative or zero");
72         }
73         if (params == null) {
74             throw new IllegalArgumentException("HTTP parameters may not be null");
75         }
76         this.outstream = outstream;
77         this.buffer = new ByteArrayBuffer(buffersize);
78         this.charset = HttpProtocolParams.getHttpElementCharset(params);
79         this.ascii = this.charset.equalsIgnoreCase(HTTP.US_ASCII)
80                      || this.charset.equalsIgnoreCase(HTTP.ASCII);
81         this.metrics = new HttpTransportMetricsImpl();
82     }
83 
flushBuffer()84     protected void flushBuffer() throws IOException {
85         int len = this.buffer.length();
86         if (len > 0) {
87             this.outstream.write(this.buffer.buffer(), 0, len);
88             this.buffer.clear();
89             this.metrics.incrementBytesTransferred(len);
90         }
91     }
92 
flush()93     public void flush() throws IOException {
94         flushBuffer();
95         this.outstream.flush();
96     }
97 
write(final byte[] b, int off, int len)98     public void write(final byte[] b, int off, int len) throws IOException {
99         if (b == null) {
100             return;
101         }
102         // Do not want to buffer largish chunks
103         // if the byte array is larger then MAX_CHUNK
104         // write it directly to the output stream
105         if (len > MAX_CHUNK || len > this.buffer.capacity()) {
106             // flush the buffer
107             flushBuffer();
108             // write directly to the out stream
109             this.outstream.write(b, off, len);
110             this.metrics.incrementBytesTransferred(len);
111         } else {
112             // Do not let the buffer grow unnecessarily
113             int freecapacity = this.buffer.capacity() - this.buffer.length();
114             if (len > freecapacity) {
115                 // flush the buffer
116                 flushBuffer();
117             }
118             // buffer
119             this.buffer.append(b, off, len);
120         }
121     }
122 
write(final byte[] b)123     public void write(final byte[] b) throws IOException {
124         if (b == null) {
125             return;
126         }
127         write(b, 0, b.length);
128     }
129 
write(int b)130     public void write(int b) throws IOException {
131         if (this.buffer.isFull()) {
132             flushBuffer();
133         }
134         this.buffer.append(b);
135     }
136 
writeLine(final String s)137     public void writeLine(final String s) throws IOException {
138         if (s == null) {
139             return;
140         }
141         if (s.length() > 0) {
142             write(s.getBytes(this.charset));
143         }
144         write(CRLF);
145     }
146 
writeLine(final CharArrayBuffer s)147     public void writeLine(final CharArrayBuffer s) throws IOException {
148         if (s == null) {
149             return;
150         }
151         if (this.ascii) {
152             int off = 0;
153             int remaining = s.length();
154             while (remaining > 0) {
155                 int chunk = this.buffer.capacity() - this.buffer.length();
156                 chunk = Math.min(chunk, remaining);
157                 if (chunk > 0) {
158                     this.buffer.append(s, off, chunk);
159                 }
160                 if (this.buffer.isFull()) {
161                     flushBuffer();
162                 }
163                 off += chunk;
164                 remaining -= chunk;
165             }
166         } else {
167             // This is VERY memory inefficient, BUT since non-ASCII charsets are
168             // NOT meant to be used anyway, there's no point optimizing it
169             byte[] tmp = s.toString().getBytes(this.charset);
170             write(tmp);
171         }
172         write(CRLF);
173     }
174 
getMetrics()175     public HttpTransportMetrics getMetrics() {
176         return this.metrics;
177     }
178 
179 }
180