com.liferay.portal.kernel.servlet.BufferCacheServletResponse Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of com.liferay.portal.kernel Show documentation
Show all versions of com.liferay.portal.kernel Show documentation
Contains interfaces for the portal services. Interfaces are only loaded by the global class loader and are shared by all plugins.
/**
* Copyright (c) 2000-present Liferay, Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*/
package com.liferay.portal.kernel.servlet;
import com.liferay.portal.kernel.io.DummyOutputStream;
import com.liferay.portal.kernel.io.DummyWriter;
import com.liferay.portal.kernel.io.unsync.UnsyncByteArrayOutputStream;
import com.liferay.portal.kernel.io.unsync.UnsyncStringWriter;
import com.liferay.portal.kernel.nio.charset.CharsetDecoderUtil;
import com.liferay.portal.kernel.nio.charset.CharsetEncoderUtil;
import com.liferay.portal.kernel.util.StringBundler;
import com.liferay.portal.kernel.util.StringPool;
import com.liferay.portal.kernel.util.UnsyncPrintWriterPool;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
/**
* @author Shuyang Zhou
*/
public class BufferCacheServletResponse extends MetaInfoCacheServletResponse {
public BufferCacheServletResponse(HttpServletResponse response) {
super(response);
}
/**
* This method is very expensive when used in char mode because it has to
* encode every char to byte in order to calculate the final byte size.
*
* @return used buffer size in byte.
*/
@Override
public int getBufferSize() {
if (_byteBuffer != null) {
return _byteBuffer.limit();
}
if (_charBuffer != null) {
ByteBuffer byteBuffer = CharsetEncoderUtil.encode(
getCharacterEncoding(), _charBuffer.duplicate());
return byteBuffer.limit();
}
try {
_flushInternalBuffer();
}
catch (IOException ioe) {
throw new RuntimeException(ioe);
}
if (_unsyncByteArrayOutputStream != null) {
return _unsyncByteArrayOutputStream.size();
}
if (_unsyncStringWriter != null) {
String content = _unsyncStringWriter.toString();
ByteBuffer byteBuffer = CharsetEncoderUtil.encode(
getCharacterEncoding(), content);
return byteBuffer.limit();
}
return 0;
}
/**
* In char mode, this method will encode every char to byte using the
* character set from {@link #getCharacterEncoding()}. Generally, this
* method should be called after the last text based post-processing.
* Otherwise, you may need decode the byte back to char again which will
* result in a lot of unnecessary CPU overhead.
*/
public ByteBuffer getByteBuffer() throws IOException {
if (_byteBuffer != null) {
return _byteBuffer;
}
if (_charBuffer != null) {
return CharsetEncoderUtil.encode(
getCharacterEncoding(), _charBuffer.duplicate());
}
_flushInternalBuffer();
if (_unsyncByteArrayOutputStream != null) {
return _unsyncByteArrayOutputStream.unsafeGetByteBuffer();
}
if (_unsyncStringWriter != null) {
String content = _unsyncStringWriter.toString();
return CharsetEncoderUtil.encode(getCharacterEncoding(), content);
}
return _emptyByteBuffer;
}
/**
* In char mode, this method will encode every byte to char using the
* character set from {@link #getCharacterEncoding()}. Make sure the byte
* data is actually encoded chars. Otherwise, the decoding will generate
* meaningless data, or worse, even encode the output back and the exact
* same character set may not able to retrieve the exact same byte data. For
* example, decode an image byte data to char, then encode the chars back to
* byte with same character set, will most likely create a corrupted image.
*/
public CharBuffer getCharBuffer() throws IOException {
if (_charBuffer != null) {
return _charBuffer;
}
if (_byteBuffer != null) {
return CharsetDecoderUtil.decode(
getCharacterEncoding(), _byteBuffer.duplicate());
}
_flushInternalBuffer();
if (_unsyncStringWriter != null) {
return CharBuffer.wrap(_unsyncStringWriter.toString());
}
if (_unsyncByteArrayOutputStream != null) {
ByteBuffer byteBuffer =
_unsyncByteArrayOutputStream.unsafeGetByteBuffer();
return CharsetDecoderUtil.decode(
getCharacterEncoding(), byteBuffer);
}
return _emptyCharBuffer;
}
@Override
public ServletOutputStream getOutputStream() {
if (calledGetWriter) {
throw new IllegalStateException(
"Unable to obtain OutputStream because Writer is already in " +
"use");
}
if (_servletOutputStream != null) {
return _servletOutputStream;
}
resetBuffer(true);
_unsyncByteArrayOutputStream = new UnsyncByteArrayOutputStream();
_servletOutputStream = new ServletOutputStreamAdapter(
_unsyncByteArrayOutputStream);
calledGetOutputStream = true;
return _servletOutputStream;
}
/**
* @see #getCharBuffer()
*/
public String getString() throws IOException {
if (_charBuffer != null) {
return _charBuffer.toString();
}
if (_byteBuffer != null) {
CharBuffer charBuffer = CharsetDecoderUtil.decode(
getCharacterEncoding(), _byteBuffer.duplicate());
return charBuffer.toString();
}
_flushInternalBuffer();
if (_unsyncStringWriter != null) {
return _unsyncStringWriter.toString();
}
if (_unsyncByteArrayOutputStream != null) {
ByteBuffer byteBuffer =
_unsyncByteArrayOutputStream.unsafeGetByteBuffer();
CharBuffer charBuffer = CharsetDecoderUtil.decode(
getCharacterEncoding(), byteBuffer);
return charBuffer.toString();
}
return StringPool.BLANK;
}
/**
* @see #getCharBuffer()
*/
public StringBundler getStringBundler() throws IOException {
if (_charBuffer != null) {
StringBundler sb = new StringBundler(1);
sb.append(_charBuffer.toString());
return sb;
}
if (_byteBuffer != null) {
CharBuffer charBuffer = CharsetDecoderUtil.decode(
getCharacterEncoding(), _byteBuffer.duplicate());
StringBundler sb = new StringBundler(1);
sb.append(charBuffer.toString());
return sb;
}
_flushInternalBuffer();
if (_unsyncStringWriter != null) {
return _unsyncStringWriter.getStringBundler();
}
if (_unsyncByteArrayOutputStream != null) {
ByteBuffer byteBuffer =
_unsyncByteArrayOutputStream.unsafeGetByteBuffer();
CharBuffer charBuffer = CharsetDecoderUtil.decode(
getCharacterEncoding(), byteBuffer);
StringBundler sb = new StringBundler(1);
sb.append(charBuffer.toString());
return sb;
}
return new StringBundler(1);
}
@Override
public PrintWriter getWriter() {
if (calledGetOutputStream) {
throw new IllegalStateException(
"Cannot obtain Writer because OutputStream is already in use");
}
if (_printWriter != null) {
return _printWriter;
}
resetBuffer(true);
_unsyncStringWriter = new UnsyncStringWriter();
_printWriter = UnsyncPrintWriterPool.borrow(_unsyncStringWriter);
calledGetWriter = true;
return _printWriter;
}
public boolean isByteMode() {
if ((_byteBuffer != null) || (_unsyncByteArrayOutputStream != null)) {
return true;
}
return false;
}
public boolean isCharMode() {
if ((_charBuffer != null) || (_unsyncStringWriter != null)) {
return true;
}
return false;
}
public void outputBuffer() throws IOException {
_flushInternalBuffer();
HttpServletResponse response = (HttpServletResponse)getResponse();
if ((_byteBuffer != null) || calledGetOutputStream) {
ServletResponseUtil.write(response, getByteBuffer());
}
else if ((_charBuffer != null) || calledGetWriter) {
ServletResponseUtil.write(response, getCharBuffer());
}
}
@Override
public void setBufferSize(int bufferSize) {
if (isCommitted()) {
throw new IllegalStateException("Set buffer size after commit");
}
// Buffered response cannot accept buffer size because it has an
// internal buffer that grows as needed
}
public void setByteBuffer(ByteBuffer byteBuffer) {
resetBuffer(true);
_byteBuffer = byteBuffer;
if (byteBuffer != null) {
_servletOutputStream = new ServletOutputStreamAdapter(
new DummyOutputStream());
calledGetOutputStream = true;
}
}
public void setCharBuffer(CharBuffer charBuffer) {
resetBuffer(true);
_charBuffer = charBuffer;
if (charBuffer != null) {
_printWriter = UnsyncPrintWriterPool.borrow(new DummyWriter());
calledGetWriter = true;
}
}
@Override
public void setContentLength(int contentLength) {
// Buffered response cannot accept content length because content post
// processing may cause length change
}
public void setString(String string) {
setCharBuffer(CharBuffer.wrap(string));
}
@Override
protected void resetBuffer(boolean nullOutReferences) {
if (nullOutReferences) {
calledGetOutputStream = false;
calledGetWriter = false;
_printWriter = null;
_servletOutputStream = null;
_unsyncByteArrayOutputStream = null;
_unsyncStringWriter = null;
}
else {
if (_unsyncByteArrayOutputStream != null) {
_unsyncByteArrayOutputStream.reset();
}
if (_unsyncStringWriter != null) {
_unsyncStringWriter.reset();
}
if (_byteBuffer != null) {
_servletOutputStream = null;
calledGetOutputStream = false;
}
if (_charBuffer != null) {
_printWriter = null;
calledGetWriter = false;
}
}
_byteBuffer = null;
_charBuffer = null;
}
private void _flushInternalBuffer() throws IOException {
if (calledGetOutputStream) {
_servletOutputStream.flush();
}
else if (calledGetWriter) {
_printWriter.flush();
}
}
private static final ByteBuffer _emptyByteBuffer = ByteBuffer.allocate(0);
private static final CharBuffer _emptyCharBuffer = CharBuffer.allocate(0);
private ByteBuffer _byteBuffer;
private CharBuffer _charBuffer;
private PrintWriter _printWriter;
private ServletOutputStream _servletOutputStream;
private UnsyncByteArrayOutputStream _unsyncByteArrayOutputStream;
private UnsyncStringWriter _unsyncStringWriter;
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy