All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.liferay.portlet.internal.InvokerPortletImpl Maven / Gradle / Ivy

/**
 * 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.portlet.internal;

import com.liferay.petra.reflect.ReflectionUtil;
import com.liferay.petra.string.StringBundler;
import com.liferay.petra.string.StringPool;
import com.liferay.portal.kernel.language.LanguageUtil;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.liferay.portal.kernel.model.Layout;
import com.liferay.portal.kernel.portlet.InvokerFilterContainer;
import com.liferay.portal.kernel.portlet.InvokerPortlet;
import com.liferay.portal.kernel.portlet.LiferayPortletConfig;
import com.liferay.portal.kernel.portlet.LiferayPortletContext;
import com.liferay.portal.kernel.portlet.LiferayPortletRequest;
import com.liferay.portal.kernel.portlet.LiferayPortletResponse;
import com.liferay.portal.kernel.portlet.PortletFilterUtil;
import com.liferay.portal.kernel.portlet.PortletIdCodec;
import com.liferay.portal.kernel.service.PortletLocalServiceUtil;
import com.liferay.portal.kernel.servlet.BufferCacheServletResponse;
import com.liferay.portal.kernel.servlet.PluginContextListener;
import com.liferay.portal.kernel.servlet.PortletServlet;
import com.liferay.portal.kernel.util.ClassUtil;
import com.liferay.portal.kernel.util.GetterUtil;
import com.liferay.portal.kernel.util.JavaConstants;
import com.liferay.portal.kernel.util.MapUtil;
import com.liferay.portal.kernel.util.PortalUtil;
import com.liferay.portal.kernel.util.Time;
import com.liferay.portal.kernel.util.WebKeys;
import com.liferay.portlet.InvokerPortletResponse;
import com.liferay.portlet.InvokerPortletUtil;

import java.io.Closeable;
import java.io.IOException;
import java.io.PrintWriter;

import java.util.List;
import java.util.Map;

import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
import javax.portlet.EventRequest;
import javax.portlet.EventResponse;
import javax.portlet.HeaderRequest;
import javax.portlet.HeaderResponse;
import javax.portlet.Portlet;
import javax.portlet.PortletConfig;
import javax.portlet.PortletContext;
import javax.portlet.PortletException;
import javax.portlet.PortletRequest;
import javax.portlet.PortletResponse;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;
import javax.portlet.ResourceRequest;
import javax.portlet.ResourceResponse;
import javax.portlet.UnavailableException;
import javax.portlet.filter.ActionFilter;
import javax.portlet.filter.EventFilter;
import javax.portlet.filter.FilterChain;
import javax.portlet.filter.HeaderFilter;
import javax.portlet.filter.PortletFilter;
import javax.portlet.filter.RenderFilter;
import javax.portlet.filter.ResourceFilter;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang.time.StopWatch;

/**
 * @author Brian Wing Shun Chan
 * @author Brian Myunghun Kim
 * @author Raymond Augé
 * @author Neil Griffin
 */
public class InvokerPortletImpl
	implements InvokerFilterContainer, InvokerPortlet {

	public InvokerPortletImpl(
		com.liferay.portal.kernel.model.Portlet portletModel, Portlet portlet,
		PortletConfig portletConfig, PortletContext portletContext,
		InvokerFilterContainer invokerFilterContainer, boolean checkAuthToken,
		boolean facesPortlet, boolean headerPortlet) {

		_initialize(
			portletModel, portlet, portletConfig, portletContext,
			invokerFilterContainer, checkAuthToken, facesPortlet,
			headerPortlet);
	}

	public InvokerPortletImpl(
		com.liferay.portal.kernel.model.Portlet portletModel, Portlet portlet,
		PortletContext portletContext,
		InvokerFilterContainer invokerFilterContainer) {

		Map initParams = portletModel.getInitParams();

		boolean checkAuthToken = GetterUtil.getBoolean(
			initParams.get("check-auth-token"), true);

		boolean facesPortlet = false;

		Class portletClass = portlet.getClass();

		if (ClassUtil.isSubclass(
				portletClass, "javax.portlet.faces.GenericFacesPortlet")) {

			facesPortlet = true;
		}
		else if (portlet instanceof InvokerPortlet) {
			InvokerPortlet invokerPortlet = (InvokerPortlet)portlet;

			facesPortlet = invokerPortlet.isFacesPortlet();
		}

		boolean headerPortlet = PortletTypeUtil.isHeaderPortlet(portlet);

		_initialize(
			portletModel, portlet, null, portletContext, invokerFilterContainer,
			checkAuthToken, facesPortlet, headerPortlet);
	}

	@Override
	public void destroy() {
		if (PortletIdCodec.hasInstanceId(_portletModel.getPortletId())) {
			if (_log.isWarnEnabled()) {
				_log.warn("Destroying an instanced portlet is not allowed");
			}

			return;
		}

		Thread currentThread = Thread.currentThread();

		ClassLoader contextClassLoader = currentThread.getContextClassLoader();

		try {
			if (_portletClassLoader != null) {
				currentThread.setContextClassLoader(_portletClassLoader);
			}

			cleanUp();

			_portlet.destroy();
		}
		finally {
			if (_portletClassLoader != null) {
				currentThread.setContextClassLoader(contextClassLoader);
			}
		}
	}

	@Override
	public List getActionFilters() {
		return _invokerFilterContainer.getActionFilters();
	}

	@Override
	public List getEventFilters() {
		return _invokerFilterContainer.getEventFilters();
	}

	@Override
	public Integer getExpCache() {
		return _expCache;
	}

	@Override
	public List getHeaderFilters() {
		return _invokerFilterContainer.getHeaderFilters();
	}

	@Override
	public Portlet getPortlet() {
		return _portlet;
	}

	@Override
	public ClassLoader getPortletClassLoader() {
		if (_portlet instanceof InvokerPortlet) {
			InvokerPortlet invokerPortlet = (InvokerPortlet)_portlet;

			return invokerPortlet.getPortletClassLoader();
		}

		ClassLoader classLoader =
			(ClassLoader)_liferayPortletContext.getAttribute(
				PluginContextListener.PLUGIN_CLASS_LOADER);

		if (classLoader != null) {
			return classLoader;
		}

		Class portletClass = _portlet.getClass();

		return portletClass.getClassLoader();
	}

	@Override
	public PortletConfig getPortletConfig() {
		return _liferayPortletConfig;
	}

	@Override
	public PortletContext getPortletContext() {
		return _liferayPortletContext;
	}

	@Override
	public Portlet getPortletInstance() {
		return _portlet;
	}

	@Override
	public List getRenderFilters() {
		return _invokerFilterContainer.getRenderFilters();
	}

	@Override
	public List getResourceFilters() {
		return _invokerFilterContainer.getResourceFilters();
	}

	@Override
	public void init(PortletConfig portletConfig) throws PortletException {
		_liferayPortletConfig = (LiferayPortletConfig)portletConfig;

		Thread currentThread = Thread.currentThread();

		ClassLoader contextClassLoader = currentThread.getContextClassLoader();

		_portletClassLoader = getPortletClassLoader();

		try {
			if (_portletClassLoader != null) {
				currentThread.setContextClassLoader(_portletClassLoader);
			}

			_portlet.init(portletConfig);
		}
		catch (Throwable throwable) {
			cleanUp();

			throw throwable;
		}
		finally {
			if (_portletClassLoader != null) {
				currentThread.setContextClassLoader(contextClassLoader);
			}
		}
	}

	@Override
	public boolean isCheckAuthToken() {
		return _checkAuthToken;
	}

	@Override
	public boolean isFacesPortlet() {
		return _facesPortlet;
	}

	@Override
	public boolean isHeaderPortlet() {
		return _headerPortlet;
	}

	@Override
	public void processAction(
		ActionRequest actionRequest, ActionResponse actionResponse) {

		StopWatch stopWatch = new StopWatch();

		stopWatch.start();

		try {
			invokeAction(actionRequest, actionResponse);
		}
		catch (Exception exception) {
			processException(exception, actionRequest, actionResponse);
		}

		if (_log.isDebugEnabled()) {
			_log.debug(
				StringBundler.concat(
					"processAction for ", _portletId, " takes ",
					stopWatch.getTime(), " ms"));
		}
	}

	@Override
	public void processEvent(
		EventRequest eventRequest, EventResponse eventResponse) {

		StopWatch stopWatch = new StopWatch();

		stopWatch.start();

		try {
			invokeEvent(eventRequest, eventResponse);
		}
		catch (Exception exception) {
			processException(exception, eventRequest, eventResponse);
		}

		if (_log.isDebugEnabled()) {
			_log.debug(
				StringBundler.concat(
					"processEvent for ", _portletId, " takes ",
					stopWatch.getTime(), " ms"));
		}
	}

	@Override
	public void render(
			RenderRequest renderRequest, RenderResponse renderResponse)
		throws IOException, PortletException {

		PortletException portletException =
			(PortletException)renderRequest.getAttribute(_errorKey);

		if (portletException != null) {
			throw portletException;
		}

		StopWatch stopWatch = new StopWatch();

		stopWatch.start();

		String remoteUser = renderRequest.getRemoteUser();

		if ((remoteUser == null) || (_expCache == null) ||
			(_expCache.intValue() == 0)) {

			invokeRender(renderRequest, renderResponse);
		}
		else {
			RenderResponseImpl renderResponseImpl =
				(RenderResponseImpl)renderResponse;

			BufferCacheServletResponse bufferCacheServletResponse =
				(BufferCacheServletResponse)
					renderResponseImpl.getHttpServletResponse();

			long now = System.currentTimeMillis();

			Layout layout = (Layout)renderRequest.getAttribute(WebKeys.LAYOUT);

			Map sessionResponses =
				InvokerPortletUtil.getResponses(
					renderRequest.getPortletSession());

			String sessionResponseId = InvokerPortletUtil.encodeResponseKey(
				layout.getPlid(), _portletId,
				LanguageUtil.getLanguageId(renderRequest));

			InvokerPortletResponse response = sessionResponses.get(
				sessionResponseId);

			if (response == null) {
				String title = invokeRender(renderRequest, renderResponse);

				response = new InvokerPortletResponse(
					title, bufferCacheServletResponse.getString(),
					now + (Time.SECOND * _expCache.intValue()));

				sessionResponses.put(sessionResponseId, response);
			}
			else if ((response.getTime() < now) && (_expCache.intValue() > 0)) {
				response.setTitle(invokeRender(renderRequest, renderResponse));

				response.setContent(bufferCacheServletResponse.getString());
				response.setTime(now + (Time.SECOND * _expCache.intValue()));
			}
			else {
				renderResponseImpl.setTitle(response.getTitle());

				PrintWriter printWriter =
					bufferCacheServletResponse.getWriter();

				printWriter.print(response.getContent());
			}
		}

		RenderResponseImpl renderResponseImpl =
			(RenderResponseImpl)renderResponse;

		Map properties = renderResponseImpl.getProperties();

		if (properties.containsKey("clear-request-parameters")) {
			RenderRequestImpl renderRequestImpl =
				(RenderRequestImpl)renderRequest;

			renderRequestImpl.clearRenderParameters();
		}

		if (_log.isDebugEnabled()) {
			_log.debug(
				StringBundler.concat(
					"render for ", _portletId, " takes ", stopWatch.getTime(),
					" ms"));
		}
	}

	@Override
	public void renderHeaders(
			HeaderRequest headerRequest, HeaderResponse headerResponse)
		throws IOException, PortletException {

		PortletException portletException =
			(PortletException)headerRequest.getAttribute(_errorKey);

		if (portletException != null) {
			throw portletException;
		}

		StopWatch stopWatch = new StopWatch();

		stopWatch.start();

		String remoteUser = headerRequest.getRemoteUser();

		if ((remoteUser == null) || (_expCache == null) || (_expCache == 0)) {
			invokeHeader(headerRequest, headerResponse);
		}
		else {
			HeaderResponseImpl headerResponseImpl =
				(HeaderResponseImpl)headerResponse;

			BufferCacheServletResponse bufferCacheServletResponse =
				(BufferCacheServletResponse)
					headerResponseImpl.getHttpServletResponse();

			long now = System.currentTimeMillis();

			Layout layout = (Layout)headerRequest.getAttribute(WebKeys.LAYOUT);

			Map sessionResponses =
				InvokerPortletUtil.getResponses(
					headerRequest.getPortletSession());

			String sessionResponseId = InvokerPortletUtil.encodeResponseKey(
				layout.getPlid(), _portletId,
				LanguageUtil.getLanguageId(headerRequest));

			InvokerPortletResponse response = sessionResponses.get(
				sessionResponseId);

			if (response == null) {
				invokeHeader(headerRequest, headerResponse);
			}
			else if ((response.getTime() < now) && (_expCache > 0)) {
				invokeHeader(headerRequest, headerResponse);

				response.setContent(bufferCacheServletResponse.getString());
			}
			else {
				headerResponseImpl.setTitle(response.getTitle());

				PrintWriter printWriter =
					bufferCacheServletResponse.getWriter();

				printWriter.print(response.getContent());
			}
		}

		if (_log.isDebugEnabled()) {
			_log.debug(
				StringBundler.concat(
					"header for", _portletId, " takes ", stopWatch.getTime(),
					" ms"));
		}
	}

	@Override
	public void serveResource(
		ResourceRequest resourceRequest, ResourceResponse resourceResponse) {

		StopWatch stopWatch = new StopWatch();

		stopWatch.start();

		try {
			invokeResource(resourceRequest, resourceResponse);
		}
		catch (Exception exception) {
			processException(exception, resourceRequest, resourceResponse);
		}

		if (_log.isDebugEnabled()) {
			_log.debug(
				StringBundler.concat(
					"serveResource for ", _portletId, " takes ",
					stopWatch.getTime(), " ms"));
		}
	}

	@Override
	public void setPortletFilters() {
	}

	protected void cleanUp() {
		try {
			Closeable closeable = (Closeable)_invokerFilterContainer;

			closeable.close();
		}
		catch (IOException ioException) {
			_log.error("Unable to close invoker filter container", ioException);
		}
	}

	protected void invoke(
			LiferayPortletRequest liferayPortletRequest,
			LiferayPortletResponse liferayPortletResponse, String lifecycle,
			List filters)
		throws IOException, PortletException {

		FilterChain filterChain = new FilterChainImpl(_portlet, filters);

		if (_liferayPortletConfig.isWARFile()) {
			String invokerPortletName = _liferayPortletConfig.getInitParameter(
				INIT_INVOKER_PORTLET_NAME);

			if (invokerPortletName == null) {
				invokerPortletName = PortalUtil.getJsSafePortletId(
					_liferayPortletConfig.getPortletName());
			}

			String path = StringPool.SLASH + invokerPortletName + "/invoke";

			ServletContext servletContext =
				_liferayPortletContext.getServletContext();

			RequestDispatcher requestDispatcher =
				servletContext.getRequestDispatcher(path);

			HttpServletRequest httpServletRequest =
				liferayPortletRequest.getHttpServletRequest();
			HttpServletResponse httpServletResponse =
				liferayPortletResponse.getHttpServletResponse();

			httpServletRequest.setAttribute(
				JavaConstants.JAVAX_PORTLET_PORTLET, _portlet);
			httpServletRequest.setAttribute(
				PortletRequest.LIFECYCLE_PHASE, lifecycle);
			httpServletRequest.setAttribute(
				PortletServlet.PORTLET_SERVLET_FILTER_CHAIN, filterChain);

			try {

				// Resource phase must be a forward because includes do not
				// allow you to specify the content type or headers

				if (lifecycle.equals(PortletRequest.RESOURCE_PHASE)) {
					requestDispatcher.forward(
						httpServletRequest, httpServletResponse);
				}
				else {
					requestDispatcher.include(
						httpServletRequest, httpServletResponse);
				}
			}
			catch (ServletException servletException) {
				Throwable throwable = servletException.getRootCause();

				if (throwable instanceof PortletException) {
					throw (PortletException)throwable;
				}

				throw new PortletException(throwable);
			}
		}
		else {
			PortletFilterUtil.doFilter(
				liferayPortletRequest, liferayPortletResponse, lifecycle,
				filterChain);
		}

		liferayPortletResponse.transferMarkupHeadElements();

		Map properties =
			liferayPortletResponse.getProperties();

		if (MapUtil.isNotEmpty(properties) && (_expCache != null)) {
			String[] expCache = properties.get(RenderResponse.EXPIRATION_CACHE);

			if ((expCache != null) && (expCache.length > 0) &&
				(expCache[0] != null)) {

				_expCache = Integer.valueOf(GetterUtil.getInteger(expCache[0]));
			}
		}
	}

	protected void invokeAction(
			ActionRequest actionRequest, ActionResponse actionResponse)
		throws IOException, PortletException {

		invoke(
			PortalUtil.getLiferayPortletRequest(actionRequest),
			PortalUtil.getLiferayPortletResponse(actionResponse),
			PortletRequest.ACTION_PHASE,
			_invokerFilterContainer.getActionFilters());
	}

	protected void invokeEvent(
			EventRequest eventRequest, EventResponse eventResponse)
		throws IOException, PortletException {

		invoke(
			PortalUtil.getLiferayPortletRequest(eventRequest),
			PortalUtil.getLiferayPortletResponse(eventResponse),
			PortletRequest.EVENT_PHASE,
			_invokerFilterContainer.getEventFilters());
	}

	protected void invokeHeader(
			HeaderRequest headerRequest, HeaderResponse headerResponse)
		throws IOException, PortletException {

		LiferayPortletRequest liferayPortletRequest =
			PortalUtil.getLiferayPortletRequest(headerRequest);
		LiferayPortletResponse liferayPortletResponse =
			PortalUtil.getLiferayPortletResponse(headerResponse);

		try {
			invoke(
				liferayPortletRequest, liferayPortletResponse,
				PortletRequest.HEADER_PHASE,
				_invokerFilterContainer.getHeaderFilters());
		}
		catch (Exception exception) {
			processException(exception, headerRequest, headerResponse);

			throw exception;
		}
	}

	protected String invokeRender(
			RenderRequest renderRequest, RenderResponse renderResponse)
		throws IOException, PortletException {

		LiferayPortletRequest liferayPortletRequest =
			PortalUtil.getLiferayPortletRequest(renderRequest);
		LiferayPortletResponse liferayPortletResponse =
			PortalUtil.getLiferayPortletResponse(renderResponse);

		try {
			invoke(
				liferayPortletRequest, liferayPortletResponse,
				PortletRequest.RENDER_PHASE,
				_invokerFilterContainer.getRenderFilters());
		}
		catch (Exception exception) {
			processException(exception, renderRequest, renderResponse);

			throw exception;
		}

		RenderResponseImpl renderResponseImpl =
			(RenderResponseImpl)renderResponse;

		return renderResponseImpl.getTitle();
	}

	protected void invokeResource(
			ResourceRequest resourceRequest, ResourceResponse resourceResponse)
		throws IOException, PortletException {

		invoke(
			PortalUtil.getLiferayPortletRequest(resourceRequest),
			PortalUtil.getLiferayPortletResponse(resourceResponse),
			PortletRequest.RESOURCE_PHASE,
			_invokerFilterContainer.getResourceFilters());
	}

	protected void processException(
		Exception exception, PortletRequest liferayPortletRequest,
		PortletResponse liferayPortletResponse) {

		if (liferayPortletResponse instanceof StateAwareResponseImpl) {

			// PLT.5.4.7, TCK xxiii and PLT.15.2.6, cxlvi

			StateAwareResponseImpl stateAwareResponseImpl =
				(StateAwareResponseImpl)liferayPortletResponse;

			stateAwareResponseImpl.reset();
		}

		if (exception instanceof RuntimeException) {

			// PLT.5.4.7, TCK xxv

			exception = new PortletException(exception);
		}

		if (exception instanceof UnavailableException) {

			// PLT.5.4.7, TCK xxiv

			destroy();

			PortletLocalServiceUtil.deletePortlet(_portletModel);
		}

		if (exception instanceof PortletException) {
			if ((liferayPortletResponse instanceof StateAwareResponseImpl) &&
				!(exception instanceof UnavailableException)) {

				return;
			}

			if (!(liferayPortletRequest instanceof RenderRequest)) {
				liferayPortletRequest.setAttribute(_errorKey, exception);
			}
		}
		else {
			ReflectionUtil.throwException(exception);
		}
	}

	private void _initialize(
		com.liferay.portal.kernel.model.Portlet portletModel, Portlet portlet,
		PortletConfig portletConfig, PortletContext portletContext,
		InvokerFilterContainer invokerFilterContainer, boolean checkAuthToken,
		boolean facesPortlet, boolean headerPortlet) {

		_portletModel = portletModel;
		_portlet = portlet;
		_invokerFilterContainer = invokerFilterContainer;
		_checkAuthToken = checkAuthToken;
		_facesPortlet = facesPortlet;
		_headerPortlet = headerPortlet;

		_expCache = portletModel.getExpCache();
		_liferayPortletConfig = (LiferayPortletConfig)portletConfig;
		_liferayPortletContext = (LiferayPortletContext)portletContext;

		_portletId = _portletModel.getPortletId();

		_errorKey = _portletId.concat(PortletException.class.getName());

		if (_log.isDebugEnabled()) {
			com.liferay.portal.kernel.model.Portlet portletContextPortlet =
				_liferayPortletContext.getPortlet();

			_log.debug(
				"Create instance cache wrapper for " +
					portletContextPortlet.getPortletId());
		}
	}

	private static final Log _log = LogFactoryUtil.getLog(
		InvokerPortletImpl.class);

	private boolean _checkAuthToken;
	private String _errorKey;
	private Integer _expCache;
	private boolean _facesPortlet;
	private boolean _headerPortlet;
	private InvokerFilterContainer _invokerFilterContainer;
	private LiferayPortletConfig _liferayPortletConfig;
	private LiferayPortletContext _liferayPortletContext;
	private Portlet _portlet;
	private ClassLoader _portletClassLoader;
	private String _portletId;
	private com.liferay.portal.kernel.model.Portlet _portletModel;

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy