/**
* Licensed to Apereo under one or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information regarding copyright ownership. Apereo
* licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use
* this file except in compliance with the License. You may obtain a copy of the License at the
* following location:
*
* <p>http://www.apache.org/licenses/LICENSE-2.0
*
* <p>Unless required by applicable law or agreed to in writing, software distributed under the
* License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apereo.portal.utils.web;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.concurrent.Callable;
import javax.portlet.CacheControl;
import javax.portlet.MimeResponse;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import org.apereo.portal.portlet.om.IPortletWindow;
import org.apereo.portal.portlet.rendering.LazyPrintWriter;
import org.apereo.portal.portlet.rendering.LazyServletOutputStream;
import org.apereo.portal.portlet.rendering.PortletOutputHandler;
/**
* Wrapper for portlet responses that write out content: {@link MimeResponse}. As much as possible
* the {@link PortletOutputHandler} for the response is delegated to
*
* <p>Lazily retrieves the PrintWriter and ServletOutputStream objects waiting until a method is
* actually called on one or the other.
*
* <p>Also ignores the close call on either the PrintWriter or ServletOutputStream if {@link
* CacheControl#useCachedContent()} is true
*
* <p>This is needed as servlet spec says that after a {@link
* RequestDispatcher#forward(javax.servlet.ServletRequest, javax.servlet.ServletResponse)} the
* {@link PrintWriter}/{@link ServletOutputStream} must be closed. This is a problem for resource
* responses that want to use cached content as after the forward is complete the portal needs to
* replay the cached content.
*
*/
public class PortletMimeHttpServletResponseWrapper extends PortletHttpServletResponseWrapper {
private final PortletOutputHandler portletOutputHandler;
private final CacheControl cacheControl;
private ServletOutputStream servletOutputStream;
private PrintWriter printWriter;
public PortletMimeHttpServletResponseWrapper(
HttpServletResponse httpServletResponse,
IPortletWindow portletWindow,
PortletOutputHandler portletOutputHandler,
CacheControl cacheControl) {
super(httpServletResponse, portletWindow);
this.portletOutputHandler = portletOutputHandler;
this.cacheControl = cacheControl;
}
@Override
public ServletOutputStream getOutputStream() throws IOException {
if (this.servletOutputStream == null) {
this.servletOutputStream =
new LazyServletOutputStream(
new Callable<ServletOutputStream>() {
@Override
public ServletOutputStream call() throws Exception {
return PortletMimeHttpServletResponseWrapper.super
.getOutputStream();
}
}) {
@Override
public void close() throws IOException {
//Don't close the ServletOutputStream if useCachedContent is true, the PortletRendererImpl will be replaying cached content
if (!PortletMimeHttpServletResponseWrapper.this.cacheControl
.useCachedContent()) {
super.close();
}
}
};
}
return this.servletOutputStream;
}
@Override
public PrintWriter getWriter() throws IOException {
if (this.printWriter == null) {
this.printWriter =
new LazyPrintWriter(
new Callable<PrintWriter>() {
@Override
public PrintWriter call() throws Exception {
return PortletMimeHttpServletResponseWrapper.super.getWriter();
}
}) {
@Override
public void close() {
//Don't close the PrintWriter if useCachedContent is true, the PortletRendererImpl will be replaying cached content
if (!PortletMimeHttpServletResponseWrapper.this.cacheControl
.useCachedContent()) {
super.close();
}
}
};
}
return this.printWriter;
}
@Override
public void flushBuffer() throws IOException {
this.portletOutputHandler.flushBuffer();
}
@Override
public void resetBuffer() {
this.portletOutputHandler.resetBuffer();
}
@Override
public void reset() {
this.portletOutputHandler.reset();
}
@Override
public void setBufferSize(int size) {
this.portletOutputHandler.setBufferSize(size);
}
@Override
public void setContentType(String type) {
this.portletOutputHandler.setContentType(type);
}
@Override
public String getContentType() {
return this.portletOutputHandler.getContentType();
}
@Override
public int getBufferSize() {
return this.portletOutputHandler.getBufferSize();
}
@Override
public boolean isCommitted() {
return this.portletOutputHandler.isCommitted();
}
}