001: /*
002: * $HeadURL: https://svn.apache.org/repos/asf/httpcomponents/httpcore/tags/4.0-beta1/module-main/src/main/java/org/apache/http/impl/io/AbstractSessionOutputBuffer.java $
003: * $Revision: 560358 $
004: * $Date: 2007-07-27 21:30:42 +0200 (Fri, 27 Jul 2007) $
005: *
006: * ====================================================================
007: * Licensed to the Apache Software Foundation (ASF) under one
008: * or more contributor license agreements. See the NOTICE file
009: * distributed with this work for additional information
010: * regarding copyright ownership. The ASF licenses this file
011: * to you under the Apache License, Version 2.0 (the
012: * "License"); you may not use this file except in compliance
013: * with the License. You may obtain a copy of the License at
014: *
015: * http://www.apache.org/licenses/LICENSE-2.0
016: *
017: * Unless required by applicable law or agreed to in writing,
018: * software distributed under the License is distributed on an
019: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
020: * KIND, either express or implied. See the License for the
021: * specific language governing permissions and limitations
022: * under the License.
023: * ====================================================================
024: *
025: * This software consists of voluntary contributions made by many
026: * individuals on behalf of the Apache Software Foundation. For more
027: * information on the Apache Software Foundation, please see
028: * <http://www.apache.org/>.
029: *
030: */
031:
032: package org.apache.http.impl.io;
033:
034: import java.io.IOException;
035: import java.io.OutputStream;
036:
037: import org.apache.http.io.SessionOutputBuffer;
038: import org.apache.http.io.HttpTransportMetrics;
039: import org.apache.http.params.HttpParams;
040: import org.apache.http.params.HttpProtocolParams;
041: import org.apache.http.protocol.HTTP;
042: import org.apache.http.util.ByteArrayBuffer;
043: import org.apache.http.util.CharArrayBuffer;
044:
045: /**
046: * Abstract base class for session output buffers that stream data
047: * to an {@link OutputStream}.
048: *
049: * @author <a href="mailto:oleg at ural.ru">Oleg Kalnichevski</a>
050: *
051: */
052: public abstract class AbstractSessionOutputBuffer implements
053: SessionOutputBuffer {
054:
055: private static final byte[] CRLF = new byte[] { HTTP.CR, HTTP.LF };
056:
057: private static int MAX_CHUNK = 256;
058:
059: private OutputStream outstream;
060: private ByteArrayBuffer buffer;
061:
062: private String charset = HTTP.US_ASCII;
063: private boolean ascii = true;
064:
065: private HttpTransportMetricsImpl metrics;
066:
067: protected void init(final OutputStream outstream, int buffersize,
068: final HttpParams params) {
069: if (outstream == null) {
070: throw new IllegalArgumentException(
071: "Input stream may not be null");
072: }
073: if (buffersize <= 0) {
074: throw new IllegalArgumentException(
075: "Buffer size may not be negative or zero");
076: }
077: if (params == null) {
078: throw new IllegalArgumentException(
079: "HTTP parameters may not be null");
080: }
081: this .outstream = outstream;
082: this .buffer = new ByteArrayBuffer(buffersize);
083: this .charset = HttpProtocolParams.getHttpElementCharset(params);
084: this .ascii = this .charset.equalsIgnoreCase(HTTP.US_ASCII)
085: || this .charset.equalsIgnoreCase(HTTP.ASCII);
086: this .metrics = new HttpTransportMetricsImpl();
087: }
088:
089: protected void flushBuffer() throws IOException {
090: int len = this .buffer.length();
091: if (len > 0) {
092: this .outstream.write(this .buffer.buffer(), 0, len);
093: this .buffer.clear();
094: this .metrics.incrementBytesTransferred(len);
095: }
096: }
097:
098: public void flush() throws IOException {
099: flushBuffer();
100: this .outstream.flush();
101: }
102:
103: public void write(final byte[] b, int off, int len)
104: throws IOException {
105: if (b == null) {
106: return;
107: }
108: // Do not want to buffer largish chunks
109: // if the byte array is larger then MAX_CHUNK
110: // write it directly to the output stream
111: if (len > MAX_CHUNK || len > this .buffer.capacity()) {
112: // flush the buffer
113: flushBuffer();
114: // write directly to the out stream
115: this .outstream.write(b, off, len);
116: this .metrics.incrementBytesTransferred(len);
117: } else {
118: // Do not let the buffer grow unnecessarily
119: int freecapacity = this .buffer.capacity()
120: - this .buffer.length();
121: if (len > freecapacity) {
122: // flush the buffer
123: flushBuffer();
124: }
125: // buffer
126: this .buffer.append(b, off, len);
127: }
128: }
129:
130: public void write(final byte[] b) throws IOException {
131: if (b == null) {
132: return;
133: }
134: write(b, 0, b.length);
135: }
136:
137: public void write(int b) throws IOException {
138: if (this .buffer.isFull()) {
139: flushBuffer();
140: }
141: this .buffer.append(b);
142: }
143:
144: public void writeLine(final String s) throws IOException {
145: if (s == null) {
146: return;
147: }
148: if (s.length() > 0) {
149: write(s.getBytes(this .charset));
150: }
151: write(CRLF);
152: }
153:
154: public void writeLine(final CharArrayBuffer s) throws IOException {
155: if (s == null) {
156: return;
157: }
158: if (this .ascii) {
159: int off = 0;
160: int remaining = s.length();
161: while (remaining > 0) {
162: int chunk = this .buffer.capacity()
163: - this .buffer.length();
164: chunk = Math.min(chunk, remaining);
165: if (chunk > 0) {
166: this .buffer.append(s, off, chunk);
167: }
168: if (this .buffer.isFull()) {
169: flushBuffer();
170: }
171: off += chunk;
172: remaining -= chunk;
173: }
174: } else {
175: // This is VERY memory inefficient, BUT since non-ASCII charsets are
176: // NOT meant to be used anyway, there's no point optimizing it
177: byte[] tmp = s.toString().getBytes(this .charset);
178: write(tmp);
179: }
180: write(CRLF);
181: }
182:
183: public HttpTransportMetrics getMetrics() {
184: return this.metrics;
185: }
186:
187: }
|