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 if (charsetName == null) {
077 charsetName = StringPool.DEFAULT_CHARSET_NAME;
078 }
079
080 _writer = writer;
081 _charsetName = charsetName;
082 _charsetDecoder = CharsetDecoderUtil.getCharsetDecoder(charsetName);
083 _inputBuffer = ByteBuffer.allocate(inputBufferSize);
084 _outputBuffer = CharBuffer.allocate(outputBufferSize);
085 _autoFlush = autoFlush;
086 }
087
088 @Override
089 public void close() throws IOException {
090 _doDecode(true);
091 _doFlush();
092
093 _writer.close();
094 }
095
096 @Override
097 public void flush() throws IOException {
098 _doFlush();
099
100 _writer.flush();
101 }
102
103 public String getEncoding() {
104 return _charsetName;
105 }
106
107 @Override
108 public void write(byte[] bytes) throws IOException {
109 write(bytes, 0, bytes.length);
110 }
111
112 @Override
113 public void write(byte[] bytes, int offset, int length) throws IOException {
114 while (length > 0) {
115 int blockSize = Math.min(length, _inputBuffer.remaining());
116
117 _inputBuffer.put(bytes, offset, blockSize);
118
119 _doDecode(false);
120
121 length -= blockSize;
122 offset += blockSize;
123 }
124
125 if (_autoFlush) {
126 _doFlush();
127 }
128 }
129
130 @Override
131 public void write(int b) throws IOException {
132 write(new byte[] {(byte)b}, 0, 1);
133 }
134
135 private void _doDecode(boolean endOfInput) throws IOException {
136 _inputBuffer.flip();
137
138 while (true) {
139 CoderResult coderResult = _charsetDecoder.decode(
140 _inputBuffer, _outputBuffer, endOfInput);
141
142 if (coderResult.isOverflow()) {
143 _doFlush();
144 }
145 else if (coderResult.isUnderflow()) {
146 break;
147 }
148 else {
149 throw new IOException("Unexcepted coder result " + coderResult);
150 }
151 }
152
153 _inputBuffer.compact();
154 }
155
156 private void _doFlush() throws IOException {
157 if (_outputBuffer.position() > 0) {
158 _writer.write(_outputBuffer.array(), 0, _outputBuffer.position());
159
160 _outputBuffer.rewind();
161 }
162 }
163
164 private static final int _DEFAULT_INTPUT_BUFFER_SIZE = 128;
165
166 private static final int _DEFAULT_OUTPUT_BUFFER_SIZE = 1024;
167
168 private boolean _autoFlush;
169 private CharsetDecoder _charsetDecoder;
170 private String _charsetName;
171 private ByteBuffer _inputBuffer;
172 private CharBuffer _outputBuffer;
173 private Writer _writer;
174
175 }