001    /**
002     * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.kernel.io;
016    
017    import com.liferay.portal.kernel.nio.charset.CharsetEncoderUtil;
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.CharsetEncoder;
027    import java.nio.charset.CoderResult;
028    
029    /**
030     * @author Shuyang Zhou
031     */
032    public class OutputStreamWriter extends Writer {
033    
034            public OutputStreamWriter(OutputStream outputStream) {
035                    this(
036                            outputStream, StringPool.DEFAULT_CHARSET_NAME,
037                            _DEFAULT_OUTPUT_BUFFER_SIZE, false);
038            }
039    
040            public OutputStreamWriter(OutputStream outputStream, String charsetName) {
041                    this(outputStream, charsetName, _DEFAULT_OUTPUT_BUFFER_SIZE, false);
042            }
043    
044            public OutputStreamWriter(
045                    OutputStream outputStream, String charsetName, boolean autoFlush) {
046    
047                    this(outputStream, charsetName, _DEFAULT_OUTPUT_BUFFER_SIZE, autoFlush);
048            }
049    
050            public OutputStreamWriter(
051                    OutputStream outputStream, String charsetName, int outputBufferSize) {
052    
053                    this(outputStream, charsetName, outputBufferSize, false);
054            }
055    
056            public OutputStreamWriter(
057                    OutputStream outputStream, String charsetName, int outputBufferSize,
058                    boolean autoFlush) {
059    
060                    if (outputBufferSize < 4) {
061                            throw new IllegalArgumentException(
062                                    "Output buffer size " + outputBufferSize + " is less than 4");
063                    }
064    
065                    if (charsetName == null) {
066                            charsetName = StringPool.DEFAULT_CHARSET_NAME;
067                    }
068    
069                    _outputStream = outputStream;
070                    _charsetName = charsetName;
071                    _charsetEncoder = CharsetEncoderUtil.getCharsetEncoder(charsetName);
072                    _outputByteBuffer = ByteBuffer.allocate(outputBufferSize);
073                    _autoFlush = autoFlush;
074            }
075    
076            @Override
077            public void close() throws IOException {
078                    _flushBuffer();
079    
080                    _outputStream.close();
081            }
082    
083            @Override
084            public void flush() throws IOException {
085                    _flushBuffer();
086    
087                    _outputStream.flush();
088            }
089    
090            public String getEncoding() {
091                    return _charsetName;
092            }
093    
094            @Override
095            public void write(char[] chars) throws IOException {
096                    _doWrite(CharBuffer.wrap(chars, 0, chars.length));
097            }
098    
099            @Override
100            public void write(char[] chars, int offset, int length) throws IOException {
101                    _doWrite(CharBuffer.wrap(chars, offset, length));
102            }
103    
104            @Override
105            public void write(int c) throws IOException {
106                    _inputArray[0] = (char)c;
107    
108                    _doWrite(_inputCharBuffer);
109    
110                    _inputCharBuffer.clear();
111            }
112    
113            @Override
114            public void write(String string) throws IOException {
115                    _doWrite(CharBuffer.wrap(string, 0, string.length()));
116            }
117    
118            @Override
119            public void write(String string, int offset, int length)
120                    throws IOException {
121    
122                    _doWrite(CharBuffer.wrap(string, offset, offset + length));
123            }
124    
125            private void _doWrite(CharBuffer inputCharBuffer) throws IOException {
126                    while (true) {
127                            CoderResult coderResult = _charsetEncoder.encode(
128                                    inputCharBuffer, _outputByteBuffer, true);
129    
130                            if (coderResult.isOverflow()) {
131                                    _flushBuffer();
132                            }
133                            else if (coderResult.isUnderflow()) {
134                                    if (_autoFlush) {
135                                            _flushBuffer();
136                                    }
137    
138                                    break;
139                            }
140                            else {
141                                    throw new IOException("Unexcepted coder result " + coderResult);
142                            }
143                    }
144            }
145    
146            private void _flushBuffer() throws IOException {
147                    if (_outputByteBuffer.position() > 0) {
148                            _outputStream.write(
149                                    _outputByteBuffer.array(), 0, _outputByteBuffer.position());
150    
151                            _outputByteBuffer.rewind();
152                    }
153            }
154    
155            private static final int _DEFAULT_OUTPUT_BUFFER_SIZE = 8192;
156    
157            private final boolean _autoFlush;
158            private final CharsetEncoder _charsetEncoder;
159            private final String _charsetName;
160            private final char[] _inputArray = new char[1];
161            private final CharBuffer _inputCharBuffer = CharBuffer.wrap(_inputArray);
162            private final ByteBuffer _outputByteBuffer;
163            private final OutputStream _outputStream;
164    
165    }