001
014
015 package com.liferay.portal.kernel.io;
016
017 import com.liferay.portal.kernel.nio.charset.CharsetDecoderUtil;
018 import com.liferay.portal.kernel.util.StringPool;
019
020 import java.io.IOException;
021 import java.io.OutputStream;
022 import java.io.Writer;
023
024 import java.nio.ByteBuffer;
025 import java.nio.CharBuffer;
026 import java.nio.charset.Charset;
027 import java.nio.charset.CharsetDecoder;
028 import java.nio.charset.CoderResult;
029
030
033 public class WriterOutputStream extends OutputStream {
034
035 public WriterOutputStream(Writer writer) {
036 this(
037 writer, StringPool.UTF8, _DEFAULT_INTPUT_BUFFER_SIZE,
038 _DEFAULT_OUTPUT_BUFFER_SIZE, false);
039 }
040
041 public WriterOutputStream(Writer writer, String charsetName) {
042 this(
043 writer, charsetName, _DEFAULT_INTPUT_BUFFER_SIZE,
044 _DEFAULT_OUTPUT_BUFFER_SIZE, false);
045 }
046
047 public WriterOutputStream(
048 Writer writer, String charsetName, boolean autoFlush) {
049
050 this(
051 writer, charsetName, _DEFAULT_INTPUT_BUFFER_SIZE,
052 _DEFAULT_OUTPUT_BUFFER_SIZE, autoFlush);
053 }
054
055 public WriterOutputStream(
056 Writer writer, String charsetName, int inputBufferSize,
057 int outputBufferSize) {
058
059 this(writer, charsetName, inputBufferSize, outputBufferSize, false);
060 }
061
062 public WriterOutputStream(
063 Writer writer, String charsetName, int inputBufferSize,
064 int outputBufferSize, boolean autoFlush) {
065
066 if (inputBufferSize < 4) {
067 throw new IllegalArgumentException(
068 "Input buffer size " + inputBufferSize + " is less than 4");
069 }
070
071 if (outputBufferSize <= 0) {
072 throw new IllegalArgumentException(
073 "Output buffer size " + outputBufferSize +
074 " must be a positive number");
075 }
076
077 if (charsetName == null) {
078 charsetName = _DEFAULT_CHARSET_NAME;
079 }
080
081 _writer = writer;
082 _charsetName = charsetName;
083 _charsetDecoder = CharsetDecoderUtil.getCharsetDecoder(charsetName);
084 _inputBuffer = ByteBuffer.allocate(inputBufferSize);
085 _outputBuffer = CharBuffer.allocate(outputBufferSize);
086 _autoFlush = autoFlush;
087 }
088
089 @Override
090 public void close() throws IOException {
091 _doDecode(true);
092 _doFlush();
093
094 _writer.close();
095 }
096
097 @Override
098 public void flush() throws IOException {
099 _doFlush();
100
101 _writer.flush();
102 }
103
104 public String getEncoding() {
105 return _charsetName;
106 }
107
108 @Override
109 public void write(byte[] bytes) throws IOException {
110 write(bytes, 0, bytes.length);
111 }
112
113 @Override
114 public void write(byte[] bytes, int offset, int length) throws IOException {
115 while (length > 0) {
116 int blockSize = Math.min(length, _inputBuffer.remaining());
117
118 _inputBuffer.put(bytes, offset, blockSize);
119
120 _doDecode(false);
121
122 length -= blockSize;
123 offset += blockSize;
124 }
125
126 if (_autoFlush) {
127 _doFlush();
128 }
129 }
130
131 @Override
132 public void write(int b) throws IOException {
133 write(new byte[] {(byte)b}, 0, 1);
134 }
135
136 private void _doDecode(boolean endOfInput) throws IOException {
137 _inputBuffer.flip();
138
139 while (true) {
140 CoderResult coderResult = _charsetDecoder.decode(
141 _inputBuffer, _outputBuffer, endOfInput);
142
143 if (coderResult.isOverflow()) {
144 _doFlush();
145 }
146 else if (coderResult.isUnderflow()) {
147 break;
148 }
149 else {
150 throw new IOException("Unexcepted coder result " + coderResult);
151 }
152 }
153
154 _inputBuffer.compact();
155 }
156
157 private void _doFlush() throws IOException {
158 if (_outputBuffer.position() > 0) {
159 _writer.write(_outputBuffer.array(), 0, _outputBuffer.position());
160
161 _outputBuffer.rewind();
162 }
163 }
164
165 private static final String _DEFAULT_CHARSET_NAME =
166 Charset.defaultCharset().name();
167
168 private static final int _DEFAULT_INTPUT_BUFFER_SIZE = 128;
169
170 private static final int _DEFAULT_OUTPUT_BUFFER_SIZE = 1024;
171
172 private boolean _autoFlush;
173 private CharsetDecoder _charsetDecoder;
174 private String _charsetName;
175 private ByteBuffer _inputBuffer;
176 private CharBuffer _outputBuffer;
177 private Writer _writer;
178
179 }