/** * 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.layoutconfiguration.util; import com.liferay.portal.kernel.executor.CopyThreadLocalCallable; import com.liferay.portal.kernel.model.Portlet; import com.liferay.portal.kernel.portlet.PortletContainerException; import com.liferay.portal.kernel.portlet.PortletContainerUtil; import com.liferay.portal.kernel.portlet.RestrictPortletServletRequest; import com.liferay.portal.kernel.servlet.BufferCacheServletResponse; import com.liferay.portal.kernel.util.Mergeable; import com.liferay.portal.kernel.util.StringBundler; import com.liferay.portal.kernel.util.WebKeys; import java.io.IOException; import java.util.Enumeration; import java.util.concurrent.Callable; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * @author Shuyang Zhou */ public class PortletRenderer { public PortletRenderer( Portlet portlet, String columnId, Integer columnCount, Integer columnPos) { _portlet = portlet; _columnId = columnId; _columnCount = columnCount; _columnPos = columnPos; } public void finishParallelRender() { if (_restrictPortletServletRequest != null) { _restrictPortletServletRequest.mergeSharedAttributes(); } } public Callable<StringBundler> getCallable( HttpServletRequest request, HttpServletResponse response) { return new PortletRendererCallable(request, response); } public Portlet getPortlet() { return _portlet; } public StringBundler render( HttpServletRequest request, HttpServletResponse response) throws PortletContainerException { request = PortletContainerUtil.setupOptionalRenderParameters( request, null, _columnId, _columnPos, _columnCount); return _render(request, response); } public StringBundler renderAjax( HttpServletRequest request, HttpServletResponse response) throws PortletContainerException { request = PortletContainerUtil.setupOptionalRenderParameters( request, _RENDER_PATH, _columnId, _columnPos, _columnCount); _restrictPortletServletRequest = (RestrictPortletServletRequest)request; return _render(request, response); } public StringBundler renderError( HttpServletRequest request, HttpServletResponse response) throws PortletContainerException { request = PortletContainerUtil.setupOptionalRenderParameters( request, null, _columnId, _columnPos, _columnCount); request.setAttribute( WebKeys.PARALLEL_RENDERING_TIMEOUT_ERROR, Boolean.TRUE); _restrictPortletServletRequest = (RestrictPortletServletRequest)request; try { return _render(request, response); } finally { request.removeAttribute(WebKeys.PARALLEL_RENDERING_TIMEOUT_ERROR); } } private StringBundler _render( HttpServletRequest request, HttpServletResponse response) throws PortletContainerException { BufferCacheServletResponse bufferCacheServletResponse = new BufferCacheServletResponse(response); Object lock = request.getAttribute( WebKeys.PARALLEL_RENDERING_MERGE_LOCK); request.setAttribute(WebKeys.PARALLEL_RENDERING_MERGE_LOCK, null); Object portletParallelRender = request.getAttribute( WebKeys.PORTLET_PARALLEL_RENDER); request.setAttribute(WebKeys.PORTLET_PARALLEL_RENDER, Boolean.FALSE); try { PortletContainerUtil.render( request, bufferCacheServletResponse, _portlet); return bufferCacheServletResponse.getStringBundler(); } catch (IOException ioe) { throw new PortletContainerException(ioe); } finally { request.setAttribute(WebKeys.PARALLEL_RENDERING_MERGE_LOCK, lock); request.setAttribute( WebKeys.PORTLET_PARALLEL_RENDER, portletParallelRender); } } private static final String _RENDER_PATH = "/html/portal/load_render_portlet.jsp"; private final Integer _columnCount; private final String _columnId; private final Integer _columnPos; private final Portlet _portlet; private RestrictPortletServletRequest _restrictPortletServletRequest; private class PortletRendererCallable extends CopyThreadLocalCallable<StringBundler> { public PortletRendererCallable( HttpServletRequest request, HttpServletResponse response) { super( ParallelRenderThreadLocalBinderUtil.getThreadLocalBinder(), false, true); _request = request; _response = response; } @Override public StringBundler doCall() throws Exception { HttpServletRequest request = PortletContainerUtil.setupOptionalRenderParameters( _request, null, _columnId, _columnPos, _columnCount); _restrictPortletServletRequest = (RestrictPortletServletRequest)request; try { _split(_request, _restrictPortletServletRequest); return _render(request, _response); } catch (Exception e) { // Under parallel rendering context. An interrupted state means // the call was cancelled and so we should not rethrow the // exception. Thread currentThread = Thread.currentThread(); if (!currentThread.isInterrupted()) { throw e; } return null; } } private void _split( HttpServletRequest request, RestrictPortletServletRequest restrictPortletServletRequest) { Enumeration<String> attributeNames = request.getAttributeNames(); while (attributeNames.hasMoreElements()) { String attributeName = attributeNames.nextElement(); Object attribute = request.getAttribute(attributeName); if (!(attribute instanceof Mergeable<?>) || !RestrictPortletServletRequest.isSharedRequestAttribute( attributeName)) { continue; } Mergeable<?> mergeable = (Mergeable<?>)attribute; restrictPortletServletRequest.setAttribute( attributeName, mergeable.split()); } } private final HttpServletRequest _request; private final HttpServletResponse _response; } }