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.layoutconfiguration.util.velocity;
016    
017    import com.liferay.portal.kernel.json.JSONFactoryUtil;
018    import com.liferay.portal.kernel.json.JSONObject;
019    import com.liferay.portal.kernel.portlet.PortletContainerUtil;
020    import com.liferay.portal.kernel.portlet.PortletJSONUtil;
021    import com.liferay.portal.kernel.portlet.PortletProvider;
022    import com.liferay.portal.kernel.portlet.PortletProviderUtil;
023    import com.liferay.portal.kernel.servlet.BufferCacheServletResponse;
024    import com.liferay.portal.kernel.settings.ModifiableSettings;
025    import com.liferay.portal.kernel.settings.PortletInstanceSettingsLocator;
026    import com.liferay.portal.kernel.settings.Settings;
027    import com.liferay.portal.kernel.settings.SettingsFactoryUtil;
028    import com.liferay.portal.kernel.util.ClassUtil;
029    import com.liferay.portal.kernel.util.GetterUtil;
030    import com.liferay.portal.kernel.util.StringBundler;
031    import com.liferay.portal.kernel.util.StringPool;
032    import com.liferay.portal.kernel.util.Validator;
033    import com.liferay.portal.kernel.util.WebKeys;
034    import com.liferay.portal.layoutconfiguration.util.PortletRenderer;
035    import com.liferay.portal.model.LayoutTypePortlet;
036    import com.liferay.portal.model.Portlet;
037    import com.liferay.portal.service.PortletLocalServiceUtil;
038    import com.liferay.portal.theme.ThemeDisplay;
039    
040    import java.util.ArrayList;
041    import java.util.Comparator;
042    import java.util.List;
043    import java.util.Map;
044    import java.util.TreeMap;
045    
046    import javax.servlet.http.HttpServletRequest;
047    import javax.servlet.http.HttpServletResponse;
048    
049    /**
050     * @author Ivica Cardic
051     * @author Brian Wing Shun Chan
052     * @author Shuyang Zhou
053     * @author Oliver Teichmann
054     */
055    public class TemplateProcessor implements ColumnProcessor {
056    
057            public TemplateProcessor(
058                    HttpServletRequest request, HttpServletResponse response,
059                    String portletId) {
060    
061                    _request = request;
062                    _response = response;
063    
064                    if (Validator.isNotNull(portletId)) {
065                            ThemeDisplay themeDisplay = (ThemeDisplay)request.getAttribute(
066                                    WebKeys.THEME_DISPLAY);
067    
068                            _portlet = PortletLocalServiceUtil.getPortletById(
069                                    themeDisplay.getCompanyId(), portletId);
070                    }
071                    else {
072                            _portlet = null;
073                    }
074    
075                    _portletAjaxRender = GetterUtil.getBoolean(
076                            request.getAttribute(WebKeys.PORTLET_AJAX_RENDER));
077    
078                    _portletRenderers = new TreeMap<>(_renderWeightComparator);
079            }
080    
081            public Map<Integer, List<PortletRenderer>> getPortletRenderers() {
082                    return _portletRenderers;
083            }
084    
085            public boolean isPortletAjaxRender() {
086                    return _portletAjaxRender;
087            }
088    
089            @Override
090            public String processColumn(String columnId) throws Exception {
091                    return processColumn(columnId, StringPool.BLANK);
092            }
093    
094            @Override
095            public String processColumn(String columnId, String classNames)
096                    throws Exception {
097    
098                    ThemeDisplay themeDisplay = (ThemeDisplay)_request.getAttribute(
099                            WebKeys.THEME_DISPLAY);
100    
101                    LayoutTypePortlet layoutTypePortlet =
102                            themeDisplay.getLayoutTypePortlet();
103    
104                    List<Portlet> portlets = layoutTypePortlet.getAllPortlets(columnId);
105    
106                    StringBundler sb = new StringBundler(portlets.size() * 3 + 11);
107    
108                    sb.append("<div class=\"");
109                    sb.append("portlet-dropzone");
110    
111                    if (layoutTypePortlet.isCustomizable() &&
112                            layoutTypePortlet.isColumnDisabled(columnId)) {
113    
114                            sb.append(" portlet-dropzone-disabled");
115                    }
116    
117                    if (layoutTypePortlet.isColumnCustomizable(columnId)) {
118                            sb.append(" customizable");
119                    }
120    
121                    if (portlets.isEmpty()) {
122                            sb.append(" empty");
123                    }
124    
125                    if (Validator.isNotNull(classNames)) {
126                            sb.append(" ");
127                            sb.append(classNames);
128                    }
129    
130                    sb.append("\" id=\"layout-column_");
131                    sb.append(columnId);
132                    sb.append("\">");
133    
134                    for (int i = 0; i < portlets.size(); i++) {
135                            Portlet portlet = portlets.get(i);
136    
137                            Integer columnCount = Integer.valueOf(portlets.size());
138                            Integer columnPos = Integer.valueOf(i);
139    
140                            PortletRenderer portletRenderer = new PortletRenderer(
141                                    portlet, columnId, columnCount, columnPos);
142    
143                            if (_portletAjaxRender && (portlet.getRenderWeight() < 1)) {
144                                    StringBundler renderResult = portletRenderer.renderAjax(
145                                            _request, _response);
146    
147                                    sb.append(renderResult);
148                            }
149                            else {
150                                    Integer renderWeight = portlet.getRenderWeight();
151    
152                                    List<PortletRenderer> portletRenderers = _portletRenderers.get(
153                                            renderWeight);
154    
155                                    if (portletRenderers == null) {
156                                            portletRenderers = new ArrayList<>();
157    
158                                            _portletRenderers.put(renderWeight, portletRenderers);
159                                    }
160    
161                                    portletRenderers.add(portletRenderer);
162    
163                                    sb.append("[$TEMPLATE_PORTLET_");
164                                    sb.append(portlet.getPortletId());
165                                    sb.append("$]");
166                            }
167                    }
168    
169                    sb.append("</div>");
170    
171                    return sb.toString();
172            }
173    
174            @Override
175            public String processMax() throws Exception {
176                    BufferCacheServletResponse bufferCacheServletResponse =
177                            new BufferCacheServletResponse(_response);
178    
179                    PortletContainerUtil.render(
180                            _request, bufferCacheServletResponse, _portlet);
181    
182                    return bufferCacheServletResponse.getString();
183            }
184    
185            /**
186             * @deprecated As of 6.2.0, replaced by {@link #processMax()}
187             */
188            @Deprecated
189            @Override
190            public String processMax(String classNames) throws Exception {
191                    return processMax();
192            }
193    
194            @Override
195            public String processPortlet(String portletId) throws Exception {
196                    _request.setAttribute(WebKeys.RENDER_PORTLET_RESOURCE, Boolean.TRUE);
197    
198                    BufferCacheServletResponse bufferCacheServletResponse =
199                            new BufferCacheServletResponse(_response);
200    
201                    ThemeDisplay themeDisplay = (ThemeDisplay)_request.getAttribute(
202                            WebKeys.THEME_DISPLAY);
203    
204                    Portlet portlet = PortletLocalServiceUtil.getPortletById(
205                            themeDisplay.getCompanyId(), portletId);
206    
207                    JSONObject jsonObject = JSONFactoryUtil.createJSONObject();
208    
209                    PortletJSONUtil.populatePortletJSONObject(
210                            _request, StringPool.BLANK, portlet, jsonObject);
211    
212                    try {
213                            PortletJSONUtil.writeHeaderPaths(_response, jsonObject);
214    
215                            PortletContainerUtil.render(
216                                    _request, bufferCacheServletResponse, portlet);
217    
218                            PortletJSONUtil.writeFooterPaths(_response, jsonObject);
219    
220                            return bufferCacheServletResponse.getString();
221                    }
222                    finally {
223                            _request.removeAttribute(WebKeys.RENDER_PORTLET_RESOURCE);
224                    }
225            }
226    
227            @Override
228            public String processPortlet(
229                            String portletId, Map<String, ?> defaultSettingsMap)
230                    throws Exception {
231    
232                    ThemeDisplay themeDisplay = (ThemeDisplay)_request.getAttribute(
233                            WebKeys.THEME_DISPLAY);
234    
235                    Settings settings = SettingsFactoryUtil.getSettings(
236                            new PortletInstanceSettingsLocator(
237                                    themeDisplay.getLayout(), portletId));
238    
239                    ModifiableSettings modifiableSettings =
240                            settings.getModifiableSettings();
241    
242                    for (Map.Entry<String, ?> entry : defaultSettingsMap.entrySet()) {
243                            String key = entry.getKey();
244                            Object value = entry.getValue();
245    
246                            if (value instanceof String) {
247                                    modifiableSettings.setValue(key, (String)value);
248                            }
249                            else if (value instanceof String[]) {
250                                    modifiableSettings.setValues(key, (String[])value);
251                            }
252                            else {
253                                    throw new IllegalArgumentException(
254                                            "Key " + key + " has unsupported value of type " +
255                                                    ClassUtil.getClassName(value.getClass()));
256                            }
257                    }
258    
259                    modifiableSettings.store();
260    
261                    return processPortlet(portletId);
262            }
263    
264            @Override
265            public String processPortlet(
266                            String portletProviderClassName,
267                            PortletProvider.Action portletProviderAction)
268                    throws Exception {
269    
270                    String portletId = PortletProviderUtil.getPortletId(
271                            portletProviderClassName, portletProviderAction);
272    
273                    return processPortlet(portletId);
274            }
275    
276            private static final RenderWeightComparator _renderWeightComparator =
277                    new RenderWeightComparator();
278    
279            private final Portlet _portlet;
280            private final boolean _portletAjaxRender;
281            private final Map<Integer, List<PortletRenderer>> _portletRenderers;
282            private final HttpServletRequest _request;
283            private final HttpServletResponse _response;
284    
285            private static class RenderWeightComparator implements Comparator<Integer> {
286    
287                    @Override
288                    public int compare(Integer renderWeight1, Integer renderWeight2) {
289                            return renderWeight2.intValue() - renderWeight1.intValue();
290                    }
291    
292            }
293    
294    }