/**
* 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.taglib.portletext;
import com.liferay.portal.kernel.json.JSONFactoryUtil;
import com.liferay.portal.kernel.json.JSONObject;
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.LayoutTypePortlet;
import com.liferay.portal.kernel.model.Portlet;
import com.liferay.portal.kernel.model.PortletInstance;
import com.liferay.portal.kernel.model.PortletWrapper;
import com.liferay.portal.kernel.portlet.PortletContainerUtil;
import com.liferay.portal.kernel.portlet.PortletJSONUtil;
import com.liferay.portal.kernel.portlet.PortletLayoutListener;
import com.liferay.portal.kernel.portlet.PortletParameterUtil;
import com.liferay.portal.kernel.portlet.PortletPreferencesFactoryConstants;
import com.liferay.portal.kernel.portlet.PortletPreferencesFactoryUtil;
import com.liferay.portal.kernel.portlet.PortletProvider;
import com.liferay.portal.kernel.portlet.PortletProviderUtil;
import com.liferay.portal.kernel.portlet.RestrictPortletServletRequest;
import com.liferay.portal.kernel.security.permission.ActionKeys;
import com.liferay.portal.kernel.service.PortletLocalServiceUtil;
import com.liferay.portal.kernel.service.PortletPreferencesLocalServiceUtil;
import com.liferay.portal.kernel.service.permission.LayoutPermissionUtil;
import com.liferay.portal.kernel.servlet.DynamicServletRequest;
import com.liferay.portal.kernel.theme.ThemeDisplay;
import com.liferay.portal.kernel.util.AutoResetThreadLocal;
import com.liferay.portal.kernel.util.MapUtil;
import com.liferay.portal.kernel.util.PortalUtil;
import com.liferay.portal.kernel.util.PortletKeys;
import com.liferay.portal.kernel.util.StringPool;
import com.liferay.portal.kernel.util.Validator;
import com.liferay.portal.kernel.util.WebKeys;
import com.liferay.taglib.DirectTag;
import com.liferay.taglib.servlet.PipingServletResponse;
import com.liferay.taglib.util.PortalIncludeUtil;
import java.util.Map;
import java.util.Objects;
import java.util.Stack;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.jsp.JspException;
import javax.servlet.jsp.PageContext;
import javax.servlet.jsp.tagext.TagSupport;
/**
* @author Brian Wing Shun Chan
*/
public class RuntimeTag extends TagSupport implements DirectTag {
public static void doTag(
String portletName, PageContext pageContext,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
doTag(portletName, null, pageContext, request, response);
}
public static void doTag(
String portletProviderClassName,
PortletProvider.Action portletProviderAction, String instanceId,
String queryString, String defaultPreferences,
boolean persistSettings, PageContext pageContext,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
String portletId = PortletProviderUtil.getPortletId(
portletProviderClassName, portletProviderAction);
if (Validator.isNotNull(portletId)) {
doTag(
portletId, instanceId, queryString, _SETTINGS_SCOPE_DEFAULT,
defaultPreferences, persistSettings, pageContext, request,
response);
}
else {
ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
WebKeys.THEME_DISPLAY);
Layout layout = themeDisplay.getLayout();
if (!layout.isTypeControlPanel() &&
!LayoutPermissionUtil.contains(
themeDisplay.getPermissionChecker(), layout,
ActionKeys.UPDATE)) {
return;
}
String errorMessage = LanguageUtil.format(
request, "an-app-that-can-x-x-belongs-here",
new Object[] {
portletProviderAction.name(), portletProviderClassName
},
false);
request.setAttribute(
"liferay-portlet:runtime:errorMessage", errorMessage);
PortalIncludeUtil.include(pageContext, _ERROR_PAGE);
}
}
public static void doTag(
String portletName, String queryString, PageContext pageContext,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
doTag(portletName, queryString, null, pageContext, request, response);
}
public static void doTag(
String portletName, String queryString, String defaultPreferences,
PageContext pageContext, HttpServletRequest request,
HttpServletResponse response)
throws Exception {
doTag(
portletName, StringPool.BLANK, queryString, _SETTINGS_SCOPE_DEFAULT,
defaultPreferences, true, pageContext, request, response);
}
public static void doTag(
String portletName, String instanceId, String queryString,
String defaultPreferences, PageContext pageContext,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
doTag(
portletName, instanceId, queryString, _SETTINGS_SCOPE_DEFAULT,
defaultPreferences, true, pageContext, request, response);
}
public static void doTag(
String portletName, String instanceId, String queryString,
String settingsScope, String defaultPreferences,
boolean persistSettings, PageContext pageContext,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
if (pageContext != null) {
if (response == pageContext.getResponse()) {
response = PipingServletResponse.createPipingServletResponse(
pageContext);
}
else {
response = new PipingServletResponse(
response, pageContext.getOut());
}
}
PortletInstance portletInstance =
PortletInstance.fromPortletInstanceKey(portletName);
if (Validator.isNotNull(instanceId)) {
portletInstance = new PortletInstance(
portletInstance.getPortletName(), portletInstance.getUserId(),
instanceId);
}
RestrictPortletServletRequest restrictPortletServletRequest =
new RestrictPortletServletRequest(
PortalUtil.getOriginalServletRequest(request));
queryString = PortletParameterUtil.addNamespace(
portletInstance.getPortletInstanceKey(), queryString);
Map<String, String[]> parameterMap = request.getParameterMap();
if (!Objects.equals(
portletInstance.getPortletInstanceKey(),
request.getParameter("p_p_id"))) {
parameterMap = MapUtil.filterByKeys(
parameterMap, (key) -> !key.startsWith("p_p_"));
}
request = DynamicServletRequest.addQueryString(
restrictPortletServletRequest, parameterMap, queryString, false);
try {
request.setAttribute(WebKeys.RENDER_PORTLET_RESOURCE, Boolean.TRUE);
ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
WebKeys.THEME_DISPLAY);
Portlet portlet = getPortlet(
themeDisplay.getCompanyId(),
portletInstance.getPortletInstanceKey());
Stack<String> embeddedPortletIds = _embeddedPortletIds.get();
if (embeddedPortletIds == null) {
embeddedPortletIds = new Stack<>();
_embeddedPortletIds.set(embeddedPortletIds);
}
if (embeddedPortletIds.search(portlet.getPortletId()) > -1) {
String errorMessage = LanguageUtil.get(
request, "the-application-cannot-include-itself");
request.setAttribute(
"liferay-portlet:runtime:errorMessage", errorMessage);
PortalIncludeUtil.include(pageContext, _ERROR_PAGE);
return;
}
if (themeDisplay.isStateMaximized()) {
LayoutTypePortlet layoutTypePortlet =
themeDisplay.getLayoutTypePortlet();
if (layoutTypePortlet.hasStateMaxPortletId(
portletInstance.getPortletInstanceKey())) {
// A portlet in the maximized state has already been
// processed
return;
}
}
Layout layout = themeDisplay.getLayout();
request.setAttribute(WebKeys.SETTINGS_SCOPE, settingsScope);
JSONObject jsonObject = null;
boolean writeObject = false;
LayoutTypePortlet layoutTypePortlet =
themeDisplay.getLayoutTypePortlet();
if (persistSettings &&
!layoutTypePortlet.isPortletEmbedded(portlet.getPortletId())) {
PortletPreferencesFactoryUtil.getLayoutPortletSetup(
themeDisplay.getCompanyId(), themeDisplay.getScopeGroupId(),
PortletKeys.PREFS_OWNER_TYPE_LAYOUT,
PortletKeys.PREFS_PLID_SHARED,
portletInstance.getPortletInstanceKey(),
defaultPreferences);
writeObject = true;
}
if (PortletPreferencesLocalServiceUtil.getPortletPreferencesCount(
PortletKeys.PREFS_OWNER_TYPE_LAYOUT, themeDisplay.getPlid(),
portletInstance.getPortletInstanceKey()) < 1) {
PortletPreferencesFactoryUtil.getLayoutPortletSetup(
layout, portletInstance.getPortletInstanceKey(),
defaultPreferences);
PortletPreferencesFactoryUtil.getPortletSetup(
request, portletInstance.getPortletInstanceKey(),
defaultPreferences);
PortletLayoutListener portletLayoutListener =
portlet.getPortletLayoutListenerInstance();
if (portletLayoutListener != null) {
portletLayoutListener.onAddToLayout(
portletInstance.getPortletInstanceKey(),
themeDisplay.getPlid());
}
writeObject = true;
}
if (writeObject) {
jsonObject = JSONFactoryUtil.createJSONObject();
PortletJSONUtil.populatePortletJSONObject(
request, StringPool.BLANK, portlet, jsonObject);
}
if (jsonObject != null) {
PortletJSONUtil.writeHeaderPaths(response, jsonObject);
}
embeddedPortletIds.push(portletInstance.getPortletInstanceKey());
PortletContainerUtil.render(request, response, portlet);
embeddedPortletIds.pop();
if (jsonObject != null) {
PortletJSONUtil.writeFooterPaths(response, jsonObject);
}
}
finally {
restrictPortletServletRequest.mergeSharedAttributes();
}
}
@Override
public int doEndTag() throws JspException {
try {
HttpServletRequest request =
(HttpServletRequest)pageContext.getRequest();
Layout layout = (Layout)request.getAttribute(WebKeys.LAYOUT);
if (layout == null) {
return EVAL_PAGE;
}
HttpServletResponse response =
(HttpServletResponse)pageContext.getResponse();
if (Validator.isNotNull(_portletProviderClassName) &&
(_portletProviderAction != null)) {
doTag(
_portletProviderClassName, _portletProviderAction,
_instanceId, _queryString, _defaultPreferences,
_persistSettings, pageContext, request, response);
}
else {
doTag(
_portletName, _instanceId, _queryString, _settingsScope,
_defaultPreferences, _persistSettings, pageContext, request,
response);
}
return EVAL_PAGE;
}
catch (Exception e) {
_log.error(e, e);
throw new JspException(e);
}
}
public void setDefaultPreferences(String defaultPreferences) {
_defaultPreferences = defaultPreferences;
}
public void setInstanceId(String instanceId) {
_instanceId = instanceId;
}
public void setPersistSettings(boolean persistSettings) {
_persistSettings = persistSettings;
}
public void setPortletName(String portletName) {
_portletName = portletName;
}
public void setPortletProviderAction(
PortletProvider.Action portletProviderAction) {
_portletProviderAction = portletProviderAction;
}
public void setPortletProviderClassName(String portletProviderClassName) {
_portletProviderClassName = portletProviderClassName;
}
public void setQueryString(String queryString) {
_queryString = queryString;
}
public void setSettingsScope(String settingsScope) {
_settingsScope = settingsScope;
}
/**
* @see com.liferay.portal.model.impl.LayoutTypePortletImpl#getStaticPortlets(
* String)
*/
protected static Portlet getPortlet(long companyId, String portletId)
throws Exception {
Portlet portlet = PortletLocalServiceUtil.getPortletById(
companyId, portletId);
// See LayoutTypePortletImpl#getStaticPortlets for why we only clone
// non-instanceable portlets
if (!portlet.isInstanceable()) {
portlet = new PortletWrapper(portlet) {
@Override
public boolean getStatic() {
return _staticPortlet;
}
@Override
public boolean isStatic() {
return _staticPortlet;
}
@Override
public void setStatic(boolean staticPortlet) {
_staticPortlet = staticPortlet;
}
private boolean _staticPortlet;
};
}
portlet.setStatic(true);
return portlet;
}
private static final String _ERROR_PAGE =
"/html/taglib/portlet/runtime/error.jsp";
private static final String _SETTINGS_SCOPE_DEFAULT =
PortletPreferencesFactoryConstants.SETTINGS_SCOPE_PORTLET_INSTANCE;
private static final Log _log = LogFactoryUtil.getLog(RuntimeTag.class);
private static final ThreadLocal<Stack<String>> _embeddedPortletIds =
new AutoResetThreadLocal<>(RuntimeTag.class + "._embeddedPortletIds");
private String _defaultPreferences;
private String _instanceId;
private boolean _persistSettings = true;
private String _portletName;
private PortletProvider.Action _portletProviderAction;
private String _portletProviderClassName;
private String _queryString;
private String _settingsScope = _SETTINGS_SCOPE_DEFAULT;
}