001    /**
002     * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
003     *
004     * The contents of this file are subject to the terms of the Liferay Enterprise
005     * Subscription License ("License"). You may not use this file except in
006     * compliance with the License. You can obtain a copy of the License by
007     * contacting Liferay, Inc. See the License for the specific language governing
008     * permissions and limitations under the License, including but not limited to
009     * distribution rights of the Software.
010     *
011     *
012     *
013     */
014    
015    package com.liferay.portal.util;
016    
017    import com.liferay.portal.kernel.cache.Lifecycle;
018    import com.liferay.portal.kernel.cache.ThreadLocalCache;
019    import com.liferay.portal.kernel.cache.ThreadLocalCacheManager;
020    import com.liferay.portal.kernel.exception.PortalException;
021    import com.liferay.portal.kernel.exception.SystemException;
022    import com.liferay.portal.kernel.util.LocaleUtil;
023    import com.liferay.portal.kernel.util.ObjectValuePair;
024    import com.liferay.portal.kernel.util.StringBundler;
025    import com.liferay.portal.kernel.util.StringPool;
026    import com.liferay.portal.kernel.util.StringUtil;
027    import com.liferay.portal.model.Layout;
028    import com.liferay.portal.model.LayoutConstants;
029    import com.liferay.portal.model.impl.LayoutImpl;
030    import com.liferay.portal.service.LayoutLocalServiceUtil;
031    
032    import java.util.ArrayList;
033    import java.util.Deque;
034    import java.util.LinkedList;
035    import java.util.List;
036    import java.util.ListIterator;
037    import java.util.Locale;
038    
039    /**
040     * @author Brian Wing Shun Chan
041     * @author Shuyang Zhou
042     */
043    public class LayoutLister {
044    
045            public List<LayoutDescription> getLayoutDescriptions(
046                            long groupId, boolean privateLayout, String rootNodeName,
047                            Locale locale)
048                    throws PortalException, SystemException {
049    
050                    ThreadLocalCache<List<LayoutDescription>> threadLocalCache =
051                            ThreadLocalCacheManager.getThreadLocalCache(
052                                    Lifecycle.REQUEST, LayoutLister.class.getName());
053    
054                    String cacheKey = buildCacheKey(
055                            groupId, privateLayout, rootNodeName, locale);
056    
057                    List<LayoutDescription> layoutDescriptions = threadLocalCache.get(
058                            cacheKey);
059    
060                    if (layoutDescriptions == null) {
061                            layoutDescriptions = doGetLayoutDescriptions(
062                                    groupId, privateLayout, rootNodeName, locale);
063    
064                            threadLocalCache.put(cacheKey, layoutDescriptions);
065                    }
066    
067                    return layoutDescriptions;
068            }
069    
070            protected static String buildCacheKey(
071                    long groupId, boolean privateLayout, String rootNodeName,
072                    Locale locale) {
073    
074                    StringBundler sb = new StringBundler(7);
075    
076                    sb.append(StringUtil.toHexString(groupId));
077                    sb.append(StringPool.POUND);
078                    sb.append(privateLayout);
079                    sb.append(StringPool.POUND);
080                    sb.append(rootNodeName);
081                    sb.append(StringPool.POUND);
082                    sb.append(LocaleUtil.toLanguageId(locale));
083    
084                    return sb.toString();
085            }
086    
087            protected static List<LayoutDescription> doGetLayoutDescriptions(
088                            long groupId, boolean privateLayout, String rootNodeName,
089                            Locale locale)
090                    throws PortalException, SystemException {
091    
092                    List<LayoutDescription> layoutDescriptions =
093                            new ArrayList<LayoutDescription>();
094    
095                    List<Layout> layouts = new ArrayList<Layout>(
096                            LayoutLocalServiceUtil.getLayouts(groupId, privateLayout));
097    
098                    Deque<ObjectValuePair<Layout, Integer>> deque =
099                            new LinkedList<ObjectValuePair<Layout, Integer>>();
100    
101                    Layout rootLayout = new LayoutImpl();
102    
103                    rootLayout.setPlid(LayoutConstants.DEFAULT_PLID);
104                    rootLayout.setName(rootNodeName);
105    
106                    deque.push(new ObjectValuePair<Layout, Integer>(rootLayout, 0));
107    
108                    ObjectValuePair<Layout, Integer> objectValuePair = null;
109    
110                    while ((objectValuePair = deque.pollFirst()) != null) {
111                            Layout currentLayout = objectValuePair.getKey();
112    
113                            Integer currentDepth = objectValuePair.getValue();
114    
115                            layoutDescriptions.add(
116                                    new LayoutDescription(
117                                            currentLayout.getPlid(), currentLayout.getName(locale),
118                                            currentDepth));
119    
120                            ListIterator<Layout> listIterator = layouts.listIterator(
121                                    layouts.size());
122    
123                            while (listIterator.hasPrevious()) {
124                                    Layout previousLayout = listIterator.previous();
125    
126                                    if (previousLayout.getParentLayoutId() ==
127                                                    currentLayout.getLayoutId()) {
128    
129                                            listIterator.remove();
130    
131                                            deque.push(
132                                                    new ObjectValuePair<Layout, Integer>(
133                                                            previousLayout, currentDepth + 1));
134                                    }
135                            }
136                    }
137    
138                    return layoutDescriptions;
139            }
140    
141    }