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