Home | History | Annotate | Download | only in io
      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 
     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 
     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 
     93     public void flush() throws IOException {
     94         flushBuffer();
     95         this.outstream.flush();
     96     }
     97 
     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 
    123     public void write(final byte[] b) throws IOException {
    124         if (b == null) {
    125             return;
    126         }
    127         write(b, 0, b.length);
    128     }
    129 
    130     public void write(int b) throws IOException {
    131         if (this.buffer.isFull()) {
    132             flushBuffer();
    133         }
    134         this.buffer.append(b);
    135     }
    136 
    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 
    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 
    175     public HttpTransportMetrics getMetrics() {
    176         return this.metrics;
    177     }
    178 
    179 }
    180