/**
* 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;
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.model.PortletConstants;
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.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.ClassLoaderUtil;
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.ReflectionUtil;
import com.liferay.portal.kernel.util.StringBundler;
import com.liferay.portal.kernel.util.StringPool;
import com.liferay.portal.kernel.util.StringUtil;
import com.liferay.portal.kernel.util.Time;
import com.liferay.portal.kernel.util.WebKeys;
import com.liferay.portal.tools.deploy.PortletDeployer;
import java.io.Closeable;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
import javax.portlet.EventRequest;
import javax.portlet.EventResponse;
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.PortletSession;
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.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 javax.servlet.http.HttpSession;
import org.apache.commons.lang.time.StopWatch;
/**
* @author Brian Wing Shun Chan
* @author Brian Myunghun Kim
* @author Raymond Augé
*/
public class InvokerPortletImpl
implements InvokerFilterContainer, InvokerPortlet {
public static void clearResponse(
HttpSession session, long plid, String portletId, String languageId) {
String sesResponseId = encodeResponseKey(plid, portletId, languageId);
getResponses(session).remove(sesResponseId);
}
public static void clearResponses(HttpSession session) {
getResponses(session).clear();
}
public static void clearResponses(PortletSession session) {
getResponses(session).clear();
}
public static String encodeResponseKey(
long plid, String portletId, String languageId) {
StringBundler sb = new StringBundler(5);
sb.append(StringUtil.toHexString(plid));
sb.append(StringPool.UNDERLINE);
sb.append(portletId);
sb.append(StringPool.UNDERLINE);
sb.append(languageId);
return sb.toString();
}
public static Map<String, InvokerPortletResponse> getResponses(
HttpSession session) {
Map<String, InvokerPortletResponse> responses =
(Map<String, InvokerPortletResponse>)session.getAttribute(
WebKeys.CACHE_PORTLET_RESPONSES);
if (responses == null) {
responses = new ConcurrentHashMap<>();
session.setAttribute(WebKeys.CACHE_PORTLET_RESPONSES, responses);
}
return responses;
}
public static Map<String, InvokerPortletResponse> getResponses(
PortletSession portletSession) {
return getResponses(
((PortletSessionImpl)portletSession).getHttpSession());
}
public InvokerPortletImpl(
com.liferay.portal.kernel.model.Portlet portletModel, Portlet portlet,
PortletConfig portletConfig, PortletContext portletContext,
InvokerFilterContainer invokerFilterContainer, boolean checkAuthToken,
boolean facesPortlet, boolean strutsPortlet,
boolean strutsBridgePortlet) {
_initialize(
portletModel, portlet, portletConfig, portletContext,
invokerFilterContainer, checkAuthToken, facesPortlet, strutsPortlet,
strutsBridgePortlet);
}
public InvokerPortletImpl(
com.liferay.portal.kernel.model.Portlet portletModel, Portlet portlet,
PortletContext portletContext,
InvokerFilterContainer invokerFilterContainer) {
Map<String, String> initParams = portletModel.getInitParams();
boolean checkAuthToken = GetterUtil.getBoolean(
initParams.get("check-auth-token"), true);
boolean facesPortlet = false;
if (ClassUtil.isSubclass(
portlet.getClass(), PortletDeployer.JSF_STANDARD)) {
facesPortlet = true;
}
boolean strutsPortlet = ClassUtil.isSubclass(
portlet.getClass(), StrutsPortlet.class);
boolean strutsBridgePortlet = ClassUtil.isSubclass(
portlet.getClass(),
"org.apache.portals.bridges.struts.StrutsPortlet");
_initialize(
portletModel, portlet, null, portletContext, invokerFilterContainer,
checkAuthToken, facesPortlet, strutsPortlet, strutsBridgePortlet);
}
@Override
public void destroy() {
if (PortletConstants.hasInstanceId(_portletModel.getPortletId())) {
if (_log.isWarnEnabled()) {
_log.warn("Destroying an instanced portlet is not allowed");
}
return;
}
ClassLoader contextClassLoader =
ClassLoaderUtil.getContextClassLoader();
try {
if (_portletClassLoader != null) {
ClassLoaderUtil.setContextClassLoader(_portletClassLoader);
}
Closeable closeable = (Closeable)_invokerFilterContainer;
closeable.close();
_portlet.destroy();
}
catch (IOException ioe) {
_log.error(ioe, ioe);
}
finally {
if (_portletClassLoader != null) {
ClassLoaderUtil.setContextClassLoader(contextClassLoader);
}
}
}
@Override
public List<ActionFilter> getActionFilters() {
return _invokerFilterContainer.getActionFilters();
}
@Override
public List<EventFilter> getEventFilters() {
return _invokerFilterContainer.getEventFilters();
}
@Override
public Integer getExpCache() {
return _expCache;
}
@Override
public Portlet getPortlet() {
return _portlet;
}
@Override
public ClassLoader getPortletClassLoader() {
ClassLoader classLoader =
(ClassLoader)_liferayPortletContext.getAttribute(
PluginContextListener.PLUGIN_CLASS_LOADER);
if (classLoader == null) {
classLoader = ClassLoaderUtil.getPortalClassLoader();
}
return classLoader;
}
@Override
public PortletConfig getPortletConfig() {
return _liferayPortletConfig;
}
@Override
public PortletContext getPortletContext() {
return _liferayPortletContext;
}
@Override
public Portlet getPortletInstance() {
return _portlet;
}
@Override
public List<RenderFilter> getRenderFilters() {
return _invokerFilterContainer.getRenderFilters();
}
@Override
public List<ResourceFilter> getResourceFilters() {
return _invokerFilterContainer.getResourceFilters();
}
@Override
public void init(PortletConfig portletConfig) throws PortletException {
_liferayPortletConfig = (LiferayPortletConfig)portletConfig;
ClassLoader contextClassLoader =
ClassLoaderUtil.getContextClassLoader();
_portletClassLoader = getPortletClassLoader();
try {
if (_portletClassLoader != null) {
ClassLoaderUtil.setContextClassLoader(_portletClassLoader);
}
_portlet.init(portletConfig);
}
finally {
if (_portletClassLoader != null) {
ClassLoaderUtil.setContextClassLoader(contextClassLoader);
}
}
}
@Override
public boolean isCheckAuthToken() {
return _checkAuthToken;
}
@Override
public boolean isFacesPortlet() {
return _facesPortlet;
}
@Override
public boolean isStrutsBridgePortlet() {
return _strutsBridgePortlet;
}
@Override
public boolean isStrutsPortlet() {
return _strutsPortlet;
}
@Override
public void processAction(
ActionRequest actionRequest, ActionResponse actionResponse) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
try {
invokeAction(actionRequest, actionResponse);
}
catch (Exception e) {
processException(e, actionRequest, actionResponse);
}
if (_log.isDebugEnabled()) {
_log.debug(
"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 e) {
processException(e, eventRequest, eventResponse);
}
if (_log.isDebugEnabled()) {
_log.debug(
"processEvent for " + _portletId + " takes " +
stopWatch.getTime() + " ms");
}
}
@Override
public void render(
RenderRequest renderRequest, RenderResponse renderResponse)
throws IOException, PortletException {
PortletException portletException =
(PortletException)renderRequest.getAttribute(
_portletId + PortletException.class.getName());
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();
PortletSession portletSession = renderRequest.getPortletSession();
long now = System.currentTimeMillis();
Layout layout = (Layout)renderRequest.getAttribute(WebKeys.LAYOUT);
Map<String, InvokerPortletResponse> sessionResponses = getResponses(
portletSession);
String sessionResponseId = 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)) {
String title = invokeRender(renderRequest, renderResponse);
response.setTitle(title);
response.setContent(bufferCacheServletResponse.getString());
response.setTime(now + Time.SECOND * _expCache.intValue());
}
else {
renderResponseImpl.setTitle(response.getTitle());
PrintWriter printWriter =
bufferCacheServletResponse.getWriter();
printWriter.print(response.getContent());
}
}
Map<String, String[]> properties =
((RenderResponseImpl)renderResponse).getProperties();
if (properties.containsKey("clear-request-parameters")) {
((RenderRequestImpl)renderRequest).clearRenderParameters();
}
if (_log.isDebugEnabled()) {
_log.debug(
"render 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 e) {
processException(e, resourceRequest, resourceResponse);
}
if (_log.isDebugEnabled()) {
_log.debug(
"serveResource for " + _portletId + " takes " +
stopWatch.getTime() + " ms");
}
}
/**
* @deprecated As of 7.0.0
*/
@Deprecated
@Override
public void setPortletFilters() {
}
protected void invoke(
LiferayPortletRequest portletRequest,
LiferayPortletResponse portletResponse, String lifecycle,
List<? extends PortletFilter> 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 = _liferayPortletConfig.getPortletName();
}
String path = StringPool.SLASH + invokerPortletName + "/invoke";
ServletContext servletContext =
_liferayPortletContext.getServletContext();
RequestDispatcher requestDispatcher =
servletContext.getRequestDispatcher(path);
HttpServletRequest request = portletRequest.getHttpServletRequest();
HttpServletResponse response =
portletResponse.getHttpServletResponse();
request.setAttribute(JavaConstants.JAVAX_PORTLET_PORTLET, _portlet);
request.setAttribute(PortletRequest.LIFECYCLE_PHASE, lifecycle);
request.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(request, response);
}
else {
requestDispatcher.include(request, response);
}
}
catch (ServletException se) {
Throwable cause = se.getRootCause();
if (cause instanceof PortletException) {
throw (PortletException)cause;
}
throw new PortletException(cause);
}
}
else {
PortletFilterUtil.doFilter(
portletRequest, portletResponse, lifecycle, filterChain);
}
portletResponse.transferMarkupHeadElements();
Map<String, String[]> properties = portletResponse.getProperties();
if (MapUtil.isNotEmpty(properties)) {
if (_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 {
LiferayPortletRequest portletRequest =
(LiferayPortletRequest)actionRequest;
LiferayPortletResponse portletResponse =
(LiferayPortletResponse)actionResponse;
invoke(
portletRequest, portletResponse, PortletRequest.ACTION_PHASE,
_invokerFilterContainer.getActionFilters());
}
protected void invokeEvent(
EventRequest eventRequest, EventResponse eventResponse)
throws IOException, PortletException {
LiferayPortletRequest portletRequest =
(LiferayPortletRequest)eventRequest;
LiferayPortletResponse portletResponse =
(LiferayPortletResponse)eventResponse;
invoke(
portletRequest, portletResponse, PortletRequest.EVENT_PHASE,
_invokerFilterContainer.getEventFilters());
}
protected String invokeRender(
RenderRequest renderRequest, RenderResponse renderResponse)
throws IOException, PortletException {
LiferayPortletRequest portletRequest =
(LiferayPortletRequest)renderRequest;
LiferayPortletResponse portletResponse =
(LiferayPortletResponse)renderResponse;
try {
invoke(
portletRequest, portletResponse, PortletRequest.RENDER_PHASE,
_invokerFilterContainer.getRenderFilters());
}
catch (Exception e) {
processException(e, renderRequest, renderResponse);
throw e;
}
RenderResponseImpl renderResponseImpl =
(RenderResponseImpl)renderResponse;
return renderResponseImpl.getTitle();
}
protected void invokeResource(
ResourceRequest resourceRequest, ResourceResponse resourceResponse)
throws IOException, PortletException {
LiferayPortletRequest portletRequest =
(LiferayPortletRequest)resourceRequest;
LiferayPortletResponse portletResponse =
(LiferayPortletResponse)resourceResponse;
invoke(
portletRequest, portletResponse, PortletRequest.RESOURCE_PHASE,
_invokerFilterContainer.getResourceFilters());
}
protected void processException(
Exception e, PortletRequest portletRequest,
PortletResponse portletResponse) {
if (portletResponse instanceof StateAwareResponseImpl) {
// PLT.5.4.7, TCK xxiii and PLT.15.2.6, cxlvi
StateAwareResponseImpl stateAwareResponseImpl =
(StateAwareResponseImpl)portletResponse;
stateAwareResponseImpl.reset();
}
if (e instanceof RuntimeException) {
// PLT.5.4.7, TCK xxv
e = new PortletException(e);
}
if (e instanceof UnavailableException) {
// PLT.5.4.7, TCK xxiv
destroy();
PortletLocalServiceUtil.deletePortlet(_portletModel);
}
if (e instanceof PortletException) {
if (!(portletRequest instanceof RenderRequest)) {
portletRequest.setAttribute(
_portletId + PortletException.class.getName(), e);
}
}
else {
ReflectionUtil.throwException(e);
}
}
private void _initialize(
com.liferay.portal.kernel.model.Portlet portletModel, Portlet portlet,
PortletConfig portletConfig, PortletContext portletContext,
InvokerFilterContainer invokerFilterContainer, boolean checkAuthToken,
boolean facesPortlet, boolean strutsPortlet,
boolean strutsBridgePortlet) {
_portletModel = portletModel;
_portlet = portlet;
_liferayPortletConfig = (LiferayPortletConfig)portletConfig;
_portletId = _portletModel.getPortletId();
_liferayPortletContext = (LiferayPortletContext)portletContext;
_invokerFilterContainer = invokerFilterContainer;
_checkAuthToken = checkAuthToken;
_facesPortlet = facesPortlet;
_strutsPortlet = strutsPortlet;
_strutsBridgePortlet = strutsBridgePortlet;
_expCache = portletModel.getExpCache();
if (_log.isDebugEnabled()) {
_log.debug(
"Create instance cache wrapper for " +
_liferayPortletContext.getPortlet().getPortletId());
}
}
private static final Log _log = LogFactoryUtil.getLog(
InvokerPortletImpl.class);
private boolean _checkAuthToken;
private Integer _expCache;
private boolean _facesPortlet;
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;
private boolean _strutsBridgePortlet;
private boolean _strutsPortlet;
}