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)
110 throws IOException {
111
112 while (length > 0) {
113 int blockSize = Math.min(length, _inputBuffer.remaining());
114
115 _inputBuffer.put(bytes, offset, blockSize);
116
117 _doDecode(false);
118
119 length -= blockSize;
120 offset += blockSize;
121 }
122
123 if (_autoFlush) {
124 _doFlush();
125 }
126 }
127
128 @Override
129 public void write(int b) throws IOException {
130 write(new byte[] {(byte)b}, 0, 1);
131 }
132
133 private void _doDecode(boolean endOfInput) throws IOException {
134 _inputBuffer.flip();
135
136 while (true) {
137 CoderResult coderResult = _charsetDecoder.decode(
138 _inputBuffer, _outputBuffer, endOfInput);
139
140 if (coderResult.isOverflow()) {
141 _doFlush();
142 }
143 else if (coderResult.isUnderflow()) {
144 break;
145 }
146 else {
147 throw new IOException("Unexcepted coder result " + coderResult);
148 }
149 }
150
151 _inputBuffer.compact();
152 }
153
154 private void _doFlush() throws IOException {
155 if (_outputBuffer.position() > 0) {
156 _writer.write(_outputBuffer.array(), 0, _outputBuffer.position());
157
158 _outputBuffer.rewind();
159 }
160 }
161
162 private static final int _DEFAULT_INTPUT_BUFFER_SIZE = 128;
163
164 private static final int _DEFAULT_OUTPUT_BUFFER_SIZE = 1024;
165
166 private boolean _autoFlush;
167 private CharsetDecoder _charsetDecoder;
168 private String _charsetName;
169 private ByteBuffer _inputBuffer;
170 private CharBuffer _outputBuffer;
171 private Writer _writer;
172
173 }