/**
* 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.layoutsadmin.util;
import com.liferay.exportimport.kernel.staging.LayoutStagingUtil;
import com.liferay.exportimport.kernel.staging.StagingUtil;
import com.liferay.portal.kernel.dao.orm.QueryUtil;
import com.liferay.portal.kernel.exception.PortalException;
import com.liferay.portal.kernel.json.JSONArray;
import com.liferay.portal.kernel.json.JSONFactoryUtil;
import com.liferay.portal.kernel.json.JSONObject;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.liferay.portal.kernel.model.Group;
import com.liferay.portal.kernel.model.Layout;
import com.liferay.portal.kernel.model.LayoutBranch;
import com.liferay.portal.kernel.model.LayoutConstants;
import com.liferay.portal.kernel.model.LayoutRevision;
import com.liferay.portal.kernel.model.LayoutSetBranch;
import com.liferay.portal.kernel.model.impl.VirtualLayout;
import com.liferay.portal.kernel.security.permission.ActionKeys;
import com.liferay.portal.kernel.service.LayoutLocalServiceUtil;
import com.liferay.portal.kernel.service.LayoutServiceUtil;
import com.liferay.portal.kernel.service.LayoutSetBranchLocalServiceUtil;
import com.liferay.portal.kernel.service.permission.GroupPermissionUtil;
import com.liferay.portal.kernel.service.permission.LayoutPermissionUtil;
import com.liferay.portal.kernel.theme.ThemeDisplay;
import com.liferay.portal.kernel.util.ArrayUtil;
import com.liferay.portal.kernel.util.ParamUtil;
import com.liferay.portal.kernel.util.PortalUtil;
import com.liferay.portal.kernel.util.SessionClicks;
import com.liferay.portal.kernel.util.StringBundler;
import com.liferay.portal.kernel.util.StringPool;
import com.liferay.portal.kernel.util.WebKeys;
import com.liferay.portal.util.PropsValues;
import com.liferay.sites.kernel.util.SitesUtil;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
/**
* @author Brian Wing Shun Chan
* @author Eduardo Lundgren
* @author Bruno Basto
* @author Marcellus Tavares
* @author Zsolt Szabó
* @author Tibor Lipusz
*/
public class LayoutsTreeUtil {
public static String getLayoutsJSON(
HttpServletRequest request, long groupId, boolean privateLayout,
long parentLayoutId, boolean incomplete, String treeId)
throws Exception {
return getLayoutsJSON(
request, groupId, privateLayout, parentLayoutId, null, incomplete,
treeId);
}
public static String getLayoutsJSON(
HttpServletRequest request, long groupId, boolean privateLayout,
long layoutId, int max)
throws Exception {
Layout layout = LayoutLocalServiceUtil.getLayout(
groupId, privateLayout, layoutId);
long parentLayoutId = layout.getParentLayoutId();
long includedLayoutIndex = LayoutServiceUtil.getLayoutsCount(
groupId, privateLayout, parentLayoutId, layout.getPriority());
int total = LayoutServiceUtil.getLayoutsCount(
groupId, privateLayout, parentLayoutId);
int start = (int)includedLayoutIndex - 1;
int end = (int)includedLayoutIndex + max;
if (end > total) {
start = total - max;
end = total;
if (start < 0) {
start = 0;
}
}
List<Layout> layouts = LayoutServiceUtil.getLayouts(
groupId, privateLayout, parentLayoutId, true, start, end);
JSONObject jsonObject = _toJSONObject(request, groupId, layouts, total);
List<Layout> ancestorLayouts = LayoutServiceUtil.getAncestorLayouts(
layout.getPlid());
long[] ancestorLayoutIds = new long[ancestorLayouts.size()];
String[] ancestorLayoutNames = new String[ancestorLayouts.size()];
Locale locale = PortalUtil.getLocale(request);
for (int i = 0; i < ancestorLayouts.size(); i++) {
Layout ancestorLayout = ancestorLayouts.get(i);
ancestorLayoutIds[i] = ancestorLayout.getLayoutId();
ancestorLayoutNames[i] = ancestorLayout.getName(locale);
}
jsonObject.put("ancestorLayoutIds", ancestorLayoutIds);
jsonObject.put("ancestorLayoutNames", ancestorLayoutNames);
jsonObject.put("start", start);
return jsonObject.toString();
}
public static String getLayoutsJSON(
HttpServletRequest request, long groupId, boolean privateLayout,
long parentLayoutId, long[] expandedLayoutIds, boolean incomplete,
String treeId)
throws Exception {
if (_log.isDebugEnabled()) {
StringBundler sb = new StringBundler(13);
sb.append("getLayoutsJSON(groupId=");
sb.append(groupId);
sb.append(", privateLayout=");
sb.append(privateLayout);
sb.append(", parentLayoutId=");
sb.append(parentLayoutId);
sb.append(", expandedLayoutIds=");
sb.append(expandedLayoutIds);
sb.append(", incomplete=");
sb.append(incomplete);
sb.append(", treeId=");
sb.append(treeId);
sb.append(StringPool.CLOSE_PARENTHESIS);
_log.debug(sb.toString());
}
LayoutTreeNodes layoutTreeNodes = _getLayoutTreeNodes(
request, groupId, privateLayout, parentLayoutId, incomplete,
expandedLayoutIds, treeId);
return _toJSON(request, groupId, layoutTreeNodes);
}
public static String getLayoutsJSON(
HttpServletRequest request, long groupId, String treeId)
throws Exception {
if (_log.isDebugEnabled()) {
StringBundler sb = new StringBundler(5);
sb.append("getLayoutsJSON(groupId=");
sb.append(groupId);
sb.append(", treeId=");
sb.append(treeId);
sb.append(StringPool.CLOSE_PARENTHESIS);
_log.debug(sb.toString());
}
LayoutTreeNodes layoutTreeNodes = new LayoutTreeNodes();
layoutTreeNodes.addAll(
_getLayoutTreeNodes(
request, groupId, true,
LayoutConstants.DEFAULT_PARENT_LAYOUT_ID, false, null, treeId));
layoutTreeNodes.addAll(
_getLayoutTreeNodes(
request, groupId, false,
LayoutConstants.DEFAULT_PARENT_LAYOUT_ID, false, null, treeId));
return _toJSON(request, groupId, layoutTreeNodes);
}
private static Layout _fetchCurrentLayout(HttpServletRequest request) {
long selPlid = ParamUtil.getLong(request, "selPlid");
if (selPlid > 0) {
return LayoutLocalServiceUtil.fetchLayout(selPlid);
}
ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
WebKeys.THEME_DISPLAY);
Layout layout = themeDisplay.getLayout();
if (!layout.isTypeControlPanel()) {
return layout;
}
return null;
}
private static List<Layout> _getAncestorLayouts(HttpServletRequest request)
throws Exception {
Layout layout = _fetchCurrentLayout(request);
if (layout == null) {
return Collections.emptyList();
}
List<Layout> ancestorLayouts = LayoutServiceUtil.getAncestorLayouts(
layout.getPlid());
if (_log.isDebugEnabled()) {
StringBundler sb = new StringBundler(7);
sb.append("_getAncestorLayouts(plid=");
sb.append(layout.getPlid());
sb.append(", ancestorLayouts=");
sb.append(ancestorLayouts);
sb.append(", layout=");
sb.append(layout);
sb.append(StringPool.CLOSE_PARENTHESIS);
_log.debug(sb.toString());
}
ancestorLayouts.add(layout);
return ancestorLayouts;
}
private static LayoutTreeNodes _getLayoutTreeNodes(
HttpServletRequest request, long groupId, boolean privateLayout,
long parentLayoutId, boolean incomplete, long[] expandedLayoutIds,
String treeId)
throws Exception {
if (_log.isDebugEnabled()) {
StringBundler sb = new StringBundler(13);
sb.append("_getLayoutTreeNodes(groupId=");
sb.append(groupId);
sb.append(", privateLayout=");
sb.append(privateLayout);
sb.append(", parentLayoutId=");
sb.append(parentLayoutId);
sb.append(", expandedLayoutIds=");
sb.append(expandedLayoutIds);
sb.append(", incomplete=");
sb.append(incomplete);
sb.append(", treeId=");
sb.append(treeId);
sb.append(StringPool.CLOSE_PARENTHESIS);
_log.debug(sb.toString());
}
List<LayoutTreeNode> layoutTreeNodes = new ArrayList<>();
List<Layout> ancestorLayouts = _getAncestorLayouts(request);
List<Layout> layouts = LayoutServiceUtil.getLayouts(
groupId, privateLayout, parentLayoutId, incomplete,
QueryUtil.ALL_POS, QueryUtil.ALL_POS);
for (Layout layout :
_paginateLayouts(
request, groupId, privateLayout, parentLayoutId, layouts,
treeId)) {
LayoutTreeNode layoutTreeNode = new LayoutTreeNode(layout);
LayoutTreeNodes childLayoutTreeNodes = null;
if (_isExpandableLayout(
request, ancestorLayouts, expandedLayoutIds, layout)) {
if (layout instanceof VirtualLayout) {
VirtualLayout virtualLayout = (VirtualLayout)layout;
childLayoutTreeNodes = _getLayoutTreeNodes(
request, virtualLayout.getSourceGroupId(),
virtualLayout.isPrivateLayout(),
virtualLayout.getLayoutId(), incomplete,
expandedLayoutIds, treeId);
}
else {
childLayoutTreeNodes = _getLayoutTreeNodes(
request, groupId, layout.isPrivateLayout(),
layout.getLayoutId(), incomplete, expandedLayoutIds,
treeId);
}
}
else {
int childLayoutsCount = LayoutServiceUtil.getLayoutsCount(
groupId, privateLayout, layout.getLayoutId());
childLayoutTreeNodes = new LayoutTreeNodes(
new ArrayList<LayoutTreeNode>(), childLayoutsCount);
}
layoutTreeNode.setChildLayoutTreeNodes(childLayoutTreeNodes);
layoutTreeNodes.add(layoutTreeNode);
}
return new LayoutTreeNodes(layoutTreeNodes, layouts.size());
}
private static int _getLoadedLayoutsCount(
HttpSession session, long groupId, boolean privateLayout,
long layoutId, String treeId)
throws Exception {
StringBundler sb = new StringBundler(7);
sb.append(treeId);
sb.append(StringPool.COLON);
sb.append(groupId);
sb.append(StringPool.COLON);
sb.append(privateLayout);
sb.append(StringPool.COLON);
sb.append("Pagination");
String key = sb.toString();
String paginationJSON = SessionClicks.get(
session, key, JSONFactoryUtil.getNullJSON());
JSONObject paginationJSONObject = JSONFactoryUtil.createJSONObject(
paginationJSON);
if (_log.isDebugEnabled()) {
sb = new StringBundler(9);
sb.append("_getLoadedLayoutsCount(key=");
sb.append(key);
sb.append(", layoutId=");
sb.append(layoutId);
sb.append(", paginationJSON=");
sb.append(paginationJSON);
sb.append(", paginationJSONObject");
sb.append(paginationJSONObject);
sb.append(StringPool.CLOSE_PARENTHESIS);
_log.debug(sb.toString());
}
return paginationJSONObject.getInt(String.valueOf(layoutId), 0);
}
private static boolean _isDeleteable(
Layout layout, ThemeDisplay themeDisplay)
throws PortalException {
if (!LayoutPermissionUtil.contains(
themeDisplay.getPermissionChecker(), layout,
ActionKeys.DELETE)) {
return false;
}
Group group = layout.getGroup();
if (group.isGuest() && !layout.isPrivateLayout() &&
layout.isRootLayout() &&
(LayoutLocalServiceUtil.getLayoutsCount(
group, false, LayoutConstants.DEFAULT_PARENT_LAYOUT_ID) == 1)) {
return false;
}
return true;
}
private static boolean _isExpandableLayout(
HttpServletRequest request, List<Layout> ancestorLayouts,
long[] expandedLayoutIds, Layout layout) {
boolean expandParentLayouts = ParamUtil.getBoolean(
request, "expandParentLayouts");
if (expandParentLayouts || ancestorLayouts.contains(layout) ||
ArrayUtil.contains(expandedLayoutIds, layout.getLayoutId())) {
return true;
}
return false;
}
private static boolean _isPaginationEnabled(HttpServletRequest request) {
boolean paginate = ParamUtil.getBoolean(request, "paginate", true);
if (paginate &&
(PropsValues.LAYOUT_MANAGE_PAGES_INITIAL_CHILDREN > -1)) {
return true;
}
return false;
}
private static List<Layout> _paginateLayouts(
HttpServletRequest request, long groupId, boolean privateLayout,
long parentLayoutId, List<Layout> layouts, String treeId)
throws Exception {
if (!_isPaginationEnabled(request)) {
return layouts;
}
HttpSession session = request.getSession();
int loadedLayoutsCount = _getLoadedLayoutsCount(
session, groupId, privateLayout, parentLayoutId, treeId);
int start = ParamUtil.getInteger(request, "start");
start = Math.max(0, Math.min(start, layouts.size()));
int end = ParamUtil.getInteger(
request, "end",
start + PropsValues.LAYOUT_MANAGE_PAGES_INITIAL_CHILDREN);
if (loadedLayoutsCount > end) {
end = loadedLayoutsCount;
}
end = Math.max(start, Math.min(end, layouts.size()));
if (_log.isDebugEnabled()) {
StringBundler sb = new StringBundler(7);
sb.append("_paginateLayouts(loadedLayoutsCount=");
sb.append(loadedLayoutsCount);
sb.append(", start=");
sb.append(start);
sb.append(", end=");
sb.append(end);
sb.append(StringPool.CLOSE_PARENTHESIS);
_log.debug(sb.toString());
}
return layouts.subList(start, end);
}
private static String _toJSON(
HttpServletRequest request, long groupId,
LayoutTreeNodes layoutTreeNodes)
throws Exception {
JSONObject jsonObject = _toJSONObject(
request, groupId, layoutTreeNodes);
return jsonObject.toString();
}
private static JSONObject _toJSONObject(
HttpServletRequest request, long groupId,
LayoutTreeNodes layoutTreeNodes)
throws Exception {
if (_log.isDebugEnabled()) {
StringBundler sb = new StringBundler(5);
sb.append("_toJSON(groupId=");
sb.append(groupId);
sb.append(", layoutTreeNodes=");
sb.append(layoutTreeNodes);
sb.append(StringPool.CLOSE_PARENTHESIS);
_log.debug(sb.toString());
}
ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
WebKeys.THEME_DISPLAY);
JSONArray jsonArray = JSONFactoryUtil.createJSONArray();
boolean hasManageLayoutsPermission = GroupPermissionUtil.contains(
themeDisplay.getPermissionChecker(), groupId,
ActionKeys.MANAGE_LAYOUTS);
for (LayoutTreeNode layoutTreeNode : layoutTreeNodes) {
JSONObject jsonObject = JSONFactoryUtil.createJSONObject();
JSONObject childrenJSONObject = _toJSONObject(
request, groupId, layoutTreeNode.getChildLayoutTreeNodes());
jsonObject.put("children", childrenJSONObject);
Layout layout = layoutTreeNode.getLayout();
jsonObject.put("contentDisplayPage", layout.isContentDisplayPage());
jsonObject.put("deleteable", _isDeleteable(layout, themeDisplay));
jsonObject.put("friendlyURL", layout.getFriendlyURL());
if (layout instanceof VirtualLayout) {
VirtualLayout virtualLayout = (VirtualLayout)layout;
jsonObject.put("groupId", virtualLayout.getSourceGroupId());
}
else {
jsonObject.put("groupId", layout.getGroupId());
}
jsonObject.put("hasChildren", layout.hasChildren());
jsonObject.put("layoutId", layout.getLayoutId());
jsonObject.put("name", layout.getName(themeDisplay.getLocale()));
jsonObject.put(
"parentable",
LayoutPermissionUtil.contains(
themeDisplay.getPermissionChecker(), layout,
ActionKeys.ADD_LAYOUT));
jsonObject.put("parentLayoutId", layout.getParentLayoutId());
jsonObject.put("plid", layout.getPlid());
jsonObject.put("priority", layout.getPriority());
jsonObject.put("privateLayout", layout.isPrivateLayout());
jsonObject.put("regularURL", layout.getRegularURL(request));
jsonObject.put(
"sortable",
hasManageLayoutsPermission &&
SitesUtil.isLayoutSortable(layout));
jsonObject.put("type", layout.getType());
jsonObject.put(
"updateable",
LayoutPermissionUtil.contains(
themeDisplay.getPermissionChecker(), layout,
ActionKeys.UPDATE));
jsonObject.put("uuid", layout.getUuid());
LayoutRevision layoutRevision = LayoutStagingUtil.getLayoutRevision(
layout);
if (layoutRevision != null) {
long layoutSetBranchId = layoutRevision.getLayoutSetBranchId();
if (StagingUtil.isIncomplete(layout, layoutSetBranchId)) {
jsonObject.put("incomplete", true);
}
LayoutSetBranch layoutSetBranch =
LayoutSetBranchLocalServiceUtil.getLayoutSetBranch(
layoutSetBranchId);
LayoutBranch layoutBranch = layoutRevision.getLayoutBranch();
if (!layoutBranch.isMaster()) {
jsonObject.put(
"layoutBranchId", layoutBranch.getLayoutBranchId());
jsonObject.put("layoutBranchName", layoutBranch.getName());
}
if (layoutRevision.isHead()) {
jsonObject.put("layoutRevisionHead", true);
}
jsonObject.put(
"layoutRevisionId", layoutRevision.getLayoutRevisionId());
jsonObject.put("layoutSetBranchId", layoutSetBranchId);
jsonObject.put(
"layoutSetBranchName", layoutSetBranch.getName());
}
jsonArray.put(jsonObject);
}
JSONObject responseJSONObject = JSONFactoryUtil.createJSONObject();
responseJSONObject.put("layouts", jsonArray);
responseJSONObject.put("total", layoutTreeNodes.getTotal());
return responseJSONObject;
}
private static JSONObject _toJSONObject(
HttpServletRequest request, long groupId, List<Layout> layouts,
int total)
throws Exception {
List<LayoutTreeNode> layoutTreeNodesList = new ArrayList<>();
for (Layout layout : layouts) {
LayoutTreeNode layoutTreeNode = new LayoutTreeNode(layout);
layoutTreeNodesList.add(layoutTreeNode);
}
LayoutTreeNodes layoutTreeNodes = new LayoutTreeNodes(
layoutTreeNodesList, total);
return _toJSONObject(request, groupId, layoutTreeNodes);
}
private static final Log _log = LogFactoryUtil.getLog(
LayoutsTreeUtil.class);
private static class LayoutTreeNode {
public LayoutTreeNode(Layout layout) {
_layout = layout;
}
public LayoutTreeNodes getChildLayoutTreeNodes() {
return _childLayoutTreeNodes;
}
public Layout getLayout() {
return _layout;
}
public void setChildLayoutTreeNodes(
LayoutTreeNodes childLayoutTreeNodes) {
_childLayoutTreeNodes = childLayoutTreeNodes;
}
@Override
public String toString() {
StringBundler sb = new StringBundler(5);
sb.append("{childLayoutTreeNodes=");
sb.append(_childLayoutTreeNodes);
sb.append(", layout=");
sb.append(_layout);
sb.append(StringPool.CLOSE_CURLY_BRACE);
return sb.toString();
}
private LayoutTreeNodes _childLayoutTreeNodes = new LayoutTreeNodes();
private final Layout _layout;
}
private static class LayoutTreeNodes implements Iterable<LayoutTreeNode> {
public LayoutTreeNodes() {
_layoutTreeNodesList = new ArrayList<>();
}
public LayoutTreeNodes(
List<LayoutTreeNode> layoutTreeNodesList, int total) {
_layoutTreeNodesList = layoutTreeNodesList;
_total = total;
}
public void addAll(LayoutTreeNodes layoutTreeNodes) {
_layoutTreeNodesList.addAll(
layoutTreeNodes.getLayoutTreeNodesList());
_total += layoutTreeNodes.getTotal();
}
public List<LayoutTreeNode> getLayoutTreeNodesList() {
return _layoutTreeNodesList;
}
public int getTotal() {
return _total;
}
@Override
public Iterator<LayoutTreeNode> iterator() {
return _layoutTreeNodesList.iterator();
}
@Override
public String toString() {
StringBundler sb = new StringBundler(5);
sb.append("{layoutTreeNodesList=");
sb.append(_layoutTreeNodesList);
sb.append(", total=");
sb.append(_total);
sb.append(StringPool.CLOSE_CURLY_BRACE);
return sb.toString();
}
private final List<LayoutTreeNode> _layoutTreeNodesList;
private int _total;
}
}