001    /**
002     * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.util;
016    
017    import com.liferay.portal.kernel.cache.thread.local.Lifecycle;
018    import com.liferay.portal.kernel.cache.thread.local.ThreadLocalCache;
019    import com.liferay.portal.kernel.cache.thread.local.ThreadLocalCacheManager;
020    import com.liferay.portal.kernel.util.LocaleUtil;
021    import com.liferay.portal.kernel.util.ObjectValuePair;
022    import com.liferay.portal.kernel.util.StringBundler;
023    import com.liferay.portal.kernel.util.StringPool;
024    import com.liferay.portal.kernel.util.StringUtil;
025    import com.liferay.portal.model.Layout;
026    import com.liferay.portal.model.LayoutConstants;
027    import com.liferay.portal.model.impl.LayoutImpl;
028    import com.liferay.portal.service.LayoutLocalServiceUtil;
029    
030    import java.util.ArrayList;
031    import java.util.Deque;
032    import java.util.LinkedList;
033    import java.util.List;
034    import java.util.ListIterator;
035    import java.util.Locale;
036    
037    /**
038     * @author Brian Wing Shun Chan
039     * @author Shuyang Zhou
040     */
041    public class LayoutListUtil {
042    
043            public static List<LayoutDescription> getLayoutDescriptions(
044                    long groupId, boolean privateLayout, String rootNodeName,
045                    Locale locale) {
046    
047                    ThreadLocalCache<List<LayoutDescription>> threadLocalCache =
048                            ThreadLocalCacheManager.getThreadLocalCache(
049                                    Lifecycle.REQUEST, LayoutListUtil.class.getName());
050    
051                    String cacheKey = buildCacheKey(
052                            groupId, privateLayout, rootNodeName, locale);
053    
054                    List<LayoutDescription> layoutDescriptions = threadLocalCache.get(
055                            cacheKey);
056    
057                    if (layoutDescriptions == null) {
058                            layoutDescriptions = doGetLayoutDescriptions(
059                                    groupId, privateLayout, rootNodeName, locale);
060    
061                            threadLocalCache.put(cacheKey, layoutDescriptions);
062                    }
063    
064                    return layoutDescriptions;
065            }
066    
067            protected static String buildCacheKey(
068                    long groupId, boolean privateLayout, String rootNodeName,
069                    Locale locale) {
070    
071                    StringBundler sb = new StringBundler(7);
072    
073                    sb.append(StringUtil.toHexString(groupId));
074                    sb.append(StringPool.POUND);
075                    sb.append(privateLayout);
076                    sb.append(StringPool.POUND);
077                    sb.append(rootNodeName);
078                    sb.append(StringPool.POUND);
079                    sb.append(LocaleUtil.toLanguageId(locale));
080    
081                    return sb.toString();
082            }
083    
084            protected static List<LayoutDescription> doGetLayoutDescriptions(
085                    long groupId, boolean privateLayout, String rootNodeName,
086                    Locale locale) {
087    
088                    List<LayoutDescription> layoutDescriptions = new ArrayList<>();
089    
090                    List<Layout> layouts = new ArrayList<>(
091                            LayoutLocalServiceUtil.getLayouts(groupId, privateLayout));
092    
093                    Deque<ObjectValuePair<Layout, Integer>> deque = new LinkedList<>();
094    
095                    Layout rootLayout = new LayoutImpl();
096    
097                    rootLayout.setPlid(LayoutConstants.DEFAULT_PLID);
098                    rootLayout.setName(rootNodeName);
099    
100                    deque.push(new ObjectValuePair<Layout, Integer>(rootLayout, 0));
101    
102                    ObjectValuePair<Layout, Integer> objectValuePair = null;
103    
104                    while ((objectValuePair = deque.pollFirst()) != null) {
105                            Layout currentLayout = objectValuePair.getKey();
106    
107                            Integer currentDepth = objectValuePair.getValue();
108    
109                            layoutDescriptions.add(
110                                    new LayoutDescription(
111                                            currentLayout.getPlid(), currentLayout.getName(locale),
112                                            currentDepth));
113    
114                            ListIterator<Layout> listIterator = layouts.listIterator(
115                                    layouts.size());
116    
117                            while (listIterator.hasPrevious()) {
118                                    Layout previousLayout = listIterator.previous();
119    
120                                    if (previousLayout.getParentLayoutId() ==
121                                                    currentLayout.getLayoutId()) {
122    
123                                            listIterator.remove();
124    
125                                            deque.push(
126                                                    new ObjectValuePair<Layout, Integer>(
127                                                            previousLayout, currentDepth + 1));
128                                    }
129                            }
130                    }
131    
132                    return layoutDescriptions;
133            }
134    
135    }