/** * 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(); } }