blob: b18e0aced296c190a1984689d2ec7eb9d91f931e [file] [log] [blame]
/*
*/
package org.apache.tomcat.lite.http;
import java.io.IOException;
import java.io.Writer;
import org.apache.tomcat.lite.io.IOOutputStream;
import org.apache.tomcat.lite.io.IOWriter;
/**
* Implement character translation and buffering.
*
* The actual buffering happens in the IOBuffer - we translate the
* chars as soon as we get them.
*
* For servlet compat you can set a buffer size and a flush() will happen
* when the number of chars have been written. Note that writes at a lower
* layer can be done and are not counted.
*
* @author Costin Manolache
*/
public class HttpWriter extends Writer {
public static final String DEFAULT_ENCODING = "ISO-8859-1";
public static final int DEFAULT_BUFFER_SIZE = 8*1024;
// ----------------------------------------------------- Instance Variables
HttpMessage message;
/**
* The byte buffer.
*/
protected IOOutputStream bb;
int bufferSize = DEFAULT_BUFFER_SIZE;
/**
* Number of chars written.
*/
protected int wSinceFlush = 0;
/**
* Flag which indicates if the output buffer is closed.
*/
protected boolean closed = false;
/**
* Encoding to use.
* TODO: isn't it redundant ? enc, gotEnc, conv plus the enc in the bb
*/
protected String enc;
/**
* Encoder is set.
*/
protected boolean gotEnc = false;
/**
* List of encoders. The writer is reused - the encoder mapping
* avoids creating expensive objects. In future it'll contain nio.Charsets
*/
//protected Map<String, C2BConverter> encoders = new HashMap();
/**
* Current char to byte converter. TODO: replace with Charset
*/
private IOWriter conv;
/**
* Suspended flag. All output bytes will be swallowed if this is true.
*/
protected boolean suspended = false;
// ----------------------------------------------------------- Constructors
/**
* Default constructor. Allocate the buffer with the default buffer size.
* @param out
*/
public HttpWriter(HttpMessage message, IOOutputStream out,
IOWriter conv) {
this.message = message;
bb = out;
this.conv = conv;
}
// ------------------------------------------------------------- Properties
/**
* Is the response output suspended ?
*
* @return suspended flag value
*/
public boolean isSuspended() {
return this.suspended;
}
/**
* Set the suspended flag.
*
* @param suspended New suspended flag value
*/
public void setSuspended(boolean suspended) {
this.suspended = suspended;
}
// --------------------------------------------------------- Public Methods
/**
* Recycle the output buffer.
*/
public void recycle() {
wSinceFlush = 0;
bb.recycle();
closed = false;
suspended = false;
// if (conv != null) {
// conv.recycle();
// }
gotEnc = false;
enc = null;
}
public void close()
throws IOException {
if (closed)
return;
if (suspended)
return;
push();
closed = true;
bb.close();
}
/**
* Flush bytes or chars contained in the buffer.
*
* @throws IOException An underlying IOException occurred
*/
public void flush()
throws IOException {
push();
bb.flush(); // will send the data
wSinceFlush = 0;
}
/**
* Flush chars to the byte buffer.
*/
public void push()
throws IOException {
if (suspended)
return;
getConv().push();
}
private void updateSize(int cnt) throws IOException {
wSinceFlush += cnt;
if (wSinceFlush > bufferSize) {
flush();
}
}
public void write(int c)
throws IOException {
if (suspended)
return;
getConv().write(c);
updateSize(1);
}
public void write(char c[])
throws IOException {
write(c, 0, c.length);
}
public void write(char c[], int off, int len)
throws IOException {
if (suspended)
return;
getConv().write(c, off, len);
updateSize(len);
}
public void write(StringBuffer sb)
throws IOException {
if (suspended)
return;
int len = sb.length();
getConv().write(sb.toString());
updateSize(len);
}
/**
* Append a string to the buffer
*/
public void write(String s, int off, int len)
throws IOException {
if (suspended)
return;
if (s==null)
s="null";
getConv().write( s, off, len );
updateSize(len);
}
public void write(String s)
throws IOException {
if (s==null)
s="null";
write(s, 0, s.length());
}
public void println() throws IOException {
write("\n");
}
public void println(String s) throws IOException {
write(s);
write("\n");
}
public void print(String s) throws IOException {
write(s);
}
public void checkConverter()
throws IOException {
// if (gotEnc) {
// return;
// }
// if (enc == null) {
// enc = message.getCharacterEncoding();
// }
//
// gotEnc = true;
// if (enc == null)
// enc = DEFAULT_ENCODING;
// conv = (C2BConverter) encoders.get(enc);
//
// if (conv == null) {
// conv = C2BConverter.newConverter(message.getBodyOutputStream(),
// enc);
// encoders.put(enc, conv);
//
// }
}
public int getWrittenSinceFlush() {
return wSinceFlush;
}
public void setBufferSize(int size) {
if (size > bufferSize) {
bufferSize = size;
}
}
/**
* Clear any data that was buffered.
*/
public void reset() {
if (conv != null) {
conv.recycle();
}
wSinceFlush = 0;
gotEnc = false;
enc = null;
bb.reset();
}
public int getBufferSize() {
return bufferSize;
}
protected IOWriter getConv() throws IOException {
checkConverter();
return conv;
}
public void println(CharSequence key) throws IOException {
// TODO: direct
println(key.toString());
}
}