/*
* Weblounge: Web Content Management System
* Copyright (c) 2003 - 2011 The Weblounge Team
* http://entwinemedia.com/weblounge
*
* This program 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
* of the License, or (at your option) any later version.
*
* This program 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.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package ch.entwine.weblounge.dispatcher.impl;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
/**
* Implementation of a <code>HttpServletResponseWrapper</code> that allows for
* response caching by installing a custom version of an output stream which
* works like the <code>tee</code> command in un*x systems. Like this, the
* output can be written to the response cache <i>and</i> to the client at the
* same time.
*/
class BufferedHttpServletResponse extends HttpServletResponseWrapper {
/**
* Holds the special tee writer that copies the output to the network and to
* the cache.
*/
private PrintWriter out = null;
/** The output stream */
private BufferedServletOutputStream os = null;
/** Whether the getOuputStream has already been called */
private boolean osCalled = false;
/** Default encoding */
private static final String DEFAULT_ENCODING = "utf-8";
/**
* Creates a <code>CacheableHttpServletResponse</code> that is writing any
* content to the wrapped response as well as to the cached output stream,
* given a preceding call to {@link #startTransaction(CacheTransaction)}.
*
* @param tx
* the cached transaction represented by this cacheable response
*/
BufferedHttpServletResponse(HttpServletResponse response) {
super(response);
os = new BufferedServletOutputStream();
}
/**
* Returns the modified writer that enables the <code>CacheManager</cache>
* to copy the response to the cache.
*
* @return a PrintWriter object that can return character data to the client
* @throws IOException
* if the writer could not be allocated
* @see javax.servlet.ServletResponse#getWriter()
* @see ch.entwine.weblounge.OldCacheManager.cache.CacheManager
*/
@Override
public PrintWriter getWriter() throws IOException {
// Check whether there's already a writer allocated
if (out != null)
return out;
// Check whether getOutputStream() has already been called
if (osCalled)
throw new IllegalStateException("An output stream has already been allocated");
// Get the character encoding
String encoding = getCharacterEncoding();
if (encoding == null) {
encoding = DEFAULT_ENCODING;
setCharacterEncoding(encoding);
}
// Install the writer
try {
out = new PrintWriter(new OutputStreamWriter(os, encoding));
} catch (UnsupportedEncodingException e) {
throw new IOException(e.getMessage());
}
return out;
}
/**
* @see javax.servlet.ServletResponseWrapper#getOutputStream()
*/
@Override
public ServletOutputStream getOutputStream() throws IOException {
if (out != null)
throw new IllegalStateException("A writer has already been allocated");
osCalled = true;
return os;
}
/**
* {@inheritDoc}
*
* @see javax.servlet.ServletResponseWrapper#flushBuffer()
*/
@Override
public void flushBuffer() throws IOException {
if (out != null) {
out.flush();
out.close();
out = null;
}
try {
if (isCommitted())
return;
if (os != null) {
// Get the buffered content
byte[] content = os.getContent();
// Set content-related headers
setContentLength(content.length);
// Write the buffered content to the underlying output stream
super.getOutputStream().write(content);
}
// Flush the underlying buffer
super.flushBuffer();
} finally {
os = null;
}
}
}